1 module tern.regex.matcher; 2 3 import tern.state; 4 import tern.regex.builder; 5 import std.string; 6 import std.conv; 7 import std.algorithm; 8 import std.stdio; 9 10 package class State 11 { 12 package: 13 final: 14 Element[] elements; 15 uint next; 16 ubyte flags; 17 uint index; 18 } 19 20 package: 21 static: 22 pragma(inline, true) 23 pure bool isFulfilled(Element element, State state, string text) 24 { 25 const bool qlazy = element.modifiers.hasFlag(LAZY); 26 const bool qdef = state.next != -1 && !element.modifiers.hasFlag(GREEDY) && !qlazy; 27 foreach (k; 0..element.max) 28 { 29 if (qlazy && k >= element.min) 30 return true; 31 else if (qdef && k >= element.min && state.elements[state.next].isFulfilled(state, text)) 32 return true; 33 34 if (k != 0) 35 state.index++; 36 37 if (state.index >= text.length) 38 { 39 state.index--; 40 return k >= element.min; 41 } 42 43 switch (element.token) 44 { 45 case CHARACTERS: 46 bool match; 47 foreach (c; element.str) 48 { 49 if (text[state.index] == c) 50 match = true; 51 } 52 53 if (element.modifiers.hasFlag(EXCLUSIONARY) ? match : !match) 54 return k >= element.min; 55 break; 56 57 case ANCHOR_START: 58 return state.index == 0 || (state.flags.hasFlag(MULTILINE) && (text[state.index - 1] == '\r' || text[state.index - 1] == '\n' || text[state.index - 1] == '\f')); 59 60 case ANCHOR_END: 61 return state.index >= text.length || (state.flags.hasFlag(MULTILINE) && (text[state.index + 1] == '\r' || text[state.index + 1] == '\n' || text[state.index + 1] == '\f' || text[state.index + 1] == '\0')); 62 63 case ANY: 64 if (!state.flags.hasFlag(SINGLELINE) && (text[state.index] == '\r' || text[state.index] == '\n' || text[state.index] == '\f')) 65 return k >= element.min; 66 break; 67 68 case REFERENCE: 69 70 71 default: 72 return false; 73 } 74 } 75 return true; 76 } 77 78 pragma(inline, true) 79 pure string[][] matchInternal(Element[] elements, ubyte flags, string text, uint stopAt = -1) 80 { 81 string[][] matches; 82 int k = 0; 83 int g = 1; 84 int j = 0; 85 86 State state = new State(); 87 state.elements = elements; 88 state.flags = flags; 89 90 while (state.index < text.length) 91 { 92 if (matches.length == 0 || matches[$-1] != null) 93 { 94 matches ~= null; 95 matches[$-1] ~= null; 96 } 97 98 for (; j < elements.length; j++) 99 { 100 Element element = elements[j]; 101 debug element.str.writeln; 102 debug state.index.writeln; 103 uint ci = state.index; 104 state.next = j + 1 >= elements.length ? -1 : j + 1; 105 106 if (stopAt == matches.length || (element.token != ANCHOR_END && state.index >= text.length)) 107 { 108 if (elements.length != 0 && j != elements.length) 109 matches = matches[0..$-1]; 110 111 if (matches.length != 0 && matches[$-1] == null) 112 return matches[0..$-1]; 113 else 114 return matches; 115 } 116 117 if (element.isFulfilled(state, text)) 118 { 119 debug "fulfilled".writeln; 120 if (state.index != ci) 121 state.index--; 122 123 if (element.min != 0 || element.modifiers.hasFlag(QUANTIFIED)) 124 matches[k][0] ~= text[ci..++state.index]; 125 } 126 else if (element.token == RESET) 127 { 128 debug "reset".writeln; 129 matches[k] = null; 130 } 131 else if (element.modifiers.hasFlag(ALTERNATE)) 132 { 133 debug "skipped".writeln; 134 continue; 135 } 136 else 137 { 138 debug "unfulfilled".writeln; 139 if (!elements[0].isFulfilled(state, text)) 140 state.index++; 141 142 matches[k] = new string[1]; 143 debug writeln(matches[k][0] == null); 144 j = -1; 145 } 146 } 147 148 if (state.index >= text.length - 1) 149 break; 150 151 if (matches[$-1][0] != null) 152 k++; 153 j = 0; 154 } 155 156 if (elements.length != 0 && j != elements.length) 157 matches = matches[0..$-1]; 158 159 if (matches.length != 0 && matches[$-1] == null) 160 return matches[0..$-1]; 161 else 162 return matches; 163 }