@weborigami/language 0.5.4 → 0.5.6
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/index.ts +16 -6
- package/main.js +9 -4
- package/package.json +4 -3
- package/src/compiler/compile.js +10 -4
- package/src/compiler/optimize.js +115 -97
- package/src/compiler/origami.pegjs +1 -4
- package/src/compiler/parse.js +568 -588
- package/src/compiler/parserHelpers.js +3 -3
- package/src/handlers/css_handler.js +7 -0
- package/src/handlers/csv_handler.js +129 -0
- package/src/handlers/handlers.js +33 -0
- package/src/handlers/htm_handler.js +2 -0
- package/src/handlers/html_handler.js +7 -0
- package/src/handlers/jpeg_handler.js +62 -0
- package/src/handlers/jpg_handler.js +2 -0
- package/src/handlers/js_handler.js +51 -0
- package/src/handlers/json_handler.js +26 -0
- package/src/handlers/md_handler.js +7 -0
- package/src/handlers/mjs_handler.js +2 -0
- package/src/handlers/ori_handler.js +47 -0
- package/src/handlers/oridocument_handler.js +77 -0
- package/src/handlers/parseFrontMatter.js +16 -0
- package/src/handlers/ts_handler.js +1 -0
- package/src/handlers/txt_handler.js +108 -0
- package/src/handlers/wasm_handler.js +15 -0
- package/src/handlers/xhtml_handler.js +2 -0
- package/src/handlers/yaml_handler.js +33 -0
- package/src/handlers/yml_handler.js +2 -0
- package/src/project/builtins.js +5 -0
- package/src/project/coreGlobals.js +17 -0
- package/src/{runtime → project}/jsGlobals.js +3 -1
- package/src/project/projectConfig.js +36 -0
- package/src/project/projectGlobals.js +19 -0
- package/src/project/projectRoot.js +59 -0
- package/src/protocols/constructHref.js +20 -0
- package/src/protocols/constructSiteTree.js +26 -0
- package/src/protocols/explore.js +14 -0
- package/src/protocols/fetchAndHandleExtension.js +25 -0
- package/src/protocols/files.js +26 -0
- package/src/protocols/http.js +15 -0
- package/src/protocols/https.js +15 -0
- package/src/protocols/httpstree.js +14 -0
- package/src/protocols/httptree.js +14 -0
- package/src/protocols/node.js +13 -0
- package/src/protocols/package.js +67 -0
- package/src/protocols/protocolGlobals.js +12 -0
- package/src/protocols/protocols.js +8 -0
- package/src/runtime/EventTargetMixin.js +1 -1
- package/src/runtime/HandleExtensionsTransform.js +3 -12
- package/src/runtime/ImportModulesMixin.js +4 -10
- package/src/runtime/InvokeFunctionsTransform.js +1 -1
- package/src/runtime/errors.js +2 -2
- package/src/runtime/evaluate.js +15 -8
- package/src/runtime/expressionFunction.js +5 -7
- package/src/runtime/expressionObject.js +10 -20
- package/src/runtime/functionResultsMap.js +5 -12
- package/src/runtime/{handlers.js → handleExtension.js} +14 -12
- package/src/runtime/mergeTrees.js +2 -10
- package/src/runtime/ops.js +91 -106
- package/test/compiler/compile.test.js +20 -19
- package/test/compiler/optimize.test.js +60 -25
- package/test/compiler/parse.test.js +10 -10
- package/test/generator/oriEval.js +4 -5
- package/test/handlers/csv.handler.test.js +36 -0
- package/test/handlers/fixtures/add.wasm +0 -0
- package/test/handlers/fixtures/exif.jpeg +0 -0
- package/test/handlers/fixtures/frontMatter.md +5 -0
- package/test/handlers/fixtures/list.js +4 -0
- package/test/handlers/fixtures/multiple.js +4 -0
- package/test/handlers/fixtures/obj.js +3 -0
- package/test/handlers/fixtures/site.ori +5 -0
- package/test/handlers/fixtures/string.js +1 -0
- package/test/handlers/fixtures/tag.yaml +5 -0
- package/test/handlers/fixtures/test.ori +9 -0
- package/test/handlers/jpeg.handler.test.js +18 -0
- package/test/handlers/js.handler.test.js +46 -0
- package/test/handlers/json.handler.test.js +14 -0
- package/test/handlers/ori.handler.test.js +87 -0
- package/test/handlers/oridocument.handler.test.js +68 -0
- package/test/handlers/txt.handler.test.js +41 -0
- package/test/handlers/wasm.handler.test.js +20 -0
- package/test/handlers/yaml.handler.test.js +17 -0
- package/test/project/fixtures/withConfig/config.ori +4 -0
- package/test/project/fixtures/withConfig/subfolder/greet.js +1 -0
- package/test/project/fixtures/withPackageJson/package.json +0 -0
- package/test/project/jsGlobals.test.js +21 -0
- package/test/project/projectConfig.test.js +28 -0
- package/test/project/projectRoot.test.js +40 -0
- package/test/protocols/package.test.js +11 -0
- package/test/runtime/evaluate.test.js +26 -42
- package/test/runtime/expressionObject.test.js +16 -20
- package/test/runtime/functionResultsMap.test.js +5 -9
- package/test/runtime/{handlers.test.js → handleExtension.test.js} +4 -20
- package/test/runtime/jsGlobals.test.js +4 -6
- package/test/runtime/mergeTrees.test.js +2 -4
- package/test/runtime/ops.test.js +70 -72
- package/src/runtime/getHandlers.js +0 -10
package/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { UnpackFunction } from "@weborigami/async-tree";
|
|
2
|
+
import { AsyncTree } from "@weborigami/types";
|
|
2
3
|
|
|
3
4
|
export * from "./main.js";
|
|
4
5
|
|
|
@@ -38,12 +39,6 @@ export type ExtensionHandler = {
|
|
|
38
39
|
unpack?: UnpackFunction;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
export type Position = {
|
|
42
|
-
column: number;
|
|
43
|
-
line: number;
|
|
44
|
-
offset: number;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
42
|
/**
|
|
48
43
|
* A mixin is a function that takes an existing class and returns a new class.
|
|
49
44
|
*
|
|
@@ -56,6 +51,21 @@ export type Mixin<MixinMembers> = <T>(
|
|
|
56
51
|
Base: Constructor<T>
|
|
57
52
|
) => Constructor<T & MixinMembers>;
|
|
58
53
|
|
|
54
|
+
export type Position = {
|
|
55
|
+
column: number;
|
|
56
|
+
line: number;
|
|
57
|
+
offset: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type RuntimeState = {
|
|
61
|
+
/** The container (e.g., file system) that holds the code */
|
|
62
|
+
container?: AsyncTree | null;
|
|
63
|
+
/** The object to which this code is attached */
|
|
64
|
+
object?: AsyncTree | null;
|
|
65
|
+
/** The current stack of function parameter assignments */
|
|
66
|
+
stack?: Array<Record<string, any>>;
|
|
67
|
+
}
|
|
68
|
+
|
|
59
69
|
/**
|
|
60
70
|
* Source code representation used by the parser.
|
|
61
71
|
*/
|
package/main.js
CHANGED
|
@@ -2,17 +2,22 @@ export * from "./src/runtime/internal.js";
|
|
|
2
2
|
|
|
3
3
|
export * as compile from "./src/compiler/compile.js";
|
|
4
4
|
export { default as isOrigamiFrontMatter } from "./src/compiler/isOrigamiFrontMatter.js";
|
|
5
|
-
export * from "./src/
|
|
5
|
+
export * as Handlers from "./src/handlers/handlers.js";
|
|
6
|
+
export { default as builtins } from "./src/project/builtins.js";
|
|
7
|
+
export { default as jsGlobals } from "./src/project/jsGlobals.js";
|
|
8
|
+
export { default as projectGlobals } from "./src/project/projectGlobals.js";
|
|
9
|
+
export { default as projectRoot } from "./src/project/projectRoot.js";
|
|
10
|
+
export * as Protocols from "./src/protocols/protocols.js";
|
|
11
|
+
export { formatError } from "./src/runtime/errors.js";
|
|
6
12
|
export { default as evaluate } from "./src/runtime/evaluate.js";
|
|
7
13
|
export { default as EventTargetMixin } from "./src/runtime/EventTargetMixin.js";
|
|
8
14
|
export * as expressionFunction from "./src/runtime/expressionFunction.js";
|
|
9
15
|
export { default as functionResultsMap } from "./src/runtime/functionResultsMap.js";
|
|
10
|
-
export
|
|
16
|
+
export * from "./src/runtime/handleExtension.js";
|
|
17
|
+
export { default as handleExtension } from "./src/runtime/handleExtension.js";
|
|
11
18
|
export { default as HandleExtensionsTransform } from "./src/runtime/HandleExtensionsTransform.js";
|
|
12
|
-
export * from "./src/runtime/handlers.js";
|
|
13
19
|
export { default as ImportModulesMixin } from "./src/runtime/ImportModulesMixin.js";
|
|
14
20
|
export { default as InvokeFunctionsTransform } from "./src/runtime/InvokeFunctionsTransform.js";
|
|
15
|
-
export { default as jsGlobals } from "./src/runtime/jsGlobals.js";
|
|
16
21
|
export * as moduleCache from "./src/runtime/moduleCache.js";
|
|
17
22
|
export { default as OrigamiFiles } from "./src/runtime/OrigamiFiles.js";
|
|
18
23
|
export * as symbols from "./src/runtime/symbols.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
"typescript": "5.9.2"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/async-tree": "0.5.
|
|
15
|
-
"@weborigami/types": "0.5.
|
|
14
|
+
"@weborigami/async-tree": "0.5.6",
|
|
15
|
+
"@weborigami/types": "0.5.6",
|
|
16
|
+
"exif-parser": "0.1.12",
|
|
16
17
|
"watcher": "2.3.1",
|
|
17
18
|
"yaml": "2.8.1"
|
|
18
19
|
},
|
package/src/compiler/compile.js
CHANGED
|
@@ -1,27 +1,33 @@
|
|
|
1
1
|
import { createExpressionFunction } from "../runtime/expressionFunction.js";
|
|
2
|
-
import jsGlobals from "../runtime/jsGlobals.js";
|
|
3
2
|
import optimize from "./optimize.js";
|
|
4
3
|
import { parse } from "./parse.js";
|
|
5
4
|
|
|
6
5
|
function compile(source, options) {
|
|
7
|
-
const { front, startRule } = options;
|
|
6
|
+
const { front, parent, startRule } = options;
|
|
8
7
|
const mode = options.mode ?? "program";
|
|
9
|
-
const globals = options.globals ??
|
|
8
|
+
const globals = options.globals ?? {};
|
|
10
9
|
if (typeof source === "string") {
|
|
11
10
|
source = { text: source };
|
|
12
11
|
}
|
|
12
|
+
|
|
13
|
+
// Parse the code
|
|
13
14
|
let code = parse(source.text, {
|
|
14
15
|
front,
|
|
15
16
|
grammarSource: source,
|
|
16
17
|
mode,
|
|
17
18
|
startRule,
|
|
18
19
|
});
|
|
20
|
+
|
|
21
|
+
// Optimize the code
|
|
19
22
|
const cache = mode === "program" ? {} : null;
|
|
20
23
|
const optimized = optimize(code, {
|
|
21
24
|
cache,
|
|
22
25
|
globals,
|
|
26
|
+
parent,
|
|
23
27
|
});
|
|
24
|
-
|
|
28
|
+
|
|
29
|
+
// Create a function that executes the optimized code.
|
|
30
|
+
const fn = createExpressionFunction(optimized, parent);
|
|
25
31
|
return fn;
|
|
26
32
|
}
|
|
27
33
|
|
package/src/compiler/optimize.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { pathFromKeys, trailingSlash } from "@weborigami/async-tree";
|
|
2
|
+
import jsGlobals from "../project/jsGlobals.js";
|
|
2
3
|
import { entryKey } from "../runtime/expressionObject.js";
|
|
3
4
|
import { ops } from "../runtime/internal.js";
|
|
4
|
-
import jsGlobals from "../runtime/jsGlobals.js";
|
|
5
5
|
import { annotate, markers } from "./parserHelpers.js";
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
7
|
+
export const REFERENCE_PARAM = 1;
|
|
8
|
+
export const REFERENCE_INHERITED = 2;
|
|
9
|
+
export const REFERENCE_GLOBAL = 3;
|
|
10
|
+
export const REFERENCE_EXTERNAL = 4;
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Optimize an Origami code instruction:
|
|
@@ -27,10 +28,12 @@ const REFERENCE_EXTERNAL = 3;
|
|
|
27
28
|
export default function optimize(code, options = {}) {
|
|
28
29
|
const globals = options.globals ?? jsGlobals;
|
|
29
30
|
const cache = options.cache === undefined ? {} : options.cache;
|
|
31
|
+
const parent = options.parent ?? null;
|
|
30
32
|
|
|
31
33
|
// The locals is an array, one item for each function or object context that
|
|
32
|
-
// has been entered. The array grows to the right.
|
|
33
|
-
//
|
|
34
|
+
// has been entered. The array grows to the right. Array items are objects
|
|
35
|
+
// { type, names }, where type is REFERENCE_PARAM or REFERENCE_INHERITED
|
|
36
|
+
// and names is an array of the variable names in that context.
|
|
34
37
|
const locals = options.locals ? options.locals.slice() : [];
|
|
35
38
|
|
|
36
39
|
// See if we can optimize this level of the code
|
|
@@ -41,13 +44,16 @@ export default function optimize(code, options = {}) {
|
|
|
41
44
|
return globals[args[0]];
|
|
42
45
|
|
|
43
46
|
case markers.traverse:
|
|
44
|
-
return resolvePath(code, globals, locals, cache);
|
|
47
|
+
return resolvePath(code, globals, parent, locals, cache);
|
|
45
48
|
|
|
46
49
|
case ops.lambda:
|
|
47
50
|
const parameters = args[0];
|
|
48
51
|
if (parameters.length > 0) {
|
|
49
|
-
const
|
|
50
|
-
locals.push(
|
|
52
|
+
const paramNames = parameters.map((param) => param[1]);
|
|
53
|
+
locals.push({
|
|
54
|
+
type: REFERENCE_PARAM,
|
|
55
|
+
names: paramNames,
|
|
56
|
+
});
|
|
51
57
|
}
|
|
52
58
|
break;
|
|
53
59
|
|
|
@@ -56,8 +62,11 @@ export default function optimize(code, options = {}) {
|
|
|
56
62
|
|
|
57
63
|
case ops.object:
|
|
58
64
|
const entries = args;
|
|
59
|
-
const
|
|
60
|
-
locals.push(
|
|
65
|
+
const propertyNames = entries.map((entry) => entryKey(entry));
|
|
66
|
+
locals.push({
|
|
67
|
+
type: REFERENCE_INHERITED,
|
|
68
|
+
names: propertyNames,
|
|
69
|
+
});
|
|
61
70
|
break;
|
|
62
71
|
}
|
|
63
72
|
|
|
@@ -106,18 +115,29 @@ function avoidLocalRecursion(locals, key) {
|
|
|
106
115
|
key = key.slice(1, -1);
|
|
107
116
|
}
|
|
108
117
|
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
118
|
+
const currentFrameIndex = locals.length - 1;
|
|
119
|
+
if (locals[currentFrameIndex]?.type !== REFERENCE_INHERITED) {
|
|
120
|
+
// Not an inherited context, nothing to do
|
|
121
|
+
return locals;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// See if the key matches any of the local variable names in the current
|
|
125
|
+
// context (ignoring trailing slashes)
|
|
126
|
+
const matchingKeyIndex = locals[currentFrameIndex].names.findIndex(
|
|
127
|
+
(name) =>
|
|
112
128
|
// Ignore trailing slashes when comparing keys
|
|
113
|
-
trailingSlash.remove(
|
|
129
|
+
trailingSlash.remove(name) === trailingSlash.remove(key)
|
|
114
130
|
);
|
|
115
131
|
|
|
116
132
|
if (matchingKeyIndex >= 0) {
|
|
117
133
|
// Remove the key from the current context's locals
|
|
118
134
|
const adjustedLocals = locals.slice();
|
|
119
|
-
|
|
120
|
-
|
|
135
|
+
const adjustedNames = adjustedLocals[currentFrameIndex].names.slice();
|
|
136
|
+
adjustedNames.splice(matchingKeyIndex, 1);
|
|
137
|
+
adjustedLocals[currentFrameIndex] = {
|
|
138
|
+
type: REFERENCE_INHERITED,
|
|
139
|
+
names: adjustedNames,
|
|
140
|
+
};
|
|
121
141
|
return adjustedLocals;
|
|
122
142
|
} else {
|
|
123
143
|
return locals;
|
|
@@ -135,49 +155,54 @@ function compoundReference(key, globals, locals, location) {
|
|
|
135
155
|
const parts = key.split(".");
|
|
136
156
|
if (parts.length === 1) {
|
|
137
157
|
// Not a compound reference
|
|
138
|
-
return
|
|
158
|
+
return null;
|
|
139
159
|
}
|
|
140
160
|
|
|
141
161
|
// Check first part to see if it's a global or local reference
|
|
142
162
|
const [head, ...tail] = parts;
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
} else if (type === REFERENCE_LOCAL) {
|
|
148
|
-
result = localReference(head, locals, location);
|
|
149
|
-
} else {
|
|
150
|
-
// Not a compound reference
|
|
151
|
-
return { type: REFERENCE_EXTERNAL, result: null };
|
|
163
|
+
const headReference = localOrGlobalReference(head, globals, locals, location);
|
|
164
|
+
if (headReference === null) {
|
|
165
|
+
// First part isn't global/local reference, so not a compound reference
|
|
166
|
+
return null;
|
|
152
167
|
}
|
|
153
168
|
|
|
169
|
+
let result = headReference.result;
|
|
170
|
+
|
|
154
171
|
// Process the remaining parts as property accesses
|
|
155
172
|
while (tail.length > 0) {
|
|
156
173
|
const part = tail.shift();
|
|
157
174
|
result = annotate([ops.property, result, part], location);
|
|
158
175
|
}
|
|
159
176
|
|
|
160
|
-
return { type, result };
|
|
177
|
+
return { type: headReference.type, result };
|
|
161
178
|
}
|
|
162
179
|
|
|
163
|
-
function externalReference(key,
|
|
164
|
-
const scope =
|
|
180
|
+
function externalReference(key, parent, location) {
|
|
181
|
+
const scope = annotate([ops.scope, parent], location);
|
|
165
182
|
const literal = annotate([ops.literal, key], location);
|
|
166
183
|
return annotate([scope, literal], location);
|
|
167
184
|
}
|
|
168
185
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
186
|
+
function findLocalDetails(key, locals) {
|
|
187
|
+
const normalized = trailingSlash.remove(key);
|
|
188
|
+
let paramDepth = 0;
|
|
189
|
+
let inheritedDepth = 0;
|
|
190
|
+
for (let i = locals.length - 1; i >= 0; i--) {
|
|
191
|
+
const { type, names } = locals[i];
|
|
192
|
+
const local = names.find(
|
|
193
|
+
(name) => trailingSlash.remove(name) === normalized
|
|
194
|
+
);
|
|
195
|
+
if (local) {
|
|
196
|
+
const depth = type === REFERENCE_PARAM ? paramDepth : inheritedDepth;
|
|
197
|
+
return { type, depth };
|
|
198
|
+
}
|
|
199
|
+
if (type === REFERENCE_PARAM) {
|
|
200
|
+
paramDepth++;
|
|
201
|
+
} else {
|
|
202
|
+
inheritedDepth++;
|
|
203
|
+
}
|
|
178
204
|
}
|
|
179
|
-
|
|
180
|
-
return depth;
|
|
205
|
+
return null;
|
|
181
206
|
}
|
|
182
207
|
|
|
183
208
|
function globalReference(key, globals) {
|
|
@@ -185,25 +210,18 @@ function globalReference(key, globals) {
|
|
|
185
210
|
return globals[normalized];
|
|
186
211
|
}
|
|
187
212
|
|
|
213
|
+
function inheritedReference(key, depth, location) {
|
|
214
|
+
const literal = annotate([ops.literal, key], location);
|
|
215
|
+
const inherited = annotate([ops.inherited, depth], location);
|
|
216
|
+
return annotate([inherited, literal], location);
|
|
217
|
+
}
|
|
218
|
+
|
|
188
219
|
function inlineLiteral(code) {
|
|
189
220
|
// If the literal value is an array, it's likely the strings array
|
|
190
221
|
// of a template literal, so return it as is.
|
|
191
222
|
return code[0] === ops.literal && !Array.isArray(code[1]) ? code[1] : code;
|
|
192
223
|
}
|
|
193
224
|
|
|
194
|
-
function localReference(key, locals, location) {
|
|
195
|
-
const normalized = trailingSlash.remove(key);
|
|
196
|
-
const depth = getLocalReferenceDepth(locals, normalized);
|
|
197
|
-
/** @type {any[]} */
|
|
198
|
-
const context = [ops.context];
|
|
199
|
-
if (depth > 0) {
|
|
200
|
-
context.push(depth);
|
|
201
|
-
}
|
|
202
|
-
const contextCall = annotate(context, location);
|
|
203
|
-
const literal = annotate([ops.literal, key], location);
|
|
204
|
-
return annotate([contextCall, literal], location);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
225
|
function keyFromCode(code) {
|
|
208
226
|
const op = code instanceof Array ? code[0] : code;
|
|
209
227
|
switch (op) {
|
|
@@ -224,7 +242,37 @@ function keyFromCode(code) {
|
|
|
224
242
|
}
|
|
225
243
|
}
|
|
226
244
|
|
|
227
|
-
function
|
|
245
|
+
function localOrGlobalReference(key, globals, locals, location) {
|
|
246
|
+
// Is key a local?
|
|
247
|
+
const normalized = trailingSlash.remove(key);
|
|
248
|
+
const localDetails = findLocalDetails(normalized, locals);
|
|
249
|
+
if (localDetails) {
|
|
250
|
+
const { type, depth } = localDetails;
|
|
251
|
+
const result =
|
|
252
|
+
type === REFERENCE_PARAM
|
|
253
|
+
? paramReference(key, depth, location)
|
|
254
|
+
: inheritedReference(key, depth, location);
|
|
255
|
+
return { type, result };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Is key a global?
|
|
259
|
+
if (normalized in globals) {
|
|
260
|
+
return {
|
|
261
|
+
type: REFERENCE_GLOBAL,
|
|
262
|
+
result: globalReference(key, globals),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function paramReference(key, depth, location) {
|
|
270
|
+
const literal = annotate([ops.literal, key], location);
|
|
271
|
+
const params = annotate([ops.params, depth], location);
|
|
272
|
+
return annotate([params, literal], location);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function reference(code, globals, parent, locals) {
|
|
228
276
|
const key = keyFromCode(code);
|
|
229
277
|
const normalized = trailingSlash.remove(key);
|
|
230
278
|
const location = code.location;
|
|
@@ -247,61 +295,43 @@ function reference(code, globals, locals) {
|
|
|
247
295
|
// Explicit external reference
|
|
248
296
|
return {
|
|
249
297
|
type: REFERENCE_EXTERNAL,
|
|
250
|
-
result: externalReference(key,
|
|
298
|
+
result: externalReference(key, parent, location),
|
|
251
299
|
};
|
|
252
300
|
}
|
|
253
301
|
|
|
254
302
|
// See if the whole key is a global or local variable
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
return
|
|
258
|
-
type,
|
|
259
|
-
result: globalReference(key, globals),
|
|
260
|
-
};
|
|
261
|
-
} else if (type === REFERENCE_LOCAL) {
|
|
262
|
-
return {
|
|
263
|
-
type,
|
|
264
|
-
result: localReference(key, locals, location),
|
|
265
|
-
};
|
|
303
|
+
const whole = localOrGlobalReference(key, globals, locals, location);
|
|
304
|
+
if (whole) {
|
|
305
|
+
return whole;
|
|
266
306
|
}
|
|
267
307
|
|
|
268
308
|
// Try key as a compound reference x.y.z
|
|
269
309
|
const compound = compoundReference(key, globals, locals, location);
|
|
270
|
-
if (compound
|
|
310
|
+
if (compound) {
|
|
271
311
|
return compound;
|
|
272
312
|
}
|
|
273
313
|
|
|
274
|
-
//
|
|
314
|
+
// Must be external
|
|
275
315
|
return {
|
|
276
316
|
type: REFERENCE_EXTERNAL,
|
|
277
|
-
result: externalReference(key,
|
|
317
|
+
result: externalReference(key, parent, location),
|
|
278
318
|
};
|
|
279
319
|
}
|
|
280
320
|
|
|
281
|
-
function
|
|
282
|
-
// Check if the key is a global variable
|
|
283
|
-
const normalized = trailingSlash.remove(key);
|
|
284
|
-
if (getLocalReferenceDepth(locals, normalized) >= 0) {
|
|
285
|
-
return REFERENCE_LOCAL;
|
|
286
|
-
} else if (normalized in globals) {
|
|
287
|
-
return REFERENCE_GLOBAL;
|
|
288
|
-
} else {
|
|
289
|
-
return REFERENCE_EXTERNAL;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function resolvePath(code, globals, locals, cache) {
|
|
321
|
+
function resolvePath(code, globals, parent, locals, cache) {
|
|
294
322
|
const args = code.slice(1);
|
|
295
323
|
const [head, ...tail] = args;
|
|
296
324
|
|
|
297
|
-
let { type, result } = reference(head, globals, locals);
|
|
325
|
+
let { type, result } = reference(head, globals, parent, locals);
|
|
298
326
|
|
|
299
327
|
if (tail.length > 0) {
|
|
300
328
|
// If the result is a traversal, we can safely extend it
|
|
301
329
|
const extendResult =
|
|
302
330
|
result instanceof Array &&
|
|
303
331
|
result[0] instanceof Array &&
|
|
304
|
-
(result[0][0] === ops.scope ||
|
|
332
|
+
(result[0][0] === ops.scope ||
|
|
333
|
+
result[0][0] === ops.params ||
|
|
334
|
+
result[0][0] === ops.inherited);
|
|
305
335
|
if (extendResult) {
|
|
306
336
|
result.push(...tail);
|
|
307
337
|
} else {
|
|
@@ -316,15 +346,3 @@ function resolvePath(code, globals, locals, cache) {
|
|
|
316
346
|
|
|
317
347
|
return result;
|
|
318
348
|
}
|
|
319
|
-
|
|
320
|
-
function scopeCall(locals, location) {
|
|
321
|
-
const depth = locals.length;
|
|
322
|
-
/** @type {any[]} */
|
|
323
|
-
const code = [ops.scope];
|
|
324
|
-
if (depth > 0) {
|
|
325
|
-
// Add context for appropriate depth to scope call
|
|
326
|
-
const contextCode = annotate([ops.context, depth], location);
|
|
327
|
-
code.push(contextCode);
|
|
328
|
-
}
|
|
329
|
-
return annotate(code, location);
|
|
330
|
-
}
|
|
@@ -207,9 +207,6 @@ doubleQuoteStringChar
|
|
|
207
207
|
|
|
208
208
|
ellipsis
|
|
209
209
|
= "..."
|
|
210
|
-
/ "…" {
|
|
211
|
-
console.warn("The use of the Unicode ellipsis character for an object spread is deprecated; use `...` (three periods) instead.");
|
|
212
|
-
}
|
|
213
210
|
|
|
214
211
|
equalityExpression
|
|
215
212
|
= head:relationalExpression tail:(__ @equalityOperator __ @relationalExpression)* {
|
|
@@ -719,7 +716,7 @@ shorthandFunction "lambda function"
|
|
|
719
716
|
// Avoid a following equal sign (for an equality)
|
|
720
717
|
= (shellMode / programMode) "=" !"=" __ definition:implicitParenthesesCallExpression {
|
|
721
718
|
if (options.mode === "program") {
|
|
722
|
-
|
|
719
|
+
throw new Error("Parse error: shorthand function syntax isn't allowed in Origami programs. Use arrow syntax instead.");
|
|
723
720
|
}
|
|
724
721
|
const lambdaParameters = annotate(
|
|
725
722
|
[annotate([ops.literal, "_"], location())],
|