mevento 1.0.0 → 1.2.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/README.md +47 -12
- package/esm2020/lib/mevento.mjs +345 -21
- package/fesm2015/mevento.mjs +351 -20
- package/fesm2015/mevento.mjs.map +1 -1
- package/fesm2020/mevento.mjs +344 -20
- package/fesm2020/mevento.mjs.map +1 -1
- package/lib/mevento.d.ts +37 -0
- package/package.json +1 -1
package/fesm2020/mevento.mjs
CHANGED
|
@@ -26,9 +26,7 @@ function hashCode(str) {
|
|
|
26
26
|
return hash;
|
|
27
27
|
for (i = 0; i < str.length; i++) {
|
|
28
28
|
chr = str.charCodeAt(i);
|
|
29
|
-
// tslint:disable-next-line:no-bitwise
|
|
30
29
|
hash = ((hash << 5) - hash) + chr;
|
|
31
|
-
// tslint:disable-next-line:no-bitwise
|
|
32
30
|
hash |= 0; // Convert to 32bit integer
|
|
33
31
|
}
|
|
34
32
|
return hash;
|
|
@@ -71,6 +69,14 @@ TokenType.mult = 31;
|
|
|
71
69
|
TokenType.mod = 32;
|
|
72
70
|
TokenType.invalid = 33;
|
|
73
71
|
TokenType.colon = 34;
|
|
72
|
+
TokenType.WHILE_TILL = 35;
|
|
73
|
+
TokenType.FOR_LOOP = 36;
|
|
74
|
+
TokenType.up = 37;
|
|
75
|
+
TokenType.down = 38;
|
|
76
|
+
TokenType.with = 39;
|
|
77
|
+
TokenType.in = 40;
|
|
78
|
+
TokenType.TILL = 41;
|
|
79
|
+
TokenType.BREAK = 42;
|
|
74
80
|
class Token {
|
|
75
81
|
constructor(type, value, line = 1, col = 1) {
|
|
76
82
|
this.type = type;
|
|
@@ -474,15 +480,31 @@ Lexer._defaultLanguage = new LexerDictionary("en", {
|
|
|
474
480
|
"true": "true",
|
|
475
481
|
"false": "false",
|
|
476
482
|
"null": "null",
|
|
483
|
+
"while": "while",
|
|
484
|
+
"for": "for",
|
|
485
|
+
"with": "with",
|
|
486
|
+
"up": "up",
|
|
487
|
+
"down": "down",
|
|
488
|
+
"till": "till",
|
|
489
|
+
"in": "in",
|
|
490
|
+
"break": "break",
|
|
477
491
|
});
|
|
478
492
|
Lexer.languages = [
|
|
479
493
|
Lexer._defaultLanguage,
|
|
480
494
|
new LexerDictionary("fr", {
|
|
481
495
|
"si": "if",
|
|
482
496
|
"sinon": "else",
|
|
483
|
-
"vrai": "
|
|
497
|
+
"vrai": "true",
|
|
484
498
|
"faux": "false",
|
|
485
499
|
"nul": "null",
|
|
500
|
+
"tanque": "while",
|
|
501
|
+
"pour": "for",
|
|
502
|
+
"avec": "with",
|
|
503
|
+
"mon": "up",
|
|
504
|
+
"desc": "down",
|
|
505
|
+
"jusqua": "till",
|
|
506
|
+
"dans": "in",
|
|
507
|
+
"couper": "break",
|
|
486
508
|
}),
|
|
487
509
|
new LexerDictionary("bm", {
|
|
488
510
|
"nii": "if",
|
|
@@ -490,6 +512,14 @@ Lexer.languages = [
|
|
|
490
512
|
"tien": "true",
|
|
491
513
|
"galon": "false",
|
|
492
514
|
"gansan": "null",
|
|
515
|
+
"foo": "while",
|
|
516
|
+
"seginka": "for",
|
|
517
|
+
"niin": "with",
|
|
518
|
+
"kay": "up",
|
|
519
|
+
"kaj": "down",
|
|
520
|
+
"kata": "till",
|
|
521
|
+
"kono": "in",
|
|
522
|
+
"tike": "break",
|
|
493
523
|
}),
|
|
494
524
|
];
|
|
495
525
|
Lexer.RESERVED = {
|
|
@@ -498,6 +528,14 @@ Lexer.RESERVED = {
|
|
|
498
528
|
"true": Token.from(TokenType.TRUE, true),
|
|
499
529
|
"false": Token.from(TokenType.FALSE, false),
|
|
500
530
|
"null": Token.from(TokenType.NULL, null),
|
|
531
|
+
"for": Token.from(TokenType.FOR_LOOP, "for"),
|
|
532
|
+
"while": Token.from(TokenType.WHILE_TILL, "while"),
|
|
533
|
+
"with": Token.from(TokenType.with, "with"),
|
|
534
|
+
"up": Token.from(TokenType.up, "up"),
|
|
535
|
+
"down": Token.from(TokenType.down, "down"),
|
|
536
|
+
"till": Token.from(TokenType.TILL, "till"),
|
|
537
|
+
"in": Token.from(TokenType.in, "in"),
|
|
538
|
+
"break": Token.from(TokenType.BREAK, "break"),
|
|
501
539
|
};
|
|
502
540
|
/**
|
|
503
541
|
* Parser
|
|
@@ -612,7 +650,7 @@ class IfStatementAST extends AST {
|
|
|
612
650
|
this.alternate = alternate;
|
|
613
651
|
}
|
|
614
652
|
toString() {
|
|
615
|
-
return `if ${this.test} ${this.consequent} ${this.alternate
|
|
653
|
+
return `if ${this.test} ${this.consequent} ${this.alternate ? `else ${this.alternate} ` : ''}`;
|
|
616
654
|
}
|
|
617
655
|
}
|
|
618
656
|
class LogicalExpressionAST extends AST {
|
|
@@ -663,6 +701,47 @@ class ObjectProperty extends AST {
|
|
|
663
701
|
this.key = key;
|
|
664
702
|
}
|
|
665
703
|
}
|
|
704
|
+
class WhileLoopStatement extends AST {
|
|
705
|
+
constructor(test, body, startToken, endToken, retain = false) {
|
|
706
|
+
super(startToken?.line, startToken?.col);
|
|
707
|
+
this.retain = false;
|
|
708
|
+
this.test = test;
|
|
709
|
+
this.body = body;
|
|
710
|
+
this.retain = retain;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
class ForLoopStatement extends AST {
|
|
714
|
+
constructor(init, test, update, direction, body, startToken, endToken, retain = false) {
|
|
715
|
+
super(startToken?.line, startToken?.col);
|
|
716
|
+
this.init = init;
|
|
717
|
+
this.test = test;
|
|
718
|
+
this.update = update;
|
|
719
|
+
this.direction = direction;
|
|
720
|
+
this.body = body;
|
|
721
|
+
this.retain = retain;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
class ForOfStatement extends AST {
|
|
725
|
+
constructor(identifier, collection, body, startToken, endToken, retain = false) {
|
|
726
|
+
super(startToken?.line, startToken?.col);
|
|
727
|
+
this.identifier = identifier;
|
|
728
|
+
this.collection = collection;
|
|
729
|
+
this.body = body;
|
|
730
|
+
this.retain = retain;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
class TupleExpression extends AST {
|
|
734
|
+
constructor(first, second) {
|
|
735
|
+
super(first.line, first.col);
|
|
736
|
+
this.first = first;
|
|
737
|
+
this.second = second;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
class BreakAST extends AST {
|
|
741
|
+
constructor(line, col) {
|
|
742
|
+
super(line, col);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
666
745
|
class Parser {
|
|
667
746
|
constructor(lexer) {
|
|
668
747
|
this.currentToken = lexer.nextToken();
|
|
@@ -905,6 +984,8 @@ class Parser {
|
|
|
905
984
|
break;
|
|
906
985
|
}
|
|
907
986
|
body.push(this._statement());
|
|
987
|
+
if (this._expect(TokenType.rbrace))
|
|
988
|
+
break;
|
|
908
989
|
if (this.currentToken.type !== TokenType.eol &&
|
|
909
990
|
this.currentToken.type !== TokenType.semi &&
|
|
910
991
|
this.currentToken.type !== TokenType.eof) {
|
|
@@ -916,7 +997,8 @@ class Parser {
|
|
|
916
997
|
// endBlock
|
|
917
998
|
this._eat(TokenType.rbrace);
|
|
918
999
|
}
|
|
919
|
-
|
|
1000
|
+
const ret = new BlockStatementAST(body, this.currentToken);
|
|
1001
|
+
return ret;
|
|
920
1002
|
}
|
|
921
1003
|
_ifStatement() {
|
|
922
1004
|
this._eat(TokenType.IF);
|
|
@@ -952,8 +1034,94 @@ class Parser {
|
|
|
952
1034
|
}
|
|
953
1035
|
return new IfStatementAST(test, consequent, alternate);
|
|
954
1036
|
}
|
|
1037
|
+
_whileLoop() {
|
|
1038
|
+
const token = this.currentToken;
|
|
1039
|
+
this._eat(TokenType.WHILE_TILL);
|
|
1040
|
+
const test = this._expression();
|
|
1041
|
+
const body = this.currentToken.type == TokenType.lbrace ? this._blockStatement() : this._expression();
|
|
1042
|
+
return new WhileLoopStatement(test, body, token, this.currentToken);
|
|
1043
|
+
}
|
|
1044
|
+
_forOfIdentifier() {
|
|
1045
|
+
let node;
|
|
1046
|
+
switch (this.currentToken.type) {
|
|
1047
|
+
case TokenType.lparen: {
|
|
1048
|
+
// probable tuple
|
|
1049
|
+
this._eat(TokenType.lparen);
|
|
1050
|
+
const first = this._variable();
|
|
1051
|
+
this._eat(TokenType.comma);
|
|
1052
|
+
const second = this._variable();
|
|
1053
|
+
this._eat(TokenType.rparen);
|
|
1054
|
+
return new TupleExpression(first, second);
|
|
1055
|
+
}
|
|
1056
|
+
// TokenType.LBRACE -> objectPattern()
|
|
1057
|
+
// TokenType.LBRACKET -> arrayPattern()
|
|
1058
|
+
default:
|
|
1059
|
+
return this._variable();
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* # ForLoopStatement with step
|
|
1064
|
+
* (seginka|for) a=0 (foo|to) 10 (kay|kaj) niin 2 { # for a = 0; a<10; a+=2
|
|
1065
|
+
*
|
|
1066
|
+
* }
|
|
1067
|
+
* (seginka|for) mali kono a
|
|
1068
|
+
*/
|
|
1069
|
+
_forLoop() {
|
|
1070
|
+
const startToken = this.currentToken;
|
|
1071
|
+
this._eat(TokenType.FOR_LOOP);
|
|
1072
|
+
let forOf = [TokenType.lparen].includes(this.currentToken.type);
|
|
1073
|
+
let node;
|
|
1074
|
+
if (forOf) {
|
|
1075
|
+
node = this._forOfIdentifier();
|
|
1076
|
+
}
|
|
1077
|
+
else {
|
|
1078
|
+
const expr = this._expression();
|
|
1079
|
+
if (!(expr instanceof AssignmentExpressionAST)) {
|
|
1080
|
+
forOf = true;
|
|
1081
|
+
}
|
|
1082
|
+
node = expr;
|
|
1083
|
+
}
|
|
1084
|
+
if (!forOf && node instanceof AssignmentExpressionAST) {
|
|
1085
|
+
// normal for
|
|
1086
|
+
this._eat(TokenType.TILL);
|
|
1087
|
+
const test = this._expression();
|
|
1088
|
+
let direction;
|
|
1089
|
+
if (this.currentToken.type === TokenType.up || this.currentToken.type === TokenType.down) {
|
|
1090
|
+
const t = this.currentToken;
|
|
1091
|
+
this._eat(t.type);
|
|
1092
|
+
direction = t;
|
|
1093
|
+
}
|
|
1094
|
+
else {
|
|
1095
|
+
direction = new Token(TokenType.up, "up");
|
|
1096
|
+
}
|
|
1097
|
+
let update;
|
|
1098
|
+
if (this._expect(TokenType.with)) {
|
|
1099
|
+
this._eat(TokenType.with);
|
|
1100
|
+
const expr = this._expression();
|
|
1101
|
+
update = expr;
|
|
1102
|
+
}
|
|
1103
|
+
else {
|
|
1104
|
+
update = new LiteralAST(new Token(TokenType.numberConst, 1, this.currentToken.line, this.currentToken.col), "1");
|
|
1105
|
+
}
|
|
1106
|
+
const body = (this.currentToken.type == TokenType.lbrace) ? this._blockStatement() : this._expression();
|
|
1107
|
+
node = new ForLoopStatement(node, test, update, direction, body, startToken, this.currentToken);
|
|
1108
|
+
}
|
|
1109
|
+
else if (forOf) {
|
|
1110
|
+
this._eat(TokenType.in);
|
|
1111
|
+
const collection = this._expression();
|
|
1112
|
+
const body = (this.currentToken.type == TokenType.lbrace) ? this._blockStatement() : this._expression();
|
|
1113
|
+
node = new ForOfStatement(node, collection, body, startToken, this.currentToken);
|
|
1114
|
+
}
|
|
1115
|
+
else {
|
|
1116
|
+
error(this.currentToken);
|
|
1117
|
+
}
|
|
1118
|
+
return node;
|
|
1119
|
+
}
|
|
955
1120
|
_statement() {
|
|
956
1121
|
switch (this.currentToken.type) {
|
|
1122
|
+
case TokenType.BREAK:
|
|
1123
|
+
this._eat(TokenType.BREAK);
|
|
1124
|
+
return new BreakAST(this.currentToken?.line, this.currentToken?.col);
|
|
957
1125
|
case TokenType.semi:
|
|
958
1126
|
this._eatSemi();
|
|
959
1127
|
return this._statement();
|
|
@@ -962,6 +1130,10 @@ class Parser {
|
|
|
962
1130
|
return this._statement();
|
|
963
1131
|
case TokenType.IF:
|
|
964
1132
|
return this._ifStatement();
|
|
1133
|
+
case TokenType.WHILE_TILL:
|
|
1134
|
+
return this._whileLoop();
|
|
1135
|
+
case TokenType.FOR_LOOP:
|
|
1136
|
+
return this._forLoop();
|
|
965
1137
|
default:
|
|
966
1138
|
return this._statementExpression();
|
|
967
1139
|
}
|
|
@@ -969,32 +1141,31 @@ class Parser {
|
|
|
969
1141
|
_expect(type) {
|
|
970
1142
|
return this.currentToken?.type === type;
|
|
971
1143
|
}
|
|
972
|
-
|
|
973
|
-
this.
|
|
1144
|
+
_definition() {
|
|
1145
|
+
this._eatSemiOrEOL();
|
|
974
1146
|
if (this._expect(TokenType.eof)) {
|
|
975
1147
|
return [];
|
|
976
1148
|
}
|
|
977
1149
|
const results = [this._statement()];
|
|
978
|
-
while (
|
|
979
|
-
this.currentToken.type === TokenType.semi)) {
|
|
1150
|
+
while (true) {
|
|
980
1151
|
this._eatSemiOrEOL();
|
|
981
1152
|
if (this.currentToken.type === TokenType.eof) {
|
|
982
1153
|
this._eat(TokenType.eof);
|
|
983
1154
|
break;
|
|
984
1155
|
}
|
|
985
1156
|
results.push(this._statement());
|
|
986
|
-
if (this.currentToken
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
}
|
|
1157
|
+
// if (this.currentToken!.type !== TokenType.eol &&
|
|
1158
|
+
// this.currentToken!.type !== TokenType.semi &&
|
|
1159
|
+
// this.currentToken!.type !== TokenType.eof) {
|
|
1160
|
+
// error(this.currentToken!);
|
|
1161
|
+
// }
|
|
991
1162
|
}
|
|
992
1163
|
return results;
|
|
993
1164
|
}
|
|
994
1165
|
_root() {
|
|
995
1166
|
const source = this.lexer.source;
|
|
996
1167
|
const name = "<module>";
|
|
997
|
-
const list = this.
|
|
1168
|
+
const list = this._definition();
|
|
998
1169
|
return new RootAST(list, name, source);
|
|
999
1170
|
}
|
|
1000
1171
|
parse() {
|
|
@@ -1014,6 +1185,8 @@ Parser._binopPrecdences = {
|
|
|
1014
1185
|
[TokenType.div]: 40,
|
|
1015
1186
|
[TokenType.mod]: 40,
|
|
1016
1187
|
};
|
|
1188
|
+
class BreakBranch {
|
|
1189
|
+
}
|
|
1017
1190
|
// AST Wallker
|
|
1018
1191
|
class ANodeVisitor {
|
|
1019
1192
|
constructor() {
|
|
@@ -1035,6 +1208,7 @@ class AsyncNodeVisitor extends ANodeVisitor {
|
|
|
1035
1208
|
}
|
|
1036
1209
|
class NodeVisitor extends ANodeVisitor {
|
|
1037
1210
|
visit(node) {
|
|
1211
|
+
// console.log('node::', node);
|
|
1038
1212
|
const methodName = `visit${node.constructor.name}`;
|
|
1039
1213
|
// const fn = Object.getPrototypeOf(this)[methodName];
|
|
1040
1214
|
const fn = this._nodesVisitors[methodName];
|
|
@@ -1045,6 +1219,7 @@ class MEvento extends NodeVisitor {
|
|
|
1045
1219
|
constructor() {
|
|
1046
1220
|
super();
|
|
1047
1221
|
this._memory = {};
|
|
1222
|
+
this.debug = false;
|
|
1048
1223
|
this._functionsRegistry = {};
|
|
1049
1224
|
this.registerVisitor(RootAST, this.visitRootAST);
|
|
1050
1225
|
this.registerVisitor(BlockStatementAST, this.visitBlockStatementAST);
|
|
@@ -1061,8 +1236,17 @@ class MEvento extends NodeVisitor {
|
|
|
1061
1236
|
this.registerVisitor(ObjectProperty, this.visitObjectProperty);
|
|
1062
1237
|
this.registerVisitor(ObjectExpression, this.visitObjectExpression);
|
|
1063
1238
|
this.registerVisitor(ArrayExpression, this.visitArrayExpression);
|
|
1239
|
+
this.registerVisitor(WhileLoopStatement, this.visitWhileLoopStatement);
|
|
1240
|
+
this.registerVisitor(ForLoopStatement, this.visitForLoopStatement);
|
|
1241
|
+
this.registerVisitor(ForOfStatement, this.visitForOfStatement);
|
|
1242
|
+
this.registerVisitor(BreakAST, this.visitBreakAST);
|
|
1064
1243
|
this._functionsRegistry = { ...MEvento._globalFunctionsRegistry };
|
|
1065
1244
|
}
|
|
1245
|
+
log(message) {
|
|
1246
|
+
if (this.debug) {
|
|
1247
|
+
console.log(message);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1066
1250
|
visitRootAST(node) {
|
|
1067
1251
|
const list = node.body;
|
|
1068
1252
|
let last;
|
|
@@ -1219,7 +1403,7 @@ class MEvento extends NodeVisitor {
|
|
|
1219
1403
|
if (testBoolValue) {
|
|
1220
1404
|
return this.visit(node.consequent);
|
|
1221
1405
|
}
|
|
1222
|
-
if (node.alternate
|
|
1406
|
+
if (node.alternate) {
|
|
1223
1407
|
return this.visit(node.alternate);
|
|
1224
1408
|
}
|
|
1225
1409
|
return null;
|
|
@@ -1267,6 +1451,85 @@ class MEvento extends NodeVisitor {
|
|
|
1267
1451
|
const args = this.resolveArguments(node.elements);
|
|
1268
1452
|
return args;
|
|
1269
1453
|
}
|
|
1454
|
+
visitBreakAST(node) {
|
|
1455
|
+
return new BreakBranch();
|
|
1456
|
+
}
|
|
1457
|
+
visitWhileLoopStatement(node) {
|
|
1458
|
+
this.log(`WhileLoopStatement ${node.test} ${node.body}`);
|
|
1459
|
+
const retainer = node.retain ? [] : undefined;
|
|
1460
|
+
while (_boolValue(this.visit(node.test))) {
|
|
1461
|
+
const ret = this.visit(node.body);
|
|
1462
|
+
if (ret instanceof BreakBranch) {
|
|
1463
|
+
break;
|
|
1464
|
+
}
|
|
1465
|
+
retainer?.push(ret);
|
|
1466
|
+
}
|
|
1467
|
+
return retainer || null;
|
|
1468
|
+
}
|
|
1469
|
+
visitForLoopStatement(node) {
|
|
1470
|
+
const retainer = node.retain ? [] : undefined;
|
|
1471
|
+
const loopIdentifier = node.init.identifier;
|
|
1472
|
+
if (!(loopIdentifier instanceof IdentifierAST))
|
|
1473
|
+
throw new Error("Unexpected identifer found");
|
|
1474
|
+
const initialValue = this.visit(node.init.init);
|
|
1475
|
+
this._memory[loopIdentifier.value] = initialValue;
|
|
1476
|
+
retainer?.push(initialValue);
|
|
1477
|
+
const test = () => {
|
|
1478
|
+
const ret = this.visit(node.test);
|
|
1479
|
+
if (isNum(ret)) {
|
|
1480
|
+
const tmp = this._memory[loopIdentifier.value];
|
|
1481
|
+
return node.direction.type === TokenType.up ? ret >= tmp : ret <= tmp;
|
|
1482
|
+
}
|
|
1483
|
+
return _boolValue(ret);
|
|
1484
|
+
};
|
|
1485
|
+
while (test()) {
|
|
1486
|
+
const ret = this.visit(node.body);
|
|
1487
|
+
if (ret instanceof BreakBranch) {
|
|
1488
|
+
break;
|
|
1489
|
+
}
|
|
1490
|
+
retainer?.push(ret);
|
|
1491
|
+
// update
|
|
1492
|
+
if (node.update instanceof LiteralAST && isNum(node.update.value)) {
|
|
1493
|
+
// auto handle
|
|
1494
|
+
const tmp = this._memory[loopIdentifier.value];
|
|
1495
|
+
if (!isNum(tmp))
|
|
1496
|
+
throw Error("Can update value");
|
|
1497
|
+
this._memory[loopIdentifier.value] = node.direction.type === TokenType.up ? tmp + node.update.value : tmp - node.update.value;
|
|
1498
|
+
}
|
|
1499
|
+
else {
|
|
1500
|
+
this.visit(node.update);
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
return retainer || null;
|
|
1504
|
+
}
|
|
1505
|
+
visitForOfStatement(node) {
|
|
1506
|
+
const collection = this.visit(node.collection);
|
|
1507
|
+
if (!Array.isArray(collection)) {
|
|
1508
|
+
throw Error("Can iterate non array object");
|
|
1509
|
+
}
|
|
1510
|
+
const retainer = node.retain ? [] : undefined;
|
|
1511
|
+
for (const it of collection) {
|
|
1512
|
+
this._declareForIdentifier(node.identifier, it);
|
|
1513
|
+
const ret = this.visit(node.body);
|
|
1514
|
+
if (ret instanceof BreakBranch) {
|
|
1515
|
+
break;
|
|
1516
|
+
}
|
|
1517
|
+
retainer?.push(ret);
|
|
1518
|
+
}
|
|
1519
|
+
return retainer || null;
|
|
1520
|
+
}
|
|
1521
|
+
_declareForIdentifier(node, value) {
|
|
1522
|
+
if (node instanceof TupleExpression) {
|
|
1523
|
+
if (!Array.isArray(value)) {
|
|
1524
|
+
throw Error("Unable to make a tuple from non Array element");
|
|
1525
|
+
}
|
|
1526
|
+
this._memory[node.first.value] = value[0];
|
|
1527
|
+
this._memory[node.second.value] = value[1];
|
|
1528
|
+
null;
|
|
1529
|
+
}
|
|
1530
|
+
this._memory[node.value] = value;
|
|
1531
|
+
null;
|
|
1532
|
+
}
|
|
1270
1533
|
resolveArguments(args) {
|
|
1271
1534
|
return args.map((it) => {
|
|
1272
1535
|
return this.visit(it);
|
|
@@ -1476,7 +1739,7 @@ class MEventoAsync extends MEvento {
|
|
|
1476
1739
|
if (testBoolValue) {
|
|
1477
1740
|
return await this.visit(node.consequent);
|
|
1478
1741
|
}
|
|
1479
|
-
if (node.alternate
|
|
1742
|
+
if (node.alternate) {
|
|
1480
1743
|
return await this.visit(node.alternate);
|
|
1481
1744
|
}
|
|
1482
1745
|
return null;
|
|
@@ -1524,6 +1787,70 @@ class MEventoAsync extends MEvento {
|
|
|
1524
1787
|
const args = await this.resolveArgumentsAsync(node.elements);
|
|
1525
1788
|
return args;
|
|
1526
1789
|
}
|
|
1790
|
+
async visitWhileLoopStatement(node) {
|
|
1791
|
+
this.log(`WhileLoopStatement ${node.test} ${node.body}`);
|
|
1792
|
+
const retainer = node.retain ? [] : undefined;
|
|
1793
|
+
while (_boolValue(this.visit(node.test))) {
|
|
1794
|
+
const ret = await this.visit(node.body);
|
|
1795
|
+
if (ret instanceof BreakBranch) {
|
|
1796
|
+
break;
|
|
1797
|
+
}
|
|
1798
|
+
retainer?.push(ret);
|
|
1799
|
+
}
|
|
1800
|
+
return retainer;
|
|
1801
|
+
}
|
|
1802
|
+
async visitForLoopStatement(node) {
|
|
1803
|
+
const retainer = node.retain ? [] : undefined;
|
|
1804
|
+
const loopIdentifier = node.init.identifier;
|
|
1805
|
+
if (!(loopIdentifier instanceof IdentifierAST))
|
|
1806
|
+
throw new Error("Unexpected identifer found");
|
|
1807
|
+
const initialValue = this.visit(node.init.init);
|
|
1808
|
+
this._memory[loopIdentifier.value] = initialValue;
|
|
1809
|
+
retainer?.push(initialValue);
|
|
1810
|
+
const test = () => {
|
|
1811
|
+
const ret = this.visit(node.test);
|
|
1812
|
+
if (isNum(ret)) {
|
|
1813
|
+
const tmp = this._memory[loopIdentifier.value];
|
|
1814
|
+
return node.direction.type === TokenType.up ? ret >= tmp : ret <= tmp;
|
|
1815
|
+
}
|
|
1816
|
+
return _boolValue(ret);
|
|
1817
|
+
};
|
|
1818
|
+
while (test()) {
|
|
1819
|
+
const ret = await this.visit(node.body);
|
|
1820
|
+
if (ret instanceof BreakBranch) {
|
|
1821
|
+
break;
|
|
1822
|
+
}
|
|
1823
|
+
retainer?.push(ret);
|
|
1824
|
+
// update
|
|
1825
|
+
if (node.update instanceof LiteralAST && isNum(node.update.value)) {
|
|
1826
|
+
// auto handle
|
|
1827
|
+
const tmp = this._memory[loopIdentifier.value];
|
|
1828
|
+
if (!isNum(tmp))
|
|
1829
|
+
throw Error("Can update value");
|
|
1830
|
+
this._memory[loopIdentifier.value] = node.direction.type === TokenType.up ? tmp + node.update.value : tmp - node.update.value;
|
|
1831
|
+
}
|
|
1832
|
+
else {
|
|
1833
|
+
this.visit(node.update);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
return retainer;
|
|
1837
|
+
}
|
|
1838
|
+
async visitForOfStatement(node) {
|
|
1839
|
+
const collection = this.visit(node.collection);
|
|
1840
|
+
if (!Array.isArray(collection)) {
|
|
1841
|
+
throw Error("Can iterate non array object");
|
|
1842
|
+
}
|
|
1843
|
+
const retainer = node.retain ? [] : undefined;
|
|
1844
|
+
for (const it of collection) {
|
|
1845
|
+
this._declareForIdentifier(node.identifier, it);
|
|
1846
|
+
const ret = await this.visit(node.body);
|
|
1847
|
+
if (ret instanceof BreakBranch) {
|
|
1848
|
+
break;
|
|
1849
|
+
}
|
|
1850
|
+
retainer?.push(ret);
|
|
1851
|
+
}
|
|
1852
|
+
return retainer;
|
|
1853
|
+
}
|
|
1527
1854
|
async resolveArgumentsAsync(args) {
|
|
1528
1855
|
return await Promise.all(args.map(async (it) => {
|
|
1529
1856
|
return await this.visit(it);
|
|
@@ -1545,9 +1872,6 @@ class MEventoAsync extends MEvento {
|
|
|
1545
1872
|
return await mevento.visit(module);
|
|
1546
1873
|
}
|
|
1547
1874
|
static newInstance() {
|
|
1548
|
-
// const lexer = Lexer(source);
|
|
1549
|
-
// const parser = Parser(lexer);
|
|
1550
|
-
// const module = parser.parse();
|
|
1551
1875
|
return new MEventoAsync();
|
|
1552
1876
|
}
|
|
1553
1877
|
clone() {
|