@weborigami/language 0.2.1 → 0.2.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 +15 -14
- package/src/compiler/parse.js +63 -56
- package/src/runtime/errors.js +34 -12
- package/test/compiler/parse.test.js +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"yaml": "2.5.1"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@weborigami/async-tree": "0.2.
|
|
16
|
-
"@weborigami/types": "0.2.
|
|
15
|
+
"@weborigami/async-tree": "0.2.2",
|
|
16
|
+
"@weborigami/types": "0.2.2",
|
|
17
17
|
"watcher": "2.3.1"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
@@ -61,7 +61,7 @@ arrayEntries
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
arrayEntry
|
|
64
|
-
=
|
|
64
|
+
= spreadElement
|
|
65
65
|
/ pipelineExpression
|
|
66
66
|
// JavaScript treats a missing value as `undefined`
|
|
67
67
|
/ __ !"]" {
|
|
@@ -113,7 +113,7 @@ callExpression "function call"
|
|
|
113
113
|
closingBrace
|
|
114
114
|
= "}"
|
|
115
115
|
/ .? {
|
|
116
|
-
error(
|
|
116
|
+
error(`An object ended without a closing brace, or contained something that wasn't expected.\nThe top level of an object can only contain definitions ("a: b" or "a = b") or spreads ("...a").`);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
// Required closing bracket
|
|
@@ -147,18 +147,20 @@ comment "comment"
|
|
|
147
147
|
/ singleLineComment
|
|
148
148
|
|
|
149
149
|
conditionalExpression
|
|
150
|
-
= condition:logicalOrExpression __
|
|
151
|
-
"?" __
|
|
152
|
-
":" __
|
|
150
|
+
= condition:logicalOrExpression tail:(__
|
|
151
|
+
"?" __ @pipelineExpression __
|
|
152
|
+
":" __ @pipelineExpression)?
|
|
153
153
|
{
|
|
154
|
+
if (!tail) {
|
|
155
|
+
return condition;
|
|
156
|
+
}
|
|
154
157
|
return annotate([
|
|
155
158
|
ops.conditional,
|
|
156
159
|
downgradeReference(condition),
|
|
157
|
-
[ops.lambda, [], downgradeReference(
|
|
158
|
-
[ops.lambda, [], downgradeReference(
|
|
160
|
+
[ops.lambda, [], downgradeReference(tail[0])],
|
|
161
|
+
[ops.lambda, [], downgradeReference(tail[1])]
|
|
159
162
|
], location());
|
|
160
163
|
}
|
|
161
|
-
/ logicalOrExpression
|
|
162
164
|
|
|
163
165
|
digits
|
|
164
166
|
= @[0-9]+
|
|
@@ -197,10 +199,9 @@ escapedChar "backslash-escaped character"
|
|
|
197
199
|
/ "\\" @.
|
|
198
200
|
|
|
199
201
|
exponentiationExpression
|
|
200
|
-
= left:unaryExpression __ "**" __
|
|
201
|
-
return annotate([ops.exponentiation, left, right], location());
|
|
202
|
+
= left:unaryExpression right:(__ "**" __ @exponentiationExpression)? {
|
|
203
|
+
return right ? annotate([ops.exponentiation, left, right], location()) : left;
|
|
202
204
|
}
|
|
203
|
-
/ unaryExpression
|
|
204
205
|
|
|
205
206
|
// A top-level expression, possibly with leading/trailing whitespace
|
|
206
207
|
expression
|
|
@@ -358,7 +359,7 @@ objectEntries
|
|
|
358
359
|
}
|
|
359
360
|
|
|
360
361
|
objectEntry
|
|
361
|
-
=
|
|
362
|
+
= spreadElement
|
|
362
363
|
/ objectProperty
|
|
363
364
|
/ objectGetter
|
|
364
365
|
/ objectShorthandProperty
|
|
@@ -557,8 +558,8 @@ singleQuoteString "single quote string"
|
|
|
557
558
|
singleQuoteStringChar
|
|
558
559
|
= !("'" / newLine) @textChar
|
|
559
560
|
|
|
560
|
-
|
|
561
|
-
= ellipsis __ value:
|
|
561
|
+
spreadElement
|
|
562
|
+
= ellipsis __ value:pipelineExpression {
|
|
562
563
|
return annotate([ops.spread, value], location());
|
|
563
564
|
}
|
|
564
565
|
|
package/src/compiler/parse.js
CHANGED
|
@@ -202,7 +202,7 @@ function peg$parse(input, options) {
|
|
|
202
202
|
var peg$FAILED = {};
|
|
203
203
|
var peg$source = options.grammarSource;
|
|
204
204
|
|
|
205
|
-
var peg$startRuleFunctions = { __: peg$parse__, additiveExpression: peg$parseadditiveExpression, additiveOperator: peg$parseadditiveOperator, arguments: peg$parsearguments, arrayLiteral: peg$parsearrayLiteral, arrayEntries: peg$parsearrayEntries, arrayEntry: peg$parsearrayEntry, arrowFunction: peg$parsearrowFunction, bitwiseAndExpression: peg$parsebitwiseAndExpression, bitwiseAndOperator: peg$parsebitwiseAndOperator, bitwiseOrExpression: peg$parsebitwiseOrExpression, bitwiseOrOperator: peg$parsebitwiseOrOperator, bitwiseXorExpression: peg$parsebitwiseXorExpression, bitwiseXorOperator: peg$parsebitwiseXorOperator, callExpression: peg$parsecallExpression, closingBrace: peg$parseclosingBrace, closingBracket: peg$parseclosingBracket, closingParenthesis: peg$parseclosingParenthesis, commaExpression: peg$parsecommaExpression, comment: peg$parsecomment, conditionalExpression: peg$parseconditionalExpression, digits: peg$parsedigits, doubleArrow: peg$parsedoubleArrow, doubleQuoteString: peg$parsedoubleQuoteString, doubleQuoteStringChar: peg$parsedoubleQuoteStringChar, ellipsis: peg$parseellipsis, equalityExpression: peg$parseequalityExpression, equalityOperator: peg$parseequalityOperator, escapedChar: peg$parseescapedChar, exponentiationExpression: peg$parseexponentiationExpression, expression: peg$parseexpression, floatLiteral: peg$parsefloatLiteral, group: peg$parsegroup, guillemetString: peg$parseguillemetString, guillemetStringChar: peg$parseguillemetStringChar, homeDirectory: peg$parsehomeDirectory, host: peg$parsehost, identifier: peg$parseidentifier, identifierChar: peg$parseidentifierChar, identifierList: peg$parseidentifierList, implicitParenthesesCallExpression: peg$parseimplicitParenthesesCallExpression, implicitParensthesesArguments: peg$parseimplicitParensthesesArguments, inlineSpace: peg$parseinlineSpace, integerLiteral: peg$parseintegerLiteral, list: peg$parselist, literal: peg$parseliteral, logicalAndExpression: peg$parselogicalAndExpression, logicalOrExpression: peg$parselogicalOrExpression, multiLineComment: peg$parsemultiLineComment, multiplicativeExpression: peg$parsemultiplicativeExpression, multiplicativeOperator: peg$parsemultiplicativeOperator, namespace: peg$parsenamespace, newLine: peg$parsenewLine, numericLiteral: peg$parsenumericLiteral, nullishCoalescingExpression: peg$parsenullishCoalescingExpression, objectLiteral: peg$parseobjectLiteral, objectEntries: peg$parseobjectEntries, objectEntry: peg$parseobjectEntry, objectGetter: peg$parseobjectGetter, objectHiddenKey: peg$parseobjectHiddenKey, objectKey: peg$parseobjectKey, objectProperty: peg$parseobjectProperty, objectShorthandProperty: peg$parseobjectShorthandProperty, objectPublicKey: peg$parseobjectPublicKey, parenthesesArguments: peg$parseparenthesesArguments, path: peg$parsepath, pathArguments: peg$parsepathArguments, pathKey: peg$parsepathKey, pathSegment: peg$parsepathSegment, pathSegmentChar: peg$parsepathSegmentChar, pipelineExpression: peg$parsepipelineExpression, primary: peg$parseprimary, program: peg$parseprogram, protocolExpression: peg$parseprotocolExpression, qualifiedReference: peg$parsequalifiedReference, reference: peg$parsereference, relationalExpression: peg$parserelationalExpression, relationalOperator: peg$parserelationalOperator, rootDirectory: peg$parserootDirectory, scopeReference: peg$parsescopeReference, separator: peg$parseseparator, slashFollows: peg$parseslashFollows, shebang: peg$parseshebang, shiftExpression: peg$parseshiftExpression, shiftOperator: peg$parseshiftOperator, shorthandFunction: peg$parseshorthandFunction, singleArrow: peg$parsesingleArrow, singleLineComment: peg$parsesingleLineComment, singleQuoteString: peg$parsesingleQuoteString, singleQuoteStringChar: peg$parsesingleQuoteStringChar,
|
|
205
|
+
var peg$startRuleFunctions = { __: peg$parse__, additiveExpression: peg$parseadditiveExpression, additiveOperator: peg$parseadditiveOperator, arguments: peg$parsearguments, arrayLiteral: peg$parsearrayLiteral, arrayEntries: peg$parsearrayEntries, arrayEntry: peg$parsearrayEntry, arrowFunction: peg$parsearrowFunction, bitwiseAndExpression: peg$parsebitwiseAndExpression, bitwiseAndOperator: peg$parsebitwiseAndOperator, bitwiseOrExpression: peg$parsebitwiseOrExpression, bitwiseOrOperator: peg$parsebitwiseOrOperator, bitwiseXorExpression: peg$parsebitwiseXorExpression, bitwiseXorOperator: peg$parsebitwiseXorOperator, callExpression: peg$parsecallExpression, closingBrace: peg$parseclosingBrace, closingBracket: peg$parseclosingBracket, closingParenthesis: peg$parseclosingParenthesis, commaExpression: peg$parsecommaExpression, comment: peg$parsecomment, conditionalExpression: peg$parseconditionalExpression, digits: peg$parsedigits, doubleArrow: peg$parsedoubleArrow, doubleQuoteString: peg$parsedoubleQuoteString, doubleQuoteStringChar: peg$parsedoubleQuoteStringChar, ellipsis: peg$parseellipsis, equalityExpression: peg$parseequalityExpression, equalityOperator: peg$parseequalityOperator, escapedChar: peg$parseescapedChar, exponentiationExpression: peg$parseexponentiationExpression, expression: peg$parseexpression, floatLiteral: peg$parsefloatLiteral, group: peg$parsegroup, guillemetString: peg$parseguillemetString, guillemetStringChar: peg$parseguillemetStringChar, homeDirectory: peg$parsehomeDirectory, host: peg$parsehost, identifier: peg$parseidentifier, identifierChar: peg$parseidentifierChar, identifierList: peg$parseidentifierList, implicitParenthesesCallExpression: peg$parseimplicitParenthesesCallExpression, implicitParensthesesArguments: peg$parseimplicitParensthesesArguments, inlineSpace: peg$parseinlineSpace, integerLiteral: peg$parseintegerLiteral, list: peg$parselist, literal: peg$parseliteral, logicalAndExpression: peg$parselogicalAndExpression, logicalOrExpression: peg$parselogicalOrExpression, multiLineComment: peg$parsemultiLineComment, multiplicativeExpression: peg$parsemultiplicativeExpression, multiplicativeOperator: peg$parsemultiplicativeOperator, namespace: peg$parsenamespace, newLine: peg$parsenewLine, numericLiteral: peg$parsenumericLiteral, nullishCoalescingExpression: peg$parsenullishCoalescingExpression, objectLiteral: peg$parseobjectLiteral, objectEntries: peg$parseobjectEntries, objectEntry: peg$parseobjectEntry, objectGetter: peg$parseobjectGetter, objectHiddenKey: peg$parseobjectHiddenKey, objectKey: peg$parseobjectKey, objectProperty: peg$parseobjectProperty, objectShorthandProperty: peg$parseobjectShorthandProperty, objectPublicKey: peg$parseobjectPublicKey, parenthesesArguments: peg$parseparenthesesArguments, path: peg$parsepath, pathArguments: peg$parsepathArguments, pathKey: peg$parsepathKey, pathSegment: peg$parsepathSegment, pathSegmentChar: peg$parsepathSegmentChar, pipelineExpression: peg$parsepipelineExpression, primary: peg$parseprimary, program: peg$parseprogram, protocolExpression: peg$parseprotocolExpression, qualifiedReference: peg$parsequalifiedReference, reference: peg$parsereference, relationalExpression: peg$parserelationalExpression, relationalOperator: peg$parserelationalOperator, rootDirectory: peg$parserootDirectory, scopeReference: peg$parsescopeReference, separator: peg$parseseparator, slashFollows: peg$parseslashFollows, shebang: peg$parseshebang, shiftExpression: peg$parseshiftExpression, shiftOperator: peg$parseshiftOperator, shorthandFunction: peg$parseshorthandFunction, singleArrow: peg$parsesingleArrow, singleLineComment: peg$parsesingleLineComment, singleQuoteString: peg$parsesingleQuoteString, singleQuoteStringChar: peg$parsesingleQuoteStringChar, spreadElement: peg$parsespreadElement, stringLiteral: peg$parsestringLiteral, templateDocument: peg$parsetemplateDocument, templateDocumentChar: peg$parsetemplateDocumentChar, templateDocumentContents: peg$parsetemplateDocumentContents, templateDocumentText: peg$parsetemplateDocumentText, templateLiteral: peg$parsetemplateLiteral, templateLiteralChar: peg$parsetemplateLiteralChar, templateLiteralContents: peg$parsetemplateLiteralContents, templateLiteralText: peg$parsetemplateLiteralText, templateSubstitution: peg$parsetemplateSubstitution, textChar: peg$parsetextChar, unaryExpression: peg$parseunaryExpression, unaryOperator: peg$parseunaryOperator, whitespaceWithNewLine: peg$parsewhitespaceWithNewLine };
|
|
206
206
|
var peg$startRuleFunction = peg$parse__;
|
|
207
207
|
|
|
208
208
|
var peg$c0 = "[";
|
|
@@ -412,7 +412,7 @@ function peg$parse(input, options) {
|
|
|
412
412
|
return annotate(tail.reduce(makeCall, head), location());
|
|
413
413
|
};
|
|
414
414
|
var peg$f11 = function() {
|
|
415
|
-
error(
|
|
415
|
+
error(`An object ended without a closing brace, or contained something that wasn't expected.\nThe top level of an object can only contain definitions ("a: b" or "a = b") or spreads ("...a").`);
|
|
416
416
|
};
|
|
417
417
|
var peg$f12 = function() {
|
|
418
418
|
error("Expected right bracket");
|
|
@@ -425,12 +425,15 @@ function peg$parse(input, options) {
|
|
|
425
425
|
? list[0]
|
|
426
426
|
: annotate([ops.comma, ...list], location());
|
|
427
427
|
};
|
|
428
|
-
var peg$f15 = function(condition,
|
|
428
|
+
var peg$f15 = function(condition, tail) {
|
|
429
|
+
if (!tail) {
|
|
430
|
+
return condition;
|
|
431
|
+
}
|
|
429
432
|
return annotate([
|
|
430
433
|
ops.conditional,
|
|
431
434
|
downgradeReference(condition),
|
|
432
|
-
[ops.lambda, [], downgradeReference(
|
|
433
|
-
[ops.lambda, [], downgradeReference(
|
|
435
|
+
[ops.lambda, [], downgradeReference(tail[0])],
|
|
436
|
+
[ops.lambda, [], downgradeReference(tail[1])]
|
|
434
437
|
], location());
|
|
435
438
|
};
|
|
436
439
|
var peg$f16 = function(chars) {
|
|
@@ -447,7 +450,7 @@ function peg$parse(input, options) {
|
|
|
447
450
|
var peg$f23 = function() { return "\t"; };
|
|
448
451
|
var peg$f24 = function() { return "\v"; };
|
|
449
452
|
var peg$f25 = function(left, right) {
|
|
450
|
-
return annotate([ops.exponentiation, left, right], location());
|
|
453
|
+
return right ? annotate([ops.exponentiation, left, right], location()) : left;
|
|
451
454
|
};
|
|
452
455
|
var peg$f26 = function() {
|
|
453
456
|
return annotate([ops.literal, parseFloat(text())], location());
|
|
@@ -985,7 +988,7 @@ function peg$parse(input, options) {
|
|
|
985
988
|
function peg$parsearrayEntry() {
|
|
986
989
|
var s0, s1, s2, s3;
|
|
987
990
|
|
|
988
|
-
s0 = peg$
|
|
991
|
+
s0 = peg$parsespreadElement();
|
|
989
992
|
if (s0 === peg$FAILED) {
|
|
990
993
|
s0 = peg$parsepipelineExpression();
|
|
991
994
|
if (s0 === peg$FAILED) {
|
|
@@ -1546,60 +1549,62 @@ function peg$parse(input, options) {
|
|
|
1546
1549
|
}
|
|
1547
1550
|
|
|
1548
1551
|
function peg$parseconditionalExpression() {
|
|
1549
|
-
var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;
|
|
1552
|
+
var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
|
|
1550
1553
|
|
|
1551
1554
|
s0 = peg$currPos;
|
|
1552
1555
|
s1 = peg$parselogicalOrExpression();
|
|
1553
1556
|
if (s1 !== peg$FAILED) {
|
|
1554
|
-
s2 = peg$
|
|
1557
|
+
s2 = peg$currPos;
|
|
1558
|
+
s3 = peg$parse__();
|
|
1555
1559
|
if (input.charCodeAt(peg$currPos) === 63) {
|
|
1556
|
-
|
|
1560
|
+
s4 = peg$c9;
|
|
1557
1561
|
peg$currPos++;
|
|
1558
1562
|
} else {
|
|
1559
|
-
|
|
1563
|
+
s4 = peg$FAILED;
|
|
1560
1564
|
if (peg$silentFails === 0) { peg$fail(peg$e15); }
|
|
1561
1565
|
}
|
|
1562
|
-
if (
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
if (
|
|
1566
|
-
|
|
1566
|
+
if (s4 !== peg$FAILED) {
|
|
1567
|
+
s5 = peg$parse__();
|
|
1568
|
+
s6 = peg$parsepipelineExpression();
|
|
1569
|
+
if (s6 !== peg$FAILED) {
|
|
1570
|
+
s7 = peg$parse__();
|
|
1567
1571
|
if (input.charCodeAt(peg$currPos) === 58) {
|
|
1568
|
-
|
|
1572
|
+
s8 = peg$c10;
|
|
1569
1573
|
peg$currPos++;
|
|
1570
1574
|
} else {
|
|
1571
|
-
|
|
1575
|
+
s8 = peg$FAILED;
|
|
1572
1576
|
if (peg$silentFails === 0) { peg$fail(peg$e16); }
|
|
1573
1577
|
}
|
|
1574
|
-
if (
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
if (
|
|
1578
|
-
|
|
1579
|
-
s0 = peg$f15(s1, s5, s9);
|
|
1578
|
+
if (s8 !== peg$FAILED) {
|
|
1579
|
+
s9 = peg$parse__();
|
|
1580
|
+
s10 = peg$parsepipelineExpression();
|
|
1581
|
+
if (s10 !== peg$FAILED) {
|
|
1582
|
+
s2 = [ s6, s10 ];
|
|
1580
1583
|
} else {
|
|
1581
|
-
peg$currPos =
|
|
1582
|
-
|
|
1584
|
+
peg$currPos = s2;
|
|
1585
|
+
s2 = peg$FAILED;
|
|
1583
1586
|
}
|
|
1584
1587
|
} else {
|
|
1585
|
-
peg$currPos =
|
|
1586
|
-
|
|
1588
|
+
peg$currPos = s2;
|
|
1589
|
+
s2 = peg$FAILED;
|
|
1587
1590
|
}
|
|
1588
1591
|
} else {
|
|
1589
|
-
peg$currPos =
|
|
1590
|
-
|
|
1592
|
+
peg$currPos = s2;
|
|
1593
|
+
s2 = peg$FAILED;
|
|
1591
1594
|
}
|
|
1592
1595
|
} else {
|
|
1593
|
-
peg$currPos =
|
|
1594
|
-
|
|
1596
|
+
peg$currPos = s2;
|
|
1597
|
+
s2 = peg$FAILED;
|
|
1598
|
+
}
|
|
1599
|
+
if (s2 === peg$FAILED) {
|
|
1600
|
+
s2 = null;
|
|
1595
1601
|
}
|
|
1602
|
+
peg$savedPos = s0;
|
|
1603
|
+
s0 = peg$f15(s1, s2);
|
|
1596
1604
|
} else {
|
|
1597
1605
|
peg$currPos = s0;
|
|
1598
1606
|
s0 = peg$FAILED;
|
|
1599
1607
|
}
|
|
1600
|
-
if (s0 === peg$FAILED) {
|
|
1601
|
-
s0 = peg$parselogicalOrExpression();
|
|
1602
|
-
}
|
|
1603
1608
|
|
|
1604
1609
|
return s0;
|
|
1605
1610
|
}
|
|
@@ -2009,40 +2014,42 @@ function peg$parse(input, options) {
|
|
|
2009
2014
|
}
|
|
2010
2015
|
|
|
2011
2016
|
function peg$parseexponentiationExpression() {
|
|
2012
|
-
var s0, s1, s2, s3, s4, s5;
|
|
2017
|
+
var s0, s1, s2, s3, s4, s5, s6;
|
|
2013
2018
|
|
|
2014
2019
|
s0 = peg$currPos;
|
|
2015
2020
|
s1 = peg$parseunaryExpression();
|
|
2016
2021
|
if (s1 !== peg$FAILED) {
|
|
2017
|
-
s2 = peg$
|
|
2022
|
+
s2 = peg$currPos;
|
|
2023
|
+
s3 = peg$parse__();
|
|
2018
2024
|
if (input.substr(peg$currPos, 2) === peg$c28) {
|
|
2019
|
-
|
|
2025
|
+
s4 = peg$c28;
|
|
2020
2026
|
peg$currPos += 2;
|
|
2021
2027
|
} else {
|
|
2022
|
-
|
|
2028
|
+
s4 = peg$FAILED;
|
|
2023
2029
|
if (peg$silentFails === 0) { peg$fail(peg$e37); }
|
|
2024
2030
|
}
|
|
2025
|
-
if (
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
if (
|
|
2029
|
-
|
|
2030
|
-
s0 = peg$f25(s1, s5);
|
|
2031
|
+
if (s4 !== peg$FAILED) {
|
|
2032
|
+
s5 = peg$parse__();
|
|
2033
|
+
s6 = peg$parseexponentiationExpression();
|
|
2034
|
+
if (s6 !== peg$FAILED) {
|
|
2035
|
+
s2 = s6;
|
|
2031
2036
|
} else {
|
|
2032
|
-
peg$currPos =
|
|
2033
|
-
|
|
2037
|
+
peg$currPos = s2;
|
|
2038
|
+
s2 = peg$FAILED;
|
|
2034
2039
|
}
|
|
2035
2040
|
} else {
|
|
2036
|
-
peg$currPos =
|
|
2037
|
-
|
|
2041
|
+
peg$currPos = s2;
|
|
2042
|
+
s2 = peg$FAILED;
|
|
2043
|
+
}
|
|
2044
|
+
if (s2 === peg$FAILED) {
|
|
2045
|
+
s2 = null;
|
|
2038
2046
|
}
|
|
2047
|
+
peg$savedPos = s0;
|
|
2048
|
+
s0 = peg$f25(s1, s2);
|
|
2039
2049
|
} else {
|
|
2040
2050
|
peg$currPos = s0;
|
|
2041
2051
|
s0 = peg$FAILED;
|
|
2042
2052
|
}
|
|
2043
|
-
if (s0 === peg$FAILED) {
|
|
2044
|
-
s0 = peg$parseunaryExpression();
|
|
2045
|
-
}
|
|
2046
2053
|
|
|
2047
2054
|
return s0;
|
|
2048
2055
|
}
|
|
@@ -3173,7 +3180,7 @@ function peg$parse(input, options) {
|
|
|
3173
3180
|
function peg$parseobjectEntry() {
|
|
3174
3181
|
var s0;
|
|
3175
3182
|
|
|
3176
|
-
s0 = peg$
|
|
3183
|
+
s0 = peg$parsespreadElement();
|
|
3177
3184
|
if (s0 === peg$FAILED) {
|
|
3178
3185
|
s0 = peg$parseobjectProperty();
|
|
3179
3186
|
if (s0 === peg$FAILED) {
|
|
@@ -4307,14 +4314,14 @@ function peg$parse(input, options) {
|
|
|
4307
4314
|
return s0;
|
|
4308
4315
|
}
|
|
4309
4316
|
|
|
4310
|
-
function peg$
|
|
4317
|
+
function peg$parsespreadElement() {
|
|
4311
4318
|
var s0, s1, s2, s3;
|
|
4312
4319
|
|
|
4313
4320
|
s0 = peg$currPos;
|
|
4314
4321
|
s1 = peg$parseellipsis();
|
|
4315
4322
|
if (s1 !== peg$FAILED) {
|
|
4316
4323
|
s2 = peg$parse__();
|
|
4317
|
-
s3 = peg$
|
|
4324
|
+
s3 = peg$parsepipelineExpression();
|
|
4318
4325
|
if (s3 !== peg$FAILED) {
|
|
4319
4326
|
peg$savedPos = s0;
|
|
4320
4327
|
s0 = peg$f68(s3);
|
|
@@ -4845,7 +4852,7 @@ const peg$allowedStartRules = [
|
|
|
4845
4852
|
"singleLineComment",
|
|
4846
4853
|
"singleQuoteString",
|
|
4847
4854
|
"singleQuoteStringChar",
|
|
4848
|
-
"
|
|
4855
|
+
"spreadElement",
|
|
4849
4856
|
"stringLiteral",
|
|
4850
4857
|
"templateDocument",
|
|
4851
4858
|
"templateDocumentChar",
|
package/src/runtime/errors.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// Text we look for in an error stack to guess whether a given line represents a
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
scope as scopeFn,
|
|
5
|
+
trailingSlash,
|
|
6
|
+
TraverseError,
|
|
7
|
+
} from "@weborigami/async-tree";
|
|
4
8
|
import codeFragment from "./codeFragment.js";
|
|
5
9
|
import { typos } from "./typos.js";
|
|
6
10
|
|
|
@@ -13,19 +17,24 @@ const origamiSourceSignals = [
|
|
|
13
17
|
];
|
|
14
18
|
|
|
15
19
|
export async function builtinReferenceError(tree, builtins, key) {
|
|
16
|
-
const messages = [
|
|
17
|
-
`"${key}" is being called as if it were a builtin function, but it's not.`,
|
|
18
|
-
];
|
|
19
20
|
// See if the key is in scope (but not as a builtin)
|
|
20
21
|
const scope = scopeFn(tree);
|
|
21
22
|
const value = await scope.get(key);
|
|
23
|
+
let message;
|
|
22
24
|
if (value === undefined) {
|
|
25
|
+
const messages = [
|
|
26
|
+
`"${key}" is being called as if it were a builtin function, but it's not.`,
|
|
27
|
+
];
|
|
23
28
|
const typos = await formatScopeTypos(builtins, key);
|
|
24
29
|
messages.push(typos);
|
|
30
|
+
message = messages.join(" ");
|
|
25
31
|
} else {
|
|
26
|
-
messages
|
|
32
|
+
const messages = [
|
|
33
|
+
`To call a function like "${key}" that's not a builtin, include a slash: ${key}/( )`,
|
|
34
|
+
`Details: https://weborigami.org/language/syntax.html#shorthand-for-builtin-functions`,
|
|
35
|
+
];
|
|
36
|
+
message = messages.join("\n");
|
|
27
37
|
}
|
|
28
|
-
const message = messages.join(" ");
|
|
29
38
|
return new ReferenceError(message);
|
|
30
39
|
}
|
|
31
40
|
|
|
@@ -36,37 +45,50 @@ export async function builtinReferenceError(tree, builtins, key) {
|
|
|
36
45
|
*/
|
|
37
46
|
export function formatError(error) {
|
|
38
47
|
let message;
|
|
48
|
+
|
|
49
|
+
let location = /** @type {any} */ (error).location;
|
|
50
|
+
const fragment = location ? codeFragment(location) : null;
|
|
51
|
+
let fragmentInMessage = false;
|
|
52
|
+
|
|
39
53
|
if (error.stack) {
|
|
40
54
|
// Display the stack only until we reach the Origami source code.
|
|
41
55
|
message = "";
|
|
42
56
|
let lines = error.stack.split("\n");
|
|
43
57
|
for (let i = 0; i < lines.length; i++) {
|
|
44
|
-
|
|
58
|
+
let line = lines[i];
|
|
45
59
|
if (maybeOrigamiSourceCode(line)) {
|
|
46
60
|
break;
|
|
47
61
|
}
|
|
62
|
+
if (
|
|
63
|
+
error instanceof TraverseError &&
|
|
64
|
+
error.message === "A null or undefined value can't be traversed"
|
|
65
|
+
) {
|
|
66
|
+
// Provide more meaningful message for TraverseError
|
|
67
|
+
line = `TraverseError: This part of the path is null or undefined: ${fragment}`;
|
|
68
|
+
fragmentInMessage = true;
|
|
69
|
+
}
|
|
48
70
|
if (message) {
|
|
49
71
|
message += "\n";
|
|
50
72
|
}
|
|
51
|
-
message +=
|
|
73
|
+
message += line;
|
|
52
74
|
}
|
|
53
75
|
} else {
|
|
54
76
|
message = error.toString();
|
|
55
77
|
}
|
|
56
78
|
|
|
57
79
|
// Add location
|
|
58
|
-
let location = /** @type {any} */ (error).location;
|
|
59
80
|
if (location) {
|
|
60
|
-
const fragment = codeFragment(location);
|
|
61
81
|
let { source, start } = location;
|
|
62
|
-
|
|
63
|
-
|
|
82
|
+
if (!fragmentInMessage) {
|
|
83
|
+
message += `\nevaluating: ${fragment}`;
|
|
84
|
+
}
|
|
64
85
|
if (typeof source === "object" && source.url) {
|
|
65
86
|
message += `\n at ${source.url.href}:${start.line}:${start.column}`;
|
|
66
87
|
} else if (source.text.includes("\n")) {
|
|
67
88
|
message += `\n at line ${start.line}, column ${start.column}`;
|
|
68
89
|
}
|
|
69
90
|
}
|
|
91
|
+
|
|
70
92
|
return message;
|
|
71
93
|
}
|
|
72
94
|
|
|
@@ -687,7 +687,7 @@ describe("Origami parser", () => {
|
|
|
687
687
|
assertParse("objectLiteral", "{ a: 1, ...b }", [
|
|
688
688
|
ops.merge,
|
|
689
689
|
[ops.object, ["a", [ops.literal, 1]]],
|
|
690
|
-
[
|
|
690
|
+
[ops.scope, "b"],
|
|
691
691
|
]);
|
|
692
692
|
assertParse("objectLiteral", "{ (a): 1 }", [
|
|
693
693
|
ops.object,
|
|
@@ -946,9 +946,9 @@ describe("Origami parser", () => {
|
|
|
946
946
|
assertParse("singleLineComment", "// Hello, world!", null, false);
|
|
947
947
|
});
|
|
948
948
|
|
|
949
|
-
test("
|
|
950
|
-
assertParse("
|
|
951
|
-
assertParse("
|
|
949
|
+
test("spreadElement", () => {
|
|
950
|
+
assertParse("spreadElement", "...a", [ops.spread, [ops.scope, "a"]]);
|
|
951
|
+
assertParse("spreadElement", "…a", [ops.spread, [ops.scope, "a"]]);
|
|
952
952
|
});
|
|
953
953
|
|
|
954
954
|
test("stringLiteral", () => {
|