@weborigami/language 0.2.2 → 0.2.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/LICENSE +21 -0
- package/main.js +1 -0
- package/package.json +7 -7
- package/src/compiler/compile.js +43 -23
- package/src/compiler/origami.pegjs +17 -19
- package/src/compiler/parse.js +160 -142
- package/src/compiler/parserHelpers.js +18 -27
- package/src/runtime/expressionObject.js +56 -13
- package/src/runtime/mergeTrees.js +23 -3
- package/src/runtime/ops.js +10 -1
- package/src/runtime/taggedTemplate.js +1 -1
- package/src/runtime/taggedTemplateIndent.js +115 -0
- package/test/compiler/compile.test.js +19 -5
- package/test/compiler/parse.test.js +18 -3
- package/test/runtime/expressionObject.test.js +19 -1
- package/test/runtime/mergeTrees.test.js +33 -15
- package/test/runtime/taggedTemplateIndent.test.js +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Jan Miksovsky and other contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/main.js
CHANGED
|
@@ -13,5 +13,6 @@ export { default as InvokeFunctionsTransform } from "./src/runtime/InvokeFunctio
|
|
|
13
13
|
export { default as OrigamiFiles } from "./src/runtime/OrigamiFiles.js";
|
|
14
14
|
export * as symbols from "./src/runtime/symbols.js";
|
|
15
15
|
export { default as taggedTemplate } from "./src/runtime/taggedTemplate.js";
|
|
16
|
+
export { default as taggedTemplateIndent } from "./src/runtime/taggedTemplateIndent.js";
|
|
16
17
|
export { default as TreeEvent } from "./src/runtime/TreeEvent.js";
|
|
17
18
|
export { default as WatchFilesMixin } from "./src/runtime/WatchFilesMixin.js";
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
7
7
|
"types": "./index.ts",
|
|
8
8
|
"devDependencies": {
|
|
9
|
-
"@types/node": "22.
|
|
10
|
-
"peggy": "4.0.
|
|
11
|
-
"typescript": "5.
|
|
12
|
-
"yaml": "2.
|
|
9
|
+
"@types/node": "22.10.2",
|
|
10
|
+
"peggy": "4.2.0.",
|
|
11
|
+
"typescript": "5.7.2",
|
|
12
|
+
"yaml": "2.6.1"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@weborigami/async-tree": "0.2.
|
|
16
|
-
"@weborigami/types": "0.2.
|
|
15
|
+
"@weborigami/async-tree": "0.2.4",
|
|
16
|
+
"@weborigami/types": "0.2.4",
|
|
17
17
|
"watcher": "2.3.1"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
package/src/compiler/compile.js
CHANGED
|
@@ -5,7 +5,7 @@ import { parse } from "./parse.js";
|
|
|
5
5
|
import { annotate, undetermined } from "./parserHelpers.js";
|
|
6
6
|
|
|
7
7
|
function compile(source, options) {
|
|
8
|
-
const { startRule } = options;
|
|
8
|
+
const { macros, startRule } = options;
|
|
9
9
|
const enableCaching = options.scopeCaching ?? true;
|
|
10
10
|
if (typeof source === "string") {
|
|
11
11
|
source = { text: source };
|
|
@@ -15,7 +15,7 @@ function compile(source, options) {
|
|
|
15
15
|
startRule,
|
|
16
16
|
});
|
|
17
17
|
const cache = {};
|
|
18
|
-
const modified =
|
|
18
|
+
const modified = transformReferences(code, cache, enableCaching, macros);
|
|
19
19
|
const fn = createExpressionFunction(modified);
|
|
20
20
|
return fn;
|
|
21
21
|
}
|
|
@@ -27,14 +27,34 @@ export function expression(source, options = {}) {
|
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
export function program(source, options = {}) {
|
|
31
|
+
return compile(source, {
|
|
32
|
+
...options,
|
|
33
|
+
startRule: "program",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function templateDocument(source, options = {}) {
|
|
38
|
+
return compile(source, {
|
|
39
|
+
...options,
|
|
40
|
+
startRule: "templateDocument",
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Transform any remaining undetermined references to scope references.
|
|
46
|
+
*
|
|
47
|
+
* At the same time, transform those or explicit ops.scope calls to ops.external
|
|
48
|
+
* calls unless they refer to local variables (variables defined by object
|
|
49
|
+
* literals or lambda parameters).
|
|
50
|
+
*
|
|
51
|
+
* Also apply any macros to the code.
|
|
52
|
+
*/
|
|
53
|
+
export function transformReferences(
|
|
35
54
|
code,
|
|
36
55
|
cache,
|
|
37
56
|
enableCaching,
|
|
57
|
+
macros,
|
|
38
58
|
locals = {}
|
|
39
59
|
) {
|
|
40
60
|
const [fn, ...args] = code;
|
|
@@ -45,7 +65,20 @@ export function transformScopeReferences(
|
|
|
45
65
|
case ops.scope:
|
|
46
66
|
const key = args[0];
|
|
47
67
|
const normalizedKey = trailingSlash.remove(key);
|
|
48
|
-
if (
|
|
68
|
+
if (macros?.[normalizedKey]) {
|
|
69
|
+
// Apply macro
|
|
70
|
+
const macroBody = macros[normalizedKey];
|
|
71
|
+
const modified = transformReferences(
|
|
72
|
+
macroBody,
|
|
73
|
+
cache,
|
|
74
|
+
enableCaching,
|
|
75
|
+
macros,
|
|
76
|
+
locals
|
|
77
|
+
);
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
annotate(modified, code.location);
|
|
80
|
+
return modified;
|
|
81
|
+
} else if (enableCaching && !locals[normalizedKey]) {
|
|
49
82
|
// Upgrade to cached external reference
|
|
50
83
|
const modified = [ops.external, key, cache];
|
|
51
84
|
// @ts-ignore
|
|
@@ -87,10 +120,11 @@ export function transformScopeReferences(
|
|
|
87
120
|
// be preferable to only descend into instructions. This would require
|
|
88
121
|
// surrounding ops.lambda parameters with ops.literal, and ops.object
|
|
89
122
|
// entries with ops.array.
|
|
90
|
-
return
|
|
123
|
+
return transformReferences(
|
|
91
124
|
child,
|
|
92
125
|
cache,
|
|
93
126
|
enableCaching,
|
|
127
|
+
macros,
|
|
94
128
|
updatedLocals
|
|
95
129
|
);
|
|
96
130
|
} else {
|
|
@@ -103,17 +137,3 @@ export function transformScopeReferences(
|
|
|
103
137
|
}
|
|
104
138
|
return modified;
|
|
105
139
|
}
|
|
106
|
-
|
|
107
|
-
export function program(source, options = {}) {
|
|
108
|
-
return compile(source, {
|
|
109
|
-
...options,
|
|
110
|
-
startRule: "program",
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function templateDocument(source, options = {}) {
|
|
115
|
-
return compile(source, {
|
|
116
|
-
...options,
|
|
117
|
-
startRule: "templateDocument",
|
|
118
|
-
});
|
|
119
|
-
}
|
|
@@ -31,12 +31,12 @@ import {
|
|
|
31
31
|
|
|
32
32
|
// A block of optional whitespace
|
|
33
33
|
__
|
|
34
|
-
=
|
|
34
|
+
= whitespace* {
|
|
35
35
|
return null;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
additiveExpression
|
|
39
|
-
= head:multiplicativeExpression tail:(
|
|
39
|
+
= head:multiplicativeExpression tail:(whitespace @additiveOperator whitespace @multiplicativeExpression)* {
|
|
40
40
|
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -148,8 +148,8 @@ comment "comment"
|
|
|
148
148
|
|
|
149
149
|
conditionalExpression
|
|
150
150
|
= condition:logicalOrExpression tail:(__
|
|
151
|
-
"?" __ @
|
|
152
|
-
":" __ @
|
|
151
|
+
"?" __ @shorthandFunction __
|
|
152
|
+
":" __ @shorthandFunction)?
|
|
153
153
|
{
|
|
154
154
|
if (!tail) {
|
|
155
155
|
return condition;
|
|
@@ -310,7 +310,7 @@ multiLineComment
|
|
|
310
310
|
= "/*" (!"*/" .)* "*/" { return null; }
|
|
311
311
|
|
|
312
312
|
multiplicativeExpression
|
|
313
|
-
= head:exponentiationExpression tail:(
|
|
313
|
+
= head:exponentiationExpression tail:(whitespace @multiplicativeOperator whitespace @exponentiationExpression)* {
|
|
314
314
|
return annotate(tail.reduce(makeBinaryOperation, head), location());
|
|
315
315
|
}
|
|
316
316
|
|
|
@@ -571,20 +571,17 @@ stringLiteral "string"
|
|
|
571
571
|
// A top-level document defining a template. This is the same as a template
|
|
572
572
|
// literal, but can contain backticks at the top level.
|
|
573
573
|
templateDocument "template"
|
|
574
|
-
=
|
|
575
|
-
return annotate(
|
|
574
|
+
= head:templateDocumentText tail:(templateSubstitution templateDocumentText)* {
|
|
575
|
+
return annotate(
|
|
576
|
+
[ops.lambda, ["_"], makeTemplate(ops.templateIndent, head, tail)],
|
|
577
|
+
location()
|
|
578
|
+
);
|
|
576
579
|
}
|
|
577
580
|
|
|
578
581
|
// Template documents can contain backticks at the top level.
|
|
579
582
|
templateDocumentChar
|
|
580
583
|
= !("${") @textChar
|
|
581
584
|
|
|
582
|
-
// The contents of a template document containing plain text and substitutions
|
|
583
|
-
templateDocumentContents
|
|
584
|
-
= head:templateDocumentText tail:(templateSubstitution templateDocumentText)* {
|
|
585
|
-
return annotate(makeTemplate(ops.template, head, tail), location());
|
|
586
|
-
}
|
|
587
|
-
|
|
588
585
|
templateDocumentText "template text"
|
|
589
586
|
= chars:templateDocumentChar* {
|
|
590
587
|
return chars.join("");
|
|
@@ -592,17 +589,13 @@ templateDocumentText "template text"
|
|
|
592
589
|
|
|
593
590
|
// A backtick-quoted template literal
|
|
594
591
|
templateLiteral "template literal"
|
|
595
|
-
= "`"
|
|
596
|
-
return annotate(makeTemplate(ops.template,
|
|
592
|
+
= "`" head:templateLiteralText tail:(templateSubstitution templateLiteralText)* "`" {
|
|
593
|
+
return annotate(makeTemplate(ops.template, head, tail), location());
|
|
597
594
|
}
|
|
598
595
|
|
|
599
596
|
templateLiteralChar
|
|
600
597
|
= !("`" / "${") @textChar
|
|
601
598
|
|
|
602
|
-
// The contents of a template literal containing plain text and substitutions
|
|
603
|
-
templateLiteralContents
|
|
604
|
-
= head:templateLiteralText tail:(templateSubstitution templateLiteralText)*
|
|
605
|
-
|
|
606
599
|
// Plain text in a template literal
|
|
607
600
|
templateLiteralText
|
|
608
601
|
= chars:templateLiteralChar* {
|
|
@@ -632,5 +625,10 @@ unaryOperator
|
|
|
632
625
|
/ "-"
|
|
633
626
|
/ "~"
|
|
634
627
|
|
|
628
|
+
whitespace
|
|
629
|
+
= inlineSpace
|
|
630
|
+
/ newLine
|
|
631
|
+
/ comment
|
|
632
|
+
|
|
635
633
|
whitespaceWithNewLine
|
|
636
634
|
= inlineSpace* comment? newLine __
|