@weborigami/language 0.0.64 → 0.0.65-beta.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/index.ts +20 -9
- package/package.json +5 -5
- package/src/compiler/compile.js +2 -2
- package/src/compiler/origami.pegjs +73 -40
- package/src/compiler/parse.d.ts +2 -2
- package/src/compiler/parse.js +566 -390
- package/src/compiler/parserHelpers.js +42 -4
- package/src/runtime/evaluate.js +1 -1
- package/src/runtime/expressionFunction.js +6 -5
- package/test/compiler/parse.test.js +20 -4
|
@@ -2,6 +2,17 @@ import * as ops from "../runtime/ops.js";
|
|
|
2
2
|
|
|
3
3
|
// Parser helpers
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* If a parse result is an object that will be evaluated at runtime, attach the
|
|
7
|
+
* location of the source code that produced it for debugging and error messages.
|
|
8
|
+
*/
|
|
9
|
+
export function annotate(parseResult, location) {
|
|
10
|
+
if (typeof parseResult === "object" && parseResult !== null) {
|
|
11
|
+
parseResult.location = location;
|
|
12
|
+
}
|
|
13
|
+
return parseResult;
|
|
14
|
+
}
|
|
15
|
+
|
|
5
16
|
export function makeArray(entries) {
|
|
6
17
|
let currentEntries = [];
|
|
7
18
|
const spreads = [];
|
|
@@ -34,18 +45,45 @@ export function makeArray(entries) {
|
|
|
34
45
|
}
|
|
35
46
|
}
|
|
36
47
|
|
|
48
|
+
/**
|
|
49
|
+
* @typedef {import("../../index.ts").Code} Code
|
|
50
|
+
*
|
|
51
|
+
* @param {Code} target
|
|
52
|
+
* @param {Code[]} chain
|
|
53
|
+
* @returns
|
|
54
|
+
*/
|
|
37
55
|
export function makeFunctionCall(target, chain) {
|
|
38
56
|
let value = target;
|
|
57
|
+
const source = target.location.source;
|
|
39
58
|
// The chain is an array of arguments (which are themselves arrays). We
|
|
40
59
|
// successively apply the top-level elements of that chain to build up the
|
|
41
60
|
// function composition.
|
|
61
|
+
let start = target.location.start;
|
|
62
|
+
let end = target.location.end;
|
|
42
63
|
for (const args of chain) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
64
|
+
/** @type {Code} */
|
|
65
|
+
let fnCall;
|
|
66
|
+
|
|
67
|
+
// @ts-ignore
|
|
68
|
+
fnCall =
|
|
69
|
+
args[0] === ops.traverse
|
|
70
|
+
? [ops.traverse, value, ...args.slice(1)]
|
|
71
|
+
: [value, ...args];
|
|
72
|
+
|
|
73
|
+
// Create a location spanning the newly-constructed function call.
|
|
74
|
+
if (args instanceof Array) {
|
|
75
|
+
if (args.location) {
|
|
76
|
+
end = args.location.end;
|
|
77
|
+
} else {
|
|
78
|
+
throw "Internal parser error: no location for function call argument";
|
|
79
|
+
}
|
|
47
80
|
}
|
|
81
|
+
|
|
82
|
+
fnCall.location = { start, source, end };
|
|
83
|
+
|
|
84
|
+
value = fnCall;
|
|
48
85
|
}
|
|
86
|
+
|
|
49
87
|
return value;
|
|
50
88
|
}
|
|
51
89
|
|
package/src/runtime/evaluate.js
CHANGED
|
@@ -5,19 +5,20 @@ import { evaluate } from "./internal.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* Given parsed Origami code, return a function that executes that code.
|
|
7
7
|
*
|
|
8
|
-
* @param {import("../../index.js").
|
|
8
|
+
* @param {import("../../index.js").ParseResult} parsed - parsed Origami expression
|
|
9
9
|
* @param {string} [name] - optional name of the function
|
|
10
10
|
*/
|
|
11
|
-
export function createExpressionFunction(
|
|
11
|
+
export function createExpressionFunction(parsed, name) {
|
|
12
12
|
/** @this {AsyncTree|null} */
|
|
13
13
|
async function fn() {
|
|
14
|
-
return evaluate.call(this,
|
|
14
|
+
return evaluate.call(this, parsed);
|
|
15
15
|
}
|
|
16
16
|
if (name) {
|
|
17
17
|
Object.defineProperty(fn, "name", { value: name });
|
|
18
18
|
}
|
|
19
|
-
fn.code =
|
|
20
|
-
fn.toString = () =>
|
|
19
|
+
fn.code = parsed;
|
|
20
|
+
fn.toString = () =>
|
|
21
|
+
parsed instanceof Array ? parsed.location.source.text : parsed;
|
|
21
22
|
return fn;
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -112,7 +112,7 @@ describe("Origami parser", () => {
|
|
|
112
112
|
// Single slash at start of something = absolute file path
|
|
113
113
|
assertParse("expression", "/path", [[ops.filesRoot], "path"]);
|
|
114
114
|
// Consecutive slashes at start of something = comment
|
|
115
|
-
assertParse("expression", "path //comment", [ops.scope, "path"]);
|
|
115
|
+
assertParse("expression", "path //comment", [ops.scope, "path"], false);
|
|
116
116
|
});
|
|
117
117
|
|
|
118
118
|
test("functionComposition", () => {
|
|
@@ -450,6 +450,7 @@ describe("Origami parser", () => {
|
|
|
450
450
|
assertParse("string", `"foo\\"s bar"`, `foo"s bar`);
|
|
451
451
|
assertParse("string", `'bar\\'s baz'`, `bar's baz`);
|
|
452
452
|
assertParse("string", `«string»`, "string");
|
|
453
|
+
assertParse("string", `"\\0\\b\\f\\n\\r\\t\\v"`, "\0\b\f\n\r\t\v");
|
|
453
454
|
});
|
|
454
455
|
|
|
455
456
|
test("templateDocument", () => {
|
|
@@ -519,9 +520,24 @@ describe("Origami parser", () => {
|
|
|
519
520
|
});
|
|
520
521
|
});
|
|
521
522
|
|
|
522
|
-
function assertParse(startRule, source, expected) {
|
|
523
|
-
|
|
524
|
-
|
|
523
|
+
function assertParse(startRule, source, expected, checkLocation = true) {
|
|
524
|
+
const parseResult = parse(source, {
|
|
525
|
+
grammarSource: { text: source },
|
|
526
|
+
startRule,
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
// Verify that the parser returned a `location` property and that it spans the
|
|
530
|
+
// entire source. We skip this check in cases where the source starts or ends
|
|
531
|
+
// with a comment; the parser will strip those.
|
|
532
|
+
if (checkLocation && parseResult instanceof Array) {
|
|
533
|
+
assert(parseResult.location);
|
|
534
|
+
const resultSource = parseResult.location.source.text.slice(
|
|
535
|
+
parseResult.location.start.offset,
|
|
536
|
+
parseResult.location.end.offset
|
|
537
|
+
);
|
|
538
|
+
assert.equal(resultSource, source.trim());
|
|
539
|
+
}
|
|
540
|
+
|
|
525
541
|
const actual = stripLocations(parseResult);
|
|
526
542
|
assert.deepEqual(actual, expected);
|
|
527
543
|
}
|