grammar-composer 0.2.1 → 0.2.2

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.
@@ -0,0 +1,301 @@
1
+ import * as G from '../GrammarComposer.js'
2
+ import * as R from 'regexp-composer'
3
+
4
+ export class RegExpGrammar {
5
+ //////////////////////////////////////////////////////////////////////////////////////////////
6
+ // High level productions
7
+ //////////////////////////////////////////////////////////////////////////////////////////////
8
+ disjunction = () => [
9
+ this.sequence,
10
+
11
+ G.possibly([
12
+ this.disjunctionSeparator,
13
+ this.disjunction,
14
+ ])
15
+ ]
16
+
17
+ sequence = () => G.oneOrMore(this.element)
18
+
19
+ element = () => G.anyOf(
20
+ this.anchor,
21
+ this.lookaround,
22
+ this.possiblyQuantifiedExpression,
23
+ )
24
+
25
+ //////////////////////////////////////////////////////////////////////////////////////////////
26
+ // Quantifed expressions
27
+ //////////////////////////////////////////////////////////////////////////////////////////////
28
+ possiblyQuantifiedExpression = () => [
29
+ G.anyOf(
30
+ this.group,
31
+ this.backReference,
32
+ this.singleCharExpression
33
+ ),
34
+
35
+ G.possibly(G.anyOf(
36
+ this.starQuantifier,
37
+ this.plusQuantifier,
38
+ this.exactCountQuantifier,
39
+ this.countRangeQuantifier,
40
+ )),
41
+
42
+ G.possibly(this.nongreedyQuantifier), // Nongreedy quantifier
43
+ ]
44
+
45
+ exactCountQuantifier = () => G.pattern([
46
+ '{',
47
+ R.captureAs('count', R.oneOrMore(digit)),
48
+ '}',
49
+ ])
50
+
51
+ countRangeQuantifier = () => G.pattern([
52
+ '{',
53
+ R.captureAs('start', R.oneOrMore(digit)),
54
+ ',',
55
+ R.possibly(R.captureAs('end', R.oneOrMore(digit))),
56
+ '}',
57
+ ])
58
+
59
+ //////////////////////////////////////////////////////////////////////////////////////////////
60
+ // Group expressions
61
+ //////////////////////////////////////////////////////////////////////////////////////////////
62
+ group = () => G.anyOf(
63
+ this.uncapturedGroup,
64
+ this.namedCaptureGroup,
65
+ this.unnamedCaptureGroup,
66
+ )
67
+
68
+ uncapturedGroup = () => [
69
+ '(:',
70
+ this.disjunction,
71
+ ')',
72
+ ]
73
+
74
+ namedCaptureGroup = () => [
75
+ '(?<',
76
+ G.pattern(R.captureAs('name', R.oneOrMore(letter))),
77
+ '>',
78
+ this.disjunction,
79
+ ')',
80
+ ]
81
+
82
+ unnamedCaptureGroup = () => [
83
+ '(',
84
+ this.disjunction,
85
+ ')',
86
+ ]
87
+
88
+ //////////////////////////////////////////////////////////////////////////////////////////////
89
+ // Backreferences
90
+ //////////////////////////////////////////////////////////////////////////////////////////////
91
+ unnamedBackreference = () =>
92
+ G.pattern([
93
+ '\\',
94
+ R.captureAs('index', digit),
95
+ ])
96
+
97
+ namedBackreference = () =>
98
+ G.pattern([
99
+ '\\k<',
100
+ R.captureAs('name', digit),
101
+ '>',
102
+ ])
103
+
104
+ backReference = G.anyOf(
105
+ this.unnamedBackreference,
106
+ this.namedBackreference,
107
+ )
108
+
109
+ //////////////////////////////////////////////////////////////////////////////////////////////
110
+ // Lookahead and lookbehind expressions
111
+ //////////////////////////////////////////////////////////////////////////////////////////////
112
+ positiveLookahead = () => [
113
+ '(?=',
114
+ this.disjunction,
115
+ ')',
116
+ ]
117
+
118
+ negativeLookahead = () => [
119
+ '(?!',
120
+ this.disjunction,
121
+ ')',
122
+ ]
123
+
124
+ positiveLookbehind = () => [
125
+ '(?<=',
126
+ this.disjunction,
127
+ ')',
128
+ ]
129
+
130
+ negativeLookbehind = () => [
131
+ '(?<!',
132
+ this.disjunction,
133
+ ')',
134
+ ]
135
+
136
+ lookaround = G.anyOf(
137
+ this.positiveLookahead,
138
+ this.negativeLookahead,
139
+ this.positiveLookbehind,
140
+ this.negativeLookbehind,
141
+ )
142
+
143
+ //////////////////////////////////////////////////////////////////////////////////////////////
144
+ // Single character expressions
145
+ //////////////////////////////////////////////////////////////////////////////////////////////
146
+ singleCharExpression = () => G.anyOf(
147
+ this.anyCharWildcard,
148
+ this.charClass,
149
+ this.unicodeProperty,
150
+ this.notUnicodeProperty,
151
+ this.charcodeOrEscapedChar,
152
+ this.unreservedCharLiteral
153
+ )
154
+
155
+ unreservedCharLiteral = () => G.pattern(
156
+ R.notAnyOfChars('[', '.', '*', '+', '?', '^', '$', '{', '}', '(', ')', '|', ']', '\\')
157
+ )
158
+
159
+ escapedCharLiteral = () => G.pattern([
160
+ '\\',
161
+ R.anyChar
162
+ ])
163
+
164
+ hexCharcode = () =>
165
+ G.pattern([
166
+ '\\x',
167
+ hexDigit,
168
+ hexDigit
169
+ ])
170
+
171
+ controlCharcode = () => G.pattern([
172
+ '\\c',
173
+ R.charRange('A', 'Z'),
174
+ ])
175
+
176
+ codepoint = () => G.pattern([
177
+ '\\u',
178
+ '{',
179
+ R.captureAs('value', R.oneOrMore(hexDigit)),
180
+ '}',
181
+ ])
182
+
183
+ codepointRange = () => G.pattern([
184
+ '\\u',
185
+ '{',
186
+ R.captureAs('start', R.oneOrMore(hexDigit)),
187
+ '-',
188
+ R.captureAs('end', R.oneOrMore(hexDigit)),
189
+ '}',
190
+ ])
191
+
192
+ unicodeProperty = () => G.pattern([
193
+ '\\p',
194
+ this.unicodePropertyBodyPattern,
195
+ ])
196
+
197
+ notUnicodeProperty = () => G.pattern([
198
+ '\\P',
199
+ this.unicodePropertyBodyPattern,
200
+ ])
201
+
202
+ unicodePropertyBodyPattern: R.Pattern = [
203
+ '{',
204
+ R.captureAs('property', R.oneOrMore(letterOrDigit)),
205
+ R.possibly([
206
+ '=',
207
+ R.captureAs('value', R.oneOrMore(letterOrDigit)),
208
+ ]),
209
+ '}',
210
+ ]
211
+
212
+ charClassChar = () => G.pattern(R.notAnyOfChars(']'))
213
+
214
+ charClass = () => [
215
+ '[',
216
+ G.possibly(this.charClassNegator),
217
+ G.oneOrMore(G.anyOf(
218
+ this.charRange,
219
+ this.codepointRange,
220
+ this.charClass,
221
+ this.unicodeProperty,
222
+ this.notUnicodeProperty,
223
+ this.charcodeOrEscapedChar,
224
+ this.charClassChar
225
+ )),
226
+ ']',
227
+ ]
228
+
229
+ charcodeOrEscapedChar = G.anyOf(
230
+ this.codepoint,
231
+ this.hexCharcode,
232
+ this.controlCharcode,
233
+ this.escapedCharLiteral,
234
+ )
235
+
236
+ charRangeElement = G.anyOf(
237
+ this.charcodeOrEscapedChar,
238
+ G.pattern(R.anyChar),
239
+ )
240
+
241
+ charRange = () => [
242
+ this.charRangeElement,
243
+ '-',
244
+ this.charRangeElement,
245
+ ]
246
+
247
+ //////////////////////////////////////////////////////////////////////////////////////////////
248
+ // Special symbols
249
+ //////////////////////////////////////////////////////////////////////////////////////////////
250
+ starQuantifier = () => '*'
251
+ plusQuantifier = () => '+'
252
+ nongreedyQuantifier = () => '?'
253
+
254
+ charClassNegator = () => '^'
255
+
256
+ inputStartAnchor = () => '^'
257
+ inputEndAnchor = () => '$'
258
+
259
+ anyCharWildcard = () => '.'
260
+
261
+ disjunctionSeparator = () => '|'
262
+
263
+ anchor = G.anyOf(this.inputStartAnchor, this.inputEndAnchor)
264
+
265
+ escapedCharacterClass = () => G.pattern(R.anyOf(
266
+ R.captureAs('whitespace', escapedCharString.whitespace),
267
+ R.captureAs('nonWhitespace', escapedCharString.nonWhitespace),
268
+ R.captureAs('digit', escapedCharString.digit),
269
+ R.captureAs('nonDigit', escapedCharString.nonDigit),
270
+ R.captureAs('wordBoundary', escapedCharString.wordBoundary),
271
+ R.captureAs('nonWordBoundary', escapedCharString.nonWordBoundary),
272
+ R.captureAs('formFeed', escapedCharString.formFeed),
273
+ R.captureAs('carriageReturn', escapedCharString.carriageReturn),
274
+ R.captureAs('lineFeed', escapedCharString.lineFeed),
275
+ R.captureAs('tab', escapedCharString.tab),
276
+ R.captureAs('verticalTab', escapedCharString.verticalTab),
277
+ R.captureAs('backwardSlash', escapedCharString.backwardSlash),
278
+ ))
279
+ }
280
+
281
+ const digit = R.charRange('0', '9')
282
+ const letter = R.anyOf(R.charRange('a', 'z'), R.charRange('A', 'Z'))
283
+ const letterOrDigit = R.anyOf(letter, digit)
284
+ const hexDigit = R.anyOf(digit, R.charRange('a', 'f'), R.charRange('A', 'F'))
285
+
286
+ const escapedCharString = {
287
+ whitespace: '\\s',
288
+ nonWhitespace: '\\S',
289
+ digit: '\\d',
290
+ nonDigit: '\\D',
291
+ word: '\\d',
292
+ nonWord: '\\D',
293
+ wordBoundary: '\\b',
294
+ nonWordBoundary: '\\B',
295
+ formFeed: '\\f',
296
+ carriageReturn: '\\r',
297
+ lineFeed: '\\n',
298
+ tab: '\\t',
299
+ verticalTab: '\\v',
300
+ backwardSlash: '\\\\'
301
+ }