@weborigami/language 0.2.8 → 0.2.10
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 +6 -6
- package/src/compiler/optimize.js +9 -7
- package/src/compiler/origami.pegjs +90 -46
- package/src/compiler/parse.js +874 -696
- package/src/compiler/parserHelpers.js +4 -1
- package/src/runtime/EventTargetMixin.d.ts +1 -5
- package/src/runtime/ops.js +2 -1
- package/test/compiler/optimize.test.js +1 -1
- package/test/compiler/parse.test.js +50 -15
- package/test/runtime/ops.test.js +4 -1
|
@@ -50,7 +50,10 @@ function avoidRecursivePropertyCalls(code, key) {
|
|
|
50
50
|
) {
|
|
51
51
|
// Rewrite to avoid recursion
|
|
52
52
|
modified = [ops.inherited, code[1]];
|
|
53
|
-
} else if (
|
|
53
|
+
} else if (
|
|
54
|
+
code[0] === ops.lambda &&
|
|
55
|
+
code[1].some((param) => param[1] === key)
|
|
56
|
+
) {
|
|
54
57
|
// Lambda that defines the key; don't rewrite
|
|
55
58
|
return code;
|
|
56
59
|
} else {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { Mixin } from "../../index.ts";
|
|
2
2
|
|
|
3
|
-
declare const EventTargetMixin: Mixin<
|
|
4
|
-
addEventListener(type: string, listener: EventListener): void;
|
|
5
|
-
dispatchEvent(event: Event): boolean;
|
|
6
|
-
removeEventListener(type: string, listener: EventListener): void;
|
|
7
|
-
}>;
|
|
3
|
+
declare const EventTargetMixin: Mixin<EventTarget>;
|
|
8
4
|
|
|
9
5
|
export default EventTargetMixin;
|
package/src/runtime/ops.js
CHANGED
|
@@ -223,7 +223,8 @@ export function lambda(parameters, code) {
|
|
|
223
223
|
// Add arguments to scope.
|
|
224
224
|
const ambients = {};
|
|
225
225
|
for (const parameter of parameters) {
|
|
226
|
-
|
|
226
|
+
const parameterName = parameter[1];
|
|
227
|
+
ambients[parameterName] = args.shift();
|
|
227
228
|
}
|
|
228
229
|
Object.defineProperty(ambients, codeSymbol, {
|
|
229
230
|
value: code,
|
|
@@ -64,12 +64,16 @@ describe("Origami parser", () => {
|
|
|
64
64
|
]);
|
|
65
65
|
assertParse("arrowFunction", "x => y", [
|
|
66
66
|
ops.lambda,
|
|
67
|
-
["x"],
|
|
67
|
+
[[ops.literal, "x"]],
|
|
68
68
|
[ops.scope, "y"],
|
|
69
69
|
]);
|
|
70
70
|
assertParse("arrowFunction", "(a, b, c) ⇒ fn(a, b, c)", [
|
|
71
71
|
ops.lambda,
|
|
72
|
-
[
|
|
72
|
+
[
|
|
73
|
+
[ops.literal, "a"],
|
|
74
|
+
[ops.literal, "b"],
|
|
75
|
+
[ops.literal, "c"],
|
|
76
|
+
],
|
|
73
77
|
[
|
|
74
78
|
[ops.builtin, "fn"],
|
|
75
79
|
[ops.scope, "a"],
|
|
@@ -79,10 +83,10 @@ describe("Origami parser", () => {
|
|
|
79
83
|
]);
|
|
80
84
|
assertParse("arrowFunction", "a => b => fn(a, b)", [
|
|
81
85
|
ops.lambda,
|
|
82
|
-
["a"],
|
|
86
|
+
[[ops.literal, "a"]],
|
|
83
87
|
[
|
|
84
88
|
ops.lambda,
|
|
85
|
-
["b"],
|
|
89
|
+
[[ops.literal, "b"]],
|
|
86
90
|
[
|
|
87
91
|
[ops.builtin, "fn"],
|
|
88
92
|
[ops.scope, "a"],
|
|
@@ -259,7 +263,7 @@ describe("Origami parser", () => {
|
|
|
259
263
|
assertParse("conditionalExpression", "false ? =1 : 0", [
|
|
260
264
|
ops.conditional,
|
|
261
265
|
[ops.scope, "false"],
|
|
262
|
-
[ops.lambda, [], [ops.lambda, ["_"], [ops.literal, "1"]]],
|
|
266
|
+
[ops.lambda, [], [ops.lambda, [[ops.literal, "_"]], [ops.literal, "1"]]],
|
|
263
267
|
[ops.literal, "0"],
|
|
264
268
|
]);
|
|
265
269
|
});
|
|
@@ -282,6 +286,18 @@ describe("Origami parser", () => {
|
|
|
282
286
|
]);
|
|
283
287
|
});
|
|
284
288
|
|
|
289
|
+
test("errors for missing pieces", () => {
|
|
290
|
+
assertThrows("arrowFunction", "(a) => ", "Expected an expression");
|
|
291
|
+
assertThrows("arrowFunction", "a ⇒ ", "Expected an expression");
|
|
292
|
+
assertThrows("callExpression", "fn(a", "Expected right parenthesis");
|
|
293
|
+
assertThrows("doubleQuoteString", '"foo', "Expected closing quote");
|
|
294
|
+
assertThrows("guillemetString", "«foo", "Expected closing guillemet");
|
|
295
|
+
assertThrows("objectGetter", "a =", "Expected an expression");
|
|
296
|
+
assertThrows("objectProperty", "a:", "Expected an expression");
|
|
297
|
+
assertThrows("singleQuoteString", "'foo", "Expected closing quote");
|
|
298
|
+
assertThrows("templateLiteral", "`foo", "Expected closing backtick");
|
|
299
|
+
});
|
|
300
|
+
|
|
285
301
|
test("exponentiationExpression", () => {
|
|
286
302
|
assertParse("exponentiationExpression", "2 ** 2 ** 3", [
|
|
287
303
|
ops.exponentiation,
|
|
@@ -389,7 +405,7 @@ describe("Origami parser", () => {
|
|
|
389
405
|
]);
|
|
390
406
|
assertParse("expression", "fn =`x`", [
|
|
391
407
|
[ops.builtin, "fn"],
|
|
392
|
-
[ops.lambda, ["_"], [ops.template, [ops.literal, ["x"]]]],
|
|
408
|
+
[ops.lambda, [[ops.literal, "_"]], [ops.template, [ops.literal, ["x"]]]],
|
|
393
409
|
]);
|
|
394
410
|
assertParse("expression", "copy app.js(formulas), files:snapshot", [
|
|
395
411
|
[ops.builtin, "copy"],
|
|
@@ -406,7 +422,7 @@ describe("Origami parser", () => {
|
|
|
406
422
|
[ops.builtin, "map"],
|
|
407
423
|
[
|
|
408
424
|
ops.lambda,
|
|
409
|
-
["_"],
|
|
425
|
+
[[ops.literal, "_"]],
|
|
410
426
|
[
|
|
411
427
|
ops.template,
|
|
412
428
|
[ops.literal, ["<li>", "</li>"]],
|
|
@@ -426,7 +442,10 @@ describe("Origami parser", () => {
|
|
|
426
442
|
]);
|
|
427
443
|
assertParse("expression", "(post, slug) => fn.js(post, slug)", [
|
|
428
444
|
ops.lambda,
|
|
429
|
-
[
|
|
445
|
+
[
|
|
446
|
+
[ops.literal, "post"],
|
|
447
|
+
[ops.literal, "slug"],
|
|
448
|
+
],
|
|
430
449
|
[
|
|
431
450
|
[ops.scope, "fn.js"],
|
|
432
451
|
[ops.scope, "post"],
|
|
@@ -718,7 +737,7 @@ describe("Origami parser", () => {
|
|
|
718
737
|
assertParse("objectEntry", "a: a", ["a", [ops.inherited, "a"]]);
|
|
719
738
|
assertParse("objectEntry", "a: (a) => a", [
|
|
720
739
|
"a",
|
|
721
|
-
[ops.lambda, ["a"], [ops.scope, "a"]],
|
|
740
|
+
[ops.lambda, [[ops.literal, "a"]], [ops.scope, "a"]],
|
|
722
741
|
]);
|
|
723
742
|
assertParse("objectEntry", "posts/: map(posts, post.ori)", [
|
|
724
743
|
"posts/",
|
|
@@ -943,12 +962,12 @@ describe("Origami parser", () => {
|
|
|
943
962
|
test("shorthandFunction", () => {
|
|
944
963
|
assertParse("shorthandFunction", "=message", [
|
|
945
964
|
ops.lambda,
|
|
946
|
-
["_"],
|
|
965
|
+
[[ops.literal, "_"]],
|
|
947
966
|
[undetermined, "message"],
|
|
948
967
|
]);
|
|
949
968
|
assertParse("shorthandFunction", "=`Hello, ${name}.`", [
|
|
950
969
|
ops.lambda,
|
|
951
|
-
["_"],
|
|
970
|
+
[[ops.literal, "_"]],
|
|
952
971
|
[
|
|
953
972
|
ops.template,
|
|
954
973
|
[ops.literal, ["Hello, ", "."]],
|
|
@@ -957,7 +976,7 @@ describe("Origami parser", () => {
|
|
|
957
976
|
]);
|
|
958
977
|
assertParse("shorthandFunction", "=indent`hello`", [
|
|
959
978
|
ops.lambda,
|
|
960
|
-
["_"],
|
|
979
|
+
[[ops.literal, "_"]],
|
|
961
980
|
[
|
|
962
981
|
[ops.builtin, "indent"],
|
|
963
982
|
[ops.literal, ["hello"]],
|
|
@@ -991,7 +1010,7 @@ describe("Origami parser", () => {
|
|
|
991
1010
|
test("templateDocument", () => {
|
|
992
1011
|
assertParse("templateDocument", "hello${foo}world", [
|
|
993
1012
|
ops.lambda,
|
|
994
|
-
["_"],
|
|
1013
|
+
[[ops.literal, "_"]],
|
|
995
1014
|
[
|
|
996
1015
|
ops.templateIndent,
|
|
997
1016
|
[ops.literal, ["hello", "world"]],
|
|
@@ -1000,7 +1019,7 @@ describe("Origami parser", () => {
|
|
|
1000
1019
|
]);
|
|
1001
1020
|
assertParse("templateDocument", "Documents can contain ` backticks", [
|
|
1002
1021
|
ops.lambda,
|
|
1003
|
-
["_"],
|
|
1022
|
+
[[ops.literal, "_"]],
|
|
1004
1023
|
[
|
|
1005
1024
|
ops.templateIndent,
|
|
1006
1025
|
[ops.literal, ["Documents can contain ` backticks"]],
|
|
@@ -1033,7 +1052,7 @@ describe("Origami parser", () => {
|
|
|
1033
1052
|
[ops.scope, "people"],
|
|
1034
1053
|
[
|
|
1035
1054
|
ops.lambda,
|
|
1036
|
-
["_"],
|
|
1055
|
+
[[ops.literal, "_"]],
|
|
1037
1056
|
[
|
|
1038
1057
|
ops.template,
|
|
1039
1058
|
[ops.literal, ["", ""]],
|
|
@@ -1101,3 +1120,19 @@ function assertCodeLocations(code) {
|
|
|
1101
1120
|
}
|
|
1102
1121
|
}
|
|
1103
1122
|
}
|
|
1123
|
+
|
|
1124
|
+
function assertThrows(startRule, source, message) {
|
|
1125
|
+
try {
|
|
1126
|
+
parse(source, {
|
|
1127
|
+
grammarSource: { text: source },
|
|
1128
|
+
startRule,
|
|
1129
|
+
});
|
|
1130
|
+
} catch (/** @type {any} */ error) {
|
|
1131
|
+
assert(
|
|
1132
|
+
error.message.includes(message),
|
|
1133
|
+
`Error message incorrect:\n expected: "${message}"\n actual: "${error.message}"`
|
|
1134
|
+
);
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
assert.fail(`Expected error: ${message}`);
|
|
1138
|
+
}
|
package/test/runtime/ops.test.js
CHANGED
|
@@ -169,7 +169,10 @@ describe("ops", () => {
|
|
|
169
169
|
test("ops.lambda adds input parameters to scope", async () => {
|
|
170
170
|
const code = createCode([
|
|
171
171
|
ops.lambda,
|
|
172
|
-
[
|
|
172
|
+
[
|
|
173
|
+
[ops.literal, "a"],
|
|
174
|
+
[ops.literal, "b"],
|
|
175
|
+
],
|
|
173
176
|
[ops.concat, [ops.scope, "b"], [ops.scope, "a"]],
|
|
174
177
|
]);
|
|
175
178
|
const fn = await evaluate.call(null, code);
|