grammar-composer 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/parser-generator/Grammar.d.ts +4 -4
- package/dist/parser-generator/Grammar.d.ts.map +1 -1
- package/dist/parser-generator/Grammar.js +51 -38
- package/dist/parser-generator/Grammar.js.map +1 -1
- package/dist/parser-generator/TopDownParser.d.ts.map +1 -1
- package/dist/parser-generator/TopDownParser.js +11 -13
- package/dist/parser-generator/TopDownParser.js.map +1 -1
- package/dist/tests/Test.js +15 -5
- package/dist/tests/Test.js.map +1 -1
- package/dist/tests/test-grammars/RegExpGrammar.d.ts +26 -20
- package/dist/tests/test-grammars/RegExpGrammar.d.ts.map +1 -1
- package/dist/tests/test-grammars/RegExpGrammar.js +78 -51
- package/dist/tests/test-grammars/RegExpGrammar.js.map +1 -1
- package/dist/tests/test-grammars/SimpleTestGrammar1.d.ts +5 -0
- package/dist/tests/test-grammars/SimpleTestGrammar1.d.ts.map +1 -0
- package/dist/tests/test-grammars/SimpleTestGrammar1.js +7 -0
- package/dist/tests/test-grammars/SimpleTestGrammar1.js.map +1 -0
- package/dist/utilities/Utilities.d.ts +7 -7
- package/dist/utilities/Utilities.d.ts.map +1 -1
- package/dist/utilities/Utilities.js.map +1 -1
- package/package.json +2 -2
- package/src/parser-generator/Grammar.ts +63 -45
- package/src/parser-generator/TopDownParser.ts +12 -18
- package/src/tests/Test.ts +21 -7
- package/src/tests/test-grammars/RegExpGrammar.ts +170 -92
- package/src/tests/test-grammars/SimpleTestGrammar1.ts +10 -0
- package/src/utilities/Utilities.ts +7 -7
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isNumber } from '../utilities/Utilities.js'
|
|
1
2
|
import { Grammar, GrammarElement, Terminal } from './Grammar.js'
|
|
2
3
|
|
|
3
4
|
export function parse(inputString: string, grammar: Grammar<any>) {
|
|
@@ -18,37 +19,30 @@ export function parse(inputString: string, grammar: Grammar<any>) {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
function tryParse(grammarElement: GrammarElement, startOffset: number): ParseResult | null {
|
|
21
|
-
if (grammarElement.
|
|
22
|
+
if (isNumber(grammarElement.cacheId)) {
|
|
22
23
|
return tryParseCached(grammarElement, startOffset)
|
|
23
24
|
} else {
|
|
24
25
|
return tryParseUncached(grammarElement, startOffset)
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
const offsetMultiplier = grammar.maxCacheId + 1
|
|
29
30
|
|
|
30
|
-
const
|
|
31
|
+
const parseResultsCache = new Map<number, ParseResult | null>()
|
|
31
32
|
|
|
32
33
|
function tryParseCached(grammarElement: GrammarElement, startOffset: number): ParseResult | null {
|
|
33
|
-
|
|
34
|
+
const cacheId = grammarElement.cacheId!
|
|
35
|
+
const cacheKey = (startOffset * offsetMultiplier) + cacheId
|
|
34
36
|
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
cachedParseResults[startOffset] = slot
|
|
37
|
+
if (parseResultsCache.has(cacheKey)) {
|
|
38
|
+
return parseResultsCache.get(cacheKey)!
|
|
39
39
|
} else {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
if (cachedResult !== undefined) {
|
|
43
|
-
return cachedResult
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const parseResult = tryParseUncached(grammarElement, startOffset)
|
|
40
|
+
const parseResult = tryParseUncached(grammarElement, startOffset)
|
|
48
41
|
|
|
49
|
-
|
|
42
|
+
parseResultsCache.set(cacheKey, parseResult)
|
|
50
43
|
|
|
51
|
-
|
|
44
|
+
return parseResult
|
|
45
|
+
}
|
|
52
46
|
}
|
|
53
47
|
|
|
54
48
|
function tryParseUncached(grammarElement: GrammarElement, startOffset: number): ParseResult | null {
|
package/src/tests/Test.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { anyOf, buildGrammar } from '../exports/Exports.js'
|
|
|
4
4
|
import { JsonGrammar } from './test-grammars/JsonGrammar.js'
|
|
5
5
|
import { XmlGrammar } from './test-grammars/XmlGrammar.js'
|
|
6
6
|
import { RegExpGrammar } from './test-grammars/RegExpGrammar.js'
|
|
7
|
+
import { writeFile } from 'fs/promises'
|
|
8
|
+
import { SimpleTestGrammar1 } from './test-grammars/SimpleTestGrammar1.js'
|
|
7
9
|
|
|
8
10
|
const log = console.log
|
|
9
11
|
|
|
@@ -83,9 +85,11 @@ function testXmlParser() {
|
|
|
83
85
|
|
|
84
86
|
async function testRegExpParser() {
|
|
85
87
|
const regExpString = /^([+]?[1]?(1 )?[-.+]?\(?\d{1}[- .+]*\d{1}[- .+]*\d{1}\)?[- .+]*\d{1}[- .+]*\d{1}[- .+]*\d{1}[- .+]*\d{1}[- .+]*\d{1}[- .+]*\d{1}[- .+]*\d{1})$/.source
|
|
86
|
-
//const regExpString = /^
|
|
88
|
+
//const regExpString = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.source
|
|
89
|
+
//const regExpString = /(?=.*[!@#$%^&*])^mongodb:\/\/(?<user>[a-zA-Z0-9]+):(?<pass>[a-zA-Z0-9!@#$%^&*]{8,})@(?<host>[a-z0-9.-]+):(?<port>\d{2,5})$/.source
|
|
90
|
+
//const regExpString = /(abcd)*ef+g/.source
|
|
87
91
|
|
|
88
|
-
const grammar = buildGrammar(RegExpGrammar, '
|
|
92
|
+
const grammar = buildGrammar(RegExpGrammar, 'root')
|
|
89
93
|
|
|
90
94
|
const parseTree = grammar.parse(regExpString)
|
|
91
95
|
|
|
@@ -93,13 +97,10 @@ async function testRegExpParser() {
|
|
|
93
97
|
|
|
94
98
|
log(parseTreeJson)
|
|
95
99
|
|
|
96
|
-
const { writeFile } = await import('fs/promises')
|
|
97
|
-
|
|
98
100
|
await writeFile('out/out.json', parseTreeJson)
|
|
99
101
|
}
|
|
100
102
|
|
|
101
|
-
|
|
102
|
-
async function testParserError1() {
|
|
103
|
+
function testParserError1() {
|
|
103
104
|
const xmlData = `<hello> wo rld <!!! `
|
|
104
105
|
|
|
105
106
|
const grammar = buildGrammar(XmlGrammar, 'document')
|
|
@@ -109,7 +110,7 @@ async function testParserError1() {
|
|
|
109
110
|
console.log(JSON.stringify(result, undefined, 4))
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
|
|
113
|
+
function testParserError2() {
|
|
113
114
|
const jsonData = `{ "asdf": 12.5 `
|
|
114
115
|
|
|
115
116
|
const grammar = buildGrammar(JsonGrammar, 'expression')
|
|
@@ -119,6 +120,19 @@ async function testParserError2() {
|
|
|
119
120
|
console.log(JSON.stringify(result, undefined, 4))
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
function test1() {
|
|
124
|
+
const input = `abcdefg`
|
|
125
|
+
|
|
126
|
+
const grammar = buildGrammar(SimpleTestGrammar1, 'root')
|
|
127
|
+
|
|
128
|
+
const result = grammar.parse(input)
|
|
129
|
+
|
|
130
|
+
console.log(JSON.stringify(result, undefined, 4))
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
122
134
|
//testJsonParser()
|
|
123
135
|
|
|
124
136
|
testRegExpParser()
|
|
137
|
+
|
|
138
|
+
//test1()
|
|
@@ -5,99 +5,130 @@ export class RegExpGrammar {
|
|
|
5
5
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
6
6
|
// High-level productions
|
|
7
7
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
8
|
+
root = () => this.sequenceOrDisjunction
|
|
9
|
+
|
|
8
10
|
disjunction = () => [
|
|
9
11
|
this.sequence,
|
|
10
12
|
|
|
11
|
-
G.
|
|
12
|
-
|
|
13
|
-
this.
|
|
13
|
+
G.oneOrMore([
|
|
14
|
+
'|',
|
|
15
|
+
this.sequence,
|
|
14
16
|
])
|
|
15
17
|
]
|
|
16
18
|
|
|
17
|
-
sequence = () => G.
|
|
18
|
-
|
|
19
|
-
element = () => G.anyOf(
|
|
20
|
-
this.anchor,
|
|
21
|
-
this.lookaround,
|
|
22
|
-
this.possiblyQuantifiedExpression,
|
|
19
|
+
sequence = () => G.cached(
|
|
20
|
+
G.zeroOrMore(this.sequenceElement)
|
|
23
21
|
)
|
|
24
22
|
|
|
23
|
+
sequenceOrDisjunction = [
|
|
24
|
+
G.anyOf(
|
|
25
|
+
this.disjunction,
|
|
26
|
+
this.sequence,
|
|
27
|
+
)
|
|
28
|
+
]
|
|
29
|
+
|
|
25
30
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
26
|
-
//
|
|
31
|
+
// Quantifier expressions
|
|
27
32
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
this.singleCharExpression
|
|
33
|
-
),
|
|
33
|
+
starQuantifier = () => [
|
|
34
|
+
'*',
|
|
35
|
+
G.possibly(this.nongreedyQuantifier)
|
|
36
|
+
]
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this.countRangeQuantifier,
|
|
40
|
-
)),
|
|
38
|
+
plusQuantifier = () => [
|
|
39
|
+
'+',
|
|
40
|
+
G.possibly(this.nongreedyQuantifier)
|
|
41
|
+
]
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
optionalQuantifier = () => [
|
|
44
|
+
'?',
|
|
45
|
+
G.possibly(this.nongreedyQuantifier)
|
|
43
46
|
]
|
|
44
47
|
|
|
45
|
-
exactCountQuantifier = () =>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
exactCountQuantifier = () => [
|
|
49
|
+
G.pattern([
|
|
50
|
+
'{',
|
|
51
|
+
R.captureAs('count',
|
|
52
|
+
R.oneOrMore(digit)
|
|
53
|
+
),
|
|
54
|
+
'}',
|
|
55
|
+
]),
|
|
56
|
+
G.possibly(this.nongreedyQuantifier)
|
|
57
|
+
]
|
|
50
58
|
|
|
51
|
-
countRangeQuantifier = () =>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
countRangeQuantifier = () => [
|
|
60
|
+
G.pattern([
|
|
61
|
+
'{',
|
|
62
|
+
R.captureAs('start',
|
|
63
|
+
R.oneOrMore(digit)
|
|
64
|
+
),
|
|
65
|
+
',',
|
|
66
|
+
R.possibly(R.captureAs('end',
|
|
67
|
+
R.oneOrMore(digit))
|
|
68
|
+
),
|
|
69
|
+
'}',
|
|
70
|
+
]),
|
|
71
|
+
G.possibly(this.nongreedyQuantifier)
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
nongreedyQuantifier = () => '?'
|
|
75
|
+
|
|
76
|
+
quantifier = () => G.anyOf(
|
|
77
|
+
this.starQuantifier,
|
|
78
|
+
this.plusQuantifier,
|
|
79
|
+
this.optionalQuantifier,
|
|
80
|
+
this.exactCountQuantifier,
|
|
81
|
+
this.countRangeQuantifier,
|
|
82
|
+
)
|
|
58
83
|
|
|
59
84
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
60
85
|
// Group expressions
|
|
61
86
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
62
|
-
group = () => G.anyOf(
|
|
63
|
-
this.uncapturedGroup,
|
|
64
|
-
this.namedCaptureGroup,
|
|
65
|
-
this.unnamedCaptureGroup,
|
|
66
|
-
)
|
|
67
|
-
|
|
68
87
|
uncapturedGroup = () => [
|
|
69
88
|
'(?:',
|
|
70
|
-
this.
|
|
89
|
+
this.sequenceOrDisjunction,
|
|
71
90
|
')',
|
|
72
91
|
]
|
|
73
92
|
|
|
74
93
|
namedCaptureGroup = () => [
|
|
75
94
|
'(?<',
|
|
76
|
-
G.pattern(R.captureAs('name',
|
|
95
|
+
G.pattern(R.captureAs('name',
|
|
96
|
+
R.oneOrMore(identifierChar))
|
|
97
|
+
),
|
|
77
98
|
'>',
|
|
78
|
-
this.
|
|
99
|
+
this.sequenceOrDisjunction,
|
|
79
100
|
')',
|
|
80
101
|
]
|
|
81
102
|
|
|
82
103
|
unnamedCaptureGroup = () => [
|
|
83
104
|
'(',
|
|
84
|
-
this.
|
|
105
|
+
this.sequenceOrDisjunction,
|
|
85
106
|
')',
|
|
86
107
|
]
|
|
87
108
|
|
|
109
|
+
group = G.anyOf(
|
|
110
|
+
this.uncapturedGroup,
|
|
111
|
+
this.namedCaptureGroup,
|
|
112
|
+
this.unnamedCaptureGroup,
|
|
113
|
+
)
|
|
114
|
+
|
|
88
115
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
89
116
|
// Backreferences
|
|
90
117
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
91
118
|
unnamedBackreference = () =>
|
|
92
119
|
G.pattern([
|
|
93
120
|
'\\',
|
|
94
|
-
R.captureAs('index',
|
|
121
|
+
R.captureAs('index',
|
|
122
|
+
digit
|
|
123
|
+
),
|
|
95
124
|
])
|
|
96
125
|
|
|
97
126
|
namedBackreference = () =>
|
|
98
127
|
G.pattern([
|
|
99
128
|
'\\k<',
|
|
100
|
-
R.captureAs('name',
|
|
129
|
+
R.captureAs('name',
|
|
130
|
+
R.oneOrMore(identifierChar)
|
|
131
|
+
),
|
|
101
132
|
'>',
|
|
102
133
|
])
|
|
103
134
|
|
|
@@ -111,25 +142,25 @@ export class RegExpGrammar {
|
|
|
111
142
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
112
143
|
positiveLookahead = () => [
|
|
113
144
|
'(?=',
|
|
114
|
-
this.
|
|
145
|
+
this.sequenceOrDisjunction,
|
|
115
146
|
')',
|
|
116
147
|
]
|
|
117
148
|
|
|
118
149
|
negativeLookahead = () => [
|
|
119
150
|
'(?!',
|
|
120
|
-
this.
|
|
151
|
+
this.sequenceOrDisjunction,
|
|
121
152
|
')',
|
|
122
153
|
]
|
|
123
154
|
|
|
124
155
|
positiveLookbehind = () => [
|
|
125
156
|
'(?<=',
|
|
126
|
-
this.
|
|
157
|
+
this.sequenceOrDisjunction,
|
|
127
158
|
')',
|
|
128
159
|
]
|
|
129
160
|
|
|
130
161
|
negativeLookbehind = () => [
|
|
131
162
|
'(?<!',
|
|
132
|
-
this.
|
|
163
|
+
this.sequenceOrDisjunction,
|
|
133
164
|
')',
|
|
134
165
|
]
|
|
135
166
|
|
|
@@ -154,24 +185,31 @@ export class RegExpGrammar {
|
|
|
154
185
|
)
|
|
155
186
|
|
|
156
187
|
unreservedCharLiteral = () => G.pattern(
|
|
157
|
-
R.
|
|
188
|
+
R.captureAs('char',
|
|
189
|
+
R.notAnyOfChars('[', '.', '*', '+', '?', '^', '$', '{', '}', '(', ')', '|', ']', '\\')
|
|
190
|
+
)
|
|
158
191
|
)
|
|
159
192
|
|
|
160
193
|
escapedCharLiteral = () => G.pattern([
|
|
161
194
|
'\\',
|
|
162
|
-
R.
|
|
195
|
+
R.captureAs('char',
|
|
196
|
+
R.anyChar
|
|
197
|
+
)
|
|
163
198
|
])
|
|
164
199
|
|
|
165
200
|
hexCharcode = () =>
|
|
166
201
|
G.pattern([
|
|
167
202
|
'\\x',
|
|
168
|
-
|
|
169
|
-
|
|
203
|
+
R.captureAs('value',
|
|
204
|
+
R.repeated(2, hexDigit)
|
|
205
|
+
)
|
|
170
206
|
])
|
|
171
207
|
|
|
172
208
|
controlCharcode = () => G.pattern([
|
|
173
209
|
'\\c',
|
|
174
|
-
R.
|
|
210
|
+
R.captureAs('value',
|
|
211
|
+
R.anyOf(R.charRange('A', 'Z'), R.charRange('a', 'z'))
|
|
212
|
+
)
|
|
175
213
|
])
|
|
176
214
|
|
|
177
215
|
nullCharcode = () => G.pattern('\\0')
|
|
@@ -180,24 +218,29 @@ export class RegExpGrammar {
|
|
|
180
218
|
G.pattern([
|
|
181
219
|
'\\u',
|
|
182
220
|
'{',
|
|
183
|
-
R.captureAs('value',
|
|
221
|
+
R.captureAs('value',
|
|
222
|
+
R.repeated([1, 6], hexDigit)
|
|
223
|
+
),
|
|
184
224
|
'}',
|
|
185
225
|
]),
|
|
186
226
|
G.pattern([
|
|
187
227
|
'\\u',
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
hexDigit
|
|
228
|
+
R.captureAs('value',
|
|
229
|
+
R.repeated(4, hexDigit)
|
|
230
|
+
)
|
|
192
231
|
])
|
|
193
232
|
)
|
|
194
233
|
|
|
195
234
|
codepointRange = () => G.pattern([
|
|
196
235
|
'\\u',
|
|
197
236
|
'{',
|
|
198
|
-
R.captureAs('start',
|
|
237
|
+
R.captureAs('start',
|
|
238
|
+
R.oneOrMore(hexDigit)
|
|
239
|
+
),
|
|
199
240
|
'-',
|
|
200
|
-
R.captureAs('end',
|
|
241
|
+
R.captureAs('end',
|
|
242
|
+
R.oneOrMore(hexDigit)
|
|
243
|
+
),
|
|
201
244
|
'}',
|
|
202
245
|
])
|
|
203
246
|
|
|
@@ -213,16 +256,18 @@ export class RegExpGrammar {
|
|
|
213
256
|
|
|
214
257
|
unicodePropertyBodyPattern: R.Pattern = [
|
|
215
258
|
'{',
|
|
216
|
-
R.captureAs('property',
|
|
259
|
+
R.captureAs('property',
|
|
260
|
+
R.oneOrMore(R.anyOf(letter, digit, '_', '-'))
|
|
261
|
+
),
|
|
217
262
|
R.possibly([
|
|
218
263
|
'=',
|
|
219
|
-
R.captureAs('value',
|
|
264
|
+
R.captureAs('value',
|
|
265
|
+
R.oneOrMore(R.anyOf(letter, digit, '_', '-'))
|
|
266
|
+
),
|
|
220
267
|
]),
|
|
221
268
|
'}',
|
|
222
269
|
]
|
|
223
270
|
|
|
224
|
-
charClassChar = () => G.pattern(R.notAnyOfChars(']'))
|
|
225
|
-
|
|
226
271
|
charClass = () => [
|
|
227
272
|
'[',
|
|
228
273
|
G.possibly(this.charClassNegator),
|
|
@@ -233,7 +278,7 @@ export class RegExpGrammar {
|
|
|
233
278
|
this.notUnicodeProperty,
|
|
234
279
|
this.escapedCharacterClass,
|
|
235
280
|
this.charcodeOrEscapedChar,
|
|
236
|
-
this.
|
|
281
|
+
this.charClassLiteral
|
|
237
282
|
)),
|
|
238
283
|
']',
|
|
239
284
|
]
|
|
@@ -242,27 +287,33 @@ export class RegExpGrammar {
|
|
|
242
287
|
this.codepoint,
|
|
243
288
|
this.hexCharcode,
|
|
244
289
|
this.controlCharcode,
|
|
290
|
+
this.nullCharcode,
|
|
245
291
|
this.escapedCharLiteral,
|
|
246
292
|
)
|
|
247
293
|
|
|
294
|
+
charClassLiteral = () => G.pattern(
|
|
295
|
+
R.captureAs('char',
|
|
296
|
+
R.notAnyOfChars(']')
|
|
297
|
+
)
|
|
298
|
+
)
|
|
299
|
+
|
|
248
300
|
charRangeElement = G.anyOf(
|
|
249
301
|
this.charcodeOrEscapedChar,
|
|
250
|
-
|
|
302
|
+
this.charClassLiteral,
|
|
251
303
|
)
|
|
252
304
|
|
|
305
|
+
charRangeStart = () => this.charRangeElement
|
|
306
|
+
charRangeEnd = () => this.charRangeElement
|
|
307
|
+
|
|
253
308
|
charRange = () => [
|
|
254
|
-
this.
|
|
309
|
+
this.charRangeStart,
|
|
255
310
|
'-',
|
|
256
|
-
this.
|
|
311
|
+
this.charRangeEnd,
|
|
257
312
|
]
|
|
258
313
|
|
|
259
314
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
260
315
|
// Special symbols
|
|
261
316
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
262
|
-
starQuantifier = () => '*'
|
|
263
|
-
plusQuantifier = () => '+'
|
|
264
|
-
nongreedyQuantifier = () => '?'
|
|
265
|
-
|
|
266
317
|
charClassNegator = () => '^'
|
|
267
318
|
|
|
268
319
|
inputStartAnchor = () => '^'
|
|
@@ -270,34 +321,61 @@ export class RegExpGrammar {
|
|
|
270
321
|
|
|
271
322
|
anyCharWildcard = () => '.'
|
|
272
323
|
|
|
273
|
-
disjunctionSeparator = () => '|'
|
|
274
|
-
|
|
275
324
|
anchor = G.anyOf(this.inputStartAnchor, this.inputEndAnchor)
|
|
276
325
|
|
|
277
326
|
escapedCharacterClass = () => G.pattern(R.anyOf(
|
|
278
|
-
R.captureAs('whitespace',
|
|
279
|
-
R.captureAs('nonWhitespace',
|
|
280
|
-
R.captureAs('digit',
|
|
281
|
-
R.captureAs('nonDigit',
|
|
282
|
-
R.captureAs('word',
|
|
283
|
-
R.captureAs('nonWord',
|
|
284
|
-
R.captureAs('wordBoundary',
|
|
285
|
-
R.captureAs('nonWordBoundary',
|
|
286
|
-
R.captureAs('formFeed',
|
|
287
|
-
R.captureAs('carriageReturn',
|
|
288
|
-
R.captureAs('lineFeed',
|
|
289
|
-
R.captureAs('tab',
|
|
290
|
-
R.captureAs('verticalTab',
|
|
291
|
-
R.captureAs('backwardSlash',
|
|
327
|
+
R.captureAs('whitespace', escapedChars.whitespace),
|
|
328
|
+
R.captureAs('nonWhitespace', escapedChars.nonWhitespace),
|
|
329
|
+
R.captureAs('digit', escapedChars.digit),
|
|
330
|
+
R.captureAs('nonDigit', escapedChars.nonDigit),
|
|
331
|
+
R.captureAs('word', escapedChars.word),
|
|
332
|
+
R.captureAs('nonWord', escapedChars.nonWord),
|
|
333
|
+
R.captureAs('wordBoundary', escapedChars.wordBoundary),
|
|
334
|
+
R.captureAs('nonWordBoundary', escapedChars.nonWordBoundary),
|
|
335
|
+
R.captureAs('formFeed', escapedChars.formFeed),
|
|
336
|
+
R.captureAs('carriageReturn', escapedChars.carriageReturn),
|
|
337
|
+
R.captureAs('lineFeed', escapedChars.lineFeed),
|
|
338
|
+
R.captureAs('tab', escapedChars.tab),
|
|
339
|
+
R.captureAs('verticalTab', escapedChars.verticalTab),
|
|
340
|
+
R.captureAs('backwardSlash', escapedChars.backwardSlash),
|
|
292
341
|
))
|
|
342
|
+
|
|
343
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
344
|
+
// Sequence elements (positioned here due to TypeScript class member ordering requirements)
|
|
345
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
346
|
+
quantifiableExpression = G.cached(
|
|
347
|
+
G.anyOf(
|
|
348
|
+
this.group,
|
|
349
|
+
this.backReference,
|
|
350
|
+
this.singleCharExpression
|
|
351
|
+
)
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
quantifiedExpression = () => [
|
|
355
|
+
this.quantifiableExpression,
|
|
356
|
+
this.quantifier,
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
sequenceElement = G.anyOf(
|
|
360
|
+
this.anchor,
|
|
361
|
+
this.lookaround,
|
|
362
|
+
this.quantifiedExpression,
|
|
363
|
+
this.quantifiableExpression,
|
|
364
|
+
)
|
|
293
365
|
}
|
|
294
366
|
|
|
367
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
368
|
+
// Shared regular expressions
|
|
369
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
295
370
|
const digit = R.charRange('0', '9')
|
|
296
371
|
const letter = R.anyOf(R.charRange('a', 'z'), R.charRange('A', 'Z'))
|
|
297
372
|
const hexDigit = R.anyOf(digit, R.charRange('a', 'f'), R.charRange('A', 'F'))
|
|
298
373
|
const identifierChar = R.anyOf(letter, digit, '_', '$')
|
|
299
374
|
|
|
300
|
-
|
|
375
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
376
|
+
// Escaped characters lookup
|
|
377
|
+
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
378
|
+
const escapedChars = {
|
|
301
379
|
whitespace: '\\s',
|
|
302
380
|
nonWhitespace: '\\S',
|
|
303
381
|
digit: '\\d',
|
|
@@ -4,30 +4,30 @@ export function roundToDigits(val: number, digits = 3) {
|
|
|
4
4
|
return Math.round(val * multiplier) / multiplier
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export function isNumber(value:
|
|
7
|
+
export function isNumber(value: unknown): value is number {
|
|
8
8
|
return typeof value === 'number'
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export function isString(value:
|
|
11
|
+
export function isString(value: unknown): value is string {
|
|
12
12
|
return typeof value === 'string'
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function isBigInt(value:
|
|
15
|
+
export function isBigInt(value: unknown): value is bigint {
|
|
16
16
|
return typeof value === 'bigint'
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export function isObject(value:
|
|
19
|
+
export function isObject(value: unknown): value is object {
|
|
20
20
|
return typeof value === 'object' && !Array.isArray(value)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export function isArray(value:
|
|
23
|
+
export function isArray(value: unknown): value is unknown[] {
|
|
24
24
|
return Array.isArray(value)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function isBoolean(value:
|
|
27
|
+
export function isBoolean(value: unknown): value is boolean {
|
|
28
28
|
return typeof value === 'boolean'
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export function isFunction(value:
|
|
31
|
+
export function isFunction(value: unknown): value is Function {
|
|
32
32
|
return typeof value === 'function'
|
|
33
33
|
}
|