@bablr/language-en-json 0.8.0 → 0.10.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/README.md +1 -1
- package/lib/grammar.js +138 -1296
- package/lib/grammar.macro.js +166 -96
- package/package.json +15 -9
package/lib/grammar.macro.js
CHANGED
|
@@ -1,50 +1,51 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { re, spam as m } from '@bablr/boot';
|
|
2
2
|
import { triviaEnhancer } from '@bablr/helpers/trivia';
|
|
3
3
|
import * as productions from '@bablr/helpers/productions';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
CoveredBy,
|
|
8
|
-
AllowEmpty,
|
|
9
|
-
InjectFrom,
|
|
10
|
-
UnboundAttributes,
|
|
11
|
-
} from '@bablr/helpers/decorators';
|
|
4
|
+
import { o, eat, eatMatch, match, fail } from '@bablr/helpers/grammar';
|
|
5
|
+
import { buildString, buildIdentifier } from '@bablr/helpers/builders';
|
|
6
|
+
import { Node, CoveredBy, AllowEmpty, InjectFrom, Literal } from '@bablr/helpers/decorators';
|
|
12
7
|
import * as Space from '@bablr/language-en-blank-space';
|
|
13
8
|
|
|
14
9
|
export const dependencies = { Space };
|
|
15
10
|
|
|
16
|
-
export const canonicalURL = 'https://
|
|
11
|
+
export const canonicalURL = 'https://bablr.org/languages/core/en/json';
|
|
17
12
|
|
|
18
|
-
|
|
13
|
+
const escapables = new Map(
|
|
19
14
|
Object.entries({
|
|
20
|
-
b: '\b',
|
|
21
|
-
f: '\f',
|
|
15
|
+
b: '\b', // these two escapes are antiquated
|
|
16
|
+
f: '\f', // but giving their meaning away could be confusing
|
|
22
17
|
n: '\n',
|
|
23
18
|
r: '\r',
|
|
24
19
|
t: '\t',
|
|
25
|
-
|
|
26
|
-
'/': '/',
|
|
20
|
+
0: '\0',
|
|
27
21
|
}),
|
|
28
22
|
);
|
|
29
23
|
|
|
24
|
+
function first(iter) {
|
|
25
|
+
for (let value of iter) return value;
|
|
26
|
+
}
|
|
27
|
+
|
|
30
28
|
export const getCooked = (escapeNode, span, ctx) => {
|
|
31
29
|
let cooked;
|
|
32
30
|
const codeNode = escapeNode.get('code');
|
|
33
|
-
const type = ctx.sourceTextFor(codeNode.get('typeToken'));
|
|
34
|
-
const value = ctx.sourceTextFor(codeNode.get('value'));
|
|
35
|
-
|
|
36
|
-
if (!span.startsWith('String')) {
|
|
37
|
-
throw new Error('not implemented');
|
|
38
|
-
}
|
|
39
31
|
|
|
40
|
-
if (
|
|
32
|
+
if (first(codeNode.children)?.value.flags.token) {
|
|
41
33
|
const match_ = ctx.sourceTextFor(codeNode);
|
|
42
34
|
|
|
43
35
|
cooked = escapables.get(match_) || match_;
|
|
44
|
-
} else if (type === 'u') {
|
|
45
|
-
cooked = parseInt(value, 16);
|
|
46
36
|
} else {
|
|
47
|
-
|
|
37
|
+
const type = ctx.sourceTextFor(codeNode.get('typeToken'));
|
|
38
|
+
const value = ctx.sourceTextFor(codeNode.get('value'));
|
|
39
|
+
|
|
40
|
+
if (!span.startsWith('String')) {
|
|
41
|
+
throw new Error('not implemented');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (type === 'u') {
|
|
45
|
+
cooked = String.fromCharCode(parseInt(value, 16));
|
|
46
|
+
} else {
|
|
47
|
+
throw new Error();
|
|
48
|
+
}
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
return cooked.toString(10);
|
|
@@ -53,167 +54,233 @@ export const getCooked = (escapeNode, span, ctx) => {
|
|
|
53
54
|
export const grammar = triviaEnhancer(
|
|
54
55
|
{
|
|
55
56
|
triviaIsAllowed: (s) => s.span === 'Bare',
|
|
56
|
-
|
|
57
|
-
if (yield i`match(/[ \n\r\t]/)`) {
|
|
58
|
-
yield i`eat(<#*Space:Space />)`;
|
|
59
|
-
}
|
|
60
|
-
},
|
|
57
|
+
triviaMatcher: m`#: <*Space:Space /[ \n\r\t]/ />`,
|
|
61
58
|
},
|
|
62
59
|
class JSONGrammar {
|
|
63
|
-
*[Symbol.for('@bablr/fragment')]() {
|
|
60
|
+
*[Symbol.for('@bablr/fragment')]({ props: { rootMatcher } }) {
|
|
64
61
|
// needed for the trivia plugin
|
|
65
|
-
yield
|
|
62
|
+
yield eat(rootMatcher);
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
@CoveredBy('Element')
|
|
69
66
|
*Expression() {
|
|
70
|
-
yield
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
67
|
+
yield eat(m`<_Any />`, [
|
|
68
|
+
m`<Array '[' />`,
|
|
69
|
+
m`<Object '{' />`,
|
|
70
|
+
m`<String /['"]/ />`,
|
|
71
|
+
m`<Number /\d|-[\d\g]/ {span: 'Number'} />`,
|
|
72
|
+
m`<Infinity /-?Infinity/ />`,
|
|
73
|
+
m`<Null 'null' />`,
|
|
74
|
+
m`<Boolean /true|false/ />`,
|
|
75
|
+
]);
|
|
78
76
|
}
|
|
79
77
|
|
|
80
78
|
@CoveredBy('Expression')
|
|
81
79
|
@Node
|
|
82
80
|
*Array() {
|
|
83
|
-
yield
|
|
84
|
-
yield
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
81
|
+
yield eat(m`openToken: <*Punctuator '[' { balanced: ']' } />`);
|
|
82
|
+
yield eat(
|
|
83
|
+
m`<_List />`,
|
|
84
|
+
o({
|
|
85
|
+
element: m`elements[]+$: <__Expression />`,
|
|
86
|
+
separator: m`separatorTokens[]: <*Punctuator ',' />`,
|
|
87
|
+
allowTrailingSeparator: false,
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
yield eat(m`closeToken: <*Punctuator ']' { balancer: true } />`);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
@CoveredBy('Expression')
|
|
93
94
|
@Node
|
|
94
95
|
*Object() {
|
|
95
|
-
yield
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
yield eat(m`openToken: <*Punctuator '{' { balanced: '}' } />`);
|
|
97
|
+
let sep = true;
|
|
98
|
+
|
|
99
|
+
yield eatMatch(m`separatorTokens[]: []`);
|
|
100
|
+
yield eatMatch(m`properties[]$: []`);
|
|
101
|
+
|
|
102
|
+
while (sep && (yield match(re`/.|\g/s`))) {
|
|
103
|
+
let suppressGap = !!(yield match(m`<_All />`, [
|
|
104
|
+
m`key: <//>`,
|
|
105
|
+
m`sigilToken: <*Punctuator ':' />`,
|
|
106
|
+
]));
|
|
107
|
+
yield eat(m`properties[]$: <Property />`, null, o({ suppressGap }));
|
|
108
|
+
sep = yield eatMatch(m`separatorTokens[]: <*Punctuator ',' />`);
|
|
109
|
+
}
|
|
110
|
+
yield eat(m`closeToken: <*Punctuator '}' { balancer: true } />`);
|
|
102
111
|
}
|
|
103
112
|
|
|
104
113
|
@Node
|
|
105
114
|
*Property() {
|
|
106
|
-
yield
|
|
107
|
-
yield
|
|
108
|
-
yield
|
|
115
|
+
yield eat(m`key$: <*Identifier />`);
|
|
116
|
+
yield eat(m`sigilToken: <*Punctuator ':' />`);
|
|
117
|
+
yield eat(m`value+$: <__Expression />`);
|
|
109
118
|
}
|
|
110
119
|
|
|
111
|
-
@CoveredBy('Language')
|
|
112
120
|
@Node
|
|
113
|
-
*
|
|
114
|
-
yield
|
|
115
|
-
|
|
116
|
-
|
|
121
|
+
*Identifier() {
|
|
122
|
+
yield eat(re`/[a-zA-Z][a-zA-Z_-]*/`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@CoveredBy('Expression')
|
|
126
|
+
@Node
|
|
127
|
+
*String({ ctx }) {
|
|
128
|
+
let q = yield match(re`/['"]/`);
|
|
129
|
+
|
|
130
|
+
if (!q) yield fail();
|
|
131
|
+
|
|
132
|
+
const q_ = ctx.sourceTextFor(q);
|
|
133
|
+
|
|
134
|
+
yield q_ === "'"
|
|
135
|
+
? eat(m`openToken: <*Punctuator "'" { balanced: "'", balancedSpan: 'String:Single' } />`)
|
|
136
|
+
: eat(m`openToken: <*Punctuator '"' { balanced: '"', balancedSpan: 'String:Double' } />`);
|
|
137
|
+
|
|
138
|
+
yield eat(m`content$: <*StringContent />`);
|
|
139
|
+
|
|
140
|
+
yield q_ === "'"
|
|
141
|
+
? eat(m`closeToken: <*Punctuator "'" { balancer: true } />`)
|
|
142
|
+
: eat(m`closeToken: <*Punctuator '"' { balancer: true } />`);
|
|
117
143
|
}
|
|
118
144
|
|
|
119
145
|
@AllowEmpty
|
|
120
146
|
@Node
|
|
121
|
-
*StringContent() {
|
|
147
|
+
*StringContent({ state: { span } }) {
|
|
122
148
|
let esc, lit;
|
|
123
149
|
do {
|
|
124
|
-
esc = (yield
|
|
125
|
-
lit =
|
|
150
|
+
esc = (yield match('\\')) && (yield eat(m`@: <EscapeSequence />`));
|
|
151
|
+
lit =
|
|
152
|
+
span === 'String:Single'
|
|
153
|
+
? yield eatMatch(re`/[^\r\n\\'\g]+/`)
|
|
154
|
+
: yield eatMatch(re`/[^\r\n\\"\g]+/`);
|
|
126
155
|
} while (esc || lit);
|
|
127
156
|
}
|
|
128
157
|
|
|
129
158
|
@Node
|
|
130
159
|
*EscapeSequence({ state: { span }, ctx }) {
|
|
131
160
|
if (!span.startsWith('String')) {
|
|
132
|
-
yield
|
|
161
|
+
yield fail();
|
|
133
162
|
}
|
|
134
163
|
|
|
135
|
-
yield
|
|
164
|
+
yield eat(m`sigilToken: <*Punctuator '\\' { openSpan: 'Escape' } />`);
|
|
136
165
|
|
|
137
|
-
let
|
|
166
|
+
let match_;
|
|
138
167
|
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
168
|
+
if (
|
|
169
|
+
(match_ =
|
|
170
|
+
span === 'String:Single' ? yield match(re`/[\\/nrt0']/`) : yield match(re`/[\\/nrt0"]/`))
|
|
171
|
+
) {
|
|
172
|
+
const matchText = ctx.sourceTextFor(match_);
|
|
173
|
+
yield eat(m`code: <*Keyword ${buildString(matchText)} { closeSpan: 'Escape' } />`);
|
|
174
|
+
} else if (yield match('u')) {
|
|
175
|
+
yield eat(m`code: <EscapeCode { closeSpan: 'Escape' } />`);
|
|
144
176
|
} else {
|
|
145
|
-
yield
|
|
177
|
+
yield fail();
|
|
146
178
|
}
|
|
147
179
|
}
|
|
148
180
|
|
|
149
181
|
@Node
|
|
150
182
|
*EscapeCode() {
|
|
151
|
-
yield
|
|
152
|
-
|
|
183
|
+
if (yield eatMatch(m`typeToken: <*Keyword 'u' />`)) {
|
|
184
|
+
if (
|
|
185
|
+
yield eatMatch(
|
|
186
|
+
m`openToken: <*Punctuator '{' { balanced: '}' } />`,
|
|
187
|
+
null,
|
|
188
|
+
o({ bind: true }),
|
|
189
|
+
)
|
|
190
|
+
) {
|
|
191
|
+
yield eat(m`value$: <*UnsignedHexInteger />`);
|
|
192
|
+
yield eat(m`closeToken: <*Punctuator '}' { balancer: true } />`);
|
|
193
|
+
} else {
|
|
194
|
+
yield eat(m`value$: <*UnsignedHexInteger /[\da-fA-F]{4}/ />`);
|
|
195
|
+
yield eat(m`closeToken: null`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
153
198
|
}
|
|
154
199
|
|
|
155
200
|
@CoveredBy('Expression')
|
|
156
201
|
@Node
|
|
157
202
|
*Number() {
|
|
158
|
-
yield
|
|
203
|
+
yield eat(m`wholePart$: <Integer />`, o({ noDoubleZero: true, matchSign: '-' }));
|
|
159
204
|
|
|
160
|
-
let fs = yield
|
|
205
|
+
let fs = yield eatMatch(
|
|
206
|
+
m`fractionalSeparatorToken: <*Punctuator '.' />`,
|
|
207
|
+
null,
|
|
208
|
+
o({ bind: true }),
|
|
209
|
+
);
|
|
161
210
|
|
|
162
211
|
if (fs) {
|
|
163
|
-
yield
|
|
212
|
+
yield eat(m`fractionalPart$: <*UnsignedInteger />`);
|
|
164
213
|
} else {
|
|
165
|
-
yield
|
|
214
|
+
yield eat(m`fractionalPart$: null`);
|
|
166
215
|
}
|
|
167
216
|
|
|
168
|
-
let es = yield
|
|
217
|
+
let es = yield eatMatch(
|
|
218
|
+
m`exponentSeparatorToken: <*Punctuator /[eE]/ />`,
|
|
219
|
+
null,
|
|
220
|
+
o({ bind: true }),
|
|
221
|
+
);
|
|
169
222
|
|
|
170
223
|
if (es) {
|
|
171
|
-
yield
|
|
224
|
+
yield eat(m`exponentPart$: <Integer />`, { matchSign: /[+-]/ });
|
|
172
225
|
} else {
|
|
173
|
-
yield
|
|
226
|
+
yield eat(m`exponentPart$: null`);
|
|
174
227
|
}
|
|
175
228
|
}
|
|
176
229
|
|
|
177
230
|
@Node
|
|
178
|
-
*Integer({
|
|
179
|
-
const { matchSign = null, noDoubleZero = false } = (props && ctx.unbox(props)) || {};
|
|
180
|
-
|
|
231
|
+
*Integer({ props: { matchSign = null, noDoubleZero = false } }) {
|
|
181
232
|
if (matchSign) {
|
|
182
|
-
yield
|
|
233
|
+
yield eatMatch(
|
|
234
|
+
m`signToken: <*Punctuator ${buildString(matchSign)} />`,
|
|
235
|
+
null,
|
|
236
|
+
o({ bind: true }),
|
|
237
|
+
);
|
|
183
238
|
} else {
|
|
184
|
-
yield
|
|
239
|
+
yield eat(m`signToken: null`);
|
|
185
240
|
}
|
|
186
241
|
|
|
187
|
-
yield
|
|
242
|
+
yield eat(m`value$: <*UnsignedInteger />`, o({ noDoubleZero }));
|
|
188
243
|
}
|
|
189
244
|
|
|
190
245
|
@Node
|
|
191
|
-
*UnsignedInteger({
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
let [firstDigit] = ctx.allTagsFor(yield i`eat(/\d/)`);
|
|
246
|
+
*UnsignedInteger({ props: { noDoubleZero = false }, ctx }) {
|
|
247
|
+
let firstDigit = ctx.sourceTextFor(yield eat(re`/\d/`));
|
|
195
248
|
|
|
196
249
|
if (!noDoubleZero || firstDigit.value !== '0') {
|
|
197
|
-
yield
|
|
250
|
+
yield eatMatch(re`/\d+/`);
|
|
198
251
|
}
|
|
199
252
|
}
|
|
200
253
|
|
|
254
|
+
@Node
|
|
255
|
+
*UnsignedHexInteger() {
|
|
256
|
+
yield eatMatch(re`/[\da-fA-F]+/`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
@CoveredBy('Expression')
|
|
260
|
+
@Node
|
|
261
|
+
*Infinity() {
|
|
262
|
+
yield eatMatch(m`signToken: <*Punctuator '-' />`, null, o({ bind: true }));
|
|
263
|
+
yield eat(m`sigilToken: <*Keyword 'Infinity' />`);
|
|
264
|
+
}
|
|
265
|
+
|
|
201
266
|
@CoveredBy('Expression')
|
|
202
267
|
@Node
|
|
203
268
|
*Boolean() {
|
|
204
|
-
yield
|
|
269
|
+
yield eat(m`sigilToken: <*Keyword /true|false/ />`);
|
|
205
270
|
}
|
|
206
271
|
|
|
207
272
|
@CoveredBy('Expression')
|
|
208
273
|
@Node
|
|
209
274
|
*Null() {
|
|
210
|
-
yield
|
|
275
|
+
yield eat(m`sigilToken: <*Keyword 'null' />`);
|
|
211
276
|
}
|
|
212
277
|
|
|
278
|
+
@Literal
|
|
213
279
|
@Node
|
|
214
280
|
@InjectFrom(productions)
|
|
215
281
|
*Keyword() {}
|
|
216
282
|
|
|
283
|
+
@Literal
|
|
217
284
|
@Node
|
|
218
285
|
@InjectFrom(productions)
|
|
219
286
|
*Punctuator() {}
|
|
@@ -224,5 +291,8 @@ export const grammar = triviaEnhancer(
|
|
|
224
291
|
|
|
225
292
|
@InjectFrom(productions)
|
|
226
293
|
*Any() {}
|
|
294
|
+
|
|
295
|
+
@InjectFrom(productions)
|
|
296
|
+
*All() {}
|
|
227
297
|
},
|
|
228
298
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/language-en-json",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "A BABLR language for JSON",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=12.0.0"
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
".": "./lib/grammar.js",
|
|
11
11
|
"./package.json": "./package.json"
|
|
12
12
|
},
|
|
13
|
-
"files": [
|
|
13
|
+
"files": [
|
|
14
|
+
"lib/**/*.js"
|
|
15
|
+
],
|
|
14
16
|
"scripts": {
|
|
15
17
|
"build": "macrome build",
|
|
16
18
|
"watch": "macrome watch",
|
|
@@ -19,11 +21,11 @@
|
|
|
19
21
|
},
|
|
20
22
|
"sideEffects": false,
|
|
21
23
|
"dependencies": {
|
|
22
|
-
"@bablr/agast-helpers": "
|
|
23
|
-
"@bablr/agast-vm-helpers": "
|
|
24
|
-
"@bablr/boot": "
|
|
25
|
-
"@bablr/helpers": "
|
|
26
|
-
"@bablr/language-en-blank-space": "
|
|
24
|
+
"@bablr/agast-helpers": "0.7.1",
|
|
25
|
+
"@bablr/agast-vm-helpers": "0.7.1",
|
|
26
|
+
"@bablr/boot": "0.8.1",
|
|
27
|
+
"@bablr/helpers": "0.22.1",
|
|
28
|
+
"@bablr/language-en-blank-space": "0.7.0",
|
|
27
29
|
"@babel/runtime": "^7.22.15"
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
@@ -31,7 +33,7 @@
|
|
|
31
33
|
"@bablr/macrome": "^0.1.3",
|
|
32
34
|
"@bablr/macrome-generator-bablr": "^0.3.2",
|
|
33
35
|
"@qnighy/dedent": "0.1.1",
|
|
34
|
-
"bablr": "^0.
|
|
36
|
+
"bablr": "^0.7.0",
|
|
35
37
|
"enhanced-resolve": "^5.12.0",
|
|
36
38
|
"eslint": "^7.32.0",
|
|
37
39
|
"eslint-import-resolver-enhanced-resolve": "^1.0.5",
|
|
@@ -41,7 +43,11 @@
|
|
|
41
43
|
"mocha": "^10.4.0",
|
|
42
44
|
"prettier": "^2.0.5"
|
|
43
45
|
},
|
|
44
|
-
"keywords": [
|
|
46
|
+
"keywords": [
|
|
47
|
+
"bablr-language",
|
|
48
|
+
"grammar",
|
|
49
|
+
"english"
|
|
50
|
+
],
|
|
45
51
|
"repository": "git@github.com:bablr-lang/language-en-json.git",
|
|
46
52
|
"homepage": "https://github.com/bablr-lang/language-en-json",
|
|
47
53
|
"author": "Conrad Buck <conartist6@gmail.com>",
|