@graffiticode/basis 1.5.12 → 1.5.14

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.
Files changed (2) hide show
  1. package/package.json +4 -1
  2. package/src/compiler.js +251 -28
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@graffiticode/basis",
3
3
  "type": "module",
4
- "version": "1.5.12",
4
+ "version": "1.5.14",
5
5
  "description": "The basis library for creating Graffiticode languages",
6
6
  "main": "index.js",
7
7
  "scripts": {
@@ -26,5 +26,8 @@
26
26
  "https": "^1.0.0",
27
27
  "jest": "^27.0.1",
28
28
  "react": "^17.0.2"
29
+ },
30
+ "dependencies": {
31
+ "decimal.js": "^10.5.0"
29
32
  }
30
33
  }
package/src/compiler.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /* Copyright (c) 2021, ARTCOMPILER INC */
2
2
  import {assert, message, messages, reserveCodeRange} from "./share.js";
3
+ import Decimal from 'decimal.js';
3
4
  reserveCodeRange(1000, 1999, "compile");
4
5
  messages[1001] = "Node ID %1 not found in pool.";
5
6
  messages[1002] = "Invalid tag in node with Node ID %1.";
@@ -185,6 +186,15 @@ export class Checker extends Visitor {
185
186
  });
186
187
  });
187
188
  }
189
+ GET(node, options, resume) {
190
+ this.visit(node.elts[0], options, (err1, val1) => {
191
+ this.visit(node.elts[1], options, (err2, val2) => {
192
+ const err = [].concat(err1).concat(err2);
193
+ const val = node;
194
+ resume(err, val);
195
+ });
196
+ });
197
+ }
188
198
  LT(node, options, resume) {
189
199
  this.visit(node.elts[0], options, (err1, val1) => {
190
200
  this.visit(node.elts[1], options, (err2, val2) => {
@@ -308,6 +318,71 @@ export class Checker extends Visitor {
308
318
  const val = node;
309
319
  resume(err, val);
310
320
  }
321
+ GT(node, options, resume) {
322
+ this.visit(node.elts[0], options, (err1, val1) => {
323
+ this.visit(node.elts[1], options, (err2, val2) => {
324
+ const err = [].concat(err1).concat(err2);
325
+ const val = node;
326
+ resume(err, val);
327
+ });
328
+ });
329
+ }
330
+ GE(node, options, resume) {
331
+ this.visit(node.elts[0], options, (err1, val1) => {
332
+ this.visit(node.elts[1], options, (err2, val2) => {
333
+ const err = [].concat(err1).concat(err2);
334
+ const val = node;
335
+ resume(err, val);
336
+ });
337
+ });
338
+ }
339
+ LE(node, options, resume) {
340
+ this.visit(node.elts[0], options, (err1, val1) => {
341
+ this.visit(node.elts[1], options, (err2, val2) => {
342
+ const err = [].concat(err1).concat(err2);
343
+ const val = node;
344
+ resume(err, val);
345
+ });
346
+ });
347
+ }
348
+ NE(node, options, resume) {
349
+ this.visit(node.elts[0], options, (err1, val1) => {
350
+ this.visit(node.elts[1], options, (err2, val2) => {
351
+ const err = [].concat(err1).concat(err2);
352
+ const val = node;
353
+ resume(err, val);
354
+ });
355
+ });
356
+ }
357
+ RANGE(node, options, resume) {
358
+ this.visit(node.elts[0], options, (err1, val1) => {
359
+ this.visit(node.elts[1], options, (err2, val2) => {
360
+ this.visit(node.elts[2], options, (err3, val3) => {
361
+ const err = [].concat(err1).concat(err2).concat(err3);
362
+ const val = node;
363
+ resume(err, val);
364
+ });
365
+ });
366
+ });
367
+ }
368
+ EQ(node, options, resume) {
369
+ this.visit(node.elts[0], options, (err1, val1) => {
370
+ this.visit(node.elts[1], options, (err2, val2) => {
371
+ const err = [].concat(err1).concat(err2);
372
+ const val = node;
373
+ resume(err, val);
374
+ });
375
+ });
376
+ }
377
+ MOD(node, options, resume) {
378
+ this.visit(node.elts[0], options, (err1, val1) => {
379
+ this.visit(node.elts[1], options, (err2, val2) => {
380
+ const err = [].concat(err1).concat(err2);
381
+ const val = node;
382
+ resume(err, val);
383
+ });
384
+ });
385
+ }
311
386
  }
312
387
 
313
388
  function enterEnv(ctx, name, paramc) {
@@ -556,8 +631,12 @@ export class Transformer extends Visitor {
556
631
  this.visit(node.elts[0], options, (e0, v0) => {
557
632
  this.visit(node.elts[1], options, (e1, v1) => {
558
633
  const err = [].concat(e0).concat(e1);
559
- const val = +v0 + +v1;
560
- resume(err, val);
634
+ try {
635
+ const val = new Decimal(v0).plus(new Decimal(v1)).toNumber();
636
+ resume(err, val);
637
+ } catch (e) {
638
+ resume([...err, `Error in ADD operation: ${e.message}`], NaN);
639
+ }
561
640
  });
562
641
  });
563
642
  }
@@ -565,8 +644,12 @@ export class Transformer extends Visitor {
565
644
  this.visit(node.elts[0], options, (e0, v0) => {
566
645
  this.visit(node.elts[1], options, (e1, v1) => {
567
646
  const err = [].concat(e0).concat(e1);
568
- const val = +v0 - +v1;
569
- resume(err, val);
647
+ try {
648
+ const val = new Decimal(v0).minus(new Decimal(v1)).toNumber();
649
+ resume(err, val);
650
+ } catch (e) {
651
+ resume([...err, `Error in SUB operation: ${e.message}`], NaN);
652
+ }
570
653
  });
571
654
  });
572
655
  }
@@ -574,8 +657,12 @@ export class Transformer extends Visitor {
574
657
  this.visit(node.elts[0], options, (e0, v0) => {
575
658
  this.visit(node.elts[1], options, (e1, v1) => {
576
659
  const err = [].concat(e0).concat(e1);
577
- const val = +v0 < +v1;
578
- resume(err, val);
660
+ try {
661
+ const val = new Decimal(v0).lessThan(new Decimal(v1));
662
+ resume(err, val);
663
+ } catch (e) {
664
+ resume([...err, `Error in LT operation: ${e.message}`], false);
665
+ }
579
666
  });
580
667
  });
581
668
  }
@@ -623,30 +710,57 @@ export class Transformer extends Visitor {
623
710
  MUL(node, options, resume) {
624
711
  this.visit(node.elts[0], options, (err1, val1) => {
625
712
  this.visit(node.elts[1], options, (err2, val2) => {
626
- if (isNaN(+val1)) {
627
- err1 = err1.concat(error("MUL first argument must be a number: ", JSON.stringify(node, null, 2)));
628
- }
629
- if (isNaN(+val2)) {
630
- err2 = err2.concat(error("MUL second argument must be a number: ", JSON.stringify(node, null, 2)));
713
+ let err = [].concat(err1).concat(err2);
714
+ try {
715
+ const val = new Decimal(val1).times(new Decimal(val2)).toNumber();
716
+ resume(err, val);
717
+ } catch (e) {
718
+ if (isNaN(+val1)) {
719
+ err = err.concat(error("MUL first argument must be a number: ", JSON.stringify(node, null, 2)));
720
+ }
721
+ if (isNaN(+val2)) {
722
+ err = err.concat(error("MUL second argument must be a number: ", JSON.stringify(node, null, 2)));
723
+ }
724
+ resume([...err, `Error in MUL operation: ${e.message}`], NaN);
631
725
  }
632
- const err = [].concat(err1).concat(err2);
633
- const val = +val1 * +val2;
634
- resume(err, val);
635
726
  });
636
727
  });
637
728
  }
638
729
  POW(node, options, resume) {
639
730
  this.visit(node.elts[0], options, (err1, val1) => {
640
731
  this.visit(node.elts[1], options, (err2, val2) => {
641
- if (isNaN(+val1)) {
642
- err1 = err1.concat(error("Argument must be a number.", node.elts[0]));
732
+ let err = [].concat(err1).concat(err2);
733
+ try {
734
+ const val = new Decimal(val1).pow(new Decimal(val2)).toNumber();
735
+ resume(err, val);
736
+ } catch (e) {
737
+ if (isNaN(+val1)) {
738
+ err = err.concat(error("POW first argument must be a number: ", JSON.stringify(node, null, 2)));
739
+ }
740
+ if (isNaN(+val2)) {
741
+ err = err.concat(error("POW second argument must be a number: ", JSON.stringify(node, null, 2)));
742
+ }
743
+ resume([...err, `Error in POW operation: ${e.message}`], NaN);
643
744
  }
644
- if (isNaN(+val2)) {
645
- err2 = err2.concat(error("Argument must be a number.", node.elts[1]));
745
+ });
746
+ });
747
+ }
748
+ MOD(node, options, resume) {
749
+ this.visit(node.elts[0], options, (err1, val1) => {
750
+ this.visit(node.elts[1], options, (err2, val2) => {
751
+ let err = [].concat(err1).concat(err2);
752
+ try {
753
+ const val = new Decimal(val1).mod(new Decimal(val2)).toNumber();
754
+ resume(err, val);
755
+ } catch (e) {
756
+ if (isNaN(+val1)) {
757
+ err = err.concat(error("MOD first argument must be a number: ", JSON.stringify(node, null, 2)));
758
+ }
759
+ if (isNaN(+val2)) {
760
+ err = err.concat(error("MOD second argument must be a number: ", JSON.stringify(node, null, 2)));
761
+ }
762
+ resume([...err, `Error in MOD operation: ${e.message}`], NaN);
646
763
  }
647
- const err = [].concat(err1).concat(err2);
648
- const val = node;
649
- resume(err, val);
650
764
  });
651
765
  });
652
766
  }
@@ -780,13 +894,19 @@ export class Transformer extends Visitor {
780
894
  // FIXME this isn't ASYNC compatible
781
895
  options.SYNC = true;
782
896
  this.visit(node.elts[0], options, (e0, v0) => {
783
- const e0Node = this.node(node.elts[0]);
897
+ const type = typeof v0;
898
+ const val = `${v0}`;
899
+ console.log(
900
+ "CASE",
901
+ "type=" + type,
902
+ "val=" + val,
903
+ );
784
904
  const expr = (
785
- e0Node.tag === 'BOOL' ||
786
- e0Node.tag === 'NUM'
787
- ) && e0Node || {
788
- tag: 'STR', elts: [`${v0}`]
789
- };
905
+ val === null && {tag: "NUL", elts: []} ||
906
+ type === "boolean" && {tag: "BOOL", elts: [val]} ||
907
+ type === "number" && {tag: "NUM", elts: [val]} ||
908
+ {tag: "STR", elts: [val]}
909
+ );
790
910
  let foundMatch = false;
791
911
  const patterns = [];
792
912
  for (var i = 1; i < node.elts.length; i++) {
@@ -841,7 +961,7 @@ export class Transformer extends Visitor {
841
961
  this.visit(node.elts[0], options, (e0, v0) => {
842
962
  this.visit(node.elts[1], options, (e1, v1) => {
843
963
  const err = [...e0, ...e1];
844
- assert(typeof v0 === "object", "Type Error: expected v0 to be an object.");
964
+ assert(typeof v0 === "object", "Type Error: expected v0 to be an object. Got " + JSON.stringify(v0));
845
965
  assert(typeof v1 === "string", "Type Error: expected v1 to be a string.");
846
966
  const val = v0[v1];
847
967
  resume(err, val);
@@ -884,6 +1004,109 @@ export class Transformer extends Visitor {
884
1004
  resume(err, val);
885
1005
  })
886
1006
  }
1007
+ EQ(node, options, resume) {
1008
+ this.visit(node.elts[0], options, (e0, v0) => {
1009
+ this.visit(node.elts[1], options, (e1, v1) => {
1010
+ const err = [].concat(e0).concat(e1);
1011
+ try {
1012
+ const val = new Decimal(v0).equals(new Decimal(v1));
1013
+ resume(err, val);
1014
+ } catch (e) {
1015
+ resume([...err, `Error in EQ operation: ${e.message}`], false);
1016
+ }
1017
+ });
1018
+ });
1019
+ }
1020
+ GT(node, options, resume) {
1021
+ this.visit(node.elts[0], options, (e0, v0) => {
1022
+ this.visit(node.elts[1], options, (e1, v1) => {
1023
+ const err = [].concat(e0).concat(e1);
1024
+ try {
1025
+ const val = new Decimal(v0).greaterThan(new Decimal(v1));
1026
+ resume(err, val);
1027
+ } catch (e) {
1028
+ resume([...err, `Error in GT operation: ${e.message}`], false);
1029
+ }
1030
+ });
1031
+ });
1032
+ }
1033
+ GE(node, options, resume) {
1034
+ this.visit(node.elts[0], options, (e0, v0) => {
1035
+ this.visit(node.elts[1], options, (e1, v1) => {
1036
+ const err = [].concat(e0).concat(e1);
1037
+ try {
1038
+ const val = new Decimal(v0).greaterThanOrEqualTo(new Decimal(v1));
1039
+ resume(err, val);
1040
+ } catch (e) {
1041
+ resume([...err, `Error in GE operation: ${e.message}`], false);
1042
+ }
1043
+ });
1044
+ });
1045
+ }
1046
+ LE(node, options, resume) {
1047
+ this.visit(node.elts[0], options, (e0, v0) => {
1048
+ this.visit(node.elts[1], options, (e1, v1) => {
1049
+ const err = [].concat(e0).concat(e1);
1050
+ try {
1051
+ const val = new Decimal(v0).lessThanOrEqualTo(new Decimal(v1));
1052
+ resume(err, val);
1053
+ } catch (e) {
1054
+ resume([...err, `Error in LE operation: ${e.message}`], false);
1055
+ }
1056
+ });
1057
+ });
1058
+ }
1059
+ NE(node, options, resume) {
1060
+ this.visit(node.elts[0], options, (e0, v0) => {
1061
+ this.visit(node.elts[1], options, (e1, v1) => {
1062
+ const err = [].concat(e0).concat(e1);
1063
+ try {
1064
+ const val = !new Decimal(v0).equals(new Decimal(v1));
1065
+ resume(err, val);
1066
+ } catch (e) {
1067
+ resume([...err, `Error in NE operation: ${e.message}`], false);
1068
+ }
1069
+ });
1070
+ });
1071
+ }
1072
+ RANGE(node, options, resume) {
1073
+ this.visit(node.elts[0], options, (e0, v0) => {
1074
+ this.visit(node.elts[1], options, (e1, v1) => {
1075
+ this.visit(node.elts[2], options, (e2, v2) => {
1076
+ const err = [].concat(e0).concat(e1).concat(e2);
1077
+ try {
1078
+ const start = new Decimal(v0);
1079
+ const end = new Decimal(v1);
1080
+ const step = new Decimal(v2);
1081
+
1082
+ if (step.isZero()) {
1083
+ resume([...err, 'Error in RANGE operation: step cannot be zero'], []);
1084
+ return;
1085
+ }
1086
+
1087
+ const result = [];
1088
+ let current = start;
1089
+
1090
+ if (step.isPositive()) {
1091
+ while (current.lessThan(end)) {
1092
+ result.push(current.toNumber());
1093
+ current = current.plus(step);
1094
+ }
1095
+ } else {
1096
+ while (current.greaterThan(end)) {
1097
+ result.push(current.toNumber());
1098
+ current = current.plus(step);
1099
+ }
1100
+ }
1101
+
1102
+ resume(err, result);
1103
+ } catch (e) {
1104
+ resume([...err, `Error in RANGE operation: ${e.message}`], []);
1105
+ }
1106
+ });
1107
+ });
1108
+ });
1109
+ }
887
1110
  }
888
1111
 
889
1112
  export class Renderer {