@graffiticode/parser 1.3.1 → 1.4.0

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": "@graffiticode/parser",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/ast.js CHANGED
@@ -496,86 +496,40 @@ export class Ast {
496
496
  Ast.number(ctx, -1 * v1);
497
497
  }
498
498
 
499
- static add(ctx, coord) {
500
- const n2 = Ast.node(ctx, Ast.pop(ctx));
501
- const n1 = Ast.node(ctx, Ast.pop(ctx));
502
- const v2 = n2.elts[0];
503
- const v1 = n1.elts[0];
504
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
505
- Ast.push(ctx, {
506
- tag: "ADD",
507
- elts: [n1, n2],
508
- coord
509
- });
510
- } else {
511
- Ast.number(ctx, +v1 + +v2);
512
- }
499
+ static add(ctx) {
500
+ const n2 = Ast.pop(ctx);
501
+ const n1 = Ast.pop(ctx);
502
+ Ast.push(ctx, { tag: "ADD", elts: [n1, n2] });
513
503
  }
514
504
 
515
505
  static sub(ctx) {
516
- const n2 = Ast.node(ctx, Ast.pop(ctx));
517
- const n1 = Ast.node(ctx, Ast.pop(ctx));
518
- const v2 = n2.elts[0];
519
- const v1 = n1.elts[0];
520
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
521
- Ast.push(ctx, { tag: "SUB", elts: [n1, n2] });
522
- } else {
523
- Ast.number(ctx, +v1 - +v2);
524
- }
506
+ const n2 = Ast.pop(ctx);
507
+ const n1 = Ast.pop(ctx);
508
+ Ast.push(ctx, { tag: "SUB", elts: [n1, n2] });
525
509
  }
526
510
 
527
- // static mul(ctx) {
528
- // let n2 = Ast.node(ctx, Ast.pop(ctx));
529
- // let n1 = Ast.node(ctx, Ast.pop(ctx));
530
- // const v2 = n2.elts[0];
531
- // const v1 = n1.elts[0];
532
- // if (n1.tag === undefined) {
533
- // n1 = n1.elts[0];
534
- // }
535
- // if (n2.tag === undefined) {
536
- // n2 = n2.elts[0];
537
- // }
538
- // if (n1.tag !== "NUM" || n2.tag !== "NUM") {
539
- // Ast.push(ctx, { tag: "MUL", elts: [n2, n1] });
540
- // } else {
541
- // Ast.number(ctx, +v1 * +v2);
542
- // }
543
- // }
511
+ static mul(ctx) {
512
+ const n2 = Ast.pop(ctx);
513
+ const n1 = Ast.pop(ctx);
514
+ Ast.push(ctx, { tag: "MUL", elts: [n1, n2] });
515
+ }
544
516
 
545
517
  static div(ctx) {
546
- const n2 = Ast.node(ctx, Ast.pop(ctx));
547
- const n1 = Ast.node(ctx, Ast.pop(ctx));
548
- const v2 = n2.elts[0];
549
- const v1 = n1.elts[0];
550
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
551
- Ast.push(ctx, { tag: "DIV", elts: [n1, n2] });
552
- } else {
553
- Ast.number(ctx, +v1 / +v2);
554
- }
518
+ const n2 = Ast.pop(ctx);
519
+ const n1 = Ast.pop(ctx);
520
+ Ast.push(ctx, { tag: "DIV", elts: [n1, n2] });
555
521
  }
556
522
 
557
523
  static mod(ctx) {
558
- const n2 = Ast.node(ctx, Ast.pop(ctx));
559
- const n1 = Ast.node(ctx, Ast.pop(ctx));
560
- const v1 = n1.elts[0];
561
- const v2 = n2.elts[0];
562
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
563
- Ast.push(ctx, { tag: "MOD", elts: [n1, n2] });
564
- } else {
565
- Ast.number(ctx, +v1 % +v2);
566
- }
524
+ const n2 = Ast.pop(ctx);
525
+ const n1 = Ast.pop(ctx);
526
+ Ast.push(ctx, { tag: "MOD", elts: [n1, n2] });
567
527
  }
568
528
 
569
529
  static pow(ctx) {
570
- const n2 = Ast.node(ctx, Ast.pop(ctx));
571
- const n1 = Ast.node(ctx, Ast.pop(ctx));
572
- const v2 = n2.elts[0];
573
- const v1 = n1.elts[0];
574
- if (n1.tag !== "NUM" || n2.tag !== "NUM") {
575
- Ast.push(ctx, { tag: "POW", elts: [n1, n2] });
576
- } else {
577
- Ast.number(ctx, Math.pow(+v1, +v2));
578
- }
530
+ const n2 = Ast.pop(ctx);
531
+ const n1 = Ast.pop(ctx);
532
+ Ast.push(ctx, { tag: "POW", elts: [n1, n2] });
579
533
  }
580
534
 
581
535
  static concat(ctx) {
package/src/folder.js CHANGED
@@ -25,9 +25,9 @@ export class Folder {
25
25
  PARENS: Folder.unaryExpr,
26
26
  APPLY: Folder.apply,
27
27
  LAMBDA: Folder.lambda,
28
- // "MUL": mul,
29
- // "DIV": div,
30
- // "SUB": sub,
28
+ MUL: Folder.mul,
29
+ DIV: Folder.div,
30
+ SUB: Folder.sub,
31
31
  TAG: Folder.tag,
32
32
  ADD: Folder.add,
33
33
  POW: Folder.pow,
@@ -161,6 +161,24 @@ export class Folder {
161
161
  Ast.add(Folder.#ctx);
162
162
  }
163
163
 
164
+ static sub(node) {
165
+ Folder.#visit(node.elts[0]);
166
+ Folder.#visit(node.elts[1]);
167
+ Ast.sub(Folder.#ctx);
168
+ }
169
+
170
+ static mul(node) {
171
+ Folder.#visit(node.elts[0]);
172
+ Folder.#visit(node.elts[1]);
173
+ Ast.mul(Folder.#ctx);
174
+ }
175
+
176
+ static div(node) {
177
+ Folder.#visit(node.elts[0]);
178
+ Folder.#visit(node.elts[1]);
179
+ Ast.div(Folder.#ctx);
180
+ }
181
+
164
182
  static pow(node) {
165
183
  Folder.#visit(node.elts[0]);
166
184
  Folder.#visit(node.elts[1]);
@@ -2,7 +2,7 @@ import { Folder } from "./folder.js";
2
2
  import { Ast } from "./ast.js";
3
3
 
4
4
  describe("folder", () => {
5
- it("should fold 'add 2 3' to 5", () => {
5
+ it("should pass 'add 2 3' through as ADD node", () => {
6
6
  // Arrange
7
7
  const ctx = {
8
8
  state: {
@@ -35,8 +35,15 @@ describe("folder", () => {
35
35
  const resultId = ctx.state.nodeStack.pop();
36
36
  const resultNode = ctx.state.nodePool[resultId];
37
37
 
38
- // Assert
39
- expect(resultNode.tag).toBe("NUM");
40
- expect(resultNode.elts[0]).toBe("5");
38
+ // Assert - arithmetic is deferred to compiler, not folded
39
+ expect(resultNode.tag).toBe("ADD");
40
+ expect(resultNode.elts.length).toBe(2);
41
+ // elts are nids (intern recursively interns object elts)
42
+ const n1 = Ast.node(ctx, resultNode.elts[0]);
43
+ const n2 = Ast.node(ctx, resultNode.elts[1]);
44
+ expect(n1.tag).toBe("NUM");
45
+ expect(n1.elts[0]).toBe("2");
46
+ expect(n2.tag).toBe("NUM");
47
+ expect(n2.elts[0]).toBe("3");
41
48
  });
42
49
  });
@@ -370,47 +370,36 @@ describe("parser integration tests", () => {
370
370
  expect(errorNode.tag).toBe("ERROR");
371
371
  });
372
372
 
373
- it("should perform parse-time evaluation for adding two numbers", async () => {
374
- // Use basis lexicon which includes add function
375
- // Act - parse a simple addition expression
373
+ it("should parse 'add 123 456' as ADD node with operands", async () => {
374
+ // Arithmetic is deferred to the compiler, not folded at parse time
376
375
  const result = await parser.parse(0, "add 123 456..", basisLexicon);
377
- console.log(
378
- "TEST",
379
- "result=" + JSON.stringify(result, null, 2),
380
- );
381
376
 
382
377
  // Assert
383
378
  expect(result).toHaveProperty("root");
384
379
 
385
- // Verify basic structure
386
380
  const rootId = result.root;
387
381
  const rootNode = result[rootId];
388
382
  expect(rootNode.tag).toBe("PROG");
389
383
 
390
- // Find the result node - expecting a single NUM node with the sum
391
- let resultNode = null;
392
-
393
- // Check all nodes for the result of evaluation (123 + 456 = 579)
384
+ // Find the ADD node
385
+ let addNode = null;
394
386
  for (const key in result) {
395
387
  if (key !== "root") {
396
388
  const node = result[key];
397
- if (node.tag === "NUM" && node.elts[0] === "579") {
398
- resultNode = node;
389
+ if (node.tag === "ADD") {
390
+ addNode = node;
399
391
  break;
400
392
  }
401
393
  }
402
394
  }
403
395
 
404
- // We should find a node with the computed value (579)
405
- expect(resultNode).not.toBeNull();
406
- expect(resultNode.tag).toBe("NUM");
407
- expect(resultNode.elts[0]).toBe("579");
396
+ expect(addNode).not.toBeNull();
397
+ expect(addNode.tag).toBe("ADD");
398
+ expect(addNode.elts.length).toBe(2);
408
399
 
409
- // The original numbers should not be in the final AST
410
- // if parse-time evaluation is working correctly
400
+ // Original operands should be preserved
411
401
  let found123 = false;
412
402
  let found456 = false;
413
-
414
403
  for (const key in result) {
415
404
  if (key !== "root") {
416
405
  const node = result[key];
@@ -420,11 +409,8 @@ describe("parser integration tests", () => {
420
409
  }
421
410
  }
422
411
  }
423
-
424
- // The original operands should not be in the final AST
425
- // if they were properly evaluated at parse time
426
- expect(found123).toBe(false);
427
- expect(found456).toBe(false);
412
+ expect(found123).toBe(true);
413
+ expect(found456).toBe(true);
428
414
  });
429
415
 
430
416
  // Tests for escaped quotes