@weborigami/language 0.0.72 → 0.1.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/main.js +2 -2
- package/package.json +3 -3
- package/src/compiler/compile.js +28 -11
- package/src/compiler/origami.pegjs +127 -90
- package/src/compiler/parse.js +686 -688
- package/src/compiler/parserHelpers.js +13 -7
- package/src/runtime/HandleExtensionsTransform.js +1 -1
- package/src/runtime/ImportModulesMixin.js +1 -1
- package/src/runtime/codeFragment.js +2 -2
- package/src/runtime/errors.js +104 -0
- package/src/runtime/evaluate.js +3 -3
- package/src/runtime/expressionObject.js +8 -5
- package/src/runtime/{extensions.js → handlers.js} +6 -24
- package/src/runtime/internal.js +1 -0
- package/src/runtime/ops.js +59 -170
- package/src/runtime/typos.js +71 -0
- package/test/compiler/compile.test.js +4 -4
- package/test/compiler/parse.test.js +273 -145
- package/test/runtime/fixtures/templates/greet.orit +1 -1
- package/test/runtime/{extensions.test.js → handlers.test.js} +2 -2
- package/test/runtime/ops.test.js +17 -12
- package/test/runtime/typos.test.js +21 -0
- package/src/runtime/formatError.js +0 -56
package/main.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export * from "./src/runtime/internal.js";
|
|
2
2
|
|
|
3
3
|
export * as compile from "./src/compiler/compile.js";
|
|
4
|
+
export * from "./src/runtime/errors.js";
|
|
4
5
|
export { default as evaluate } from "./src/runtime/evaluate.js";
|
|
5
6
|
export { default as EventTargetMixin } from "./src/runtime/EventTargetMixin.js";
|
|
6
7
|
export * as expressionFunction from "./src/runtime/expressionFunction.js";
|
|
7
|
-
export * from "./src/runtime/extensions.js";
|
|
8
|
-
export { default as formatError } from "./src/runtime/formatError.js";
|
|
9
8
|
export { default as functionResultsMap } from "./src/runtime/functionResultsMap.js";
|
|
10
9
|
export { default as HandleExtensionsTransform } from "./src/runtime/HandleExtensionsTransform.js";
|
|
10
|
+
export * from "./src/runtime/handlers.js";
|
|
11
11
|
export { default as ImportModulesMixin } from "./src/runtime/ImportModulesMixin.js";
|
|
12
12
|
export { default as InvokeFunctionsTransform } from "./src/runtime/InvokeFunctionsTransform.js";
|
|
13
13
|
export { default as OrigamiFiles } from "./src/runtime/OrigamiFiles.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"typescript": "5.6.2"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/async-tree": "0.0
|
|
15
|
-
"@weborigami/types": "0.0
|
|
14
|
+
"@weborigami/async-tree": "0.1.0",
|
|
15
|
+
"@weborigami/types": "0.1.0",
|
|
16
16
|
"watcher": "2.3.1"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
package/src/compiler/compile.js
CHANGED
|
@@ -2,8 +2,11 @@ import { trailingSlash } from "@weborigami/async-tree";
|
|
|
2
2
|
import { createExpressionFunction } from "../runtime/expressionFunction.js";
|
|
3
3
|
import { ops } from "../runtime/internal.js";
|
|
4
4
|
import { parse } from "./parse.js";
|
|
5
|
+
import { annotate } from "./parserHelpers.js";
|
|
5
6
|
|
|
6
|
-
function compile(source,
|
|
7
|
+
function compile(source, options) {
|
|
8
|
+
const { startRule } = options;
|
|
9
|
+
const scopeCaching = options.scopeCaching ?? true;
|
|
7
10
|
if (typeof source === "string") {
|
|
8
11
|
source = { text: source };
|
|
9
12
|
}
|
|
@@ -12,20 +15,24 @@ function compile(source, startRule) {
|
|
|
12
15
|
startRule,
|
|
13
16
|
});
|
|
14
17
|
const cache = {};
|
|
15
|
-
const modified =
|
|
16
|
-
|
|
18
|
+
const modified = scopeCaching
|
|
19
|
+
? cacheExternalScopeReferences(code, cache)
|
|
20
|
+
: code;
|
|
17
21
|
const fn = createExpressionFunction(modified);
|
|
18
22
|
return fn;
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
export function expression(source) {
|
|
22
|
-
return compile(source,
|
|
25
|
+
export function expression(source, options = {}) {
|
|
26
|
+
return compile(source, {
|
|
27
|
+
...options,
|
|
28
|
+
startRule: "expression",
|
|
29
|
+
});
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
// Given code containing ops.scope calls, upgrade them to ops.cache calls unless
|
|
26
33
|
// they refer to local variables: variables defined by object literals or lambda
|
|
27
34
|
// parameters.
|
|
28
|
-
export function
|
|
35
|
+
export function cacheExternalScopeReferences(code, cache, locals = {}) {
|
|
29
36
|
const [fn, ...args] = code;
|
|
30
37
|
|
|
31
38
|
let additionalLocalNames;
|
|
@@ -38,7 +45,7 @@ export function cacheNonLocalScopeReferences(code, cache, locals = {}) {
|
|
|
38
45
|
} else {
|
|
39
46
|
// Upgrade to cached scope lookup
|
|
40
47
|
const modified = [ops.cache, key, cache];
|
|
41
|
-
|
|
48
|
+
annotate(modified, code.location);
|
|
42
49
|
return modified;
|
|
43
50
|
}
|
|
44
51
|
|
|
@@ -67,18 +74,28 @@ export function cacheNonLocalScopeReferences(code, cache, locals = {}) {
|
|
|
67
74
|
// be preferable to only descend into instructions. This would require
|
|
68
75
|
// surrounding ops.lambda parameters with ops.literal, and ops.object
|
|
69
76
|
// entries with ops.array.
|
|
70
|
-
return
|
|
77
|
+
return cacheExternalScopeReferences(child, cache, updatedLocals);
|
|
71
78
|
} else {
|
|
72
79
|
return child;
|
|
73
80
|
}
|
|
74
81
|
});
|
|
75
82
|
|
|
76
83
|
if (code.location) {
|
|
77
|
-
modified
|
|
84
|
+
annotate(modified, code.location);
|
|
78
85
|
}
|
|
79
86
|
return modified;
|
|
80
87
|
}
|
|
81
88
|
|
|
82
|
-
export function
|
|
83
|
-
return compile(source,
|
|
89
|
+
export function program(source, options = {}) {
|
|
90
|
+
return compile(source, {
|
|
91
|
+
...options,
|
|
92
|
+
startRule: "program",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function templateDocument(source, options = {}) {
|
|
97
|
+
return compile(source, {
|
|
98
|
+
...options,
|
|
99
|
+
startRule: "templateDocument",
|
|
100
|
+
});
|
|
84
101
|
}
|
|
@@ -52,20 +52,19 @@ arrayEntries
|
|
|
52
52
|
|
|
53
53
|
arrayEntry
|
|
54
54
|
= spread
|
|
55
|
-
/
|
|
55
|
+
/ pipeline
|
|
56
56
|
|
|
57
|
-
// Something that can be called. This is more restrictive than the `
|
|
57
|
+
// Something that can be called. This is more restrictive than the `value`
|
|
58
58
|
// parser; it doesn't accept regular function calls.
|
|
59
59
|
callTarget "function call"
|
|
60
60
|
= absoluteFilePath
|
|
61
|
+
/ scopeTraverse
|
|
61
62
|
/ array
|
|
62
63
|
/ object
|
|
63
|
-
/ lambda
|
|
64
|
-
/ parameterizedLambda
|
|
65
|
-
/ protocolCall
|
|
66
64
|
/ group
|
|
67
|
-
/
|
|
68
|
-
/
|
|
65
|
+
/ namespacePath
|
|
66
|
+
/ namespace
|
|
67
|
+
/ functionReference
|
|
69
68
|
|
|
70
69
|
// Required closing curly brace. We use this for the `object` term: if the
|
|
71
70
|
// parser sees a left curly brace, here we must see a right curly brace.
|
|
@@ -109,6 +108,12 @@ doubleQuoteString "double quote string"
|
|
|
109
108
|
doubleQuoteStringChar
|
|
110
109
|
= !('"' / newLine) @textChar
|
|
111
110
|
|
|
111
|
+
// Path that follows a builtin reference in a URL: `//example.com/index.html`
|
|
112
|
+
doubleSlashPath
|
|
113
|
+
= "//" host:host path:path? {
|
|
114
|
+
return annotate([host, ...(path ?? [])], location());
|
|
115
|
+
}
|
|
116
|
+
|
|
112
117
|
ellipsis = "..." / "…" // Unicode ellipsis
|
|
113
118
|
|
|
114
119
|
escapedChar "backslash-escaped character"
|
|
@@ -121,14 +126,9 @@ escapedChar "backslash-escaped character"
|
|
|
121
126
|
/ "\\v" { return "\v"; }
|
|
122
127
|
/ "\\" @.
|
|
123
128
|
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
= pipeline
|
|
127
|
-
|
|
128
|
-
// Top-level Origami expression, possible shebang directive and leading/trailing
|
|
129
|
-
// whitepsace.
|
|
130
|
-
expression "Origami expression"
|
|
131
|
-
= shebang? __ @expr __
|
|
129
|
+
// A top-level expression, possibly with leading/trailing whitespace
|
|
130
|
+
expression
|
|
131
|
+
= __ @pipeline __
|
|
132
132
|
|
|
133
133
|
float "floating-point number"
|
|
134
134
|
= sign? digits? "." digits {
|
|
@@ -153,11 +153,23 @@ functionComposition "function composition"
|
|
|
153
153
|
return annotate(makeFunctionCall(target, chain, location()), location());
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
// A reference to a function in scope: `fn` or `fn.js`.
|
|
157
|
+
functionReference
|
|
158
|
+
= ref:scopeReference {
|
|
159
|
+
// If the reference looks like a builtin name, we treat it as a builtin
|
|
160
|
+
// reference, otherwise it's a regular scope reference. We can't make this
|
|
161
|
+
// distinction in the grammar.
|
|
162
|
+
const name = ref[1];
|
|
163
|
+
const builtinRegex = /^[A-Za-z][A-Za-z0-9]*$/;
|
|
164
|
+
const op = builtinRegex.test(name) ? ops.builtin : ops.scope;
|
|
165
|
+
return annotate([op, name], location());
|
|
166
|
+
}
|
|
167
|
+
|
|
156
168
|
// An expression in parentheses: `(foo)`
|
|
157
169
|
group "parenthetical group"
|
|
158
|
-
= "(" __
|
|
159
|
-
|
|
160
|
-
|
|
170
|
+
= "(" __ pipeline:pipeline __ closingParen {
|
|
171
|
+
return annotate(pipeline, location());
|
|
172
|
+
}
|
|
161
173
|
|
|
162
174
|
guillemetString "guillemet string"
|
|
163
175
|
= '«' chars:guillemetStringChar* '»' {
|
|
@@ -167,13 +179,19 @@ guillemetString "guillemet string"
|
|
|
167
179
|
guillemetStringChar
|
|
168
180
|
= !('»' / newLine) @textChar
|
|
169
181
|
|
|
182
|
+
homeTree
|
|
183
|
+
= "~" {
|
|
184
|
+
return annotate([ops.homeTree], location());
|
|
185
|
+
}
|
|
186
|
+
|
|
170
187
|
// A host identifier that may include a colon and port number: `example.com:80`.
|
|
171
188
|
// This is used as a special case at the head of a path, where we want to
|
|
172
189
|
// interpret a colon as part of a text identifier.
|
|
173
190
|
host "HTTP/HTTPS host"
|
|
174
|
-
= identifier:identifier port:(":" @number)? {
|
|
191
|
+
= identifier:identifier port:(":" @number)? slash:"/"? {
|
|
175
192
|
const portText = port ? `:${port[1]}` : "";
|
|
176
|
-
const
|
|
193
|
+
const slashText = slash ? "/" : "";
|
|
194
|
+
const hostText = identifier + portText + slashText;
|
|
177
195
|
return annotate([ops.literal, hostText], location());
|
|
178
196
|
}
|
|
179
197
|
|
|
@@ -191,12 +209,7 @@ identifierList
|
|
|
191
209
|
}
|
|
192
210
|
|
|
193
211
|
implicitParensArgs "arguments with implicit parentheses"
|
|
194
|
-
|
|
195
|
-
// they can't contain a pipeline.
|
|
196
|
-
= inlineSpace+ args:step|1.., separator| separator? {
|
|
197
|
-
/* Stuff */
|
|
198
|
-
return annotate(args, location());
|
|
199
|
-
}
|
|
212
|
+
= inlineSpace+ @list
|
|
200
213
|
|
|
201
214
|
inlineSpace
|
|
202
215
|
= [ \t]
|
|
@@ -208,8 +221,8 @@ integer "integer"
|
|
|
208
221
|
|
|
209
222
|
// A lambda expression: `=foo()`
|
|
210
223
|
lambda "lambda function"
|
|
211
|
-
= "=" __
|
|
212
|
-
return annotate([ops.lambda, ["_"],
|
|
224
|
+
= "=" __ pipeline:pipeline {
|
|
225
|
+
return annotate([ops.lambda, ["_"], pipeline], location());
|
|
213
226
|
}
|
|
214
227
|
|
|
215
228
|
// A path that begins with a slash: `/foo/bar`
|
|
@@ -218,15 +231,31 @@ leadingSlashPath "path with a leading slash"
|
|
|
218
231
|
return annotate(path ?? [], location());
|
|
219
232
|
}
|
|
220
233
|
|
|
221
|
-
// A separated list of
|
|
234
|
+
// A separated list of values
|
|
222
235
|
list "list"
|
|
223
|
-
=
|
|
224
|
-
return annotate(
|
|
236
|
+
= values:value|1.., separator| separator? {
|
|
237
|
+
return annotate(values, location());
|
|
225
238
|
}
|
|
226
239
|
|
|
227
240
|
multiLineComment
|
|
228
241
|
= "/*" (!"*/" .)* "*/" { return null; }
|
|
229
242
|
|
|
243
|
+
// A namespace reference is a string of letters only, followed by a colon.
|
|
244
|
+
// For the time being, we also allow a leading `@`, which is deprecated.
|
|
245
|
+
namespace
|
|
246
|
+
= at:"@"? chars:[A-Za-z]+ ":" {
|
|
247
|
+
return annotate([ops.builtin, (at ?? "") + chars.join("") + ":"], location());
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// A namespace followed by a path: `fn:a/b/c`
|
|
251
|
+
namespacePath
|
|
252
|
+
= fn:namespace path:doubleSlashPath {
|
|
253
|
+
return annotate(makeFunctionCall(fn, [path], location()), location());
|
|
254
|
+
}
|
|
255
|
+
/ fn:namespace path:path {
|
|
256
|
+
return annotate(makeFunctionCall(fn, [path], location()), location());
|
|
257
|
+
}
|
|
258
|
+
|
|
230
259
|
newLine
|
|
231
260
|
= "\n"
|
|
232
261
|
/ "\r\n"
|
|
@@ -257,8 +286,11 @@ objectEntry
|
|
|
257
286
|
|
|
258
287
|
// A getter definition inside an object literal: `foo = 1`
|
|
259
288
|
objectGetter "object getter"
|
|
260
|
-
= key:objectKey __ "=" __
|
|
261
|
-
return annotate(
|
|
289
|
+
= key:objectKey __ "=" __ pipeline:pipeline {
|
|
290
|
+
return annotate(
|
|
291
|
+
makeProperty(key, annotate([ops.getter, pipeline], location())),
|
|
292
|
+
location()
|
|
293
|
+
);
|
|
262
294
|
}
|
|
263
295
|
|
|
264
296
|
objectHiddenKey
|
|
@@ -270,8 +302,8 @@ objectKey "object key"
|
|
|
270
302
|
|
|
271
303
|
// A property definition in an object literal: `x: 1`
|
|
272
304
|
objectProperty "object property"
|
|
273
|
-
= key:objectKey __ ":" __
|
|
274
|
-
return annotate(makeProperty(key,
|
|
305
|
+
= key:objectKey __ ":" __ pipeline:pipeline {
|
|
306
|
+
return annotate(makeProperty(key, pipeline), location());
|
|
275
307
|
}
|
|
276
308
|
|
|
277
309
|
// A shorthand reference inside an object literal: `foo`
|
|
@@ -290,8 +322,8 @@ objectPublicKey
|
|
|
290
322
|
}
|
|
291
323
|
|
|
292
324
|
parameterizedLambda
|
|
293
|
-
= "(" __ parameters:identifierList? __ ")" __ doubleArrow __
|
|
294
|
-
return annotate([ops.lambda, parameters ?? [],
|
|
325
|
+
= "(" __ parameters:identifierList? __ ")" __ doubleArrow __ pipeline:pipeline {
|
|
326
|
+
return annotate([ops.lambda, parameters ?? [], pipeline], location());
|
|
295
327
|
}
|
|
296
328
|
|
|
297
329
|
// Function arguments in parentheses
|
|
@@ -300,19 +332,22 @@ parensArgs "function arguments in parentheses"
|
|
|
300
332
|
return annotate(list ?? [undefined], location());
|
|
301
333
|
}
|
|
302
334
|
|
|
303
|
-
pipeline
|
|
304
|
-
= steps:(@step|1.., __ singleArrow __ |) {
|
|
305
|
-
return annotate(makePipeline(steps), location());
|
|
306
|
-
}
|
|
307
|
-
|
|
308
335
|
// A slash-separated path of keys
|
|
309
336
|
path "slash-separated path"
|
|
310
|
-
|
|
337
|
+
// Path with at least a tail
|
|
338
|
+
= head:pathElement|0..| tail:pathTail {
|
|
311
339
|
let path = tail ? [...head, tail] : head;
|
|
312
340
|
// Remove parts for consecutive slashes
|
|
313
341
|
path = path.filter((part) => part[1] !== "/");
|
|
314
342
|
return annotate(path, location());
|
|
315
343
|
}
|
|
344
|
+
// Path with slashes, maybe no tail
|
|
345
|
+
/ head:pathElement|1..| tail:pathTail? {
|
|
346
|
+
let path = tail ? [...head, tail] : head;
|
|
347
|
+
// Remove parts for consecutive slashes
|
|
348
|
+
path = path.filter((part) => part[1] !== "/");
|
|
349
|
+
return annotate(path, location());
|
|
350
|
+
}
|
|
316
351
|
|
|
317
352
|
// A path key followed by a slash
|
|
318
353
|
pathElement
|
|
@@ -333,26 +368,24 @@ pathTail
|
|
|
333
368
|
return annotate([ops.literal, chars.join("")], location());
|
|
334
369
|
}
|
|
335
370
|
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
|
|
339
|
-
=
|
|
340
|
-
return
|
|
371
|
+
// A pipeline that starts with a value and optionally applies a series of
|
|
372
|
+
// functions to it.
|
|
373
|
+
pipeline
|
|
374
|
+
= head:value tail:(__ singleArrow __ @pipelineStep)* {
|
|
375
|
+
return tail.length === 0
|
|
376
|
+
? head
|
|
377
|
+
: annotate(makePipeline([head, ...tail]), location());
|
|
341
378
|
}
|
|
342
379
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
380
|
+
// A step in a pipeline
|
|
381
|
+
pipelineStep
|
|
382
|
+
= lambda
|
|
383
|
+
/ parameterizedLambda
|
|
384
|
+
/ callTarget
|
|
346
385
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
/ "http" { return ops.http; }
|
|
351
|
-
/ "new" { return ops.constructor; }
|
|
352
|
-
/ "package" { return [ops.scope, "@package"] } // Alias
|
|
353
|
-
/ "treehttps" { return ops.treeHttps; } // Must come before `treehttp`
|
|
354
|
-
/ "treehttp" { return ops.treeHttp; } // Must come before `tree`
|
|
355
|
-
/ "tree" { return ops.treeHttps; }
|
|
386
|
+
// Top-level Origami progam with possible shebang directive (which is ignored)
|
|
387
|
+
program "Origami program"
|
|
388
|
+
= shebang? @expression
|
|
356
389
|
|
|
357
390
|
scopeReference "scope reference"
|
|
358
391
|
= key:identifier {
|
|
@@ -360,10 +393,10 @@ scopeReference "scope reference"
|
|
|
360
393
|
}
|
|
361
394
|
|
|
362
395
|
scopeTraverse
|
|
363
|
-
= ref:scopeReference "/" path:path {
|
|
396
|
+
= ref:scopeReference "/" path:path? {
|
|
364
397
|
const head = [ops.scope, `${ ref[1] }/`];
|
|
365
398
|
head.location = ref.location;
|
|
366
|
-
return annotate([ops.traverse, head, ...path], location());
|
|
399
|
+
return annotate([ops.traverse, head, ...(path ?? [])], location());
|
|
367
400
|
}
|
|
368
401
|
|
|
369
402
|
separator
|
|
@@ -376,7 +409,9 @@ shebang
|
|
|
376
409
|
sign
|
|
377
410
|
= [+\-]
|
|
378
411
|
|
|
379
|
-
singleArrow
|
|
412
|
+
singleArrow
|
|
413
|
+
= "→"
|
|
414
|
+
/ "->"
|
|
380
415
|
|
|
381
416
|
singleLineComment
|
|
382
417
|
= "//" [^\n\r]* { return null; }
|
|
@@ -390,34 +425,10 @@ singleQuoteStringChar
|
|
|
390
425
|
= !("'" / newLine) @textChar
|
|
391
426
|
|
|
392
427
|
spread
|
|
393
|
-
= ellipsis
|
|
394
|
-
return annotate([ops.spread,
|
|
428
|
+
= ellipsis value:value {
|
|
429
|
+
return annotate([ops.spread, value], location());
|
|
395
430
|
}
|
|
396
431
|
|
|
397
|
-
// A single step in a pipeline, or a top-level expression
|
|
398
|
-
step
|
|
399
|
-
// Literals that can't start a function call
|
|
400
|
-
= number
|
|
401
|
-
// Try functions next; they can start with expression types that follow
|
|
402
|
-
// (array, object, etc.), and we want to parse the larger thing first.
|
|
403
|
-
/ functionComposition
|
|
404
|
-
// Then try parsers that look for a distinctive token at the start: an opening
|
|
405
|
-
// slash, bracket, curly brace, etc.
|
|
406
|
-
/ absoluteFilePath
|
|
407
|
-
/ array
|
|
408
|
-
/ object
|
|
409
|
-
/ lambda
|
|
410
|
-
/ parameterizedLambda
|
|
411
|
-
/ templateLiteral
|
|
412
|
-
/ string
|
|
413
|
-
/ group
|
|
414
|
-
// Things that have a distinctive character, but not at the start
|
|
415
|
-
/ protocolCall
|
|
416
|
-
/ taggedTemplate
|
|
417
|
-
/ scopeTraverse
|
|
418
|
-
// Least distinctive option is a simple scope reference, so it comes last.
|
|
419
|
-
/ scopeReference
|
|
420
|
-
|
|
421
432
|
start
|
|
422
433
|
= number
|
|
423
434
|
|
|
@@ -474,11 +485,37 @@ templateLiteralText
|
|
|
474
485
|
|
|
475
486
|
// A substitution in a template literal: `${x}`
|
|
476
487
|
templateSubstitution "template substitution"
|
|
477
|
-
= "${"
|
|
488
|
+
= "${" @expression "}"
|
|
478
489
|
|
|
479
490
|
textChar
|
|
480
491
|
= escapedChar
|
|
481
492
|
/ .
|
|
482
493
|
|
|
494
|
+
// An Origami expression that produces a value, no leading/trailing whitespace
|
|
495
|
+
value
|
|
496
|
+
// Literals that can't start a function call
|
|
497
|
+
= number
|
|
498
|
+
// Try functions next; they can start with expression types that follow
|
|
499
|
+
// (array, object, etc.), and we want to parse the larger thing first.
|
|
500
|
+
/ parameterizedLambda
|
|
501
|
+
/ functionComposition
|
|
502
|
+
/ taggedTemplate
|
|
503
|
+
/ namespacePath
|
|
504
|
+
// Then try parsers that look for a distinctive token at the start: an opening
|
|
505
|
+
// slash, bracket, curly brace, etc.
|
|
506
|
+
/ absoluteFilePath
|
|
507
|
+
/ array
|
|
508
|
+
/ object
|
|
509
|
+
/ lambda
|
|
510
|
+
/ templateLiteral
|
|
511
|
+
/ string
|
|
512
|
+
/ group
|
|
513
|
+
/ homeTree
|
|
514
|
+
// Things that have a distinctive character, but not at the start
|
|
515
|
+
/ scopeTraverse
|
|
516
|
+
/ namespace
|
|
517
|
+
// Least distinctive option is a simple scope reference, so it comes last.
|
|
518
|
+
/ scopeReference
|
|
519
|
+
|
|
483
520
|
whitespaceWithNewLine
|
|
484
521
|
= inlineSpace* comment? newLine __
|