-
Notifications
You must be signed in to change notification settings - Fork 4
/
match.js
99 lines (86 loc) · 2.3 KB
/
match.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import Input from "./Input.js";
function matchInput(input, state, callSiteMap = new Map()) {
// avoid already failed match
if (this.getCacheResultIndexMap(input).get(state) === false) {
return false;
}
// endless loop
if (callSiteMap.get(state) === input.index) {
return false;
}
callSiteMap.set(state, input.index);
let groupStartIndex = this.compiler.groupStartIndex(state);
if (groupStartIndex) {
groupStartIndex--;
input.startGroupIndex[groupStartIndex] = input.index;
}
let groupEndIndex = this.compiler.groupEndIndex(state);
if (groupEndIndex) {
groupEndIndex--;
const index = input.startGroupIndex[groupEndIndex];
input.groups[groupEndIndex] = {
index,
match: input.getString(index - input.index)
};
}
if (!state.transitions.length) {
return input;
}
for (const t of state.transitions) {
let newInput = input.clone();
const find = t.perform(newInput);
if (find) {
if (find.count) {
newInput.advance(find.count);
}
const ret = matchInput.call(this, newInput, t.to, callSiteMap);
if (ret) {
return ret;
}
} else {
continue;
}
}
callSiteMap.delete(state);
this.getCacheResultIndexMap(input).set(state, false);
return false;
}
export class Matcher {
constructor(compiler, string, options) {
this.input = new Input(string, options);
this.compiler = compiler;
this.cacheResult = [];
}
reset() {
this.input.reset();
this.cacheResult = [];
}
getCacheResultIndexMap(input) {
const cacheMap = (this.cacheResult[input.index] =
this.cacheResult[input.index] || new Map());
return cacheMap;
}
match() {
let { input } = this;
do {
this.cacheResult = [];
let matchedInput = matchInput.call(this, input, this.compiler.startState);
if (matchedInput) {
input = matchedInput;
this.input = input;
const { startIndex, index } = input;
const matchString = input.getString(startIndex - index);
const ret = {
input: input.str,
match: matchString,
index: startIndex,
groups: input.groups
};
input.advanceMatch();
return ret;
}
input.advanceStartIndex();
} while (!input.isEnd());
return null;
}
}