Procházet zdrojové kódy

Implement ast parsing for the new for structure

Lucas de Souza před 5 roky
rodič
revize
58d10dc2c1
2 změnil soubory, kde provedl 79 přidání a 33 odebrání
  1. 5 4
      js/ast/commands/for.js
  2. 74 29
      js/ast/ivprogParser.js

+ 5 - 4
js/ast/commands/for.js

@@ -2,11 +2,12 @@ import { Command } from './command';
 
 export class For extends Command {
 
-  constructor (assignment, condition, increment, commandBlock) {
+  constructor (for_id, for_from, for_to, for_pass, commandBlock) {
     super();
-    this.assignment = assignment;
-    this.condition = condition;
-    this.increment = increment;
+    this.for_id = for_id;
+    this.for_from = for_from;
+    this.for_to = for_to;
+    this.for_pass = for_pass;
     this.commandBlock = commandBlock;
   }
 

+ 74 - 29
js/ast/ivprogParser.js

@@ -891,21 +891,21 @@ export class IVProgParser {
 
   parseFor () {
     this.pushScope(IVProgParser.BREAKABLE);
-    this.pos++;
-    this.checkOpenParenthesis();
-    this.pos++;
-    this.consumeNewLines();
-    const attribution = this.parseForAssign();
-    this.consumeNewLines();
-    const condition = this.parseExpressionOR();
-    this.consumeForSemiColon();
-    const increment = this.parseForAssign(true);
-    this.checkCloseParenthesis()
-    this.pos++;
+    const for_token = this.getToken();
+    this.pos += 1;
+    const for_id = this.parseID();
+    const for_from = this.parseForFrom();
+    const for_to = this.parseForTo();
+    let maybePass = this.parseForPass();
+    if (maybePass == null) {
+      maybePass = new Expressions.IntLiteral(toInt(1));
+    }
     this.consumeNewLines();
     const commandsBlock = this.parseCommandBlock();
     this.popScope();
-    return new Commands.For(attribution, condition, increment, commandsBlock);
+    const cmd = new Commands.For(for_id, for_from, for_to, maybePass, commandsBlock);
+    cmd.sourceInfo = SourceInfo.createSourceInfo(for_token);
+    return cmd;
   }
 
   parseWhile () {
@@ -999,26 +999,71 @@ export class IVProgParser {
     }
   }
 
-  parseForAssign (isLast = false) {
-    if(!isLast)
-      this.consumeNewLines();
-    if(this.checkEOS(true)) {
+  parseForFrom () {
+    const from_token = this.getToken();
+    if (from_token.type !== this.lexerClass.RK_FOR_FROM) {
+      // TODO better error message
+      const keyword = this.lexer.literalNames[this.lexerClass.RK_FOR_FROM];
+      throw new Error("Error de sintaxe no comando repita_para: esperava-se "+keyword+" mas encontrou "+from_token.text);
+    }
+    this.pos += 1;
+    const int_or_id = this.getToken();
+    if (int_or_id.type === this.lexerClass.ID) {
+      return this.parseID();
+    } else if (int_or_id.type === this.lexerClass.INTEGER) {
+      this.pos += 1;
+      return this.getIntLiteral(int_or_id);
+    } else {
+      // TODO better error message
+      const keyword = this.lexer.literalNames[this.lexerClass.RK_FOR_FROM];      
+      throw new Error("Error de sintaxe no comando repeita_para: "+ int_or_id.text + " não é compativel com o esperado para o paramentro "+ keyword + ". O valor deve ser um inteiro ou variável.");
+    }
+  }
+
+  parseForTo () {
+    const from_token = this.getToken();
+    if (from_token.type !== this.lexerClass.RK_FOR_TO) {
+      // TODO better error message
+      const keyword = this.lexer.literalNames[this.lexerClass.RK_FOR_TO];
+      throw new Error("Error de sintaxe no comando repita_para: esperava-se "+keyword+" mas encontrou "+from_token.text);
+    }
+    this.pos += 1;
+    const int_or_id = this.getToken();
+    if (int_or_id.type === this.lexerClass.ID) {
+      return this.parseID();
+    } else if (int_or_id.type === this.lexerClass.INTEGER) {
+      this.pos += 1;
+      return this.getIntLiteral(int_or_id);
+    } else {
+      // TODO better error message
+      const keyword = this.lexer.literalNames[this.lexerClass.RK_FOR_TO];      
+      throw new Error("Error de sintaxe no comando repeita_para: "+ int_or_id.text + " não é compativel com o esperado para o paramentro "+ keyword + ". O valor deve ser um inteiro ou variável.");
+    }
+  }
+
+  parseForPass () {
+    this.consumeNewLines();
+    if(this.checkOpenCurly(true)) {
       return null;
     }
-    const id = this.parseID();
-    const equal = this.getToken();
-    if (equal.type !== this.lexerClass.EQUAL) {
-      throw SyntaxErrorFactory.token_missing_one('=', equal);
+    const from_token = this.getToken();
+    if (from_token.type !== this.lexerClass.RK_FOR_PASS) {
+      // TODO better error message
+      const keyword = this.lexer.literalNames[this.lexerClass.RK_FOR_TO];
+      throw new Error("Error de sintaxe no comando repita_para: esperava-se "+keyword+" mas encontrou "+from_token.text);
     }
-    this.pos++
-    const exp = this.parseExpressionOR();
-    if(!isLast) {
-      this.consumeForSemiColon();
+    this.pos += 1;
+    const int_or_id = this.getToken();
+    if (int_or_id.type === this.lexerClass.ID) {
+      return this.parseID();
+    } else if (int_or_id.type === this.lexerClass.INTEGER) {
+      this.pos += 1;
+      return this.getIntLiteral(int_or_id);
+    } else {
+      // TODO better error message
+      const keyword = this.lexer.literalNames[this.lexerClass.RK_FOR_PASS];      
+      throw new Error("Error de sintaxe no comando repeita_para: "+ int_or_id.text + " não é compativel com o esperado para o paramentro "+ keyword + ". O valor deve ser um inteiro ou variável.");
     }
-    const sourceInfo = SourceInfo.createSourceInfo(equal);
-    const cmd = new Commands.Assign(id, exp);
-    cmd.sourceInfo = sourceInfo;
-    return cmd;
   }
 
   parseCases () {
@@ -1318,4 +1363,4 @@ export class IVProgParser {
     const types = this.insideScope(IVProgParser.FUNCTION) ? this.functionTypes : this.variableTypes;
     return types.map( x => this.lexer.literalNames[x]);
   }
-}
+}