@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.
- package/package.json +4 -1
- 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.
|
|
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
|
-
|
|
560
|
-
|
|
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
|
-
|
|
569
|
-
|
|
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
|
-
|
|
578
|
-
|
|
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
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
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
|
-
|
|
642
|
-
|
|
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
|
-
|
|
645
|
-
|
|
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
|
|
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
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
tag:
|
|
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 {
|