@weborigami/language 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/compiler/origami.pegjs +116 -30
- package/src/compiler/parse.js +1387 -625
- package/src/compiler/parserHelpers.js +38 -22
- package/src/runtime/errors.js +34 -12
- package/src/runtime/ops.js +125 -15
- package/test/compiler/parse.test.js +154 -9
- package/test/runtime/ops.test.js +144 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"yaml": "2.5.1"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@weborigami/async-tree": "0.2.
|
|
16
|
-
"@weborigami/types": "0.2.
|
|
15
|
+
"@weborigami/async-tree": "0.2.2",
|
|
16
|
+
"@weborigami/types": "0.2.2",
|
|
17
17
|
"watcher": "2.3.1"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
annotate,
|
|
17
17
|
downgradeReference,
|
|
18
18
|
makeArray,
|
|
19
|
-
|
|
19
|
+
makeBinaryOperation,
|
|
20
20
|
makeCall,
|
|
21
21
|
makeDeferredArguments,
|
|
22
22
|
makeObject,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
makeProperty,
|
|
25
25
|
makeReference,
|
|
26
26
|
makeTemplate,
|
|
27
|
-
|
|
27
|
+
makeUnaryOperation
|
|
28
28
|
} from "./parserHelpers.js";
|
|
29
29
|
|
|
30
30
|
}}
|
|
@@ -35,6 +35,15 @@ __
|
|
|
35
35
|
return null;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
additiveExpression
|
|
39
|
+
= head:multiplicativeExpression tail:(__ @additiveOperator __ @multiplicativeExpression)* {
|
|
40
|
+
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
additiveOperator
|
|
44
|
+
= "+"
|
|
45
|
+
/ "-"
|
|
46
|
+
|
|
38
47
|
arguments "function arguments"
|
|
39
48
|
= parenthesesArguments
|
|
40
49
|
/ pathArguments
|
|
@@ -52,22 +61,51 @@ arrayEntries
|
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
arrayEntry
|
|
55
|
-
=
|
|
64
|
+
= spreadElement
|
|
56
65
|
/ pipelineExpression
|
|
66
|
+
// JavaScript treats a missing value as `undefined`
|
|
67
|
+
/ __ !"]" {
|
|
68
|
+
return annotate([ops.literal, undefined], location());
|
|
69
|
+
}
|
|
57
70
|
|
|
58
71
|
arrowFunction
|
|
59
72
|
= "(" __ parameters:identifierList? __ ")" __ doubleArrow __ pipeline:pipelineExpression {
|
|
60
73
|
return annotate([ops.lambda, parameters ?? [], pipeline], location());
|
|
61
74
|
}
|
|
75
|
+
/ identifier:identifier __ doubleArrow __ pipeline:pipelineExpression {
|
|
76
|
+
return annotate([ops.lambda, [identifier], pipeline], location());
|
|
77
|
+
}
|
|
62
78
|
/ conditionalExpression
|
|
63
79
|
|
|
80
|
+
bitwiseAndExpression
|
|
81
|
+
= head:equalityExpression tail:(__ @bitwiseAndOperator __ @equalityExpression)* {
|
|
82
|
+
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
bitwiseAndOperator
|
|
86
|
+
= @"&" !"&"
|
|
87
|
+
|
|
88
|
+
bitwiseOrExpression
|
|
89
|
+
= head:bitwiseXorExpression tail:(__ @bitwiseOrOperator __ @bitwiseXorExpression)* {
|
|
90
|
+
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
bitwiseOrOperator
|
|
94
|
+
= @"|" !"|"
|
|
95
|
+
|
|
96
|
+
bitwiseXorExpression
|
|
97
|
+
= head:bitwiseAndExpression tail:(__ @bitwiseXorOperator __ @bitwiseAndExpression)* {
|
|
98
|
+
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
bitwiseXorOperator
|
|
102
|
+
= "^"
|
|
103
|
+
|
|
64
104
|
// A function call: `fn(arg)`, possibly part of a chain of function calls, like
|
|
65
105
|
// `fn(arg1)(arg2)(arg3)`.
|
|
66
106
|
callExpression "function call"
|
|
67
107
|
= head:protocolExpression tail:arguments* {
|
|
68
|
-
return tail.
|
|
69
|
-
? head
|
|
70
|
-
: annotate(tail.reduce(makeCall, head), location());
|
|
108
|
+
return annotate(tail.reduce(makeCall, head), location());
|
|
71
109
|
}
|
|
72
110
|
|
|
73
111
|
// Required closing curly brace. We use this for the `object` term: if the
|
|
@@ -75,7 +113,7 @@ callExpression "function call"
|
|
|
75
113
|
closingBrace
|
|
76
114
|
= "}"
|
|
77
115
|
/ .? {
|
|
78
|
-
error(
|
|
116
|
+
error(`An object ended without a closing brace, or contained something that wasn't expected.\nThe top level of an object can only contain definitions ("a: b" or "a = b") or spreads ("...a").`);
|
|
79
117
|
}
|
|
80
118
|
|
|
81
119
|
// Required closing bracket
|
|
@@ -94,24 +132,35 @@ closingParenthesis
|
|
|
94
132
|
error("Expected right parenthesis");
|
|
95
133
|
}
|
|
96
134
|
|
|
135
|
+
// A comma-separated list of expressions: `x, y, z`
|
|
136
|
+
commaExpression
|
|
137
|
+
// The commas are required, but the list can have a single item.
|
|
138
|
+
= list:pipelineExpression|1.., __ "," __ | {
|
|
139
|
+
return list.length === 1
|
|
140
|
+
? list[0]
|
|
141
|
+
: annotate([ops.comma, ...list], location());
|
|
142
|
+
}
|
|
143
|
+
|
|
97
144
|
// A single line comment
|
|
98
145
|
comment "comment"
|
|
99
146
|
= multiLineComment
|
|
100
147
|
/ singleLineComment
|
|
101
148
|
|
|
102
149
|
conditionalExpression
|
|
103
|
-
= condition:logicalOrExpression __
|
|
104
|
-
"?" __
|
|
105
|
-
":" __
|
|
150
|
+
= condition:logicalOrExpression tail:(__
|
|
151
|
+
"?" __ @pipelineExpression __
|
|
152
|
+
":" __ @pipelineExpression)?
|
|
106
153
|
{
|
|
154
|
+
if (!tail) {
|
|
155
|
+
return condition;
|
|
156
|
+
}
|
|
107
157
|
return annotate([
|
|
108
158
|
ops.conditional,
|
|
109
159
|
downgradeReference(condition),
|
|
110
|
-
[ops.lambda, [], downgradeReference(
|
|
111
|
-
[ops.lambda, [], downgradeReference(
|
|
160
|
+
[ops.lambda, [], downgradeReference(tail[0])],
|
|
161
|
+
[ops.lambda, [], downgradeReference(tail[1])]
|
|
112
162
|
], location());
|
|
113
163
|
}
|
|
114
|
-
/ logicalOrExpression
|
|
115
164
|
|
|
116
165
|
digits
|
|
117
166
|
= @[0-9]+
|
|
@@ -129,10 +178,8 @@ doubleQuoteStringChar
|
|
|
129
178
|
ellipsis = "..." / "…" // Unicode ellipsis
|
|
130
179
|
|
|
131
180
|
equalityExpression
|
|
132
|
-
= head:
|
|
133
|
-
return tail.
|
|
134
|
-
? head
|
|
135
|
-
: annotate(makeBinaryOperatorChain(head, tail), location());
|
|
181
|
+
= head:relationalExpression tail:(__ @equalityOperator __ @relationalExpression)* {
|
|
182
|
+
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
136
183
|
}
|
|
137
184
|
|
|
138
185
|
equalityOperator
|
|
@@ -151,12 +198,17 @@ escapedChar "backslash-escaped character"
|
|
|
151
198
|
/ "\\v" { return "\v"; }
|
|
152
199
|
/ "\\" @.
|
|
153
200
|
|
|
201
|
+
exponentiationExpression
|
|
202
|
+
= left:unaryExpression right:(__ "**" __ @exponentiationExpression)? {
|
|
203
|
+
return right ? annotate([ops.exponentiation, left, right], location()) : left;
|
|
204
|
+
}
|
|
205
|
+
|
|
154
206
|
// A top-level expression, possibly with leading/trailing whitespace
|
|
155
207
|
expression
|
|
156
|
-
= __ @
|
|
208
|
+
= __ @commaExpression __
|
|
157
209
|
|
|
158
210
|
floatLiteral "floating-point number"
|
|
159
|
-
=
|
|
211
|
+
= digits? "." digits {
|
|
160
212
|
return annotate([ops.literal, parseFloat(text())], location());
|
|
161
213
|
}
|
|
162
214
|
|
|
@@ -195,7 +247,7 @@ identifier "identifier"
|
|
|
195
247
|
= chars:identifierChar+ { return chars.join(""); }
|
|
196
248
|
|
|
197
249
|
identifierChar
|
|
198
|
-
= [^(){}\[\]
|
|
250
|
+
= [^(){}\[\]<>\?!\|\-=,/:\`"'«»\\→⇒… \t\n\r] // No unescaped whitespace or special chars
|
|
199
251
|
/ @'-' !'>' // Accept a hyphen but not in a single arrow combination
|
|
200
252
|
/ escapedChar
|
|
201
253
|
|
|
@@ -220,7 +272,7 @@ inlineSpace
|
|
|
220
272
|
= [ \t]
|
|
221
273
|
|
|
222
274
|
integerLiteral "integer"
|
|
223
|
-
=
|
|
275
|
+
= digits {
|
|
224
276
|
return annotate([ops.literal, parseInt(text())], location());
|
|
225
277
|
}
|
|
226
278
|
|
|
@@ -235,7 +287,7 @@ literal
|
|
|
235
287
|
/ stringLiteral
|
|
236
288
|
|
|
237
289
|
logicalAndExpression
|
|
238
|
-
= head:
|
|
290
|
+
= head:bitwiseOrExpression tail:(__ "&&" __ @bitwiseOrExpression)* {
|
|
239
291
|
return tail.length === 0
|
|
240
292
|
? head
|
|
241
293
|
: annotate(
|
|
@@ -257,6 +309,16 @@ logicalOrExpression
|
|
|
257
309
|
multiLineComment
|
|
258
310
|
= "/*" (!"*/" .)* "*/" { return null; }
|
|
259
311
|
|
|
312
|
+
multiplicativeExpression
|
|
313
|
+
= head:exponentiationExpression tail:(__ @multiplicativeOperator __ @exponentiationExpression)* {
|
|
314
|
+
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
multiplicativeOperator
|
|
318
|
+
= "*"
|
|
319
|
+
/ "/"
|
|
320
|
+
/ "%"
|
|
321
|
+
|
|
260
322
|
// A namespace reference is a string of letters only, followed by a colon.
|
|
261
323
|
// For the time being, we also allow a leading `@`, which is deprecated.
|
|
262
324
|
namespace
|
|
@@ -297,7 +359,7 @@ objectEntries
|
|
|
297
359
|
}
|
|
298
360
|
|
|
299
361
|
objectEntry
|
|
300
|
-
=
|
|
362
|
+
= spreadElement
|
|
301
363
|
/ objectProperty
|
|
302
364
|
/ objectGetter
|
|
303
365
|
/ objectShorthandProperty
|
|
@@ -382,7 +444,10 @@ pathSegmentChar
|
|
|
382
444
|
// functions to it.
|
|
383
445
|
pipelineExpression
|
|
384
446
|
= head:shorthandFunction tail:(__ singleArrow __ @shorthandFunction)* {
|
|
385
|
-
return
|
|
447
|
+
return annotate(
|
|
448
|
+
tail.reduce(makePipeline, downgradeReference(head)),
|
|
449
|
+
location()
|
|
450
|
+
);
|
|
386
451
|
}
|
|
387
452
|
|
|
388
453
|
primary
|
|
@@ -419,6 +484,17 @@ reference
|
|
|
419
484
|
/ namespace
|
|
420
485
|
/ scopeReference
|
|
421
486
|
|
|
487
|
+
relationalExpression
|
|
488
|
+
= head:shiftExpression tail:(__ @relationalOperator __ @shiftExpression)* {
|
|
489
|
+
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
relationalOperator
|
|
493
|
+
= "<="
|
|
494
|
+
/ "<"
|
|
495
|
+
/ ">="
|
|
496
|
+
/ ">"
|
|
497
|
+
|
|
422
498
|
// A top-level folder below the root: `/foo`
|
|
423
499
|
// or the root folder itself: `/`
|
|
424
500
|
rootDirectory
|
|
@@ -449,6 +525,16 @@ slashFollows
|
|
|
449
525
|
shebang
|
|
450
526
|
= "#!" [^\n\r]* { return null; }
|
|
451
527
|
|
|
528
|
+
shiftExpression
|
|
529
|
+
= head:additiveExpression tail:(__ @shiftOperator __ @additiveExpression)* {
|
|
530
|
+
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
shiftOperator
|
|
534
|
+
= "<<"
|
|
535
|
+
/ ">>>"
|
|
536
|
+
/ ">>"
|
|
537
|
+
|
|
452
538
|
// A shorthand lambda expression: `=foo(_)`
|
|
453
539
|
shorthandFunction "lambda function"
|
|
454
540
|
// Avoid a following equal sign (for an equality)
|
|
@@ -457,9 +543,6 @@ shorthandFunction "lambda function"
|
|
|
457
543
|
}
|
|
458
544
|
/ implicitParenthesesCallExpression
|
|
459
545
|
|
|
460
|
-
sign
|
|
461
|
-
= [+\-]
|
|
462
|
-
|
|
463
546
|
singleArrow
|
|
464
547
|
= "→"
|
|
465
548
|
/ "->"
|
|
@@ -475,8 +558,8 @@ singleQuoteString "single quote string"
|
|
|
475
558
|
singleQuoteStringChar
|
|
476
559
|
= !("'" / newLine) @textChar
|
|
477
560
|
|
|
478
|
-
|
|
479
|
-
= ellipsis __ value:
|
|
561
|
+
spreadElement
|
|
562
|
+
= ellipsis __ value:pipelineExpression {
|
|
480
563
|
return annotate([ops.spread, value], location());
|
|
481
564
|
}
|
|
482
565
|
|
|
@@ -539,12 +622,15 @@ textChar
|
|
|
539
622
|
// A unary prefix operator: `!x`
|
|
540
623
|
unaryExpression
|
|
541
624
|
= operator:unaryOperator __ expression:unaryExpression {
|
|
542
|
-
return annotate(
|
|
625
|
+
return annotate(makeUnaryOperation(operator, expression), location());
|
|
543
626
|
}
|
|
544
627
|
/ callExpression
|
|
545
628
|
|
|
546
629
|
unaryOperator
|
|
547
630
|
= "!"
|
|
631
|
+
/ "+"
|
|
632
|
+
/ "-"
|
|
633
|
+
/ "~"
|
|
548
634
|
|
|
549
635
|
whitespaceWithNewLine
|
|
550
636
|
= inlineSpace* comment? newLine __
|