@weborigami/language 0.3.0 → 0.3.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 +37 -10
- package/src/compiler/parse.js +488 -292
- package/src/compiler/parserHelpers.js +9 -0
- package/src/runtime/expressionObject.js +2 -6
- package/src/runtime/handlers.js +2 -2
- package/src/runtime/ops.js +32 -15
- package/test/compiler/parse.test.js +38 -0
|
@@ -364,6 +364,15 @@ export function makeProperty(key, value) {
|
|
|
364
364
|
return [key, modified];
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
export function makeJsPropertyAccess(expression, property) {
|
|
368
|
+
const location = {
|
|
369
|
+
source: expression.location.source,
|
|
370
|
+
start: expression.location.start,
|
|
371
|
+
end: property.location.end,
|
|
372
|
+
};
|
|
373
|
+
return annotate([expression, property], location);
|
|
374
|
+
}
|
|
375
|
+
|
|
367
376
|
export function makeReference(identifier) {
|
|
368
377
|
// We can't know for sure that an identifier is a builtin reference until we
|
|
369
378
|
// see whether it's being called as a function.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
extension,
|
|
3
3
|
ObjectTree,
|
|
4
|
+
setParent,
|
|
4
5
|
symbols,
|
|
5
6
|
trailingSlash,
|
|
6
7
|
Tree,
|
|
@@ -116,12 +117,7 @@ export default async function expressionObject(entries, parent) {
|
|
|
116
117
|
});
|
|
117
118
|
|
|
118
119
|
// Attach the parent
|
|
119
|
-
|
|
120
|
-
configurable: true,
|
|
121
|
-
enumerable: false,
|
|
122
|
-
value: parent,
|
|
123
|
-
writable: true,
|
|
124
|
-
});
|
|
120
|
+
setParent(object, parent);
|
|
125
121
|
|
|
126
122
|
// Evaluate any properties that were declared as immediate: get their value
|
|
127
123
|
// and overwrite the property getter with the actual value.
|
package/src/runtime/handlers.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
isStringLike,
|
|
6
6
|
isUnpackable,
|
|
7
7
|
scope,
|
|
8
|
-
|
|
8
|
+
setParent,
|
|
9
9
|
trailingSlash,
|
|
10
10
|
} from "@weborigami/async-tree";
|
|
11
11
|
|
|
@@ -92,7 +92,7 @@ export async function handleExtension(parent, value, key) {
|
|
|
92
92
|
if (handler.mediaType) {
|
|
93
93
|
value.mediaType = handler.mediaType;
|
|
94
94
|
}
|
|
95
|
-
value
|
|
95
|
+
setParent(value, parent);
|
|
96
96
|
|
|
97
97
|
const unpack = handler.unpack;
|
|
98
98
|
if (unpack) {
|
package/src/runtime/ops.js
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
import {
|
|
9
9
|
ObjectTree,
|
|
10
10
|
Tree,
|
|
11
|
-
|
|
11
|
+
deepText,
|
|
12
12
|
isUnpackable,
|
|
13
13
|
scope as scopeFn,
|
|
14
|
-
|
|
14
|
+
setParent,
|
|
15
15
|
concat as treeConcat,
|
|
16
16
|
} from "@weborigami/async-tree";
|
|
17
17
|
import os from "node:os";
|
|
@@ -131,7 +131,7 @@ export async function document(frontData, bodyCode) {
|
|
|
131
131
|
...frontData,
|
|
132
132
|
"@text": body,
|
|
133
133
|
};
|
|
134
|
-
object
|
|
134
|
+
setParent(object, this);
|
|
135
135
|
return object;
|
|
136
136
|
}
|
|
137
137
|
addOpLabel(document, "«ops.document");
|
|
@@ -224,7 +224,8 @@ export async function inherited(key) {
|
|
|
224
224
|
return undefined;
|
|
225
225
|
}
|
|
226
226
|
const parentScope = scopeFn(this.parent);
|
|
227
|
-
|
|
227
|
+
const value = await parentScope.get(key);
|
|
228
|
+
return value;
|
|
228
229
|
}
|
|
229
230
|
addOpLabel(inherited, "«ops.inherited»");
|
|
230
231
|
|
|
@@ -388,17 +389,33 @@ export async function merge(...codes) {
|
|
|
388
389
|
return directObject;
|
|
389
390
|
}
|
|
390
391
|
|
|
391
|
-
//
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
392
|
+
// If we have direct property entries, create a context for them. The
|
|
393
|
+
// `expressionObject` function will set the object's parent symbol to `this`.
|
|
394
|
+
// Tree.from will call the ObjectTree constructor, which will use that symbol
|
|
395
|
+
// to set the parent for the new tree to `this`.
|
|
396
|
+
const context = directObject ? Tree.from(directObject) : this;
|
|
397
|
+
|
|
398
|
+
// Second pass: evaluate the trees. For the trees which are direct property
|
|
399
|
+
// entries, we'll copy over the values we've already calculated. We can't
|
|
400
|
+
// reuse the `directObject` as is because in a merge we need to respect the
|
|
401
|
+
// order in which the properties are defined. Trees that aren't direct
|
|
402
|
+
// property entries are evaluated with the direct property entries in scope.
|
|
400
403
|
const trees = await Promise.all(
|
|
401
|
-
codes.map(async (code) =>
|
|
404
|
+
codes.map(async (code) => {
|
|
405
|
+
if (code[0] === object) {
|
|
406
|
+
// Using the code as reference, create a new object with the direct
|
|
407
|
+
// property values we've already calculated.
|
|
408
|
+
const object = {};
|
|
409
|
+
for (const [key] of code.slice(1)) {
|
|
410
|
+
// @ts-ignore directObject will always be defined
|
|
411
|
+
object[key] = directObject[key];
|
|
412
|
+
}
|
|
413
|
+
setParent(object, this);
|
|
414
|
+
return object;
|
|
415
|
+
} else {
|
|
416
|
+
return evaluate.call(context, code);
|
|
417
|
+
}
|
|
418
|
+
})
|
|
402
419
|
);
|
|
403
420
|
|
|
404
421
|
return mergeTrees.call(this, ...trees);
|
|
@@ -533,7 +550,7 @@ addOpLabel(subtraction, "«ops.subtraction»");
|
|
|
533
550
|
* Apply the default tagged template function.
|
|
534
551
|
*/
|
|
535
552
|
export async function template(strings, ...values) {
|
|
536
|
-
return
|
|
553
|
+
return deepText(strings, ...values);
|
|
537
554
|
}
|
|
538
555
|
addOpLabel(template, "«ops.template»");
|
|
539
556
|
|
|
@@ -236,6 +236,24 @@ describe("Origami parser", () => {
|
|
|
236
236
|
]);
|
|
237
237
|
});
|
|
238
238
|
|
|
239
|
+
test("callExpression using property acccess", () => {
|
|
240
|
+
assertParse("callExpression", "(foo).bar", [
|
|
241
|
+
ops.traverse,
|
|
242
|
+
[ops.scope, "foo"],
|
|
243
|
+
[ops.literal, "bar"],
|
|
244
|
+
]);
|
|
245
|
+
assertParse("callExpression", "(foo).bar.baz", [
|
|
246
|
+
ops.traverse,
|
|
247
|
+
[ops.traverse, [ops.scope, "foo"], [ops.literal, "bar"]],
|
|
248
|
+
[ops.literal, "baz"],
|
|
249
|
+
]);
|
|
250
|
+
assertParse("callExpression", "foo[bar]", [
|
|
251
|
+
ops.traverse,
|
|
252
|
+
[ops.scope, "foo/"],
|
|
253
|
+
[ops.scope, "bar"],
|
|
254
|
+
]);
|
|
255
|
+
});
|
|
256
|
+
|
|
239
257
|
test("commaExpression", () => {
|
|
240
258
|
assertParse("commaExpression", "1", [ops.literal, 1]);
|
|
241
259
|
assertParse("commaExpression", "a, b, c", [
|
|
@@ -567,6 +585,26 @@ Body`,
|
|
|
567
585
|
]);
|
|
568
586
|
});
|
|
569
587
|
|
|
588
|
+
test("jsIdentifier", () => {
|
|
589
|
+
assertParse("jsIdentifier", "foo", "foo", false);
|
|
590
|
+
assertParse("jsIdentifier", "$Δelta", "$Δelta", false);
|
|
591
|
+
assertThrows(
|
|
592
|
+
"jsIdentifier",
|
|
593
|
+
"1stCharacterIsNumber",
|
|
594
|
+
"Expected JavaScript identifier start"
|
|
595
|
+
);
|
|
596
|
+
assertThrows(
|
|
597
|
+
"jsIdentifier",
|
|
598
|
+
"has space",
|
|
599
|
+
"Expected JavaScript identifier continuation"
|
|
600
|
+
);
|
|
601
|
+
assertThrows(
|
|
602
|
+
"jsIdentifier",
|
|
603
|
+
"foo.bar",
|
|
604
|
+
"Expected JavaScript identifier continuation"
|
|
605
|
+
);
|
|
606
|
+
});
|
|
607
|
+
|
|
570
608
|
test("list", () => {
|
|
571
609
|
assertParse("list", "1", [[ops.literal, 1]]);
|
|
572
610
|
assertParse("list", "1,2,3", [
|