@graffiticode/parser 1.4.2 → 1.4.3

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.
@@ -8,7 +8,8 @@
8
8
  "Bash(grep:*)",
9
9
  "Bash(npm install:*)",
10
10
  "Bash(NODE_OPTIONS=--experimental-vm-modules node -e \"\nimport { parser } from './src/parser.js';\nimport { unparse } from './src/unparse.js';\nimport { lexicon as basisLexicon } from '@graffiticode/basis';\n\nconst src = 'case x of 1: \\\\\"one\\\\\" 2: \\\\\"two\\\\\" end..';\nconsole.log\\('Input:', src\\);\nconst ast = await parser.parse\\(0, src, basisLexicon\\);\nconsole.log\\('AST:', JSON.stringify\\(ast, null, 2\\)\\);\nconst result = unparse\\(ast, basisLexicon\\);\nconsole.log\\('Unparsed:', result\\);\n\")",
11
- "Bash(NODE_OPTIONS=--experimental-vm-modules node -e \"\nimport { parser } from './src/parser.js';\nimport { unparse } from './src/unparse.js';\nimport { lexicon as basisLexicon } from '@graffiticode/basis';\n\n// Test nested case-of\nconst src1 = 'case x of 1: case y of 3: \\\\\"a\\\\\" 4: \\\\\"b\\\\\" end 2: \\\\\"two\\\\\" end..';\nconsole.log\\('Input:', src1\\);\ntry {\n const ast1 = await parser.parse\\(0, src1, basisLexicon\\);\n console.log\\('Unparsed:', unparse\\(ast1, basisLexicon\\)\\);\n} catch\\(e\\) { console.log\\('Error:', e.message\\); }\n\nconsole.log\\('---'\\);\n\n// Test with expression as case target\nconst src2 = 'case add 1 2 of 3: \\\\\"yes\\\\\" 4: \\\\\"no\\\\\" end..';\nconsole.log\\('Input:', src2\\);\ntry {\n const ast2 = await parser.parse\\(0, src2, basisLexicon\\);\n console.log\\('AST:', JSON.stringify\\(ast2, null, 2\\)\\);\n console.log\\('Unparsed:', unparse\\(ast2, basisLexicon\\)\\);\n} catch\\(e\\) { console.log\\('Error:', e.message\\); }\n\nconsole.log\\('---'\\);\n\n// Test with identifier patterns\nconst src3 = 'case x of y: y end..';\nconsole.log\\('Input:', src3\\);\ntry {\n const ast3 = await parser.parse\\(0, src3, basisLexicon\\);\n console.log\\('AST:', JSON.stringify\\(ast3, null, 2\\)\\);\n console.log\\('Unparsed:', unparse\\(ast3, basisLexicon\\)\\);\n} catch\\(e\\) { console.log\\('Error:', e.message\\); }\n\nconsole.log\\('---'\\);\n\n// Test case-of inside a let or other expression\nconst src4 = 'let x = 5 in case x of 5: \\\\\"five\\\\\" end..';\nconsole.log\\('Input:', src4\\);\ntry {\n const ast4 = await parser.parse\\(0, src4, basisLexicon\\);\n console.log\\('Unparsed:', unparse\\(ast4, basisLexicon\\)\\);\n} catch\\(e\\) { console.log\\('Error:', e.message\\); }\n\nconsole.log\\('---'\\);\n\n// Test case-of as argument to a function\nconst src5 = 'add \\(case x of 1: 10 2: 20 end\\) 5..';\nconsole.log\\('Input:', src5\\);\ntry {\n const ast5 = await parser.parse\\(0, src5, basisLexicon\\);\n console.log\\('Unparsed:', unparse\\(ast5, basisLexicon\\)\\);\n} catch\\(e\\) { console.log\\('Error:', e.message\\); }\n\")"
11
+ "Bash(NODE_OPTIONS=--experimental-vm-modules node -e \"\nimport { parser } from './src/parser.js';\nimport { unparse } from './src/unparse.js';\nimport { lexicon as basisLexicon } from '@graffiticode/basis';\n\n// Test nested case-of\nconst src1 = 'case x of 1: case y of 3: \\\\\"a\\\\\" 4: \\\\\"b\\\\\" end 2: \\\\\"two\\\\\" end..';\nconsole.log\\('Input:', src1\\);\ntry {\n const ast1 = await parser.parse\\(0, src1, basisLexicon\\);\n console.log\\('Unparsed:', unparse\\(ast1, basisLexicon\\)\\);\n} catch\\(e\\) { console.log\\('Error:', e.message\\); }\n\nconsole.log\\('---'\\);\n\n// Test with expression as case target\nconst src2 = 'case add 1 2 of 3: \\\\\"yes\\\\\" 4: \\\\\"no\\\\\" end..';\nconsole.log\\('Input:', src2\\);\ntry {\n const ast2 = await parser.parse\\(0, src2, basisLexicon\\);\n console.log\\('AST:', JSON.stringify\\(ast2, null, 2\\)\\);\n console.log\\('Unparsed:', unparse\\(ast2, basisLexicon\\)\\);\n} catch\\(e\\) { console.log\\('Error:', e.message\\); }\n\nconsole.log\\('---'\\);\n\n// Test with identifier patterns\nconst src3 = 'case x of y: y end..';\nconsole.log\\('Input:', src3\\);\ntry {\n const ast3 = await parser.parse\\(0, src3, basisLexicon\\);\n console.log\\('AST:', JSON.stringify\\(ast3, null, 2\\)\\);\n console.log\\('Unparsed:', unparse\\(ast3, basisLexicon\\)\\);\n} catch\\(e\\) { console.log\\('Error:', e.message\\); }\n\nconsole.log\\('---'\\);\n\n// Test case-of inside a let or other expression\nconst src4 = 'let x = 5 in case x of 5: \\\\\"five\\\\\" end..';\nconsole.log\\('Input:', src4\\);\ntry {\n const ast4 = await parser.parse\\(0, src4, basisLexicon\\);\n console.log\\('Unparsed:', unparse\\(ast4, basisLexicon\\)\\);\n} catch\\(e\\) { console.log\\('Error:', e.message\\); }\n\nconsole.log\\('---'\\);\n\n// Test case-of as argument to a function\nconst src5 = 'add \\(case x of 1: 10 2: 20 end\\) 5..';\nconsole.log\\('Input:', src5\\);\ntry {\n const ast5 = await parser.parse\\(0, src5, basisLexicon\\);\n console.log\\('Unparsed:', unparse\\(ast5, basisLexicon\\)\\);\n} catch\\(e\\) { console.log\\('Error:', e.message\\); }\n\")",
12
+ "Bash(git:*)"
12
13
  ]
13
14
  }
14
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graffiticode/parser",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -22,6 +22,6 @@
22
22
  "license": "MIT",
23
23
  "description": "",
24
24
  "dependencies": {
25
- "@graffiticode/basis": "^1.6.4"
25
+ "@graffiticode/basis": "^1.7.0"
26
26
  }
27
27
  }
package/src/ast.js CHANGED
@@ -532,12 +532,18 @@ export class Ast {
532
532
  Ast.push(ctx, { tag: "POW", elts: [n1, n2] });
533
533
  }
534
534
 
535
- static concat(ctx) {
536
- const n1 = Ast.node(ctx, Ast.pop(ctx));
537
- Ast.push(ctx, {
538
- tag: "CONCAT",
539
- elts: [n1]
540
- });
535
+ static concat(ctx, count) {
536
+ // Chain binary CONCATs from the parts on the stack.
537
+ // E.g. 3 parts [a, b, c] becomes CONCAT(CONCAT(a, b), c)
538
+ const parts = [];
539
+ for (let i = 0; i < count; i++) {
540
+ parts.unshift(Ast.pop(ctx));
541
+ }
542
+ let result = parts[0];
543
+ for (let i = 1; i < parts.length; i++) {
544
+ result = { tag: "CONCAT", elts: [result, parts[i]] };
545
+ }
546
+ Ast.push(ctx, result);
541
547
  }
542
548
 
543
549
  static eq(ctx) {
package/src/folder.js CHANGED
@@ -187,7 +187,8 @@ export class Folder {
187
187
 
188
188
  static concat(node) {
189
189
  Folder.#visit(node.elts[0]);
190
- Ast.concat(Folder.#ctx);
190
+ Folder.#visit(node.elts[1]);
191
+ Ast.concat(Folder.#ctx, 2);
191
192
  }
192
193
 
193
194
  static mod(node) {
package/src/parse.js CHANGED
@@ -108,8 +108,8 @@ export const parse = (function () {
108
108
  null: { tk: 0x15, cls: "val", length: 0 },
109
109
  val: { tk: 1, name: "VAL", cls: "function", length: 2, arity: 2 },
110
110
  key: { tk: 1, name: "KEY", cls: "function", length: 2, arity: 2 },
111
- len: { tk: 1, name: "LEN", cls: "function", length: 1, arity: 1 },
112
- concat: { tk: 1, name: "CONCAT", cls: "function", length: 1, arity: 1 },
111
+ length: { tk: 1, name: "LEN", cls: "function", length: 1, arity: 1 },
112
+ concat: { tk: 1, name: "CONCAT", cls: "function", length: 2, arity: 2 },
113
113
  add: { tk: 1, name: "ADD", cls: "function", length: 2, arity: 2 },
114
114
  mul: { tk: 1, name: "MUL", cls: "function", length: 2, arity: 2 },
115
115
  pow: { tk: 1, name: "POW", cls: "function", length: 2, arity: 2 },
@@ -362,9 +362,9 @@ export const parse = (function () {
362
362
  const processedSuffix = processEscapeSequences(lexeme);
363
363
  Ast.string(ctx, processedSuffix, getCoord(ctx)); // strip quotes;
364
364
  countCounter(ctx);
365
- Ast.list(ctx, ctx.state.exprc);
365
+ const count = ctx.state.exprc;
366
366
  stopCounter(ctx);
367
- Ast.concat(ctx);
367
+ Ast.concat(ctx, count);
368
368
  cc.cls = "string";
369
369
  return cc;
370
370
  });
@@ -1240,7 +1240,7 @@ export const parse = (function () {
1240
1240
  }
1241
1241
 
1242
1242
  // `abc` --> "abc"
1243
- // `a${x}c` --> concat ["a", x, "b"]
1243
+ // `a${x}c` --> concat (concat "a" x) "c"
1244
1244
  function string(ctx, c) {
1245
1245
  const quoteChar = c;
1246
1246
  ctx.state.quoteCharStack.push(c);
@@ -162,6 +162,12 @@ describe("unparse", () => {
162
162
  expect(unparsed).toBe("concat 'hello' ' world'..");
163
163
  });
164
164
 
165
+ it("should unparse template literal", async () => {
166
+ const source = 'let x = "world"..`hello ${x}`..';
167
+ const unparsed = await testRoundTrip(source);
168
+ expect(unparsed).toBe('concat concat "hello " "world" ""..');
169
+ });
170
+
165
171
  it.skip("should unparse complex arithmetic expression", async () => {
166
172
  const source = "mul (add 1 2) 3..";
167
173
  const unparsed = await testRoundTrip(source);