mevento 2.0.6 → 2.1.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.
@@ -178,6 +178,15 @@ class Lexer {
178
178
  this._currentChar = this._source[this._position].charCodeAt(0);
179
179
  this._col++;
180
180
  }
181
+ _jump(n) {
182
+ this._position += n;
183
+ if (this._position >= this._source.length) {
184
+ this._currentChar = -1;
185
+ return;
186
+ }
187
+ this._currentChar = this._source[this._position].charCodeAt(0);
188
+ this._col += n;
189
+ }
181
190
  _pick() {
182
191
  if (this._position + 1 >= this._source.length) {
183
192
  return -1;
@@ -311,28 +320,62 @@ class Lexer {
311
320
  const lastL = this._line;
312
321
  while (this._currentChar !== -1) {
313
322
  const next = String.fromCharCode(this._pick());
314
- if (this._currentChar === Chars.backslash) {
315
- // scape char
316
- if ([
317
- startChar,
318
- '\\',
319
- '0',
320
- 'a',
321
- 'b',
322
- 'e',
323
- 'f',
324
- 'n',
325
- 'r',
326
- 't',
327
- 'u',
328
- 'U',
329
- 'v',
330
- 'x'
331
- ].includes(next)) {
332
- lastChar = this._currentChar;
333
- this._advance();
334
- continue;
323
+ if (this._currentChar == Chars.backslash) {
324
+ switch (next) {
325
+ case '\\':
326
+ ret += "\\";
327
+ break;
328
+ case '0':
329
+ ret += "\0";
330
+ break;
331
+ case 'a':
332
+ ret += "\a";
333
+ break;
334
+ case 'b':
335
+ ret += "\b";
336
+ break;
337
+ case 'f':
338
+ ret += "\f";
339
+ break;
340
+ case 'n':
341
+ ret += "\n";
342
+ break;
343
+ case 'r':
344
+ ret += "\r";
345
+ break;
346
+ case 't':
347
+ ret += "\t";
348
+ break;
349
+ case 'u':
350
+ ret += String.fromCharCode(Number.parseInt(this._source.substring(this._position + 2, this._position + 6), 16));
351
+ this._jump(4);
352
+ // consume 4 unicode chars
353
+ break;
354
+ case 'v':
355
+ ret += "\v";
356
+ break;
357
+ case 'x':
358
+ ret += String.fromCharCode(Number.parseInt(this._source.substring(this._position + 2, this._position + 4), 16));
359
+ this._jump(2);
360
+ break;
361
+ default:
362
+ {
363
+ if (String.fromCharCode(startChar) == next) {
364
+ ret += String.fromCharCode(startChar);
365
+ }
366
+ else {
367
+ this._advance();
368
+ lastChar = this._currentChar;
369
+ ret += String.fromCharCode(this._currentChar);
370
+ this._advance();
371
+ continue;
372
+ }
373
+ }
335
374
  }
375
+ // scape char
376
+ this._jump(2);
377
+ lastChar = this._currentChar;
378
+ continue;
336
379
  }
337
380
  if (this._currentChar === startChar && lastChar !== Chars.backslash) {
338
381
  // end
@@ -798,8 +841,33 @@ class ContinueAST extends AST {
798
841
  super(line, col);
799
842
  }
800
843
  }
844
+ class ListQueue {
845
+ constructor(capacity = Infinity) {
846
+ this.capacity = capacity;
847
+ this.storage = [];
848
+ }
849
+ push(item) {
850
+ if (this.size() === this.capacity) {
851
+ throw Error("Stack has reached max capacity, you cannot add more items");
852
+ }
853
+ this.storage.push(item);
854
+ }
855
+ pop() {
856
+ return this.storage.pop();
857
+ }
858
+ peek() {
859
+ return this.storage[this.size() - 1];
860
+ }
861
+ size() {
862
+ return this.storage.length;
863
+ }
864
+ get isEmpty() {
865
+ return this.storage.length === 0;
866
+ }
867
+ }
801
868
  class Parser {
802
869
  constructor(lexer) {
870
+ this._loopTrack = new ListQueue();
803
871
  this.currentToken = lexer.nextToken();
804
872
  this.lexer = lexer;
805
873
  }
@@ -873,10 +941,32 @@ class Parser {
873
941
  return this._objectExpression();
874
942
  case TokenType.IF:
875
943
  return this._ifStatement();
944
+ case TokenType.WHILE_TILL:
945
+ return this._whileLoop(true);
946
+ case TokenType.FOR_LOOP:
947
+ return this._forLoop(true);
948
+ case TokenType.BREAK:
949
+ return this._breakExpression();
950
+ case TokenType.CONTINUE:
951
+ return this._continueExpression();
876
952
  default:
877
953
  return this._variable();
878
954
  }
879
955
  }
956
+ _breakExpression() {
957
+ if (this._loopTrack.isEmpty) {
958
+ error(this.currentToken);
959
+ }
960
+ this._eat(TokenType.BREAK);
961
+ return new BreakAST(this.currentToken?.line, this.currentToken?.col);
962
+ }
963
+ _continueExpression() {
964
+ if (this._loopTrack.isEmpty) {
965
+ error(this.currentToken);
966
+ }
967
+ this._eat(TokenType.CONTINUE);
968
+ return new ContinueAST(this.currentToken?.line, this.currentToken?.col);
969
+ }
880
970
  _term() {
881
971
  let node = this._factor();
882
972
  node = this._tryParsingFunctionCall(node);
@@ -1111,12 +1201,20 @@ class Parser {
1111
1201
  }
1112
1202
  return new IfStatementAST(test, consequent, alternate);
1113
1203
  }
1114
- _whileLoop() {
1204
+ _pushLoop() {
1205
+ this._loopTrack.push(true);
1206
+ }
1207
+ _popLoop() {
1208
+ this._loopTrack.pop();
1209
+ }
1210
+ _whileLoop(retain = false) {
1115
1211
  const token = this.currentToken;
1116
1212
  this._eat(TokenType.WHILE_TILL);
1213
+ this._pushLoop();
1117
1214
  const test = this._expression();
1118
1215
  const body = this.currentToken.type === TokenType.lbrace ? this._blockStatement() : this._expression();
1119
- return new WhileLoopStatement(test, body, token, this.currentToken);
1216
+ this._popLoop();
1217
+ return new WhileLoopStatement(test, body, token, this.currentToken, retain);
1120
1218
  }
1121
1219
  _forOfIdentifier() {
1122
1220
  switch (this.currentToken.type) {
@@ -1142,9 +1240,10 @@ class Parser {
1142
1240
  * }
1143
1241
  * (seginka|for) mali kono a
1144
1242
  */
1145
- _forLoop() {
1243
+ _forLoop(retain = false) {
1146
1244
  const startToken = this.currentToken;
1147
1245
  this._eat(TokenType.FOR_LOOP);
1246
+ this._pushLoop();
1148
1247
  let forOf = [TokenType.lparen].includes(this.currentToken.type);
1149
1248
  let node;
1150
1249
  if (forOf) {
@@ -1180,13 +1279,15 @@ class Parser {
1180
1279
  update = new LiteralAST(new Token(TokenType.numberConst, 1, this.currentToken.line, this.currentToken.col), "1");
1181
1280
  }
1182
1281
  const body = (this.currentToken.type === TokenType.lbrace) ? this._blockStatement() : this._expression();
1183
- node = new ForLoopStatement(node, test, update, direction, body, startToken, this.currentToken);
1282
+ node = new ForLoopStatement(node, test, update, direction, body, startToken, this.currentToken, retain);
1283
+ this._popLoop();
1184
1284
  }
1185
1285
  else if (forOf) {
1186
1286
  this._eat(TokenType.in);
1187
1287
  const collection = this._expression();
1188
1288
  const body = (this.currentToken.type === TokenType.lbrace) ? this._blockStatement() : this._expression();
1189
- node = new ForOfStatement(node, collection, body, startToken, this.currentToken);
1289
+ node = new ForOfStatement(node, collection, body, startToken, this.currentToken, retain);
1290
+ this._popLoop();
1190
1291
  }
1191
1292
  else {
1192
1293
  error(this.currentToken);
@@ -1196,11 +1297,9 @@ class Parser {
1196
1297
  _statement() {
1197
1298
  switch (this.currentToken.type) {
1198
1299
  case TokenType.BREAK:
1199
- this._eat(TokenType.BREAK);
1200
- return new BreakAST(this.currentToken?.line, this.currentToken?.col);
1300
+ return this._breakExpression();
1201
1301
  case TokenType.CONTINUE:
1202
- this._eat(TokenType.CONTINUE);
1203
- return new ContinueAST(this.currentToken?.line, this.currentToken?.col);
1302
+ return this._continueExpression();
1204
1303
  case TokenType.RETURN:
1205
1304
  this._eat(TokenType.RETURN);
1206
1305
  return this._return();
@@ -1648,7 +1747,7 @@ class MEvento extends NodeVisitor {
1648
1747
  this.pushScope("ForLoopStatement");
1649
1748
  const initialValue = this.visit(node.init.init);
1650
1749
  this.changeVariable(loopIdentifier.value, initialValue);
1651
- retainer?.push(initialValue);
1750
+ // retainer?.push(initialValue)
1652
1751
  const test = () => {
1653
1752
  const ret = this.visit(node.test);
1654
1753
  if (isNum(ret)) {
@@ -2056,7 +2155,7 @@ class MEventoAsync extends MEvento {
2056
2155
  this.pushScope("ForLoopStatement");
2057
2156
  const initialValue = await this.visit(node.init.init);
2058
2157
  this.changeVariable(loopIdentifier.value, initialValue);
2059
- retainer?.push(initialValue);
2158
+ // retainer?.push(initialValue)
2060
2159
  const test = async () => {
2061
2160
  const ret = await this.visit(node.test);
2062
2161
  if (isNum(ret)) {