@weborigami/language 0.3.3-jse.3 → 0.3.3
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/main.js +1 -3
- package/package.json +3 -3
- package/src/compiler/compile.js +2 -10
- package/src/compiler/optimize.js +93 -147
- package/src/compiler/origami.pegjs +67 -171
- package/src/compiler/parse.js +946 -1810
- package/src/compiler/parserHelpers.js +58 -159
- package/src/runtime/HandleExtensionsTransform.js +1 -10
- package/src/runtime/evaluate.js +35 -28
- package/src/runtime/expressionObject.js +4 -4
- package/src/runtime/handlers.js +54 -18
- package/src/runtime/mergeTrees.js +5 -0
- package/src/runtime/ops.js +156 -101
- package/src/runtime/symbols.js +0 -1
- package/src/runtime/{templateIndent.js → taggedTemplateIndent.js} +2 -2
- package/test/compiler/codeHelpers.js +1 -3
- package/test/compiler/compile.test.js +27 -52
- package/test/compiler/optimize.test.js +23 -92
- package/test/compiler/parse.test.js +342 -574
- package/test/runtime/evaluate.test.js +20 -4
- package/test/runtime/expressionObject.test.js +4 -5
- package/test/runtime/handlers.test.js +10 -19
- package/test/runtime/mergeTrees.test.js +5 -0
- package/test/runtime/ops.test.js +82 -103
- package/test/runtime/taggedTemplateIndent.test.js +1 -1
- package/src/runtime/getHandlers.js +0 -10
- package/src/runtime/jsGlobals.js +0 -99
- package/src/runtime/templateStandard.js +0 -13
- package/test/runtime/templateText.test.js +0 -18
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
3
|
import { parse } from "../../src/compiler/parse.js";
|
|
4
|
-
import {
|
|
4
|
+
import { undetermined } from "../../src/compiler/parserHelpers.js";
|
|
5
5
|
import * as ops from "../../src/runtime/ops.js";
|
|
6
6
|
import { assertCodeEqual } from "./codeHelpers.js";
|
|
7
7
|
|
|
@@ -19,63 +19,6 @@ describe("Origami parser", () => {
|
|
|
19
19
|
]);
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
describe("angleBracketLiteral", () => {
|
|
23
|
-
test("with path", () => {
|
|
24
|
-
assertParse(
|
|
25
|
-
"angleBracketLiteral",
|
|
26
|
-
"<index.html>",
|
|
27
|
-
[[ops.scope], [ops.literal, "index.html"]],
|
|
28
|
-
"jse"
|
|
29
|
-
);
|
|
30
|
-
assertParse(
|
|
31
|
-
"angleBracketLiteral",
|
|
32
|
-
"<foo/bar/baz>",
|
|
33
|
-
[
|
|
34
|
-
[ops.scope],
|
|
35
|
-
[ops.literal, "foo/"],
|
|
36
|
-
[ops.literal, "bar/"],
|
|
37
|
-
[ops.literal, "baz"],
|
|
38
|
-
],
|
|
39
|
-
"jse"
|
|
40
|
-
);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("root directory", () => {
|
|
44
|
-
assertParse("angleBracketLiteral", "</>", [ops.rootDirectory]);
|
|
45
|
-
assertParse("angleBracketLiteral", "</etc/passwd>", [
|
|
46
|
-
[ops.rootDirectory],
|
|
47
|
-
[ops.literal, "etc/"],
|
|
48
|
-
[ops.literal, "passwd"],
|
|
49
|
-
]);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("home directory", () => {
|
|
53
|
-
assertParse("angleBracketLiteral", "<~>", [ops.homeDirectory]);
|
|
54
|
-
assertParse("angleBracketLiteral", "<~/.bash_profile>", [
|
|
55
|
-
[ops.homeDirectory],
|
|
56
|
-
[ops.literal, ".bash_profile"],
|
|
57
|
-
]);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test("with protocol URL", () => {
|
|
61
|
-
assertParse("angleBracketLiteral", "<files:src/assets>", [
|
|
62
|
-
[markers.global, "files:"],
|
|
63
|
-
[ops.literal, "src/"],
|
|
64
|
-
[ops.literal, "assets"],
|
|
65
|
-
]);
|
|
66
|
-
assertParse(
|
|
67
|
-
"angleBracketLiteral",
|
|
68
|
-
"<https://example.com/data.yaml>",
|
|
69
|
-
[
|
|
70
|
-
[markers.global, "https:"],
|
|
71
|
-
[ops.literal, "example.com/"],
|
|
72
|
-
[ops.literal, "data.yaml"],
|
|
73
|
-
],
|
|
74
|
-
"jse"
|
|
75
|
-
);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
22
|
test("arrayLiteral", () => {
|
|
80
23
|
assertParse("arrayLiteral", "[]", [ops.array]);
|
|
81
24
|
assertParse("arrayLiteral", "[1, 2, 3]", [
|
|
@@ -98,7 +41,7 @@ describe("Origami parser", () => {
|
|
|
98
41
|
[ops.literal, 4],
|
|
99
42
|
]);
|
|
100
43
|
assertParse("arrayLiteral", "[ 1, ...[2, 3]]", [
|
|
101
|
-
ops.
|
|
44
|
+
ops.merge,
|
|
102
45
|
[ops.array, [ops.literal, 1]],
|
|
103
46
|
[ops.array, [ops.literal, 2], [ops.literal, 3]],
|
|
104
47
|
]);
|
|
@@ -117,12 +60,12 @@ describe("Origami parser", () => {
|
|
|
117
60
|
assertParse("arrowFunction", "() => foo", [
|
|
118
61
|
ops.lambda,
|
|
119
62
|
[],
|
|
120
|
-
[
|
|
63
|
+
[ops.scope, "foo"],
|
|
121
64
|
]);
|
|
122
65
|
assertParse("arrowFunction", "x => y", [
|
|
123
66
|
ops.lambda,
|
|
124
67
|
[[ops.literal, "x"]],
|
|
125
|
-
[
|
|
68
|
+
[ops.scope, "y"],
|
|
126
69
|
]);
|
|
127
70
|
assertParse("arrowFunction", "(a, b, c) ⇒ fn(a, b, c)", [
|
|
128
71
|
ops.lambda,
|
|
@@ -132,10 +75,10 @@ describe("Origami parser", () => {
|
|
|
132
75
|
[ops.literal, "c"],
|
|
133
76
|
],
|
|
134
77
|
[
|
|
135
|
-
[
|
|
136
|
-
[
|
|
137
|
-
[
|
|
138
|
-
[
|
|
78
|
+
[ops.builtin, "fn"],
|
|
79
|
+
[ops.scope, "a"],
|
|
80
|
+
[ops.scope, "b"],
|
|
81
|
+
[ops.scope, "c"],
|
|
139
82
|
],
|
|
140
83
|
]);
|
|
141
84
|
assertParse("arrowFunction", "a => b => fn(a, b)", [
|
|
@@ -145,9 +88,9 @@ describe("Origami parser", () => {
|
|
|
145
88
|
ops.lambda,
|
|
146
89
|
[[ops.literal, "b"]],
|
|
147
90
|
[
|
|
148
|
-
[
|
|
149
|
-
[
|
|
150
|
-
[
|
|
91
|
+
[ops.builtin, "fn"],
|
|
92
|
+
[ops.scope, "a"],
|
|
93
|
+
[ops.scope, "b"],
|
|
151
94
|
],
|
|
152
95
|
],
|
|
153
96
|
]);
|
|
@@ -177,177 +120,147 @@ describe("Origami parser", () => {
|
|
|
177
120
|
]);
|
|
178
121
|
});
|
|
179
122
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
]
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
]
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
]
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
]
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
]
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
]
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
]
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
[ops.
|
|
239
|
-
[ops.literal, "
|
|
240
|
-
]
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
]
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
]
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
]
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
[
|
|
265
|
-
[ops.literal, "key"],
|
|
266
|
-
]);
|
|
267
|
-
assertParse("callExpression", "tree/key()", [
|
|
268
|
-
[markers.reference, [ops.literal, "tree/"], [ops.literal, "key"]],
|
|
269
|
-
undefined,
|
|
270
|
-
]);
|
|
271
|
-
assertParse("callExpression", "(tree)/", [
|
|
272
|
-
ops.unpack,
|
|
273
|
-
[markers.reference, [ops.literal, "tree/"]],
|
|
274
|
-
]);
|
|
275
|
-
assertParse("callExpression", "fn()/key()", [
|
|
276
|
-
[
|
|
277
|
-
[[markers.global, "fn"], undefined],
|
|
278
|
-
[ops.literal, "key"],
|
|
279
|
-
],
|
|
280
|
-
undefined,
|
|
281
|
-
]);
|
|
282
|
-
assertParse("callExpression", "package:@weborigami/dropbox/auth(creds)", [
|
|
283
|
-
[
|
|
284
|
-
[markers.global, "package:"],
|
|
285
|
-
[ops.literal, "@weborigami/"],
|
|
286
|
-
[ops.literal, "dropbox/"],
|
|
287
|
-
[ops.literal, "auth"],
|
|
288
|
-
],
|
|
289
|
-
[markers.reference, [ops.literal, "creds"]],
|
|
290
|
-
]);
|
|
291
|
-
});
|
|
292
|
-
test("tagged templates", () => {
|
|
293
|
-
assertParse("callExpression", "indent`hello`", [
|
|
294
|
-
[markers.global, "indent"],
|
|
295
|
-
[ops.literal, ["hello"]],
|
|
296
|
-
]);
|
|
297
|
-
assertParse("callExpression", "fn.js`Hello, world.`", [
|
|
298
|
-
[markers.reference, [ops.literal, "fn.js"]],
|
|
299
|
-
[ops.literal, ["Hello, world."]],
|
|
300
|
-
]);
|
|
301
|
-
});
|
|
302
|
-
test("protocols", () => {
|
|
303
|
-
assertParse("callExpression", "files:src/assets", [
|
|
304
|
-
[markers.global, "files:"],
|
|
123
|
+
test("callExpression", () => {
|
|
124
|
+
assertParse("callExpression", "fn()", [[ops.builtin, "fn"], undefined]);
|
|
125
|
+
assertParse("callExpression", "foo.js(arg)", [
|
|
126
|
+
[ops.scope, "foo.js"],
|
|
127
|
+
[ops.scope, "arg"],
|
|
128
|
+
]);
|
|
129
|
+
assertParse("callExpression", "fn(a, b)", [
|
|
130
|
+
[ops.builtin, "fn"],
|
|
131
|
+
[ops.scope, "a"],
|
|
132
|
+
[ops.scope, "b"],
|
|
133
|
+
]);
|
|
134
|
+
assertParse("callExpression", "foo.js( a , b )", [
|
|
135
|
+
[ops.scope, "foo.js"],
|
|
136
|
+
[ops.scope, "a"],
|
|
137
|
+
[ops.scope, "b"],
|
|
138
|
+
]);
|
|
139
|
+
assertParse("callExpression", "fn()(arg)", [
|
|
140
|
+
[[ops.builtin, "fn"], undefined],
|
|
141
|
+
[ops.scope, "arg"],
|
|
142
|
+
]);
|
|
143
|
+
assertParse("callExpression", "tree/", [ops.unpack, [ops.scope, "tree/"]]);
|
|
144
|
+
assertParse("callExpression", "tree/foo/bar", [
|
|
145
|
+
ops.traverse,
|
|
146
|
+
[ops.scope, "tree/"],
|
|
147
|
+
[ops.literal, "foo/"],
|
|
148
|
+
[ops.literal, "bar"],
|
|
149
|
+
]);
|
|
150
|
+
assertParse("callExpression", "tree/foo/bar/", [
|
|
151
|
+
ops.traverse,
|
|
152
|
+
[ops.scope, "tree/"],
|
|
153
|
+
[ops.literal, "foo/"],
|
|
154
|
+
[ops.literal, "bar/"],
|
|
155
|
+
]);
|
|
156
|
+
assertParse("callExpression", "/foo/bar", [
|
|
157
|
+
ops.traverse,
|
|
158
|
+
[ops.rootDirectory, [ops.literal, "foo/"]],
|
|
159
|
+
[ops.literal, "bar"],
|
|
160
|
+
]);
|
|
161
|
+
assertParse("callExpression", "foo.js()/key", [
|
|
162
|
+
ops.traverse,
|
|
163
|
+
[[ops.scope, "foo.js"], undefined],
|
|
164
|
+
[ops.literal, "key"],
|
|
165
|
+
]);
|
|
166
|
+
assertParse("callExpression", "tree/key()", [
|
|
167
|
+
[ops.traverse, [ops.scope, "tree/"], [ops.literal, "key"]],
|
|
168
|
+
undefined,
|
|
169
|
+
]);
|
|
170
|
+
assertParse("callExpression", "(tree)/", [ops.unpack, [ops.scope, "tree"]]);
|
|
171
|
+
assertParse("callExpression", "fn()/key()", [
|
|
172
|
+
[ops.traverse, [[ops.builtin, "fn"], undefined], [ops.literal, "key"]],
|
|
173
|
+
undefined,
|
|
174
|
+
]);
|
|
175
|
+
assertParse("callExpression", "(foo.js())('arg')", [
|
|
176
|
+
[[ops.scope, "foo.js"], undefined],
|
|
177
|
+
[ops.literal, "arg"],
|
|
178
|
+
]);
|
|
179
|
+
assertParse("callExpression", "fn('a')('b')", [
|
|
180
|
+
[
|
|
181
|
+
[ops.builtin, "fn"],
|
|
182
|
+
[ops.literal, "a"],
|
|
183
|
+
],
|
|
184
|
+
[ops.literal, "b"],
|
|
185
|
+
]);
|
|
186
|
+
assertParse("callExpression", "(foo.js())(a, b)", [
|
|
187
|
+
[[ops.scope, "foo.js"], undefined],
|
|
188
|
+
[ops.scope, "a"],
|
|
189
|
+
[ops.scope, "b"],
|
|
190
|
+
]);
|
|
191
|
+
assertParse("callExpression", "{ a: 1, b: 2}/b", [
|
|
192
|
+
ops.traverse,
|
|
193
|
+
[ops.object, ["a", [ops.literal, 1]], ["b", [ops.literal, 2]]],
|
|
194
|
+
[ops.literal, "b"],
|
|
195
|
+
]);
|
|
196
|
+
assertParse("callExpression", "indent`hello`", [
|
|
197
|
+
[ops.builtin, "indent"],
|
|
198
|
+
[ops.literal, ["hello"]],
|
|
199
|
+
]);
|
|
200
|
+
assertParse("callExpression", "fn.js`Hello, world.`", [
|
|
201
|
+
[ops.scope, "fn.js"],
|
|
202
|
+
[ops.literal, ["Hello, world."]],
|
|
203
|
+
]);
|
|
204
|
+
assertParse("callExpression", "files:src/assets", [
|
|
205
|
+
ops.traverse,
|
|
206
|
+
[
|
|
207
|
+
[ops.builtin, "files:"],
|
|
305
208
|
[ops.literal, "src/"],
|
|
306
|
-
|
|
307
|
-
]
|
|
308
|
-
|
|
309
|
-
|
|
209
|
+
],
|
|
210
|
+
[ops.literal, "assets"],
|
|
211
|
+
]);
|
|
212
|
+
assertParse("callExpression", "new:(js:Date, '2025-01-01')", [
|
|
213
|
+
[ops.builtin, "new:"],
|
|
214
|
+
[
|
|
215
|
+
[ops.builtin, "js:"],
|
|
216
|
+
[ops.literal, "Date"],
|
|
217
|
+
],
|
|
218
|
+
[ops.literal, "2025-01-01"],
|
|
219
|
+
]);
|
|
220
|
+
assertParse("callExpression", "map(markdown, mdHtml)", [
|
|
221
|
+
[ops.builtin, "map"],
|
|
222
|
+
[ops.scope, "markdown"],
|
|
223
|
+
[ops.scope, "mdHtml"],
|
|
224
|
+
]);
|
|
225
|
+
assertParse("callExpression", "package:@weborigami/dropbox/auth(creds)", [
|
|
226
|
+
[
|
|
227
|
+
ops.traverse,
|
|
310
228
|
[
|
|
311
|
-
[
|
|
312
|
-
[ops.literal, "
|
|
229
|
+
[ops.builtin, "package:"],
|
|
230
|
+
[ops.literal, "@weborigami/"],
|
|
313
231
|
],
|
|
314
|
-
[ops.literal, "
|
|
315
|
-
|
|
316
|
-
|
|
232
|
+
[ops.literal, "dropbox/"],
|
|
233
|
+
[ops.literal, "auth"],
|
|
234
|
+
],
|
|
235
|
+
[ops.scope, "creds"],
|
|
236
|
+
]);
|
|
317
237
|
});
|
|
318
238
|
|
|
319
239
|
test("callExpression using property acccess", () => {
|
|
320
240
|
assertParse("callExpression", "(foo).bar", [
|
|
321
|
-
|
|
322
|
-
[ops.
|
|
241
|
+
ops.traverse,
|
|
242
|
+
[ops.scope, "foo"],
|
|
323
243
|
[ops.literal, "bar"],
|
|
324
244
|
]);
|
|
325
245
|
assertParse("callExpression", "(foo).bar.baz", [
|
|
326
|
-
|
|
327
|
-
[ops.
|
|
328
|
-
[ops.literal, "bar/"],
|
|
246
|
+
ops.traverse,
|
|
247
|
+
[ops.traverse, [ops.scope, "foo"], [ops.literal, "bar"]],
|
|
329
248
|
[ops.literal, "baz"],
|
|
330
249
|
]);
|
|
331
250
|
assertParse("callExpression", "foo[bar]", [
|
|
332
|
-
|
|
333
|
-
[ops.
|
|
334
|
-
[
|
|
251
|
+
ops.traverse,
|
|
252
|
+
[ops.scope, "foo/"],
|
|
253
|
+
[ops.scope, "bar"],
|
|
335
254
|
]);
|
|
336
|
-
assertParse(
|
|
337
|
-
"callExpression",
|
|
338
|
-
"Tree.map",
|
|
339
|
-
[markers.reference, [ops.literal, "Tree/"], [ops.literal, "map"]],
|
|
340
|
-
"jse"
|
|
341
|
-
);
|
|
342
255
|
});
|
|
343
256
|
|
|
344
257
|
test("commaExpression", () => {
|
|
345
258
|
assertParse("commaExpression", "1", [ops.literal, 1]);
|
|
346
259
|
assertParse("commaExpression", "a, b, c", [
|
|
347
260
|
ops.comma,
|
|
348
|
-
[
|
|
349
|
-
[
|
|
350
|
-
[
|
|
261
|
+
[ops.scope, "a"],
|
|
262
|
+
[ops.scope, "b"],
|
|
263
|
+
[ops.scope, "c"],
|
|
351
264
|
]);
|
|
352
265
|
});
|
|
353
266
|
|
|
@@ -355,19 +268,19 @@ describe("Origami parser", () => {
|
|
|
355
268
|
assertParse("conditionalExpression", "1", [ops.literal, 1]);
|
|
356
269
|
assertParse("conditionalExpression", "true ? 1 : 0", [
|
|
357
270
|
ops.conditional,
|
|
358
|
-
[
|
|
271
|
+
[ops.scope, "true"],
|
|
359
272
|
[ops.literal, 1],
|
|
360
273
|
[ops.literal, 0],
|
|
361
274
|
]);
|
|
362
275
|
assertParse("conditionalExpression", "false ? () => 1 : 0", [
|
|
363
276
|
ops.conditional,
|
|
364
|
-
[
|
|
277
|
+
[ops.scope, "false"],
|
|
365
278
|
[ops.lambda, [], [ops.lambda, [], [ops.literal, 1]]],
|
|
366
279
|
[ops.literal, 0],
|
|
367
280
|
]);
|
|
368
281
|
assertParse("conditionalExpression", "false ? =1 : 0", [
|
|
369
282
|
ops.conditional,
|
|
370
|
-
[
|
|
283
|
+
[ops.scope, "false"],
|
|
371
284
|
[ops.lambda, [], [ops.lambda, [[ops.literal, "_"]], [ops.literal, 1]]],
|
|
372
285
|
[ops.literal, 0],
|
|
373
286
|
]);
|
|
@@ -381,12 +294,8 @@ describe("Origami parser", () => {
|
|
|
381
294
|
]);
|
|
382
295
|
assertParse("equalityExpression", "a === b === c", [
|
|
383
296
|
ops.strictEqual,
|
|
384
|
-
[
|
|
385
|
-
|
|
386
|
-
[markers.reference, [ops.literal, "a"]],
|
|
387
|
-
[markers.reference, [ops.literal, "b"]],
|
|
388
|
-
],
|
|
389
|
-
[markers.reference, [ops.literal, "c"]],
|
|
297
|
+
[ops.strictEqual, [undetermined, "a"], [undetermined, "b"]],
|
|
298
|
+
[undetermined, "c"],
|
|
390
299
|
]);
|
|
391
300
|
assertParse("equalityExpression", "1 !== 1", [
|
|
392
301
|
ops.notStrictEqual,
|
|
@@ -454,8 +363,8 @@ Body`,
|
|
|
454
363
|
[
|
|
455
364
|
ops.getter,
|
|
456
365
|
[
|
|
457
|
-
[
|
|
458
|
-
[
|
|
366
|
+
[ops.scope, "index.ori"],
|
|
367
|
+
[ops.scope, "teamData.yaml"],
|
|
459
368
|
],
|
|
460
369
|
],
|
|
461
370
|
],
|
|
@@ -464,12 +373,9 @@ Body`,
|
|
|
464
373
|
[
|
|
465
374
|
ops.getter,
|
|
466
375
|
[
|
|
467
|
-
[
|
|
468
|
-
[
|
|
469
|
-
[
|
|
470
|
-
ops.object,
|
|
471
|
-
["value", [markers.reference, [ops.literal, "thumbnail.js"]]],
|
|
472
|
-
],
|
|
376
|
+
[ops.builtin, "map"],
|
|
377
|
+
[ops.scope, "images"],
|
|
378
|
+
[ops.object, ["value", [ops.scope, "thumbnail.js"]]],
|
|
473
379
|
],
|
|
474
380
|
],
|
|
475
381
|
],
|
|
@@ -477,54 +383,57 @@ Body`,
|
|
|
477
383
|
);
|
|
478
384
|
|
|
479
385
|
// Builtin on its own is the function itself, not a function call
|
|
480
|
-
assertParse("expression", "mdHtml:", [
|
|
386
|
+
assertParse("expression", "mdHtml:", [ops.builtin, "mdHtml:"]);
|
|
481
387
|
|
|
482
|
-
// Consecutive
|
|
483
|
-
assertParse(
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
[
|
|
487
|
-
|
|
488
|
-
false
|
|
489
|
-
);
|
|
388
|
+
// Consecutive slahes in a path are removed
|
|
389
|
+
assertParse("expression", "path//key", [
|
|
390
|
+
ops.traverse,
|
|
391
|
+
[ops.scope, "path/"],
|
|
392
|
+
[ops.literal, "key"],
|
|
393
|
+
]);
|
|
490
394
|
|
|
395
|
+
// Single slash at start of something = absolute file path
|
|
396
|
+
assertParse("expression", "/path", [
|
|
397
|
+
ops.rootDirectory,
|
|
398
|
+
[ops.literal, "path"],
|
|
399
|
+
]);
|
|
400
|
+
|
|
401
|
+
// Consecutive slashes at start of something = comment
|
|
402
|
+
assertParse("expression", "path //comment", [ops.scope, "path"], false);
|
|
491
403
|
assertParse("expression", "page.ori(mdHtml:(about.md))", [
|
|
492
|
-
[
|
|
404
|
+
[ops.scope, "page.ori"],
|
|
493
405
|
[
|
|
494
|
-
[
|
|
495
|
-
[
|
|
406
|
+
[ops.builtin, "mdHtml:"],
|
|
407
|
+
[ops.scope, "about.md"],
|
|
496
408
|
],
|
|
497
409
|
]);
|
|
498
410
|
|
|
499
411
|
// Slash on its own is the root folder
|
|
500
412
|
assertParse("expression", "keys /", [
|
|
501
|
-
[
|
|
413
|
+
[ops.builtin, "keys"],
|
|
502
414
|
[ops.rootDirectory],
|
|
503
415
|
]);
|
|
504
416
|
|
|
505
417
|
assertParse("expression", "'Hello' -> test.orit", [
|
|
506
|
-
[
|
|
418
|
+
[ops.scope, "test.orit"],
|
|
507
419
|
[ops.literal, "Hello"],
|
|
508
420
|
]);
|
|
509
|
-
assertParse("expression", "obj.json", [
|
|
510
|
-
markers.reference,
|
|
511
|
-
[ops.literal, "obj.json"],
|
|
512
|
-
]);
|
|
421
|
+
assertParse("expression", "obj.json", [ops.scope, "obj.json"]);
|
|
513
422
|
assertParse("expression", "(fn a, b, c)", [
|
|
514
|
-
[
|
|
515
|
-
[
|
|
516
|
-
[
|
|
517
|
-
[
|
|
423
|
+
[ops.builtin, "fn"],
|
|
424
|
+
[undetermined, "a"],
|
|
425
|
+
[undetermined, "b"],
|
|
426
|
+
[undetermined, "c"],
|
|
518
427
|
]);
|
|
519
428
|
assertParse("expression", "foo.bar('hello', 'world')", [
|
|
520
|
-
[
|
|
429
|
+
[ops.scope, "foo.bar"],
|
|
521
430
|
[ops.literal, "hello"],
|
|
522
431
|
[ops.literal, "world"],
|
|
523
432
|
]);
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
433
|
+
assertParse("expression", "(key)('a')", [
|
|
434
|
+
[ops.scope, "key"],
|
|
435
|
+
[ops.literal, "a"],
|
|
436
|
+
]);
|
|
528
437
|
assertParse("expression", "1", [ops.literal, 1]);
|
|
529
438
|
assertParse("expression", "{ a: 1, b: 2 }", [
|
|
530
439
|
ops.object,
|
|
@@ -532,49 +441,41 @@ Body`,
|
|
|
532
441
|
["b", [ops.literal, 2]],
|
|
533
442
|
]);
|
|
534
443
|
assertParse("expression", "serve { index.html: 'hello' }", [
|
|
535
|
-
[
|
|
444
|
+
[ops.builtin, "serve"],
|
|
536
445
|
[ops.object, ["index.html", [ops.literal, "hello"]]],
|
|
537
446
|
]);
|
|
538
447
|
assertParse("expression", "fn =`x`", [
|
|
539
|
-
[
|
|
540
|
-
[
|
|
541
|
-
ops.lambda,
|
|
542
|
-
[[ops.literal, "_"]],
|
|
543
|
-
[ops.templateTree, [ops.literal, ["x"]]],
|
|
544
|
-
],
|
|
448
|
+
[ops.builtin, "fn"],
|
|
449
|
+
[ops.lambda, [[ops.literal, "_"]], [ops.template, [ops.literal, ["x"]]]],
|
|
545
450
|
]);
|
|
546
451
|
assertParse("expression", "copy app.js(formulas), files:snapshot", [
|
|
547
|
-
[
|
|
452
|
+
[ops.builtin, "copy"],
|
|
548
453
|
[
|
|
549
|
-
[
|
|
550
|
-
[
|
|
454
|
+
[ops.scope, "app.js"],
|
|
455
|
+
[ops.scope, "formulas"],
|
|
551
456
|
],
|
|
552
457
|
[
|
|
553
|
-
[
|
|
458
|
+
[ops.builtin, "files:"],
|
|
554
459
|
[ops.literal, "snapshot"],
|
|
555
460
|
],
|
|
556
461
|
]);
|
|
557
462
|
assertParse("expression", "map =`<li>${_}</li>`", [
|
|
558
|
-
[
|
|
463
|
+
[ops.builtin, "map"],
|
|
559
464
|
[
|
|
560
465
|
ops.lambda,
|
|
561
466
|
[[ops.literal, "_"]],
|
|
562
|
-
[
|
|
563
|
-
ops.templateTree,
|
|
564
|
-
[ops.literal, ["<li>", "</li>"]],
|
|
565
|
-
[markers.reference, [ops.literal, "_"]],
|
|
566
|
-
],
|
|
467
|
+
[ops.template, [ops.literal, ["<li>", "</li>"]], [ops.scope, "_"]],
|
|
567
468
|
],
|
|
568
469
|
]);
|
|
569
470
|
assertParse("expression", `https://example.com/about/`, [
|
|
570
|
-
[
|
|
471
|
+
[ops.builtin, "https:"],
|
|
571
472
|
[ops.literal, "example.com/"],
|
|
572
473
|
[ops.literal, "about/"],
|
|
573
474
|
]);
|
|
574
475
|
assertParse("expression", "tag`Hello, ${name}!`", [
|
|
575
|
-
[
|
|
476
|
+
[ops.builtin, "tag"],
|
|
576
477
|
[ops.literal, ["Hello, ", "!"]],
|
|
577
|
-
[ops.concat, [
|
|
478
|
+
[ops.concat, [ops.scope, "name"]],
|
|
578
479
|
]);
|
|
579
480
|
assertParse("expression", "(post, slug) => fn.js(post, slug)", [
|
|
580
481
|
ops.lambda,
|
|
@@ -583,71 +484,52 @@ Body`,
|
|
|
583
484
|
[ops.literal, "slug"],
|
|
584
485
|
],
|
|
585
486
|
[
|
|
586
|
-
[
|
|
587
|
-
[
|
|
588
|
-
[
|
|
487
|
+
[ops.scope, "fn.js"],
|
|
488
|
+
[ops.scope, "post"],
|
|
489
|
+
[ops.scope, "slug"],
|
|
589
490
|
],
|
|
590
491
|
]);
|
|
591
492
|
assertParse("expression", "keys ~", [
|
|
592
|
-
[
|
|
493
|
+
[ops.builtin, "keys"],
|
|
593
494
|
[ops.homeDirectory],
|
|
594
495
|
]);
|
|
595
496
|
assertParse("expression", "keys /Users/alice", [
|
|
596
|
-
[
|
|
597
|
-
[
|
|
497
|
+
[ops.builtin, "keys"],
|
|
498
|
+
[
|
|
499
|
+
ops.traverse,
|
|
500
|
+
[ops.rootDirectory, [ops.literal, "Users/"]],
|
|
501
|
+
[ops.literal, "alice"],
|
|
502
|
+
],
|
|
598
503
|
]);
|
|
599
504
|
|
|
600
505
|
// Verify parser treatment of identifiers containing operators
|
|
601
506
|
assertParse("expression", "a + b", [
|
|
602
507
|
ops.addition,
|
|
603
|
-
[
|
|
604
|
-
[
|
|
508
|
+
[undetermined, "a"],
|
|
509
|
+
[undetermined, "b"],
|
|
605
510
|
]);
|
|
606
|
-
assertParse("expression", "a+b", [
|
|
511
|
+
assertParse("expression", "a+b", [ops.scope, "a+b"]);
|
|
607
512
|
assertParse("expression", "a - b", [
|
|
608
513
|
ops.subtraction,
|
|
609
|
-
[
|
|
610
|
-
[
|
|
514
|
+
[undetermined, "a"],
|
|
515
|
+
[undetermined, "b"],
|
|
611
516
|
]);
|
|
612
|
-
assertParse("expression", "a-b", [
|
|
613
|
-
assertParse("expression", "a&b", [
|
|
517
|
+
assertParse("expression", "a-b", [ops.scope, "a-b"]);
|
|
518
|
+
assertParse("expression", "a&b", [ops.scope, "a&b"]);
|
|
614
519
|
assertParse("expression", "a & b", [
|
|
615
520
|
ops.bitwiseAnd,
|
|
616
|
-
[
|
|
617
|
-
[
|
|
521
|
+
[undetermined, "a"],
|
|
522
|
+
[undetermined, "b"],
|
|
618
523
|
]);
|
|
619
524
|
});
|
|
620
525
|
|
|
621
|
-
test("frontMatterExpression", () => {
|
|
622
|
-
assertParse(
|
|
623
|
-
"frontMatterExpression",
|
|
624
|
-
`---
|
|
625
|
-
(name) => _template()
|
|
626
|
-
---
|
|
627
|
-
`,
|
|
628
|
-
[
|
|
629
|
-
ops.lambda,
|
|
630
|
-
[[ops.literal, "name"]],
|
|
631
|
-
[[markers.reference, [ops.literal, "_template"]], undefined],
|
|
632
|
-
],
|
|
633
|
-
"jse",
|
|
634
|
-
false
|
|
635
|
-
);
|
|
636
|
-
});
|
|
637
|
-
|
|
638
526
|
test("group", () => {
|
|
639
|
-
assertParse("group", "(hello)", [
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
]);
|
|
643
|
-
assertParse("group", "(((nested)))", [
|
|
644
|
-
markers.reference,
|
|
645
|
-
[ops.literal, "nested"],
|
|
646
|
-
]);
|
|
647
|
-
assertParse("group", "(fn())", [[markers.global, "fn"], undefined]);
|
|
527
|
+
assertParse("group", "(hello)", [ops.scope, "hello"]);
|
|
528
|
+
assertParse("group", "(((nested)))", [ops.scope, "nested"]);
|
|
529
|
+
assertParse("group", "(fn())", [[ops.builtin, "fn"], undefined]);
|
|
648
530
|
assertParse("group", "(a -> b)", [
|
|
649
|
-
[
|
|
650
|
-
[
|
|
531
|
+
[ops.builtin, "b"],
|
|
532
|
+
[ops.scope, "a"],
|
|
651
533
|
]);
|
|
652
534
|
});
|
|
653
535
|
|
|
@@ -662,50 +544,50 @@ Body`,
|
|
|
662
544
|
});
|
|
663
545
|
|
|
664
546
|
test("identifier", () => {
|
|
665
|
-
assertParse("identifier", "abc", "abc",
|
|
666
|
-
assertParse("identifier", "index.html", "index.html",
|
|
667
|
-
assertParse("identifier", "foo\\ bar", "foo bar",
|
|
668
|
-
assertParse("identifier", "x-y-z", "x-y-z",
|
|
547
|
+
assertParse("identifier", "abc", "abc", false);
|
|
548
|
+
assertParse("identifier", "index.html", "index.html", false);
|
|
549
|
+
assertParse("identifier", "foo\\ bar", "foo bar", false);
|
|
550
|
+
assertParse("identifier", "x-y-z", "x-y-z", false);
|
|
669
551
|
});
|
|
670
552
|
|
|
671
553
|
test("implicitParenthesesCallExpression", () => {
|
|
672
554
|
assertParse("implicitParenthesesCallExpression", "fn arg", [
|
|
673
|
-
[
|
|
674
|
-
[
|
|
555
|
+
[ops.builtin, "fn"],
|
|
556
|
+
[undetermined, "arg"],
|
|
675
557
|
]);
|
|
676
558
|
assertParse("implicitParenthesesCallExpression", "page.ori 'a', 'b'", [
|
|
677
|
-
[
|
|
559
|
+
[ops.scope, "page.ori"],
|
|
678
560
|
[ops.literal, "a"],
|
|
679
561
|
[ops.literal, "b"],
|
|
680
562
|
]);
|
|
681
563
|
assertParse("implicitParenthesesCallExpression", "fn a(b), c", [
|
|
682
|
-
[
|
|
564
|
+
[ops.builtin, "fn"],
|
|
683
565
|
[
|
|
684
|
-
[
|
|
685
|
-
[
|
|
566
|
+
[ops.builtin, "a"],
|
|
567
|
+
[ops.scope, "b"],
|
|
686
568
|
],
|
|
687
|
-
[
|
|
569
|
+
[undetermined, "c"],
|
|
688
570
|
]);
|
|
689
571
|
assertParse("implicitParenthesesCallExpression", "(fn()) 'arg'", [
|
|
690
|
-
[[
|
|
572
|
+
[[ops.builtin, "fn"], undefined],
|
|
691
573
|
[ops.literal, "arg"],
|
|
692
574
|
]);
|
|
693
575
|
assertParse("implicitParenthesesCallExpression", "tree/key arg", [
|
|
694
|
-
[
|
|
695
|
-
[
|
|
576
|
+
[ops.traverse, [ops.scope, "tree/"], [ops.literal, "key"]],
|
|
577
|
+
[undetermined, "arg"],
|
|
696
578
|
]);
|
|
697
579
|
assertParse("implicitParenthesesCallExpression", "foo.js bar.ori 'arg'", [
|
|
698
|
-
[
|
|
580
|
+
[ops.scope, "foo.js"],
|
|
699
581
|
[
|
|
700
|
-
[
|
|
582
|
+
[ops.scope, "bar.ori"],
|
|
701
583
|
[ops.literal, "arg"],
|
|
702
584
|
],
|
|
703
585
|
]);
|
|
704
586
|
});
|
|
705
587
|
|
|
706
588
|
test("jsIdentifier", () => {
|
|
707
|
-
assertParse("jsIdentifier", "foo",
|
|
708
|
-
assertParse("jsIdentifier", "$Δelta",
|
|
589
|
+
assertParse("jsIdentifier", "foo", "foo", false);
|
|
590
|
+
assertParse("jsIdentifier", "$Δelta", "$Δelta", false);
|
|
709
591
|
assertThrows(
|
|
710
592
|
"jsIdentifier",
|
|
711
593
|
"1stCharacterIsNumber",
|
|
@@ -755,8 +637,8 @@ Body`,
|
|
|
755
637
|
test("logicalAndExpression", () => {
|
|
756
638
|
assertParse("logicalAndExpression", "true && false", [
|
|
757
639
|
ops.logicalAnd,
|
|
758
|
-
[
|
|
759
|
-
[ops.lambda, [], [
|
|
640
|
+
[ops.scope, "true"],
|
|
641
|
+
[ops.lambda, [], [undetermined, "false"]],
|
|
760
642
|
]);
|
|
761
643
|
});
|
|
762
644
|
|
|
@@ -768,9 +650,9 @@ Body`,
|
|
|
768
650
|
]);
|
|
769
651
|
assertParse("logicalOrExpression", "false || false || true", [
|
|
770
652
|
ops.logicalOr,
|
|
771
|
-
[
|
|
772
|
-
[ops.lambda, [], [
|
|
773
|
-
[ops.lambda, [], [
|
|
653
|
+
[ops.scope, "false"],
|
|
654
|
+
[ops.lambda, [], [undetermined, "false"]],
|
|
655
|
+
[ops.lambda, [], [undetermined, "true"]],
|
|
774
656
|
]);
|
|
775
657
|
assertParse("logicalOrExpression", "1 || 2 && 0", [
|
|
776
658
|
ops.logicalOr,
|
|
@@ -780,13 +662,7 @@ Body`,
|
|
|
780
662
|
});
|
|
781
663
|
|
|
782
664
|
test("multiLineComment", () => {
|
|
783
|
-
assertParse(
|
|
784
|
-
"multiLineComment",
|
|
785
|
-
"/*\nHello, world!\n*/",
|
|
786
|
-
null,
|
|
787
|
-
"jse",
|
|
788
|
-
false
|
|
789
|
-
);
|
|
665
|
+
assertParse("multiLineComment", "/*\nHello, world!\n*/", null, false);
|
|
790
666
|
});
|
|
791
667
|
|
|
792
668
|
test("multiplicativeExpression", () => {
|
|
@@ -808,31 +684,20 @@ Body`,
|
|
|
808
684
|
});
|
|
809
685
|
|
|
810
686
|
test("namespace", () => {
|
|
811
|
-
assertParse("namespace", "js:", [
|
|
812
|
-
});
|
|
813
|
-
|
|
814
|
-
test("newExpression", () => {
|
|
815
|
-
assertParse("newExpression", "new Foo()", [
|
|
816
|
-
ops.construct,
|
|
817
|
-
[markers.reference, [ops.literal, "Foo"]],
|
|
818
|
-
]);
|
|
819
|
-
assertParse("newExpression", "new:Foo()", [
|
|
820
|
-
ops.construct,
|
|
821
|
-
[markers.reference, [ops.literal, "Foo"]],
|
|
822
|
-
]);
|
|
687
|
+
assertParse("namespace", "js:", [ops.builtin, "js:"]);
|
|
823
688
|
});
|
|
824
689
|
|
|
825
690
|
test("nullishCoalescingExpression", () => {
|
|
826
691
|
assertParse("nullishCoalescingExpression", "a ?? b", [
|
|
827
692
|
ops.nullishCoalescing,
|
|
828
|
-
[
|
|
829
|
-
[ops.lambda, [], [
|
|
693
|
+
[ops.scope, "a"],
|
|
694
|
+
[ops.lambda, [], [undetermined, "b"]],
|
|
830
695
|
]);
|
|
831
696
|
assertParse("nullishCoalescingExpression", "a ?? b ?? c", [
|
|
832
697
|
ops.nullishCoalescing,
|
|
833
|
-
[
|
|
834
|
-
[ops.lambda, [], [
|
|
835
|
-
[ops.lambda, [], [
|
|
698
|
+
[ops.scope, "a"],
|
|
699
|
+
[ops.lambda, [], [undetermined, "b"]],
|
|
700
|
+
[ops.lambda, [], [undetermined, "c"]],
|
|
836
701
|
]);
|
|
837
702
|
});
|
|
838
703
|
|
|
@@ -847,7 +712,7 @@ Body`,
|
|
|
847
712
|
assertParse("objectLiteral", "{ a: 1, b }", [
|
|
848
713
|
ops.object,
|
|
849
714
|
["a", [ops.literal, 1]],
|
|
850
|
-
["b", [
|
|
715
|
+
["b", [ops.inherited, "b"]],
|
|
851
716
|
]);
|
|
852
717
|
assertParse("objectLiteral", "{ sub: { a: 1 } }", [
|
|
853
718
|
ops.object,
|
|
@@ -864,7 +729,7 @@ Body`,
|
|
|
864
729
|
]);
|
|
865
730
|
assertParse("objectLiteral", "{ a = b, b = 2 }", [
|
|
866
731
|
ops.object,
|
|
867
|
-
["a", [ops.getter, [
|
|
732
|
+
["a", [ops.getter, [ops.scope, "b"]]],
|
|
868
733
|
["b", [ops.literal, 2]],
|
|
869
734
|
]);
|
|
870
735
|
assertParse(
|
|
@@ -875,7 +740,7 @@ Body`,
|
|
|
875
740
|
}`,
|
|
876
741
|
[
|
|
877
742
|
ops.object,
|
|
878
|
-
["a", [ops.getter, [
|
|
743
|
+
["a", [ops.getter, [ops.scope, "b"]]],
|
|
879
744
|
["b", [ops.literal, 2]],
|
|
880
745
|
]
|
|
881
746
|
);
|
|
@@ -891,7 +756,7 @@ Body`,
|
|
|
891
756
|
ops.object,
|
|
892
757
|
[
|
|
893
758
|
"a",
|
|
894
|
-
[ops.object, ["b", [ops.getter, [[
|
|
759
|
+
[ops.object, ["b", [ops.getter, [[ops.builtin, "fn"], undefined]]]],
|
|
895
760
|
],
|
|
896
761
|
]);
|
|
897
762
|
assertParse("objectLiteral", "{ x = fn.js('a') }", [
|
|
@@ -901,28 +766,16 @@ Body`,
|
|
|
901
766
|
[
|
|
902
767
|
ops.getter,
|
|
903
768
|
[
|
|
904
|
-
[
|
|
769
|
+
[ops.scope, "fn.js"],
|
|
905
770
|
[ops.literal, "a"],
|
|
906
771
|
],
|
|
907
772
|
],
|
|
908
773
|
],
|
|
909
774
|
]);
|
|
910
|
-
assertParse("objectLiteral", "{ a: 1, ...
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
["c", [markers.reference, [ops.literal, "a"]]],
|
|
915
|
-
[
|
|
916
|
-
"_result",
|
|
917
|
-
[
|
|
918
|
-
ops.merge,
|
|
919
|
-
[ops.object, ["a", [ops.getter, [[ops.context, 1], "a"]]]],
|
|
920
|
-
[markers.reference, [ops.literal, "more"]],
|
|
921
|
-
[ops.object, ["c", [ops.getter, [[ops.context, 1], "c"]]]],
|
|
922
|
-
],
|
|
923
|
-
],
|
|
924
|
-
],
|
|
925
|
-
"_result",
|
|
775
|
+
assertParse("objectLiteral", "{ a: 1, ...b }", [
|
|
776
|
+
ops.merge,
|
|
777
|
+
[ops.object, ["a", [ops.literal, 1]]],
|
|
778
|
+
[ops.scope, "b"],
|
|
926
779
|
]);
|
|
927
780
|
assertParse("objectLiteral", "{ a: 1, ...{ b: 2 } }", [
|
|
928
781
|
ops.object,
|
|
@@ -933,63 +786,22 @@ Body`,
|
|
|
933
786
|
ops.object,
|
|
934
787
|
["(a)", [ops.literal, 1]],
|
|
935
788
|
]);
|
|
936
|
-
assertParse(
|
|
937
|
-
"objectLiteral",
|
|
938
|
-
"{ <path/to/file.txt> }",
|
|
939
|
-
[
|
|
940
|
-
ops.object,
|
|
941
|
-
[
|
|
942
|
-
"file.txt",
|
|
943
|
-
[
|
|
944
|
-
[ops.scope],
|
|
945
|
-
[ops.literal, "path/"],
|
|
946
|
-
[ops.literal, "to/"],
|
|
947
|
-
[ops.literal, "file.txt"],
|
|
948
|
-
],
|
|
949
|
-
],
|
|
950
|
-
],
|
|
951
|
-
"jse"
|
|
952
|
-
);
|
|
953
789
|
});
|
|
954
790
|
|
|
955
791
|
test("objectEntry", () => {
|
|
956
|
-
assertParse("objectEntry", "foo", ["foo", [
|
|
957
|
-
assertParse("objectEntry", "x: y", [
|
|
958
|
-
|
|
959
|
-
[markers.reference, [ops.literal, "y"]],
|
|
960
|
-
]);
|
|
961
|
-
assertParse("objectEntry", "a: a", [
|
|
962
|
-
"a",
|
|
963
|
-
[markers.reference, [ops.literal, "a"]],
|
|
964
|
-
]);
|
|
965
|
-
assertParse(
|
|
966
|
-
"objectEntry",
|
|
967
|
-
"<path/to/file.txt>",
|
|
968
|
-
[
|
|
969
|
-
"file.txt",
|
|
970
|
-
[
|
|
971
|
-
[ops.scope],
|
|
972
|
-
[ops.literal, "path/"],
|
|
973
|
-
[ops.literal, "to/"],
|
|
974
|
-
[ops.literal, "file.txt"],
|
|
975
|
-
],
|
|
976
|
-
],
|
|
977
|
-
"jse"
|
|
978
|
-
);
|
|
792
|
+
assertParse("objectEntry", "foo", ["foo", [ops.inherited, "foo"]]);
|
|
793
|
+
assertParse("objectEntry", "x: y", ["x", [ops.scope, "y"]]);
|
|
794
|
+
assertParse("objectEntry", "a: a", ["a", [ops.inherited, "a"]]);
|
|
979
795
|
assertParse("objectEntry", "a: (a) => a", [
|
|
980
796
|
"a",
|
|
981
|
-
[
|
|
982
|
-
ops.lambda,
|
|
983
|
-
[[ops.literal, "a"]],
|
|
984
|
-
[markers.reference, [ops.literal, "a"]],
|
|
985
|
-
],
|
|
797
|
+
[ops.lambda, [[ops.literal, "a"]], [ops.scope, "a"]],
|
|
986
798
|
]);
|
|
987
799
|
assertParse("objectEntry", "posts/: map(posts, post.ori)", [
|
|
988
800
|
"posts/",
|
|
989
801
|
[
|
|
990
|
-
[
|
|
991
|
-
[
|
|
992
|
-
[
|
|
802
|
+
[ops.builtin, "map"],
|
|
803
|
+
[ops.inherited, "posts"],
|
|
804
|
+
[ops.scope, "post.ori"],
|
|
993
805
|
],
|
|
994
806
|
]);
|
|
995
807
|
});
|
|
@@ -997,14 +809,14 @@ Body`,
|
|
|
997
809
|
test("objectGetter", () => {
|
|
998
810
|
assertParse("objectGetter", "data = obj.json", [
|
|
999
811
|
"data",
|
|
1000
|
-
[ops.getter, [
|
|
812
|
+
[ops.getter, [ops.scope, "obj.json"]],
|
|
1001
813
|
]);
|
|
1002
814
|
assertParse("objectGetter", "foo = page.ori 'bar'", [
|
|
1003
815
|
"foo",
|
|
1004
816
|
[
|
|
1005
817
|
ops.getter,
|
|
1006
818
|
[
|
|
1007
|
-
[
|
|
819
|
+
[ops.scope, "page.ori"],
|
|
1008
820
|
[ops.literal, "bar"],
|
|
1009
821
|
],
|
|
1010
822
|
],
|
|
@@ -1020,31 +832,24 @@ Body`,
|
|
|
1020
832
|
assertParse("objectProperty", "x: fn('a')", [
|
|
1021
833
|
"x",
|
|
1022
834
|
[
|
|
1023
|
-
[
|
|
835
|
+
[ops.builtin, "fn"],
|
|
1024
836
|
[ops.literal, "a"],
|
|
1025
837
|
],
|
|
1026
838
|
]);
|
|
1027
839
|
});
|
|
1028
840
|
|
|
1029
841
|
test("objectPublicKey", () => {
|
|
1030
|
-
assertParse("objectPublicKey", "a", "a",
|
|
1031
|
-
assertParse("objectPublicKey", "markdown/", "markdown/",
|
|
1032
|
-
assertParse("objectPublicKey", "foo\\ bar", "foo bar",
|
|
1033
|
-
});
|
|
1034
|
-
|
|
1035
|
-
test("optionalChaining", () => {
|
|
1036
|
-
assertParse("optionalChaining", "?.key", [
|
|
1037
|
-
ops.optionalTraverse,
|
|
1038
|
-
[ops.literal, "key"],
|
|
1039
|
-
]);
|
|
842
|
+
assertParse("objectPublicKey", "a", "a", false);
|
|
843
|
+
assertParse("objectPublicKey", "markdown/", "markdown/", false);
|
|
844
|
+
assertParse("objectPublicKey", "foo\\ bar", "foo bar", false);
|
|
1040
845
|
});
|
|
1041
846
|
|
|
1042
847
|
test("parenthesesArguments", () => {
|
|
1043
848
|
assertParse("parenthesesArguments", "()", [undefined]);
|
|
1044
849
|
assertParse("parenthesesArguments", "(a, b, c)", [
|
|
1045
|
-
[
|
|
1046
|
-
[
|
|
1047
|
-
[
|
|
850
|
+
[ops.scope, "a"],
|
|
851
|
+
[ops.scope, "b"],
|
|
852
|
+
[ops.scope, "c"],
|
|
1048
853
|
]);
|
|
1049
854
|
});
|
|
1050
855
|
|
|
@@ -1066,61 +871,46 @@ Body`,
|
|
|
1066
871
|
});
|
|
1067
872
|
|
|
1068
873
|
test("pathArguments", () => {
|
|
1069
|
-
assertParse("pathArguments", "/", [
|
|
874
|
+
assertParse("pathArguments", "/", [ops.traverse]);
|
|
1070
875
|
assertParse("pathArguments", "/tree", [
|
|
1071
|
-
|
|
876
|
+
ops.traverse,
|
|
1072
877
|
[ops.literal, "tree"],
|
|
1073
878
|
]);
|
|
1074
879
|
assertParse("pathArguments", "/tree/", [
|
|
1075
|
-
|
|
880
|
+
ops.traverse,
|
|
1076
881
|
[ops.literal, "tree/"],
|
|
1077
882
|
]);
|
|
1078
883
|
});
|
|
1079
884
|
|
|
1080
885
|
test("pipelineExpression", () => {
|
|
1081
|
-
assertParse("pipelineExpression", "foo", [
|
|
1082
|
-
markers.reference,
|
|
1083
|
-
[ops.literal, "foo"],
|
|
1084
|
-
]);
|
|
886
|
+
assertParse("pipelineExpression", "foo", [ops.scope, "foo"]);
|
|
1085
887
|
assertParse("pipelineExpression", "a -> b", [
|
|
1086
|
-
[
|
|
1087
|
-
[
|
|
888
|
+
[ops.builtin, "b"],
|
|
889
|
+
[ops.scope, "a"],
|
|
1088
890
|
]);
|
|
1089
891
|
assertParse("pipelineExpression", "input → one.js → two.js", [
|
|
1090
|
-
[
|
|
892
|
+
[ops.scope, "two.js"],
|
|
1091
893
|
[
|
|
1092
|
-
[
|
|
1093
|
-
[
|
|
894
|
+
[ops.scope, "one.js"],
|
|
895
|
+
[ops.scope, "input"],
|
|
1094
896
|
],
|
|
1095
897
|
]);
|
|
1096
898
|
assertParse("pipelineExpression", "fn a -> b", [
|
|
1097
|
-
[
|
|
899
|
+
[ops.builtin, "b"],
|
|
1098
900
|
[
|
|
1099
|
-
[
|
|
1100
|
-
[
|
|
901
|
+
[ops.builtin, "fn"],
|
|
902
|
+
[undetermined, "a"],
|
|
1101
903
|
],
|
|
1102
904
|
]);
|
|
1103
905
|
});
|
|
1104
906
|
|
|
1105
907
|
test("primary", () => {
|
|
1106
|
-
assertParse("primary", "foo.js", [
|
|
1107
|
-
markers.reference,
|
|
1108
|
-
[ops.literal, "foo.js"],
|
|
1109
|
-
]);
|
|
908
|
+
assertParse("primary", "foo.js", [ops.scope, "foo.js"]);
|
|
1110
909
|
assertParse("primary", "[1, 2]", [
|
|
1111
910
|
ops.array,
|
|
1112
911
|
[ops.literal, 1],
|
|
1113
912
|
[ops.literal, 2],
|
|
1114
913
|
]);
|
|
1115
|
-
// Only in JSE
|
|
1116
|
-
assertParse(
|
|
1117
|
-
"primary",
|
|
1118
|
-
"<index.html>",
|
|
1119
|
-
[[ops.scope], [ops.literal, "index.html"]],
|
|
1120
|
-
"jse",
|
|
1121
|
-
false
|
|
1122
|
-
);
|
|
1123
|
-
assertThrows("primary", "<index.html>", `but "<" found`, 0, "shell");
|
|
1124
914
|
});
|
|
1125
915
|
|
|
1126
916
|
test("program", () => {
|
|
@@ -1130,39 +920,37 @@ Body`,
|
|
|
1130
920
|
'Hello'
|
|
1131
921
|
`,
|
|
1132
922
|
[ops.literal, "Hello"],
|
|
1133
|
-
"jse",
|
|
1134
923
|
false
|
|
1135
924
|
);
|
|
1136
925
|
});
|
|
1137
926
|
|
|
1138
927
|
test("protocolExpression", () => {
|
|
1139
|
-
assertParse("protocolExpression", "foo://bar
|
|
1140
|
-
[
|
|
1141
|
-
[ops.literal, "bar
|
|
1142
|
-
[ops.literal, "baz"],
|
|
928
|
+
assertParse("protocolExpression", "foo://bar", [
|
|
929
|
+
[ops.builtin, "foo:"],
|
|
930
|
+
[ops.literal, "bar"],
|
|
1143
931
|
]);
|
|
1144
932
|
assertParse("protocolExpression", "http://example.com", [
|
|
1145
|
-
[
|
|
933
|
+
[ops.builtin, "http:"],
|
|
1146
934
|
[ops.literal, "example.com"],
|
|
1147
935
|
]);
|
|
1148
936
|
assertParse("protocolExpression", "https://example.com/about/", [
|
|
1149
|
-
[
|
|
937
|
+
[ops.builtin, "https:"],
|
|
1150
938
|
[ops.literal, "example.com/"],
|
|
1151
939
|
[ops.literal, "about/"],
|
|
1152
940
|
]);
|
|
1153
941
|
assertParse("protocolExpression", "https://example.com/about/index.html", [
|
|
1154
|
-
[
|
|
942
|
+
[ops.builtin, "https:"],
|
|
1155
943
|
[ops.literal, "example.com/"],
|
|
1156
944
|
[ops.literal, "about/"],
|
|
1157
945
|
[ops.literal, "index.html"],
|
|
1158
946
|
]);
|
|
1159
947
|
assertParse("protocolExpression", "http://localhost:5000/foo", [
|
|
1160
|
-
[
|
|
948
|
+
[ops.builtin, "http:"],
|
|
1161
949
|
[ops.literal, "localhost:5000/"],
|
|
1162
950
|
[ops.literal, "foo"],
|
|
1163
951
|
]);
|
|
1164
952
|
assertParse("protocolExpression", "files:///foo/bar.txt", [
|
|
1165
|
-
[
|
|
953
|
+
[ops.builtin, "files:"],
|
|
1166
954
|
[ops.literal, "/"],
|
|
1167
955
|
[ops.literal, "foo/"],
|
|
1168
956
|
[ops.literal, "bar.txt"],
|
|
@@ -1171,15 +959,11 @@ Body`,
|
|
|
1171
959
|
|
|
1172
960
|
test("qualifiedReference", () => {
|
|
1173
961
|
assertParse("qualifiedReference", "js:Date", [
|
|
1174
|
-
[
|
|
962
|
+
[ops.builtin, "js:"],
|
|
1175
963
|
[ops.literal, "Date"],
|
|
1176
964
|
]);
|
|
1177
965
|
});
|
|
1178
966
|
|
|
1179
|
-
test("regexLiteral", () => {
|
|
1180
|
-
assertParse("regexLiteral", "/abc+/g", [ops.literal, /abc+/g]);
|
|
1181
|
-
});
|
|
1182
|
-
|
|
1183
967
|
test("relationalExpression", () => {
|
|
1184
968
|
assertParse("relationalExpression", "1 < 2", [
|
|
1185
969
|
ops.lessThan,
|
|
@@ -1203,15 +987,15 @@ Body`,
|
|
|
1203
987
|
]);
|
|
1204
988
|
});
|
|
1205
989
|
|
|
990
|
+
test("rootDirectory", () => {
|
|
991
|
+
assertParse("rootDirectory", "/", [ops.rootDirectory]);
|
|
992
|
+
});
|
|
993
|
+
|
|
1206
994
|
test("scopeReference", () => {
|
|
1207
|
-
assertParse("scopeReference", "keys", [
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
]);
|
|
1211
|
-
assertParse("scopeReference", "greet.js", [
|
|
1212
|
-
markers.reference,
|
|
1213
|
-
[ops.literal, "greet.js"],
|
|
1214
|
-
]);
|
|
995
|
+
assertParse("scopeReference", "keys", [undetermined, "keys"]);
|
|
996
|
+
assertParse("scopeReference", "greet.js", [ops.scope, "greet.js"]);
|
|
997
|
+
// scopeReference checks whether a slash follows; hard to test in isolation
|
|
998
|
+
// assertParse("scopeReference", "markdown/", [ops.scope, "markdown"]);
|
|
1215
999
|
});
|
|
1216
1000
|
|
|
1217
1001
|
test("shiftExpression", () => {
|
|
@@ -1236,40 +1020,30 @@ Body`,
|
|
|
1236
1020
|
assertParse("shorthandFunction", "=message", [
|
|
1237
1021
|
ops.lambda,
|
|
1238
1022
|
[[ops.literal, "_"]],
|
|
1239
|
-
[
|
|
1023
|
+
[undetermined, "message"],
|
|
1240
1024
|
]);
|
|
1241
1025
|
assertParse("shorthandFunction", "=`Hello, ${name}.`", [
|
|
1242
1026
|
ops.lambda,
|
|
1243
1027
|
[[ops.literal, "_"]],
|
|
1244
|
-
[
|
|
1245
|
-
ops.templateTree,
|
|
1246
|
-
[ops.literal, ["Hello, ", "."]],
|
|
1247
|
-
[markers.reference, [ops.literal, "name"]],
|
|
1248
|
-
],
|
|
1028
|
+
[ops.template, [ops.literal, ["Hello, ", "."]], [ops.scope, "name"]],
|
|
1249
1029
|
]);
|
|
1250
1030
|
assertParse("shorthandFunction", "=indent`hello`", [
|
|
1251
1031
|
ops.lambda,
|
|
1252
1032
|
[[ops.literal, "_"]],
|
|
1253
1033
|
[
|
|
1254
|
-
[
|
|
1034
|
+
[ops.builtin, "indent"],
|
|
1255
1035
|
[ops.literal, ["hello"]],
|
|
1256
1036
|
],
|
|
1257
1037
|
]);
|
|
1258
1038
|
});
|
|
1259
1039
|
|
|
1260
1040
|
test("singleLineComment", () => {
|
|
1261
|
-
assertParse("singleLineComment", "// Hello, world!", null,
|
|
1041
|
+
assertParse("singleLineComment", "// Hello, world!", null, false);
|
|
1262
1042
|
});
|
|
1263
1043
|
|
|
1264
1044
|
test("spreadElement", () => {
|
|
1265
|
-
assertParse("spreadElement", "...a", [
|
|
1266
|
-
|
|
1267
|
-
[markers.reference, [ops.literal, "a"]],
|
|
1268
|
-
]);
|
|
1269
|
-
assertParse("spreadElement", "…a", [
|
|
1270
|
-
ops.spread,
|
|
1271
|
-
[markers.reference, [ops.literal, "a"]],
|
|
1272
|
-
]);
|
|
1045
|
+
assertParse("spreadElement", "...a", [ops.spread, [ops.scope, "a"]]);
|
|
1046
|
+
assertParse("spreadElement", "…a", [ops.spread, [ops.scope, "a"]]);
|
|
1273
1047
|
});
|
|
1274
1048
|
|
|
1275
1049
|
test("stringLiteral", () => {
|
|
@@ -1288,13 +1062,21 @@ Body`,
|
|
|
1288
1062
|
|
|
1289
1063
|
test("templateBody", () => {
|
|
1290
1064
|
assertParse("templateBody", "hello${foo}world", [
|
|
1291
|
-
ops.
|
|
1292
|
-
[ops.literal,
|
|
1293
|
-
[
|
|
1065
|
+
ops.lambda,
|
|
1066
|
+
[[ops.literal, "_"]],
|
|
1067
|
+
[
|
|
1068
|
+
ops.templateIndent,
|
|
1069
|
+
[ops.literal, ["hello", "world"]],
|
|
1070
|
+
[ops.scope, "foo"],
|
|
1071
|
+
],
|
|
1294
1072
|
]);
|
|
1295
1073
|
assertParse("templateBody", "Documents can contain ` backticks", [
|
|
1296
|
-
ops.
|
|
1297
|
-
[ops.literal,
|
|
1074
|
+
ops.lambda,
|
|
1075
|
+
[[ops.literal, "_"]],
|
|
1076
|
+
[
|
|
1077
|
+
ops.templateIndent,
|
|
1078
|
+
[ops.literal, ["Documents can contain ` backticks"]],
|
|
1079
|
+
],
|
|
1298
1080
|
]);
|
|
1299
1081
|
});
|
|
1300
1082
|
|
|
@@ -1314,9 +1096,13 @@ title: Title goes here
|
|
|
1314
1096
|
---
|
|
1315
1097
|
Body text`,
|
|
1316
1098
|
[
|
|
1317
|
-
ops.
|
|
1318
|
-
[
|
|
1319
|
-
[
|
|
1099
|
+
ops.document,
|
|
1100
|
+
[ops.literal, { title: "Title goes here" }],
|
|
1101
|
+
[
|
|
1102
|
+
ops.lambda,
|
|
1103
|
+
[[ops.literal, "_"]],
|
|
1104
|
+
[ops.templateIndent, [ops.literal, ["Body text"]]],
|
|
1105
|
+
],
|
|
1320
1106
|
]
|
|
1321
1107
|
);
|
|
1322
1108
|
});
|
|
@@ -1338,9 +1124,16 @@ Body text`,
|
|
|
1338
1124
|
[
|
|
1339
1125
|
"@text",
|
|
1340
1126
|
[
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1127
|
+
[
|
|
1128
|
+
ops.lambda,
|
|
1129
|
+
[[ops.literal, "_"]],
|
|
1130
|
+
[
|
|
1131
|
+
ops.templateIndent,
|
|
1132
|
+
[ops.literal, ["<h1>", "</h1>\n"]],
|
|
1133
|
+
[ops.scope, "title"],
|
|
1134
|
+
],
|
|
1135
|
+
],
|
|
1136
|
+
undefined,
|
|
1344
1137
|
],
|
|
1345
1138
|
],
|
|
1346
1139
|
]
|
|
@@ -1349,52 +1142,36 @@ Body text`,
|
|
|
1349
1142
|
|
|
1350
1143
|
test("templateLiteral", () => {
|
|
1351
1144
|
assertParse("templateLiteral", "`Hello, world.`", [
|
|
1352
|
-
ops.
|
|
1145
|
+
ops.template,
|
|
1353
1146
|
[ops.literal, ["Hello, world."]],
|
|
1354
1147
|
]);
|
|
1355
|
-
assertParse(
|
|
1356
|
-
"templateLiteral",
|
|
1357
|
-
"`Hello, world.`",
|
|
1358
|
-
[ops.templateStandard, [ops.literal, ["Hello, world."]]],
|
|
1359
|
-
"jse"
|
|
1360
|
-
);
|
|
1361
1148
|
assertParse("templateLiteral", "`foo ${x} bar`", [
|
|
1362
|
-
ops.
|
|
1149
|
+
ops.template,
|
|
1363
1150
|
[ops.literal, ["foo ", " bar"]],
|
|
1364
|
-
[
|
|
1151
|
+
[ops.scope, "x"],
|
|
1365
1152
|
]);
|
|
1366
1153
|
assertParse("templateLiteral", "`${`nested`}`", [
|
|
1367
|
-
ops.
|
|
1154
|
+
ops.template,
|
|
1368
1155
|
[ops.literal, ["", ""]],
|
|
1369
|
-
[ops.
|
|
1156
|
+
[ops.template, [ops.literal, ["nested"]]],
|
|
1370
1157
|
]);
|
|
1371
1158
|
assertParse("templateLiteral", "`${ map:(people, =`${name}`) }`", [
|
|
1372
|
-
ops.
|
|
1159
|
+
ops.template,
|
|
1373
1160
|
[ops.literal, ["", ""]],
|
|
1374
1161
|
[
|
|
1375
|
-
[
|
|
1376
|
-
[
|
|
1162
|
+
[ops.builtin, "map:"],
|
|
1163
|
+
[ops.scope, "people"],
|
|
1377
1164
|
[
|
|
1378
1165
|
ops.lambda,
|
|
1379
1166
|
[[ops.literal, "_"]],
|
|
1380
|
-
[
|
|
1381
|
-
ops.templateTree,
|
|
1382
|
-
[ops.literal, ["", ""]],
|
|
1383
|
-
[markers.reference, [ops.literal, "name"]],
|
|
1384
|
-
],
|
|
1167
|
+
[ops.template, [ops.literal, ["", ""]], [ops.scope, "name"]],
|
|
1385
1168
|
],
|
|
1386
1169
|
],
|
|
1387
1170
|
]);
|
|
1388
1171
|
});
|
|
1389
1172
|
|
|
1390
1173
|
test("templateSubtitution", () => {
|
|
1391
|
-
assertParse(
|
|
1392
|
-
"templateSubstitution",
|
|
1393
|
-
"${foo}",
|
|
1394
|
-
[markers.reference, [ops.literal, "foo"]],
|
|
1395
|
-
"shell",
|
|
1396
|
-
false
|
|
1397
|
-
);
|
|
1174
|
+
assertParse("templateSubstitution", "${foo}", [ops.scope, "foo"], false);
|
|
1398
1175
|
});
|
|
1399
1176
|
|
|
1400
1177
|
test("whitespace block", () => {
|
|
@@ -1405,7 +1182,6 @@ Body text`,
|
|
|
1405
1182
|
// Second comment
|
|
1406
1183
|
`,
|
|
1407
1184
|
null,
|
|
1408
|
-
"jse",
|
|
1409
1185
|
false
|
|
1410
1186
|
);
|
|
1411
1187
|
});
|
|
@@ -1413,7 +1189,7 @@ Body text`,
|
|
|
1413
1189
|
test("unaryExpression", () => {
|
|
1414
1190
|
assertParse("unaryExpression", "!true", [
|
|
1415
1191
|
ops.logicalNot,
|
|
1416
|
-
[
|
|
1192
|
+
[undetermined, "true"],
|
|
1417
1193
|
]);
|
|
1418
1194
|
assertParse("unaryExpression", "+1", [ops.unaryPlus, [ops.literal, 1]]);
|
|
1419
1195
|
assertParse("unaryExpression", "-2", [ops.unaryMinus, [ops.literal, 2]]);
|
|
@@ -1421,16 +1197,9 @@ Body text`,
|
|
|
1421
1197
|
});
|
|
1422
1198
|
});
|
|
1423
1199
|
|
|
1424
|
-
function assertParse(
|
|
1425
|
-
startRule,
|
|
1426
|
-
source,
|
|
1427
|
-
expected,
|
|
1428
|
-
mode = "shell",
|
|
1429
|
-
checkLocation = true
|
|
1430
|
-
) {
|
|
1200
|
+
function assertParse(startRule, source, expected, checkLocation = true) {
|
|
1431
1201
|
const code = parse(source, {
|
|
1432
1202
|
grammarSource: { text: source },
|
|
1433
|
-
mode,
|
|
1434
1203
|
startRule,
|
|
1435
1204
|
});
|
|
1436
1205
|
|
|
@@ -1458,11 +1227,10 @@ function assertCodeLocations(code) {
|
|
|
1458
1227
|
}
|
|
1459
1228
|
}
|
|
1460
1229
|
|
|
1461
|
-
function assertThrows(startRule, source, message, position
|
|
1230
|
+
function assertThrows(startRule, source, message, position) {
|
|
1462
1231
|
try {
|
|
1463
1232
|
parse(source, {
|
|
1464
1233
|
grammarSource: { text: source },
|
|
1465
|
-
mode,
|
|
1466
1234
|
startRule,
|
|
1467
1235
|
});
|
|
1468
1236
|
} catch (/** @type {any} */ error) {
|