-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.js
118 lines (96 loc) · 2.33 KB
/
parser.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// This implementation only focus on element matching and quantifiers
/*
Elements: Literals => a, b
Wild cards => .
Escaped => \.
Groups => (a+c)
Quantifiers: Optional (one or zero) => ?
Zero or more => *
One or more => +
*/
const parseRegex = (regex) => {
// The state will keep the state of matching // Stack up buy parser // Queue down by matcher
// The parent array keep the state of the whole regex string
// The child array consider as a group. Initially there is a one group.
const state = [[]]
let index = 0
// Last method return last element of state
const last = (array) => {
return array ? array[array.length - 1] : state[state.length - 1]
}
while (index < regex.length) {
const matcher = regex[index]
if (matcher === '(') {
// New group introduced. Need to add new child array to state array to keep group state
state.push([])
index++
continue
}
if (matcher === ')') {
// End of a group. Should close the group state and push to main state
if (state.length === 1) {
throw Exception('Unclosed group in index: ' + index)
}
const groupState = state.pop()
last().push({
type: 'ElementGroup',
groupState,
quantifier: 'OnlyOne'
})
index++
continue
}
if (matcher === '.') {
last().push({
type: 'WildCard',
quantifier: 'OnlyOne'
})
index++
continue
}
if (matcher === '\\') {
if (regex.length === index + 1) {
throw Exception('Unsupported escape character at index: ' + index)
}
last().push({
type: 'Element',
value: regex[++index],
quantifier: 'OnlyOne'
})
index++
continue
}
if (matcher === '?') {
// Zero or one quantifire
last(last()).quantifier = 'ZeroOrOne'
index++
continue
}
if (matcher === '*') {
// Zero or one quantifire
last(last()).quantifier = 'ZeroOrMore'
index++
continue
}
if (matcher === '+') {
// One or more = OnlyOne + ZeroOrMore
last().push({...last(last()), quantifier: 'ZeroOrMore'})
index++
continue
}
// Default element state
last().push({
type: 'Element',
value: regex[index],
quantifier: 'OnlyOne'
})
index++
}
if (state.length !== 1) {
throw Exception('Unclosed group detected')
}
return last()
};
const regex = 'ab?(a*b)+c.\\.d'
console.log(regex)
console.table(parseRegex(regex))