@bablr/boot 0.6.3 → 0.7.1
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/lib/index.js +37 -218
- package/lib/languages/cstml.js +86 -375
- package/lib/languages/instruction.js +84 -119
- package/lib/languages/json.js +243 -0
- package/lib/languages/regex.js +76 -52
- package/lib/languages/spamex.js +119 -82
- package/lib/match.js +13 -11
- package/lib/miniparser.js +101 -80
- package/lib/path.js +42 -18
- package/lib/utils.js +14 -100
- package/package.json +7 -24
- package/dist/cjs.bundle.cjs +0 -5141
- package/dist/esm.bundle.mjs +0 -5139
- package/lib/builders.js +0 -475
- package/lib/esm-entry.mjs +0 -3
- package/lib/print.js +0 -401
- package/shorthand.macro.js +0 -380
|
@@ -1,133 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import * as sym from '@bablr/agast-helpers/symbols';
|
|
2
|
+
import * as Spamex from './spamex.js';
|
|
3
|
+
import * as CSTML from './cstml.js';
|
|
4
|
+
import * as Regex from './regex.js';
|
|
5
|
+
import * as BaseJSON from './json.js';
|
|
6
6
|
|
|
7
7
|
const _ = /\s+/y;
|
|
8
8
|
const PN = 'Punctuator';
|
|
9
9
|
const ID = 'Identifier';
|
|
10
10
|
const KW = 'Keyword';
|
|
11
|
-
const LIT = 'Literal';
|
|
12
|
-
|
|
13
|
-
const name = 'Instruction';
|
|
14
|
-
|
|
15
|
-
const canonicalURL = 'https://bablr.org/languages/core/en/bablr-vm-instruction';
|
|
16
|
-
|
|
17
|
-
const dependencies = { Spamex, CSTML, Regex };
|
|
18
|
-
|
|
19
|
-
const covers = buildCovers({
|
|
20
|
-
[node]: ['Call', 'Punctuator', 'Property', 'Expression'],
|
|
21
|
-
Expression: [
|
|
22
|
-
'Object',
|
|
23
|
-
'Array',
|
|
24
|
-
'Tuple',
|
|
25
|
-
'Identifier',
|
|
26
|
-
'CSTML:String',
|
|
27
|
-
'CSTML:Gap',
|
|
28
|
-
'Regex:Pattern',
|
|
29
|
-
'Boolean',
|
|
30
|
-
'Null',
|
|
31
|
-
'Spamex:Matcher',
|
|
32
|
-
'Separator',
|
|
33
|
-
],
|
|
34
|
-
});
|
|
35
11
|
|
|
36
|
-
const
|
|
37
|
-
// @Node
|
|
38
|
-
Call(p) {
|
|
39
|
-
p.eat(/[a-zA-Z]+/y, ID, { path: 'verb' });
|
|
40
|
-
p.eatMatchTrivia(_);
|
|
41
|
-
p.eatProduction('Tuple', { path: 'arguments' });
|
|
42
|
-
}
|
|
12
|
+
export const name = 'Instruction';
|
|
43
13
|
|
|
44
|
-
|
|
14
|
+
export const canonicalURL = 'https://bablr.org/languages/core/en/bablr-vm-instruction';
|
|
15
|
+
|
|
16
|
+
class JSONGrammar extends BaseJSON.grammar {
|
|
45
17
|
Expression(p) {
|
|
46
|
-
if (p.match(
|
|
47
|
-
|
|
48
|
-
} else
|
|
49
|
-
|
|
50
|
-
} else if (p.match('(')) {
|
|
51
|
-
p.eatProduction('Tuple');
|
|
52
|
-
} else if (p.match(/['"]/y)) {
|
|
53
|
-
p.eatProduction('CSTML:String');
|
|
54
|
-
} else if (p.match('<//>')) {
|
|
55
|
-
p.eatProduction('CSTML:Gap');
|
|
56
|
-
} else if (p.match('/')) {
|
|
57
|
-
p.eatProduction('Regex:Pattern');
|
|
58
|
-
} else if (p.match(/true|false/y)) {
|
|
59
|
-
p.eatProduction('Boolean');
|
|
60
|
-
} else if (p.match('null')) {
|
|
61
|
-
p.eatProduction('Null');
|
|
62
|
-
} else if (p.match(/[a-zA-Z]/y)) {
|
|
63
|
-
p.eat(/[a-zA-Z]+/y, ID, p.m.attributes);
|
|
64
|
-
} else if (p.match('<')) {
|
|
65
|
-
p.eatProduction('Spamex:Matcher');
|
|
18
|
+
if (p.match(/(m|re|t)['"`]/y)) {
|
|
19
|
+
grammar.prototype.Expression.call(this, p);
|
|
20
|
+
} else {
|
|
21
|
+
super.Expression(p);
|
|
66
22
|
}
|
|
67
23
|
}
|
|
24
|
+
}
|
|
68
25
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
p.eatMatchTrivia(_);
|
|
74
|
-
|
|
75
|
-
let first = true;
|
|
76
|
-
let sep;
|
|
77
|
-
while (first || (sep && (p.match(/./y) || p.atExpression))) {
|
|
78
|
-
p.eatProduction('Property', { path: 'properties[]' });
|
|
79
|
-
if (p.match(/\s*,?/y)) {
|
|
80
|
-
sep = p.eatProduction('Separator', { path: 'separators[]' });
|
|
81
|
-
}
|
|
82
|
-
first = false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
p.eatMatchTrivia(_);
|
|
86
|
-
|
|
87
|
-
p.eat('}', PN, { path: 'closeToken', balancer: true });
|
|
88
|
-
}
|
|
26
|
+
const JSON = {
|
|
27
|
+
...BaseJSON,
|
|
28
|
+
grammar: JSONGrammar,
|
|
29
|
+
};
|
|
89
30
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
31
|
+
export const dependencies = { Spamex, CSTML, Regex, JSON };
|
|
32
|
+
|
|
33
|
+
export const covers = new Map([
|
|
34
|
+
[sym.node, new Set(['Call', 'Punctuator'])],
|
|
35
|
+
[
|
|
36
|
+
'Expression',
|
|
37
|
+
new Set([
|
|
38
|
+
'Object',
|
|
39
|
+
'Array',
|
|
40
|
+
'Number',
|
|
41
|
+
'JSON:String',
|
|
42
|
+
'CSTML:GapTag',
|
|
43
|
+
'RegexString',
|
|
44
|
+
'SpamexString',
|
|
45
|
+
'CSTMLString',
|
|
46
|
+
'Boolean',
|
|
47
|
+
'Null',
|
|
48
|
+
]),
|
|
49
|
+
],
|
|
50
|
+
]);
|
|
98
51
|
|
|
52
|
+
export const grammar = class InstructionMiniparserGrammar {
|
|
99
53
|
// @Node
|
|
100
|
-
|
|
101
|
-
p.eat(
|
|
102
|
-
|
|
54
|
+
Call(p) {
|
|
55
|
+
p.eat(/[a-zA-Z]+/y, ID, { path: 'verb' });
|
|
103
56
|
p.eatMatchTrivia(_);
|
|
104
57
|
|
|
105
|
-
let first = true;
|
|
106
|
-
let sep;
|
|
107
|
-
while (first || (sep && (p.match(/./y) || p.atExpression))) {
|
|
108
|
-
p.eatProduction('Expression', { path: 'elements[]' });
|
|
109
|
-
if (p.match(/\s*,?/y)) {
|
|
110
|
-
sep = p.eatProduction('Separator', { path: 'separators[]' });
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
first = false;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
p.eat(']', PN, { path: 'closeToken', balancer: true });
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// @Node
|
|
120
|
-
Tuple(p) {
|
|
121
58
|
p.eat('(', PN, { path: 'openToken', balanced: ')' });
|
|
122
59
|
|
|
123
|
-
let sep;
|
|
60
|
+
let sep = p.eatMatchTrivia(_);
|
|
124
61
|
|
|
125
62
|
let i = 0;
|
|
126
63
|
while (i === 0 || (sep && (p.match(/./y) || p.atExpression))) {
|
|
127
64
|
p.eatProduction('Expression', { path: 'values[]' });
|
|
128
|
-
|
|
129
|
-
sep = p.eatProduction('Separator', { path: 'separators[]' });
|
|
130
|
-
}
|
|
65
|
+
sep = p.eatMatchTrivia(_);
|
|
131
66
|
i++;
|
|
132
67
|
}
|
|
133
68
|
|
|
@@ -135,21 +70,51 @@ const grammar = class InstructionMiniparserGrammar {
|
|
|
135
70
|
}
|
|
136
71
|
|
|
137
72
|
// @Node
|
|
138
|
-
|
|
139
|
-
p.eat(
|
|
73
|
+
SpamexString(p) {
|
|
74
|
+
p.eat('m', KW, { path: 'sigilToken' });
|
|
75
|
+
let quot = p.match(/['"`]/);
|
|
76
|
+
p.eat(quot, PN, { path: 'openToken', balanced: quot });
|
|
77
|
+
p.eatProduction('Spamex:Matcher', { path: 'content' });
|
|
78
|
+
|
|
79
|
+
p.eat(quot, PN, { path: 'closeToken', balancer: true });
|
|
140
80
|
}
|
|
141
81
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
p.
|
|
145
|
-
p.
|
|
146
|
-
p.
|
|
82
|
+
// @Node
|
|
83
|
+
CSTMLString(p) {
|
|
84
|
+
p.eat('t', KW, { path: 'sigilToken' });
|
|
85
|
+
let quot = p.match(/['"`]/);
|
|
86
|
+
p.eat(quot, PN, { path: 'openToken', balanced: quot });
|
|
87
|
+
p.eatProduction('CSTML:Tag', { path: 'content' });
|
|
88
|
+
|
|
89
|
+
p.eat(quot, PN, { path: 'closeToken', balancer: true });
|
|
147
90
|
}
|
|
148
91
|
|
|
149
92
|
// @Node
|
|
150
|
-
|
|
151
|
-
p.eat('
|
|
93
|
+
RegexString(p) {
|
|
94
|
+
p.eat('re', KW, { path: 'sigilToken' });
|
|
95
|
+
let quot = p.match(/['"`]/);
|
|
96
|
+
p.eat(quot, PN, { path: 'openToken', balanced: quot });
|
|
97
|
+
p.eatProduction('Regex:Pattern', { path: 'content' });
|
|
98
|
+
|
|
99
|
+
p.eat(quot, PN, { path: 'closeToken', balancer: true });
|
|
152
100
|
}
|
|
153
|
-
};
|
|
154
101
|
|
|
155
|
-
|
|
102
|
+
// @Cover
|
|
103
|
+
Expression(p) {
|
|
104
|
+
if (p.match('[')) {
|
|
105
|
+
p.eatProduction('JSON:Array');
|
|
106
|
+
} else if (p.match('{')) {
|
|
107
|
+
p.eatProduction('JSON:Object');
|
|
108
|
+
} else if (p.match(/['"]/y)) {
|
|
109
|
+
p.eatProduction('JSON:String');
|
|
110
|
+
} else if (p.match(/re['"`]/y)) {
|
|
111
|
+
p.eatProduction('RegexString');
|
|
112
|
+
} else if (p.match(/m['"`]/y)) {
|
|
113
|
+
p.eatProduction('SpamexString');
|
|
114
|
+
} else if (p.match(/true|false/y)) {
|
|
115
|
+
p.eatProduction('JSON:Boolean');
|
|
116
|
+
} else if (p.match('null')) {
|
|
117
|
+
p.eatProduction('JSON:Null');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import objectEntries from 'iter-tools/methods/object-entries';
|
|
2
|
+
import * as sym from '@bablr/agast-helpers/symbols';
|
|
3
|
+
import * as Spamex from './spamex.js';
|
|
4
|
+
import * as CSTML from './cstml.js';
|
|
5
|
+
import * as Regex from './regex.js';
|
|
6
|
+
|
|
7
|
+
const _ = /\s+/y;
|
|
8
|
+
const PN = 'Punctuator';
|
|
9
|
+
const KW = 'Keyword';
|
|
10
|
+
const ID = 'Identifier';
|
|
11
|
+
|
|
12
|
+
export const name = 'JSON';
|
|
13
|
+
|
|
14
|
+
export const canonicalURL = 'https://bablr.org/languages/core/en/cstml-json';
|
|
15
|
+
|
|
16
|
+
export const dependencies = { Spamex, CSTML, Regex };
|
|
17
|
+
|
|
18
|
+
export const covers = new Map([
|
|
19
|
+
[
|
|
20
|
+
sym.node,
|
|
21
|
+
new Set([
|
|
22
|
+
'Punctuator',
|
|
23
|
+
'Property',
|
|
24
|
+
'Object',
|
|
25
|
+
'Array',
|
|
26
|
+
'Boolean',
|
|
27
|
+
'Null',
|
|
28
|
+
'Number',
|
|
29
|
+
'UnsignedInteger',
|
|
30
|
+
'Infinity',
|
|
31
|
+
'NaN',
|
|
32
|
+
'Digit',
|
|
33
|
+
'Integer',
|
|
34
|
+
'String',
|
|
35
|
+
'StringContent',
|
|
36
|
+
]),
|
|
37
|
+
],
|
|
38
|
+
['Expression', new Set(['Object', 'Array', 'Boolean', 'Null', 'Number', 'String'])],
|
|
39
|
+
['Number', new Set(['Integer', 'Infinity', 'NaN'])],
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
export const escapables = new Map(
|
|
43
|
+
objectEntries({
|
|
44
|
+
b: '\b',
|
|
45
|
+
f: '\f',
|
|
46
|
+
n: '\n',
|
|
47
|
+
r: '\r',
|
|
48
|
+
t: '\t',
|
|
49
|
+
0: '\0',
|
|
50
|
+
}),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
export const cookEscape = (escape, span) => {
|
|
54
|
+
let hexMatch;
|
|
55
|
+
|
|
56
|
+
if (!escape.startsWith('\\')) {
|
|
57
|
+
throw new Error('string escape must start with \\');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if ((hexMatch = /\\u([0-9a-f]{4})/iy.exec(escape))) {
|
|
61
|
+
//continue
|
|
62
|
+
} else if ((hexMatch = /\\u{([0-9a-f]+)}/iy.exec(escape))) {
|
|
63
|
+
//continue
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (hexMatch) {
|
|
67
|
+
return String.fromCodePoint(parseInt(hexMatch[1], 16));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const litPattern = span === 'Single' ? /\\([\\gnrt0'])/y : /\\([\\gnrt0"])/y;
|
|
71
|
+
const litMatch = litPattern.exec(escape);
|
|
72
|
+
|
|
73
|
+
if (litMatch) {
|
|
74
|
+
if (litMatch[1] === 'g') {
|
|
75
|
+
return null;
|
|
76
|
+
} else {
|
|
77
|
+
return escapables.get(litMatch[1]) || litMatch[1];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw new Error('unable to cook string escape');
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const grammar = class JSONMiniparserGrammar {
|
|
85
|
+
// @Cover
|
|
86
|
+
Expression(p) {
|
|
87
|
+
if (p.match('[')) {
|
|
88
|
+
p.eatProduction('Array');
|
|
89
|
+
} else if (p.match('{')) {
|
|
90
|
+
p.eatProduction('Object');
|
|
91
|
+
} else if (p.match(/true|false/y)) {
|
|
92
|
+
p.eatProduction('Boolean');
|
|
93
|
+
} else if (p.match('null')) {
|
|
94
|
+
p.eatProduction('Null');
|
|
95
|
+
} else if (p.match(/[+-]?(?:\d|Infinity)|NaN/y)) {
|
|
96
|
+
p.eatProduction('Number');
|
|
97
|
+
} else if (p.match(/['"]/y)) {
|
|
98
|
+
p.eatProduction('String');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// @Node
|
|
103
|
+
Object(p) {
|
|
104
|
+
p.eat('{', PN, { path: 'openToken', balanced: '}' });
|
|
105
|
+
|
|
106
|
+
p.eatMatchTrivia(_);
|
|
107
|
+
|
|
108
|
+
let first = true;
|
|
109
|
+
let sep;
|
|
110
|
+
while (first || (sep && (p.match(/./y) || p.atExpression))) {
|
|
111
|
+
p.eatProduction('Property', { path: 'properties[]' });
|
|
112
|
+
if (p.match(/\s*,?/y)) {
|
|
113
|
+
sep = p.eatProduction('ListSeparator', { path: 'separators[]' });
|
|
114
|
+
}
|
|
115
|
+
first = false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
p.eatMatchTrivia(_);
|
|
119
|
+
|
|
120
|
+
p.eat('}', PN, { path: 'closeToken', balancer: true });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// @Node
|
|
124
|
+
Property(p) {
|
|
125
|
+
p.eat(/[a-zA-Z]+/y, ID, { path: 'key' });
|
|
126
|
+
p.eatMatchTrivia(_);
|
|
127
|
+
p.eat(':', PN, { path: 'mapToken' });
|
|
128
|
+
p.eatMatchTrivia(_);
|
|
129
|
+
p.eatProduction('Expression', { path: 'value' });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// @Node
|
|
133
|
+
Array(p) {
|
|
134
|
+
p.eat('[', PN, { path: 'openToken', balanced: ']' });
|
|
135
|
+
|
|
136
|
+
p.eatMatchTrivia(_);
|
|
137
|
+
|
|
138
|
+
let first = true;
|
|
139
|
+
let sep;
|
|
140
|
+
while (first || (sep && (p.match(/./y) || p.atExpression))) {
|
|
141
|
+
p.eatProduction('Expression', { path: 'elements[]' });
|
|
142
|
+
if (p.match(/\s*,?/y)) {
|
|
143
|
+
sep = p.eatProduction('ListSeparator', { path: 'separators[]' });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
first = false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
p.eat(']', PN, { path: 'closeToken', balancer: true });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// @Node
|
|
153
|
+
Boolean(p) {
|
|
154
|
+
p.eat(/true|false/y, KW, { path: 'sigilToken' });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// @Node
|
|
158
|
+
Null(p) {
|
|
159
|
+
p.eat('null', KW, { path: 'sigilToken' });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
ListSeparator(p) {
|
|
163
|
+
p.eatMatchTrivia(_);
|
|
164
|
+
p.eatMatch(/,/y, PN, { path: 'separators[]' });
|
|
165
|
+
p.eatMatchTrivia(_);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
Number(p) {
|
|
169
|
+
if (p.match(/-?\d/y)) {
|
|
170
|
+
p.eatProduction('Integer');
|
|
171
|
+
} else if (p.match('NaN')) {
|
|
172
|
+
p.eatProduction('NaN');
|
|
173
|
+
} else {
|
|
174
|
+
p.eatProduction('Infinity');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// @Node
|
|
179
|
+
Integer(p) {
|
|
180
|
+
p.eatMatch('-', 'Punctuator', { path: 'negative' });
|
|
181
|
+
p.eatProduction('Digits', { path: 'digits[]' });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// @Node
|
|
185
|
+
UnsignedInteger(p) {
|
|
186
|
+
p.eatProduction('Digits', { path: 'digits[]' });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// @Node
|
|
190
|
+
Infinity(p) {
|
|
191
|
+
p.eatMatch(/[+-]/, 'Punctuator', { path: 'sign' });
|
|
192
|
+
p.eat('Infinity', 'Keyword', { path: 'sigilToken' });
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// @Node
|
|
196
|
+
NaN(p) {
|
|
197
|
+
p.eat('NaN', 'Keyword', { path: 'sigilToken' });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
Digits(p) {
|
|
201
|
+
while (p.match(/\d/y)) {
|
|
202
|
+
p.eatProduction('Digit');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// @Node
|
|
207
|
+
Digit(p) {
|
|
208
|
+
p.eatLiteral(/\d/y);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// @Node
|
|
212
|
+
String(p) {
|
|
213
|
+
const q = p.match(/['"]/y) || '"';
|
|
214
|
+
|
|
215
|
+
const span = q === '"' ? 'Double' : 'Single';
|
|
216
|
+
|
|
217
|
+
p.eat(q, PN, { path: 'openToken', startSpan: span, balanced: q });
|
|
218
|
+
while (p.match(/./sy) || p.atExpression) {
|
|
219
|
+
p.eatProduction('StringContent', { path: 'content' });
|
|
220
|
+
}
|
|
221
|
+
p.eat(q, PN, { path: 'closeToken', endSpan: span, balancer: true });
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// @Node
|
|
225
|
+
StringContent(p) {
|
|
226
|
+
let esc, lit;
|
|
227
|
+
let i = 0;
|
|
228
|
+
do {
|
|
229
|
+
esc =
|
|
230
|
+
p.span.type === 'Single'
|
|
231
|
+
? p.eatMatchEscape(/\\(u(\{\d{1,6}\}|\d{4})|[\\gnrt0'])/y)
|
|
232
|
+
: p.eatMatchEscape(/\\(u(\{\d{1,6}\}|\d{4})|[\\gnrt0"])/y);
|
|
233
|
+
lit =
|
|
234
|
+
p.span.type === 'Single'
|
|
235
|
+
? p.eatMatchLiteral(/[^\r\n\0\\']+/y)
|
|
236
|
+
: p.eatMatchLiteral(/[^\r\n\0\\"]+/y);
|
|
237
|
+
i++;
|
|
238
|
+
} while (esc || lit);
|
|
239
|
+
if (i === 1 && !esc && !lit) {
|
|
240
|
+
throw new Error('Invalid string content');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
package/lib/languages/regex.js
CHANGED
|
@@ -1,51 +1,77 @@
|
|
|
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
|
-
|
|
1
|
+
import * as sym from '@bablr/agast-helpers/symbols';
|
|
2
|
+
import when from 'iter-tools/methods/when';
|
|
3
|
+
import { escapables } from './json.js';
|
|
4
|
+
|
|
5
|
+
export const name = 'Regex';
|
|
6
|
+
|
|
7
|
+
export const canonicalURL = 'https://bablr.org/languages/core/en/bablr-regex-pattern';
|
|
8
|
+
|
|
9
|
+
export const dependencies = {};
|
|
10
|
+
|
|
11
|
+
export const covers = new Map([
|
|
12
|
+
[
|
|
13
|
+
sym.node,
|
|
14
|
+
new Set([
|
|
15
|
+
'RegExpLiteral',
|
|
16
|
+
'Flags',
|
|
17
|
+
'Pattern',
|
|
18
|
+
'Alternative',
|
|
19
|
+
'Group',
|
|
20
|
+
'CapturingGroup',
|
|
21
|
+
'StartOfInputAssertion',
|
|
22
|
+
'EndOfInputAssertion',
|
|
23
|
+
'WordBoundaryAssertion',
|
|
24
|
+
'Character',
|
|
25
|
+
'CharacterClass',
|
|
26
|
+
'CharacterClassRange',
|
|
27
|
+
'AnyCharacterSet',
|
|
28
|
+
'WordCharacterSet',
|
|
29
|
+
'SpaceCharacterSet',
|
|
30
|
+
'DigitCharacterSet',
|
|
31
|
+
'Quantifier',
|
|
32
|
+
'Punctuator',
|
|
33
|
+
'Keyword',
|
|
34
|
+
'Escape',
|
|
35
|
+
'Number',
|
|
36
|
+
'Gap',
|
|
37
|
+
]),
|
|
34
38
|
],
|
|
35
|
-
Assertion
|
|
36
|
-
|
|
37
|
-
'
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
['Assertion', new Set(['StartOfInputAssertion', 'EndOfInputAssertion', 'WordBoundaryAssertion'])],
|
|
40
|
+
[
|
|
41
|
+
'Element',
|
|
42
|
+
new Set([
|
|
43
|
+
'CharacterClass',
|
|
44
|
+
'Group',
|
|
45
|
+
'CapturingGroup',
|
|
46
|
+
'StartOfInputAssertion',
|
|
47
|
+
'EndOfInputAssertion',
|
|
48
|
+
'WordBoundaryAssertion',
|
|
49
|
+
'AnyCharacterSet',
|
|
50
|
+
'WordCharacterSet',
|
|
51
|
+
'SpaceCharacterSet',
|
|
52
|
+
'DigitCharacterSet',
|
|
53
|
+
'Gap',
|
|
54
|
+
'Character',
|
|
55
|
+
'Quantifier',
|
|
56
|
+
]),
|
|
57
|
+
],
|
|
58
|
+
[
|
|
59
|
+
'CharacterClassElement',
|
|
60
|
+
new Set([
|
|
61
|
+
'CharacterClassRange',
|
|
62
|
+
'AnyCharacterSet',
|
|
63
|
+
'WordCharacterSet',
|
|
64
|
+
'SpaceCharacterSet',
|
|
65
|
+
'DigitCharacterSet',
|
|
66
|
+
'Character',
|
|
67
|
+
'Gap',
|
|
68
|
+
]),
|
|
69
|
+
],
|
|
70
|
+
[
|
|
41
71
|
'CharacterSet',
|
|
42
|
-
'
|
|
43
|
-
'Character',
|
|
44
|
-
'Quantifier',
|
|
72
|
+
new Set(['AnyCharacterSet', 'WordCharacterSet', 'SpaceCharacterSet', 'DigitCharacterSet']),
|
|
45
73
|
],
|
|
46
|
-
|
|
47
|
-
CharacterSet: ['AnyCharacterSet', 'WordCharacterSet', 'SpaceCharacterSet', 'DigitCharacterSet'],
|
|
48
|
-
});
|
|
74
|
+
]);
|
|
49
75
|
|
|
50
76
|
const flags = {
|
|
51
77
|
global: 'g',
|
|
@@ -77,7 +103,7 @@ const getSpecialPattern = (span) => {
|
|
|
77
103
|
}
|
|
78
104
|
};
|
|
79
105
|
|
|
80
|
-
const cookEscape = (escape, span) => {
|
|
106
|
+
export const cookEscape = (escape, span) => {
|
|
81
107
|
let hexMatch;
|
|
82
108
|
|
|
83
109
|
if (!escape.startsWith('\\')) {
|
|
@@ -111,7 +137,7 @@ const cookEscape = (escape, span) => {
|
|
|
111
137
|
throw new Error('unable to cook regex escape');
|
|
112
138
|
};
|
|
113
139
|
|
|
114
|
-
const grammar = class RegexMiniparserGrammar {
|
|
140
|
+
export const grammar = class RegexMiniparserGrammar {
|
|
115
141
|
// @Node
|
|
116
142
|
Pattern(p) {
|
|
117
143
|
p.eat('/', PN, { path: 'openToken', balanced: '/' });
|
|
@@ -145,12 +171,12 @@ const grammar = class RegexMiniparserGrammar {
|
|
|
145
171
|
Alternatives(p) {
|
|
146
172
|
do {
|
|
147
173
|
p.eatProduction('Alternative');
|
|
148
|
-
} while (p.eatMatch('|', PN, { path: '
|
|
174
|
+
} while (p.eatMatch('|', PN, { path: 'separatorTokens[]' }));
|
|
149
175
|
}
|
|
150
176
|
|
|
151
177
|
// @Node
|
|
152
178
|
Alternative(p) {
|
|
153
|
-
p.eatProduction('Elements', { path: 'elements[]' });
|
|
179
|
+
p.eatProduction('Elements', { path: 'elements[]+' });
|
|
154
180
|
}
|
|
155
181
|
|
|
156
182
|
Elements(p) {
|
|
@@ -383,7 +409,7 @@ const grammar = class RegexMiniparserGrammar {
|
|
|
383
409
|
|
|
384
410
|
// @Node
|
|
385
411
|
Quantifier(p) {
|
|
386
|
-
p.eatHeldProduction('Element', { path: 'element' });
|
|
412
|
+
p.eatHeldProduction('Element', { path: 'element+' });
|
|
387
413
|
|
|
388
414
|
let attrs;
|
|
389
415
|
|
|
@@ -415,5 +441,3 @@ const grammar = class RegexMiniparserGrammar {
|
|
|
415
441
|
return { attrs };
|
|
416
442
|
}
|
|
417
443
|
};
|
|
418
|
-
|
|
419
|
-
module.exports = { name, canonicalURL, dependencies, covers, grammar, cookEscape };
|