Bläddra i källkod

Rework command block parser

Add the ability to optionally use '{' '}' for some commands block

Add command parser to parse a single command
Lucas de Souza 6 år sedan
förälder
incheckning
7ec75fb532
1 ändrade filer med 79 tillägg och 46 borttagningar
  1. 79 46
      js/ast/ivprogParser.js

+ 79 - 46
js/ast/ivprogParser.js

@@ -85,18 +85,26 @@ export class IVProgParser {
     }
   }
 
-  checkOpenCurly () {
+  checkOpenCurly (attempt = false) {
     const token = this.getToken();
     if(this.lexerClass.OPEN_CURLY !== token.type){
-      throw SyntaxError.createError('{', token);
+      if(!attempt)
+        throw SyntaxError.createError('{', token);
+      else
+        return false;
     }
+    return true;
   }
 
-  checkCloseCurly () {
+  checkCloseCurly (attempt = false) {
     const token = this.getToken();
     if(this.lexerClass.CLOSE_CURLY !== token.type){
-      throw SyntaxError.createError('}', token);
+      if(!attempt)
+        throw SyntaxError.createError('}', token);
+      else
+        return false;
     }
+    return true;
   }
 
   /* It checks if the current token at position pos is a ']'.
@@ -457,59 +465,76 @@ export class IVProgParser {
     throw SyntaxError.createError(this.getTypesAsString(scope), token);
   }
 
-  parseCommandBlock (scope = IVProgParser.FUNCTION) {
+  parseCommandBlock (scope = IVProgParser.FUNCTION, optionalCurly = false) {
     let variablesDecl = [];
     const commands = [];
-    this.checkOpenCurly();
-    this.pos++;
+    let hasOpen = false;
+    if (this.checkOpenCurly(optionalCurly)) {
+      this.pos++;
+      hasOpen = true;
+    }
     this.consumeNewLines();
     while(true) {
-      const token = this.getToken();
-      let cmd = null;
-      if (this.isVariableType(token)) {
-        if(scope !== IVProgParser.FUNCTION) {
-          // TODO better error message
-          throw new Error(`Cannot declare variable here (line ${token.line})`);
-        }
-        this.pos++;
-        variablesDecl = variablesDecl.concat(this.parseDeclararion(token));
-        this.checkEOS();
-        this.pos++;
-        cmd = -1;
-      } else if (token.type === this.lexerClass.ID) {
-        cmd = this.parseIDCommand();
-      } else if (token.type === this.lexerClass.RK_RETURN) {
-        cmd = this.parseReturn();
-      } else if (token.type === this.lexerClass.RK_WHILE) {
-        cmd = this.parseWhile();
-      } else if (token.type === this.lexerClass.RK_FOR) {
-        cmd = this.parseFor();
-      } else if (token.type === this.lexerClass.RK_BREAK ) {
-        if(scope !== IVProgParser.BREAKABLE) {
-          // TODO better error message
-          throw new Error("Break cannot be used outside of a loop.");
-        }
-        cmd = this.parseBreak();
-      } else if (token.type === this.lexerClass.RK_SWITCH) {
-        cmd = this.parseSwitchCase();
-      } else if (token.type === this.lexerClass.RK_DO) {
-        cmd = this.parseDoWhile();
-      } else if (token.type === this.lexerClass.RK_IF) {
-        cmd = this.parseIfThenElse();
-      }
 
+      const cmd = this.parseCommand(scope);
       if (cmd === null)
         break;
-      if(cmd !== -1)
-        commands.push(cmd);
+      if(cmd !== -1) {
+        if (cmd instanceof Commands.Declaration) {
+          variablesDecl.push(cmd);
+        } else {
+          commands.push(cmd);
+        }
+      }
     }
     this.consumeNewLines();
-    this.checkCloseCurly();
-    this.pos++;
-    this.consumeNewLines();
+    if (hasOpen) {
+      this.checkCloseCurly()
+      this.pos++;
+      this.consumeNewLines();
+    }
     return new Commands.CommandBlock(variablesDecl, commands);
   }
 
+  parseCommand (scope) {
+    const token = this.getToken();
+    let cmd = null;
+    if (this.isVariableType(token)) {
+      if(scope !== IVProgParser.FUNCTION) {
+        // TODO better error message
+        throw new Error(`Cannot declare variable here (line ${token.line})`);
+      }
+      this.pos++;
+      cmd = this.parseDeclararion(token);
+      this.checkEOS();
+      this.pos++;
+    } else if (token.type === this.lexerClass.ID) {
+      cmd = this.parseIDCommand();
+    } else if (token.type === this.lexerClass.RK_RETURN) {
+      cmd = this.parseReturn();
+    } else if (token.type === this.lexerClass.RK_WHILE) {
+      cmd = this.parseWhile();
+    } else if (token.type === this.lexerClass.RK_FOR) {
+      cmd = this.parseFor();
+    } else if (token.type === this.lexerClass.RK_BREAK ) {
+      if(scope !== IVProgParser.BREAKABLE) {
+        // TODO better error message
+        throw new Error("Break cannot be used outside of a loop.");
+      }
+      cmd = this.parseBreak();
+    } else if (token.type === this.lexerClass.RK_SWITCH) {
+      cmd = this.parseSwitchCase();
+    } else if (token.type === this.lexerClass.RK_DO) {
+      cmd = this.parseDoWhile();
+    } else if (token.type === this.lexerClass.RK_IF) {
+      cmd = this.parseIfThenElse();
+    } else if (this.checkEOS(true)){
+      this.pos++;
+      cmd = -1;
+    }
+    return cmd;
+  }
+
   parseSwitchCase () {
     this.pos++;
     this.checkOpenParenthesis();
@@ -533,7 +558,7 @@ export class IVProgParser {
   parseDoWhile () {
     this.pos++;
     this.consumeNewLines();
-    const commandsBlock = this.parseCommandBlock();
+    const commandsBlock = this.parseCommandBlock(IVProgParser.BREAKABLE);
     this.consumeNewLines(); //Maybe not...
     const whileToken = this.getToken();
     if (whileToken !== this.lexerClass.RK_WHILE) {
@@ -666,6 +691,14 @@ export class IVProgParser {
     return new Commands.Assign(id, exp);
   }
 
+  parseCases () {
+    const token = this.getToken();
+    if(token.type !== this.lexerClass.RK_CASE) {
+      throw SyntaxError.createError(this.lexer.literalNames[this.lexerClass.RK_CASE], token);
+    }
+
+  }
+
   /*
   * Parses an Expression following the structure:
   *