@weborigami/language 0.6.3 → 0.6.4
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 +2 -2
- package/src/compiler/optimize.js +16 -11
- package/src/compiler/origami.pegjs +54 -29
- package/src/compiler/parse.js +440 -255
- package/src/compiler/parserHelpers.js +116 -29
- package/src/project/jsGlobals.js +2 -2
- package/src/runtime/expressionObject.js +42 -6
- package/src/runtime/ops.js +14 -18
- package/test/compiler/compile.test.js +14 -0
- package/test/compiler/parse.test.js +202 -65
- package/test/runtime/expressionObject.test.js +11 -0
- package/test/runtime/ops.test.js +14 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"typescript": "5.9.3"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/async-tree": "0.6.
|
|
14
|
+
"@weborigami/async-tree": "0.6.4",
|
|
15
15
|
"exif-parser": "0.1.12",
|
|
16
16
|
"watcher": "2.3.1",
|
|
17
17
|
"yaml": "2.8.1"
|
package/src/compiler/optimize.js
CHANGED
|
@@ -62,7 +62,10 @@ export default function optimize(code, options = {}) {
|
|
|
62
62
|
|
|
63
63
|
case ops.object:
|
|
64
64
|
const entries = args;
|
|
65
|
-
|
|
65
|
+
// Filter out computed property keys when determining local variables
|
|
66
|
+
const propertyNames = entries
|
|
67
|
+
.map((entry) => entryKey(entry))
|
|
68
|
+
.filter((key) => key !== null);
|
|
66
69
|
locals.push({
|
|
67
70
|
type: REFERENCE_INHERITED,
|
|
68
71
|
names: propertyNames,
|
|
@@ -79,16 +82,18 @@ export default function optimize(code, options = {}) {
|
|
|
79
82
|
} else if (op === ops.object && index > 0) {
|
|
80
83
|
const [key, value] = child;
|
|
81
84
|
const adjustedLocals = avoidLocalRecursion(locals, key);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
key
|
|
85
|
-
optimize(/** @type {AnnotatedCode} */ (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
const optimizedKey =
|
|
86
|
+
typeof key === "string"
|
|
87
|
+
? key
|
|
88
|
+
: optimize(/** @type {AnnotatedCode} */ (key), {
|
|
89
|
+
...options,
|
|
90
|
+
locals: adjustedLocals,
|
|
91
|
+
});
|
|
92
|
+
const optimizedValue = optimize(/** @type {AnnotatedCode} */ (value), {
|
|
93
|
+
...options,
|
|
94
|
+
locals: adjustedLocals,
|
|
95
|
+
});
|
|
96
|
+
return annotate([optimizedKey, optimizedValue], child.location);
|
|
92
97
|
} else if (Array.isArray(child) && "location" in child) {
|
|
93
98
|
// Review: Aside from ops.object (above), what non-instruction arrays
|
|
94
99
|
// does this descend into?
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
makeArray,
|
|
19
19
|
makeBinaryOperation,
|
|
20
20
|
makeCall,
|
|
21
|
+
makeCallChain,
|
|
21
22
|
makeDeferredArguments,
|
|
22
23
|
makeDocument,
|
|
23
24
|
makeObject,
|
|
@@ -83,7 +84,7 @@ arguments "function arguments"
|
|
|
83
84
|
/ pathArguments
|
|
84
85
|
/ propertyAccess
|
|
85
86
|
/ computedPropertyAccess
|
|
86
|
-
|
|
87
|
+
/ optional
|
|
87
88
|
/ templateLiteral
|
|
88
89
|
|
|
89
90
|
arrayLiteral "array"
|
|
@@ -143,10 +144,7 @@ bitwiseXorOperator
|
|
|
143
144
|
// `fn(arg1)(arg2)(arg3)`.
|
|
144
145
|
callExpression "function call"
|
|
145
146
|
= head:uriExpression tail:arguments* {
|
|
146
|
-
return tail
|
|
147
|
-
(target, args) => makeCall(target, args, location()),
|
|
148
|
-
head
|
|
149
|
-
);
|
|
147
|
+
return makeCallChain(head, tail, location());
|
|
150
148
|
}
|
|
151
149
|
|
|
152
150
|
// A comma-separated list of expressions: `x, y, z`
|
|
@@ -168,9 +166,9 @@ computedPropertyAccess
|
|
|
168
166
|
return annotate([markers.property, expression], location());
|
|
169
167
|
}
|
|
170
168
|
|
|
171
|
-
// A space before a computed property access. This is allowed when
|
|
172
|
-
//
|
|
173
|
-
//
|
|
169
|
+
// A space before a computed property access. This is allowed when not in shell
|
|
170
|
+
// mode. In shell mode `foo [bar]` should parse as a function call with a single
|
|
171
|
+
// argument of an array, not as a property access.
|
|
174
172
|
computedPropertySpace
|
|
175
173
|
= shellMode
|
|
176
174
|
/ !shellMode __
|
|
@@ -383,16 +381,27 @@ identifierPart "JavaScript identifier continuation"
|
|
|
383
381
|
identifierStart "JavaScript identifier start"
|
|
384
382
|
= char:. &{ return char.match(/[$_\p{ID_Start}]/u) }
|
|
385
383
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
384
|
+
// A single argument for an implicit parens call. This differs from
|
|
385
|
+
// `parenthesesArgument` in that the term can't be a pipeline.
|
|
386
|
+
implicitParenthesesArgument
|
|
387
|
+
= "..." arg:shorthandFunction {
|
|
388
|
+
return annotate([markers.spread, arg], location());
|
|
389
|
+
}
|
|
390
|
+
/ shorthandFunction
|
|
391
|
+
|
|
392
|
+
// A separated list of arguments for an implicit parens call.
|
|
393
|
+
implicitParenthesesArgumentList "list"
|
|
394
|
+
= args:implicitParenthesesArgument|1.., separator| separator? {
|
|
395
|
+
return annotate(args, location());
|
|
389
396
|
}
|
|
390
397
|
|
|
391
|
-
// A separated list of values for an implicit parens call.
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
398
|
+
// A separated list of values for an implicit parens call.
|
|
399
|
+
implicitParenthesesArguments
|
|
400
|
+
= shellMode inlineSpace+ @implicitParenthesesArgumentList
|
|
401
|
+
|
|
402
|
+
implicitParenthesesCallExpression "function call with implicit parentheses"
|
|
403
|
+
= head:arrowFunction args:implicitParenthesesArguments? {
|
|
404
|
+
return args ? makeCall(head, args, location()) : head;
|
|
396
405
|
}
|
|
397
406
|
|
|
398
407
|
inlineSpace
|
|
@@ -430,12 +439,6 @@ keyCharStart
|
|
|
430
439
|
/ "@"
|
|
431
440
|
/ "~"
|
|
432
441
|
|
|
433
|
-
// A separated list of values
|
|
434
|
-
list "list"
|
|
435
|
-
= values:pipelineExpression|1.., separator| separator? {
|
|
436
|
-
return annotate(values, location());
|
|
437
|
-
}
|
|
438
|
-
|
|
439
442
|
logicalAndExpression
|
|
440
443
|
= head:bitwiseOrExpression tail:(__ "&&" __ @bitwiseOrExpression)* {
|
|
441
444
|
return tail.length === 0
|
|
@@ -561,7 +564,8 @@ objectShorthandProperty "object identifier"
|
|
|
561
564
|
}
|
|
562
565
|
|
|
563
566
|
objectPublicKey
|
|
564
|
-
=
|
|
567
|
+
= "[" __ @pipelineExpression __ expectClosingBracket
|
|
568
|
+
/ key:key slash:"/"? {
|
|
565
569
|
return text();
|
|
566
570
|
}
|
|
567
571
|
/ string:stringLiteral {
|
|
@@ -569,12 +573,20 @@ objectPublicKey
|
|
|
569
573
|
return string[1];
|
|
570
574
|
}
|
|
571
575
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
576
|
+
// Optional chaining
|
|
577
|
+
optional
|
|
578
|
+
= __ "?." args:parenthesesArguments {
|
|
579
|
+
return annotate([ops.optional, args], location());
|
|
580
|
+
}
|
|
581
|
+
/ __ "?." access:computedPropertyAccess {
|
|
582
|
+
return annotate([ops.optional, access], location());
|
|
583
|
+
}
|
|
584
|
+
/ __ "?." whitespaceOptionalForProgram property:identifierLiteral {
|
|
585
|
+
const propertyAccess = annotate([markers.property, property], location());
|
|
586
|
+
return annotate([ops.optional, propertyAccess], location());
|
|
575
587
|
}
|
|
576
588
|
|
|
577
|
-
// Name of a
|
|
589
|
+
// Name of a function parameter
|
|
578
590
|
parameter
|
|
579
591
|
= key:key {
|
|
580
592
|
return annotate([ops.literal, key], location());
|
|
@@ -591,9 +603,22 @@ parameterSingleton
|
|
|
591
603
|
return annotate([param], location());
|
|
592
604
|
}
|
|
593
605
|
|
|
606
|
+
// A single argument inside parentheses
|
|
607
|
+
parenthesesArgument
|
|
608
|
+
= "..." arg:pipelineExpression {
|
|
609
|
+
return annotate([markers.spread, arg], location());
|
|
610
|
+
}
|
|
611
|
+
/ pipelineExpression
|
|
612
|
+
|
|
613
|
+
// A separated list of arguments inside parentheses
|
|
614
|
+
parenthesesArgumentList "list"
|
|
615
|
+
= args:parenthesesArgument|1.., separator| separator? {
|
|
616
|
+
return annotate(args, location());
|
|
617
|
+
}
|
|
618
|
+
|
|
594
619
|
// Function arguments in parentheses
|
|
595
620
|
parenthesesArguments "function arguments in parentheses"
|
|
596
|
-
= "(" __ list:
|
|
621
|
+
= inlineSpace* "(" __ list:parenthesesArgumentList? __ expectClosingParenthesis {
|
|
597
622
|
return annotate(list ?? [undefined], location());
|
|
598
623
|
}
|
|
599
624
|
|
|
@@ -764,7 +789,7 @@ slashFollows
|
|
|
764
789
|
|
|
765
790
|
spreadElement
|
|
766
791
|
= ellipsis __ value:expectPipelineExpression {
|
|
767
|
-
return annotate([
|
|
792
|
+
return annotate([markers.spread, value], location());
|
|
768
793
|
}
|
|
769
794
|
|
|
770
795
|
stringLiteral "string"
|