@weborigami/language 0.0.52 → 0.0.53

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/language",
3
- "version": "0.0.52",
3
+ "version": "0.0.53",
4
4
  "description": "Web Origami expression language compiler and runtime",
5
5
  "type": "module",
6
6
  "main": "./main.js",
@@ -11,8 +11,8 @@
11
11
  "typescript": "5.4.5"
12
12
  },
13
13
  "dependencies": {
14
- "@weborigami/async-tree": "0.0.52",
15
- "@weborigami/types": "0.0.52",
14
+ "@weborigami/async-tree": "0.0.53",
15
+ "@weborigami/types": "0.0.53",
16
16
  "watcher": "2.3.1"
17
17
  },
18
18
  "scripts": {
@@ -7,7 +7,7 @@
7
7
  //
8
8
 
9
9
  import * as ops from "../runtime/ops.js";
10
- import { makeFunctionCall, makeObject, makePipeline, makeTemplate } from "./parserHelpers.js";
10
+ import { makeArray, makeFunctionCall, makeObject, makePipeline, makeTemplate } from "./parserHelpers.js";
11
11
 
12
12
  // If a parse result is an object that will be evaluated at runtime, attach the
13
13
  // location of the source code that produced it for debugging and error messages.
@@ -39,10 +39,18 @@ args "function arguments"
39
39
  }
40
40
 
41
41
  array "array"
42
- = "[" __ list:list? __ closingBracket {
43
- return annotate([ops.array, ...(list ?? [])], location());
42
+ = "[" __ entries:arrayEntries? __ closingBracket {
43
+ return annotate(makeArray(entries ?? []), location());
44
44
  }
45
45
 
46
+ // A separated list of array entries
47
+ arrayEntries
48
+ = @arrayEntry|1.., separator| separator?
49
+
50
+ arrayEntry
51
+ = spread
52
+ / expr
53
+
46
54
  // Something that can be called. This is more restrictive than the `expr`
47
55
  // parser; it doesn't accept regular function calls.
48
56
  callTarget "function call"
@@ -12,7 +12,7 @@
12
12
  //
13
13
 
14
14
  import * as ops from "../runtime/ops.js";
15
- import { makeFunctionCall, makeObject, makePipeline, makeTemplate } from "./parserHelpers.js";
15
+ import { makeArray, makeFunctionCall, makeObject, makePipeline, makeTemplate } from "./parserHelpers.js";
16
16
 
17
17
  // If a parse result is an object that will be evaluated at runtime, attach the
18
18
  // location of the source code that produced it for debugging and error messages.
@@ -193,7 +193,7 @@ function peg$parse(input, options) {
193
193
  var peg$FAILED = {};
194
194
  var peg$source = options.grammarSource;
195
195
 
196
- var peg$startRuleFunctions = { __: peg$parse__, absoluteFilePath: peg$parseabsoluteFilePath, args: peg$parseargs, array: peg$parsearray, callTarget: peg$parsecallTarget, closingBrace: peg$parseclosingBrace, closingBracket: peg$parseclosingBracket, closingParen: peg$parseclosingParen, comment: peg$parsecomment, digits: peg$parsedigits, doubleArrow: peg$parsedoubleArrow, doubleQuoteString: peg$parsedoubleQuoteString, doubleQuoteStringChar: peg$parsedoubleQuoteStringChar, ellipsis: peg$parseellipsis, escapedChar: peg$parseescapedChar, expr: peg$parseexpr, expression: peg$parseexpression, float: peg$parsefloat, functionComposition: peg$parsefunctionComposition, group: peg$parsegroup, host: peg$parsehost, identifier: peg$parseidentifier, identifierChar: peg$parseidentifierChar, identifierList: peg$parseidentifierList, implicitParensArgs: peg$parseimplicitParensArgs, inlineSpace: peg$parseinlineSpace, integer: peg$parseinteger, lambda: peg$parselambda, leadingSlashPath: peg$parseleadingSlashPath, list: peg$parselist, multiLineComment: peg$parsemultiLineComment, newLine: peg$parsenewLine, number: peg$parsenumber, object: peg$parseobject, objectEntries: peg$parseobjectEntries, objectEntry: peg$parseobjectEntry, objectProperty: peg$parseobjectProperty, parameterizedLambda: peg$parseparameterizedLambda, parensArgs: peg$parseparensArgs, pipeline: peg$parsepipeline, path: peg$parsepath, pathKey: peg$parsepathKey, protocolCall: peg$parseprotocolCall, protocol: peg$parseprotocol, reservedProtocol: peg$parsereservedProtocol, scopeReference: peg$parsescopeReference, separator: peg$parseseparator, shebang: peg$parseshebang, sign: peg$parsesign, singleArrow: peg$parsesingleArrow, singleLineComment: peg$parsesingleLineComment, singleQuoteString: peg$parsesingleQuoteString, singleQuoteStringChar: peg$parsesingleQuoteStringChar, spread: peg$parsespread, step: peg$parsestep, start: peg$parsestart, string: peg$parsestring, 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, tree: peg$parsetree, treeAssignment: peg$parsetreeAssignment, treeEntries: peg$parsetreeEntries, treeEntry: peg$parsetreeEntry, whitespaceWithNewLine: peg$parsewhitespaceWithNewLine };
196
+ var peg$startRuleFunctions = { __: peg$parse__, absoluteFilePath: peg$parseabsoluteFilePath, args: peg$parseargs, array: peg$parsearray, arrayEntries: peg$parsearrayEntries, arrayEntry: peg$parsearrayEntry, callTarget: peg$parsecallTarget, closingBrace: peg$parseclosingBrace, closingBracket: peg$parseclosingBracket, closingParen: peg$parseclosingParen, comment: peg$parsecomment, digits: peg$parsedigits, doubleArrow: peg$parsedoubleArrow, doubleQuoteString: peg$parsedoubleQuoteString, doubleQuoteStringChar: peg$parsedoubleQuoteStringChar, ellipsis: peg$parseellipsis, escapedChar: peg$parseescapedChar, expr: peg$parseexpr, expression: peg$parseexpression, float: peg$parsefloat, functionComposition: peg$parsefunctionComposition, group: peg$parsegroup, host: peg$parsehost, identifier: peg$parseidentifier, identifierChar: peg$parseidentifierChar, identifierList: peg$parseidentifierList, implicitParensArgs: peg$parseimplicitParensArgs, inlineSpace: peg$parseinlineSpace, integer: peg$parseinteger, lambda: peg$parselambda, leadingSlashPath: peg$parseleadingSlashPath, list: peg$parselist, multiLineComment: peg$parsemultiLineComment, newLine: peg$parsenewLine, number: peg$parsenumber, object: peg$parseobject, objectEntries: peg$parseobjectEntries, objectEntry: peg$parseobjectEntry, objectProperty: peg$parseobjectProperty, parameterizedLambda: peg$parseparameterizedLambda, parensArgs: peg$parseparensArgs, pipeline: peg$parsepipeline, path: peg$parsepath, pathKey: peg$parsepathKey, protocolCall: peg$parseprotocolCall, protocol: peg$parseprotocol, reservedProtocol: peg$parsereservedProtocol, scopeReference: peg$parsescopeReference, separator: peg$parseseparator, shebang: peg$parseshebang, sign: peg$parsesign, singleArrow: peg$parsesingleArrow, singleLineComment: peg$parsesingleLineComment, singleQuoteString: peg$parsesingleQuoteString, singleQuoteStringChar: peg$parsesingleQuoteStringChar, spread: peg$parsespread, step: peg$parsestep, start: peg$parsestart, string: peg$parsestring, 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, tree: peg$parsetree, treeAssignment: peg$parsetreeAssignment, treeEntries: peg$parsetreeEntries, treeEntry: peg$parsetreeEntry, whitespaceWithNewLine: peg$parsewhitespaceWithNewLine };
197
197
  var peg$startRuleFunction = peg$parse__;
198
198
 
199
199
  var peg$c0 = "//";
@@ -329,8 +329,8 @@ function peg$parse(input, options) {
329
329
  var peg$f2 = function(path) {
330
330
  return annotate([ops.traverse, ...path], location());
331
331
  };
332
- var peg$f3 = function(list) {
333
- return annotate([ops.array, ...(list ?? [])], location());
332
+ var peg$f3 = function(entries) {
333
+ return annotate(makeArray(entries ?? []), location());
334
334
  };
335
335
  var peg$f4 = function() {
336
336
  error("Expected right curly brace");
@@ -682,7 +682,7 @@ function peg$parse(input, options) {
682
682
  }
683
683
  if (s1 !== peg$FAILED) {
684
684
  s2 = peg$parse__();
685
- s3 = peg$parselist();
685
+ s3 = peg$parsearrayEntries();
686
686
  if (s3 === peg$FAILED) {
687
687
  s3 = null;
688
688
  }
@@ -708,6 +708,60 @@ function peg$parse(input, options) {
708
708
  return s0;
709
709
  }
710
710
 
711
+ function peg$parsearrayEntries() {
712
+ var s0, s1, s2, s3, s4;
713
+
714
+ s0 = peg$currPos;
715
+ s1 = peg$currPos;
716
+ s2 = [];
717
+ s3 = peg$parsearrayEntry();
718
+ while (s3 !== peg$FAILED) {
719
+ s2.push(s3);
720
+ s3 = peg$currPos;
721
+ s4 = peg$parseseparator();
722
+ if (s4 !== peg$FAILED) {
723
+ s4 = peg$parsearrayEntry();
724
+ if (s4 === peg$FAILED) {
725
+ peg$currPos = s3;
726
+ s3 = peg$FAILED;
727
+ } else {
728
+ s3 = s4;
729
+ }
730
+ } else {
731
+ s3 = s4;
732
+ }
733
+ }
734
+ if (s2.length < 1) {
735
+ peg$currPos = s1;
736
+ s1 = peg$FAILED;
737
+ } else {
738
+ s1 = s2;
739
+ }
740
+ if (s1 !== peg$FAILED) {
741
+ s2 = peg$parseseparator();
742
+ if (s2 === peg$FAILED) {
743
+ s2 = null;
744
+ }
745
+ s0 = s1;
746
+ } else {
747
+ peg$currPos = s0;
748
+ s0 = peg$FAILED;
749
+ }
750
+
751
+ return s0;
752
+ }
753
+
754
+ function peg$parsearrayEntry() {
755
+ var s0;
756
+
757
+ s0 = peg$parsespread();
758
+ if (s0 === peg$FAILED) {
759
+ s0 = peg$parsepipeline();
760
+ }
761
+
762
+ return s0;
763
+ }
764
+
711
765
  function peg$parsecallTarget() {
712
766
  var s0, s1;
713
767
 
@@ -3146,6 +3200,8 @@ const peg$allowedStartRules = [
3146
3200
  "absoluteFilePath",
3147
3201
  "args",
3148
3202
  "array",
3203
+ "arrayEntries",
3204
+ "arrayEntry",
3149
3205
  "callTarget",
3150
3206
  "closingBrace",
3151
3207
  "closingBracket",
@@ -2,6 +2,38 @@ import * as ops from "../runtime/ops.js";
2
2
 
3
3
  // Parser helpers
4
4
 
5
+ export function makeArray(entries) {
6
+ let currentEntries = [];
7
+ const spreads = [];
8
+
9
+ for (const value of entries) {
10
+ if (Array.isArray(value) && value[0] === ops.spread) {
11
+ if (currentEntries.length > 0) {
12
+ spreads.push([ops.array, ...currentEntries]);
13
+ currentEntries = [];
14
+ }
15
+ spreads.push(...value.slice(1));
16
+ } else {
17
+ currentEntries.push(value);
18
+ }
19
+ }
20
+
21
+ // Finish any current entries.
22
+ if (currentEntries.length > 0) {
23
+ spreads.push([ops.array, ...currentEntries]);
24
+ currentEntries = [];
25
+ }
26
+
27
+ if (spreads.length > 1) {
28
+ return [ops.merge, ...spreads];
29
+ }
30
+ if (spreads.length === 1) {
31
+ return spreads[0];
32
+ } else {
33
+ return [ops.array];
34
+ }
35
+ }
36
+
5
37
  export function makeFunctionCall(target, chain) {
6
38
  let value = target;
7
39
  // The chain is an array of arguments (which are themselves arrays). We
@@ -33,6 +33,11 @@ export default async function mergeTrees(...trees) {
33
33
  return mergeObjects(...unpacked);
34
34
  }
35
35
 
36
+ // If all trees are arrays, return an array.
37
+ if (unpacked.every((tree) => Array.isArray(tree))) {
38
+ return unpacked.flat();
39
+ }
40
+
36
41
  // If a tree can take a scope, give it one that includes the other trees and
37
42
  // the current scope.
38
43
  const scopedTrees = unpacked.map((tree) => {
@@ -17,6 +17,11 @@ describe("Origami parser", () => {
17
17
  assertParse("array", "[]", [ops.array]);
18
18
  assertParse("array", "[1, 2, 3]", [ops.array, 1, 2, 3]);
19
19
  assertParse("array", "[ 1 , 2 , 3 ]", [ops.array, 1, 2, 3]);
20
+ assertParse("array", "[ 1, ...[2, 3]]", [
21
+ ops.merge,
22
+ [ops.array, 1],
23
+ [ops.array, 2, 3],
24
+ ]);
20
25
  });
21
26
 
22
27
  test("treeAssignment", () => {
@@ -66,4 +66,9 @@ describe("mergeTrees", () => {
66
66
  d: 4,
67
67
  });
68
68
  });
69
+
70
+ test("if all arguments are arrays, result is an array", async () => {
71
+ const result = await mergeTrees.call(null, [1, 2], [3, 4]);
72
+ assert.deepEqual(result, [1, 2, 3, 4]);
73
+ });
69
74
  });