A minimal implementation of a regular expression engine. @author Johannes Schindelin
| 16 | * @author Johannes Schindelin |
| 17 | */ |
| 18 | class PikeVM implements PikeVMOpcodes { |
| 19 | private final int[] program; |
| 20 | private final int groupCount; |
| 21 | private final int offsetsCount; |
| 22 | /* |
| 23 | * For find(), we do not want to anchor the match at the start offset. Our |
| 24 | * compiler allows this by prefixing the code with an implicit '(?:.*?)'. For |
| 25 | * regular matches() calls, we want to skip that code and start at {@code |
| 26 | * findPrefixLength} instead. |
| 27 | */ |
| 28 | private final int findPrefixLength; |
| 29 | private final CharacterMatcher[] classes; |
| 30 | private final PikeVM[] lookarounds; |
| 31 | private final static CharacterMatcher wordCharacter = |
| 32 | CharacterMatcher.parse("\\w"); |
| 33 | private final static CharacterMatcher lineTerminator = |
| 34 | CharacterMatcher.parse("[\n\r\u0085\u2028\u2029]"); |
| 35 | private boolean multiLine; |
| 36 | |
| 37 | public interface Result { |
| 38 | void set(int[] start, int[] end); |
| 39 | } |
| 40 | |
| 41 | protected PikeVM(int[] program, int findPrefixLength, int groupCount, |
| 42 | CharacterMatcher[] classes, PikeVM[] lookarounds) |
| 43 | { |
| 44 | this.program = program; |
| 45 | this.findPrefixLength = findPrefixLength; |
| 46 | this.groupCount = groupCount; |
| 47 | offsetsCount = 2 * groupCount + 2; |
| 48 | this.classes = classes; |
| 49 | this.lookarounds = lookarounds; |
| 50 | } |
| 51 | |
| 52 | /** |
| 53 | * The current thread states. |
| 54 | * <p> |
| 55 | * The threads are identified by their program counter. The rationale: as all |
| 56 | * threads are executed in lock-step, i.e. for the same character in the |
| 57 | * string to be matched, it does not make sense for two threads to be at the |
| 58 | * same program counter -- they would both do exactly the same for the rest of |
| 59 | * the execution. |
| 60 | * </p> |
| 61 | * <p> |
| 62 | * For efficiency, the threads are kept in a linked list that actually lives |
| 63 | * in an array indexed by the program counter, pointing to the next thread's |
| 64 | * program counter, in the order of high to low priority. |
| 65 | * </p> |
| 66 | * <p> |
| 67 | * Program counters which have no thread associated thread are marked as -1. |
| 68 | * The program counter associated with the least-priority thread (the last one |
| 69 | * in the linked list) is marked as -2 to be able to tell it apart from |
| 70 | * unscheduled threads. |
| 71 | * </p> |
| 72 | * <p> |
| 73 | * We actually never need to have an explicit value for the priority, the |
| 74 | * ordering is sufficient: whenever a new thread is to be scheduled and it is |
| 75 | * found to be scheduled already, it was already scheduled by a |