Package com.google.minijoe.compiler

Source Code of com.google.minijoe.compiler.Parser

// Copyright 2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.minijoe.compiler;

import com.google.minijoe.compiler.ast.ArrayLiteral;
import com.google.minijoe.compiler.ast.AssignmentExpression;
import com.google.minijoe.compiler.ast.AssignmentOperatorExpression;
import com.google.minijoe.compiler.ast.BinaryOperatorExpression;
import com.google.minijoe.compiler.ast.BlockStatement;
import com.google.minijoe.compiler.ast.BooleanLiteral;
import com.google.minijoe.compiler.ast.BreakStatement;
import com.google.minijoe.compiler.ast.CallExpression;
import com.google.minijoe.compiler.ast.CaseStatement;
import com.google.minijoe.compiler.ast.ConditionalExpression;
import com.google.minijoe.compiler.ast.ContinueStatement;
import com.google.minijoe.compiler.ast.DeleteExpression;
import com.google.minijoe.compiler.ast.DoStatement;
import com.google.minijoe.compiler.ast.EmptyStatement;
import com.google.minijoe.compiler.ast.Expression;
import com.google.minijoe.compiler.ast.ExpressionStatement;
import com.google.minijoe.compiler.ast.ForInStatement;
import com.google.minijoe.compiler.ast.ForStatement;
import com.google.minijoe.compiler.ast.FunctionDeclaration;
import com.google.minijoe.compiler.ast.FunctionLiteral;
import com.google.minijoe.compiler.ast.Identifier;
import com.google.minijoe.compiler.ast.IfStatement;
import com.google.minijoe.compiler.ast.IncrementExpression;
import com.google.minijoe.compiler.ast.LabelledStatement;
import com.google.minijoe.compiler.ast.LogicalAndExpression;
import com.google.minijoe.compiler.ast.LogicalOrExpression;
import com.google.minijoe.compiler.ast.NewExpression;
import com.google.minijoe.compiler.ast.NullLiteral;
import com.google.minijoe.compiler.ast.NumberLiteral;
import com.google.minijoe.compiler.ast.ObjectLiteral;
import com.google.minijoe.compiler.ast.ObjectLiteralProperty;
import com.google.minijoe.compiler.ast.Program;
import com.google.minijoe.compiler.ast.PropertyExpression;
import com.google.minijoe.compiler.ast.ReturnStatement;
import com.google.minijoe.compiler.ast.Statement;
import com.google.minijoe.compiler.ast.StringLiteral;
import com.google.minijoe.compiler.ast.SwitchStatement;
import com.google.minijoe.compiler.ast.ThisLiteral;
import com.google.minijoe.compiler.ast.ThrowStatement;
import com.google.minijoe.compiler.ast.TryStatement;
import com.google.minijoe.compiler.ast.UnaryOperatorExpression;
import com.google.minijoe.compiler.ast.VariableDeclaration;
import com.google.minijoe.compiler.ast.VariableExpression;
import com.google.minijoe.compiler.ast.VariableStatement;
import com.google.minijoe.compiler.ast.WhileStatement;
import com.google.minijoe.compiler.ast.WithStatement;

import java.util.Vector;

/**
* @author Andy Hayward
*/
public class Parser {
  private Lexer lexer;
  private Token nextToken;
  private boolean seenNewline;

  public Parser(Lexer lexer) throws CompilerException {
    this.lexer = lexer;

    readToken();
  }

  //
  // program
  //

  public Program parseProgram() throws CompilerException {
    Vector statementVector = new Vector();

    statementVector.addElement(parseSourceElement());

    while (nextToken != Token.EOF) {
      statementVector.addElement(parseSourceElement());
    }

    return new Program(Util.vectorToStatementArray(statementVector));
  }

  //
  // Statements
  //

  public Statement parseSourceElement() throws CompilerException {
    if (nextToken == Token.KEYWORD_FUNCTION) {
      return parseFunctionDeclaration();
    } else {
      return parseStatement();
    }
  }

  private Statement parseFunctionDeclaration() throws CompilerException {
    return new FunctionDeclaration(parseFunctionLiteral(true));
  }

  public Statement parseStatement() throws CompilerException {
    Statement statement;
    int lineNumber;

    if (Config.LINENUMBER) {
      lineNumber = getLineNumber();
    }

    if (nextToken == Token.OPERATOR_SEMICOLON) {
      readToken(Token.OPERATOR_SEMICOLON);
      statement = new EmptyStatement();

    } else if (nextToken == Token.OPERATOR_OPENBRACE) {
      statement = parseBlockStatement();

    } else if (nextToken == Token.KEYWORD_BREAK) {
      statement = parseBreakStatement();

    } else if (nextToken == Token.KEYWORD_CONTINUE) {
      statement = parseContinueStatement();

    } else if (nextToken == Token.KEYWORD_DO) {
      statement = parseDoStatement();

    } else if (nextToken == Token.KEYWORD_FOR) {
      statement = parseForStatement();

    } else if (nextToken == Token.KEYWORD_IF) {
      statement = parseIfStatement();

    } else if (nextToken == Token.KEYWORD_RETURN) {
      statement = parseReturnStatement();

    } else if (nextToken == Token.KEYWORD_THROW) {
      statement = parseThrowStatement();

    } else if (nextToken == Token.KEYWORD_TRY) {
      statement = parseTryStatement();

    } else if (nextToken == Token.KEYWORD_SWITCH) {
      statement = parseSwitchStatement();

    } else if (nextToken == Token.KEYWORD_VAR) {
      statement = parseVariableStatement();

    } else if (nextToken == Token.KEYWORD_WHILE) {
      statement = parseWhileStatement();

    } else if (nextToken == Token.KEYWORD_WITH) {
      statement = parseWithStatement();

    } else {
      statement = parseExpressionStatement();

    }

    if (Config.LINENUMBER) {
      statement.setLineNumber(lineNumber);
    }

    return statement;
  }

  private Statement parseBlockStatement() throws CompilerException {
    readToken(Token.OPERATOR_OPENBRACE);

    Vector vector = new Vector();
    while (nextToken != Token.OPERATOR_CLOSEBRACE) {
      vector.addElement(parseStatement());
    }

    readToken(Token.OPERATOR_CLOSEBRACE);

    return new BlockStatement(Util.vectorToStatementArray(vector));
  }

  private Statement parseBreakStatement() throws CompilerException {
    Identifier identifier = null;

    readToken(Token.KEYWORD_BREAK);

    if (nextToken != Token.OPERATOR_SEMICOLON) {
      identifier = parseIdentifier();
    }

    readTokenSemicolon();

    return new BreakStatement(identifier);
  }

  private Statement parseContinueStatement() throws CompilerException {
    Identifier identifier = null;

    readToken(Token.KEYWORD_CONTINUE);

    if (nextToken != Token.OPERATOR_SEMICOLON) {
      identifier = parseIdentifier();
    }

    readTokenSemicolon();

    return new ContinueStatement(identifier);
  }

  private Statement parseDoStatement() throws CompilerException {
    Statement statement;
    Expression expression;

    readToken(Token.KEYWORD_DO);
    statement = parseStatement();
    readToken(Token.KEYWORD_WHILE);
    readToken(Token.OPERATOR_OPENPAREN);
    expression = parseExpression(true);
    readToken(Token.OPERATOR_CLOSEPAREN);

    return new DoStatement(statement, expression);
  }

  private Statement parseExpressionStatement() throws CompilerException {
    Expression expression = parseExpression(true);

    // TODO there are comments in the v8 code about wrapping a
    // labelled try statement in a block and applying the label to the outer
    // block. we should consider doing something similar here if handling a
    // labelled try block proves problematic.

    if (expression instanceof Identifier && nextToken == Token.OPERATOR_COLON) {
      readToken(Token.OPERATOR_COLON);
      return new LabelledStatement((Identifier) expression, parseStatement());
    } else {
      readTokenSemicolon();
      return new ExpressionStatement(expression);
    }
  }

  private Statement parseForStatement() throws CompilerException {
    Expression declaration = null;
    Expression initial = null;
    Expression condition = null;
    Expression increment = null;
    Expression variable = null;
    Expression expression = null;
    Statement statement = null;

    // 'for' statements can be one of the follow four productions:
    //
    // for ( ExpressionNoIn_opt; Expression_opt ; Expression_opt ) Statement
    // for ( var VariableDeclarationListNoIn; Expression_opt ; Expression_opt ) Statement
    // for ( LeftHandSideExpression in Expression ) Statement
    // for ( var VariableDeclarationNoIn in Expression ) Statement

    readToken(Token.KEYWORD_FOR);
    readToken(Token.OPERATOR_OPENPAREN);

    int state = 0;
    while (statement == null) {
      switch (state) {
        case 0:
          // initial state
          if (nextToken == Token.KEYWORD_VAR) {
            state = 1;
          } else if (nextToken != Token.OPERATOR_SEMICOLON) {
            state = 2;
          } else {
            state = 5;
          }
          break;

        case 1:
          // 'for' '(' 'var'
          readToken(Token.KEYWORD_VAR);
          declaration = parseVariableDeclaration(false);
          if (nextToken == Token.KEYWORD_IN) {
            variable = declaration;
            state = 3;
          } else {
            state = 4;
          }
          break;

        case 2:
          // 'for' '(' Expression
          initial = parseExpression(false);
          if (nextToken == Token.KEYWORD_IN) {
            variable = initial;
            state = 3;
          } else {
            state = 5;
          }
          break;

        case 3:
          // 'for' '(' ... 'in'
          readToken(Token.KEYWORD_IN);
          expression = parseExpression(true);
          readToken(Token.OPERATOR_CLOSEPAREN);

          // 'for' '(' ... 'in' ... ')' Statement
          statement = new ForInStatement(variable, expression, parseStatement());
          break;

        case 4:
          // 'for' '(' 'var' VariableDeclarationList
          Vector declarationVector = new Vector();

          declarationVector.addElement(declaration);
          while (nextToken == Token.OPERATOR_COMMA) {
            readToken(Token.OPERATOR_COMMA);
            declarationVector.addElement(parseVariableDeclaration(false));
          }
          initial = new VariableExpression(Util.vectorToDeclarationArray(declarationVector));

          // fall through

        case 5:
          // 'for' '(' ... ';'
          readToken(Token.OPERATOR_SEMICOLON);

          // 'for' '(' ... ';' ...
          if (nextToken != Token.OPERATOR_SEMICOLON) {
            condition = parseExpression(true);
          }

          // 'for' '(' ... ';' ... ';'
          readToken(Token.OPERATOR_SEMICOLON);

          // 'for' '(' ... ';' ... ';' ...
          if (nextToken != Token.OPERATOR_CLOSEPAREN) {
            increment = parseExpression(true);
          }

          // 'for' '(' ... ';' ... ';' ... ')'
          readToken(Token.OPERATOR_CLOSEPAREN);

          // 'for' '(' ... ';' ... ';' ... ')' Statement
          statement = new ForStatement(initial, condition, increment, parseStatement());
          break;
      }
    }

    return statement;
  }

  private Statement parseIfStatement() throws CompilerException {
    Expression expression = null;
    Statement trueStatement = null;
    Statement falseStatement = null;

    readToken(Token.KEYWORD_IF);
    readToken(Token.OPERATOR_OPENPAREN);
    expression = parseExpression(true);
    readToken(Token.OPERATOR_CLOSEPAREN);

    trueStatement = parseStatement();

    if (nextToken == Token.KEYWORD_ELSE) {
      readToken(Token.KEYWORD_ELSE);
      falseStatement = parseStatement();
    }

    return new IfStatement(expression, trueStatement, falseStatement);
  }

  private Statement parseReturnStatement() throws CompilerException {
    Expression result = null;

    readToken(Token.KEYWORD_RETURN);

    if (nextToken != Token.OPERATOR_SEMICOLON) {
      result = parseExpression(true);
    }

    readTokenSemicolon();

    return new ReturnStatement(result);
  }

  private Statement parseSwitchStatement() throws CompilerException {
    Vector caseClauseVector = new Vector();
    boolean defaultSeen = false;

    readToken(Token.KEYWORD_SWITCH);
    readToken(Token.OPERATOR_OPENPAREN);
    Expression switchExpression = parseExpression(true);
    readToken(Token.OPERATOR_CLOSEPAREN);

    readToken(Token.OPERATOR_OPENBRACE);

    while (nextToken != Token.OPERATOR_CLOSEBRACE) {
      Expression caseExpression = null;
      Vector caseStatements = new Vector();

      if (nextToken == Token.KEYWORD_CASE) {
        readToken(Token.KEYWORD_CASE);
        caseExpression = parseExpression(true);
        readToken(Token.OPERATOR_COLON);
      } else {
        if (defaultSeen == false) {
          defaultSeen = true;
        } else {
          throwCompilerException("duplication default clause in switch statement");
        }

        readToken(Token.KEYWORD_DEFAULT);
        caseExpression = null;
        readToken(Token.OPERATOR_COLON);
      }

      while (nextToken != Token.KEYWORD_CASE
          && nextToken != Token.KEYWORD_DEFAULT
          && nextToken != Token.OPERATOR_CLOSEBRACE) {
        caseStatements.addElement(parseStatement());
      }

      caseClauseVector.addElement(
          new CaseStatement(caseExpression, Util.vectorToStatementArray(caseStatements)));
    }

    readToken(Token.OPERATOR_CLOSEBRACE);

    CaseStatement[] caseClauseArray = new CaseStatement[caseClauseVector.size()];

    caseClauseVector.copyInto(caseClauseArray);

    return new SwitchStatement(switchExpression, caseClauseArray);
  }

  private Statement parseThrowStatement() throws CompilerException {
    readToken(Token.KEYWORD_THROW);

    return new ThrowStatement(parseExpression(true));
  }

  private Statement parseTryStatement() throws CompilerException {
    Statement tryBlock = null;
    Identifier catchIdentifier = null;
    Statement catchBlock = null;
    Statement finallyBlock = null;

    readToken(Token.KEYWORD_TRY);
    tryBlock = parseBlockStatement();

    if (nextToken != Token.KEYWORD_CATCH && nextToken != Token.KEYWORD_FINALLY) {
      throwCompilerException("catch or finally expected after try");
    }

    if (nextToken == Token.KEYWORD_CATCH) {
      readToken(Token.KEYWORD_CATCH);
      readToken(Token.OPERATOR_OPENPAREN);
      catchIdentifier = parseIdentifier();
      readToken(Token.OPERATOR_CLOSEPAREN);
      catchBlock = parseBlockStatement();
    }

    if (nextToken == Token.KEYWORD_FINALLY) {
      readToken(Token.KEYWORD_FINALLY);
      finallyBlock = parseBlockStatement();
    }

    return new TryStatement(tryBlock, catchIdentifier, catchBlock, finallyBlock);
  }

  private Statement parseVariableStatement() throws CompilerException {
    Vector declarationVector = new Vector();

    readToken(Token.KEYWORD_VAR);

    // there must be at least one variable declaration

    declarationVector.addElement(parseVariableDeclaration(true));
    while (nextToken == Token.OPERATOR_COMMA) {
      readToken(Token.OPERATOR_COMMA);
      declarationVector.addElement(parseVariableDeclaration(true));
    }

    readTokenSemicolon();

    return new VariableStatement(Util.vectorToDeclarationArray(declarationVector));
  }

  private Statement parseWhileStatement() throws CompilerException {
    Statement statement;
    Expression expression;

    readToken(Token.KEYWORD_WHILE);
    readToken(Token.OPERATOR_OPENPAREN);
    expression = parseExpression(true);
    readToken(Token.OPERATOR_CLOSEPAREN);
    statement = parseStatement();

    return new WhileStatement(expression, statement);
  }

  private Statement parseWithStatement() throws CompilerException {
    Statement statement;
    Expression expression;

    readToken(Token.KEYWORD_WITH);
    readToken(Token.OPERATOR_OPENPAREN);
    expression = parseExpression(true);
    readToken(Token.OPERATOR_CLOSEPAREN);
    statement = parseStatement();

    return new WithStatement(expression, statement);
  }

  //
  // Expressions
  //

  private VariableDeclaration parseVariableDeclaration(boolean inFlag) throws CompilerException {
    Identifier identifier = parseIdentifier();
    Expression initializer = null;

    if (nextToken == Token.OPERATOR_ASSIGNMENT) {
      readToken(Token.OPERATOR_ASSIGNMENT);
      initializer = parseAssignmentExpression(inFlag);
    }

    return new VariableDeclaration(identifier, initializer);
  }

  private Expression parseExpression(boolean inFlag) throws CompilerException {
    Expression left = parseAssignmentExpression(inFlag);

    // comma expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_COMMA) {
        readToken(Token.OPERATOR_COMMA);
        Expression right = parseAssignmentExpression(inFlag);
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_COMMA);
      } else {
        return left;
      }
    }
  }

  private Expression parseAssignmentExpression(boolean inFlag) throws CompilerException {
    Expression left = parseConditionalExpression(inFlag);

    // assignment expressions are right associative
    if (nextToken == Token.OPERATOR_ASSIGNMENT) {
      readToken();
      return new AssignmentExpression(left, parseAssignmentExpression(inFlag));
    } else if (nextToken == Token.OPERATOR_ASSIGNMENT
            || nextToken == Token.OPERATOR_MULTIPLYASSIGNMENT
            || nextToken == Token.OPERATOR_DIVIDEASSIGNMENT
            || nextToken == Token.OPERATOR_MODULOASSIGNMENT
            || nextToken == Token.OPERATOR_PLUSASSIGNMENT
            || nextToken == Token.OPERATOR_MINUSASSIGNMENT
            || nextToken == Token.OPERATOR_SHIFTLEFTASSIGNMENT
            || nextToken == Token.OPERATOR_SHIFTRIGHTASSIGNMENT
            || nextToken == Token.OPERATOR_SHIFTRIGHTUNSIGNEDASSIGNMENT
            || nextToken == Token.OPERATOR_BITWISEANDASSIGNMENT
            || nextToken == Token.OPERATOR_BITWISEORASSIGNMENT
            || nextToken == Token.OPERATOR_BITWISEXORASSIGNMENT) {
      Token op = nextToken;
      readToken();
      return new AssignmentOperatorExpression(left, parseAssignmentExpression(inFlag), op);
    } else {
      return left;
    }
  }

  private Expression parseConditionalExpression(boolean inFlag) throws CompilerException {
    Expression expression = parseLogicalOrExpression(inFlag);

    // conditional expressions are right associative
    if (nextToken == Token.OPERATOR_CONDITIONAL) {
      readToken(Token.OPERATOR_CONDITIONAL);
      Expression trueExpression = parseAssignmentExpression(inFlag);
      readToken(Token.OPERATOR_COLON);
      Expression falseExpression = parseAssignmentExpression(inFlag);
      return new ConditionalExpression(expression, trueExpression, falseExpression);
    } else {
      return expression;
    }
  }

  private Expression parseLogicalOrExpression(boolean inFlag) throws CompilerException {
    Expression left = parseLogicalAndExpression(inFlag);
    Expression right;

    // logical or expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_LOGICALOR) {
        readToken(Token.OPERATOR_LOGICALOR);
        right = parseLogicalAndExpression(inFlag);
        left = new LogicalOrExpression(left, right);
      } else {
        return left;
      }
    }
  }

  private Expression parseLogicalAndExpression(boolean inFlag) throws CompilerException {
    Expression left = parseBitwiseOrExpression(inFlag);
    Expression right;

    // logical and expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_LOGICALAND) {
        readToken(Token.OPERATOR_LOGICALAND);
        right = parseBitwiseOrExpression(inFlag);
        left = new LogicalAndExpression(left, right);
      } else {
        return left;
      }
    }
  }

  private Expression parseBitwiseOrExpression(boolean inFlag) throws CompilerException {
    Expression left = parseBitwiseXorExpression(inFlag);
    Expression right;

    // bitwise or expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_BITWISEOR) {
        readToken(Token.OPERATOR_BITWISEOR);
        right = parseBitwiseXorExpression(inFlag);
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_BITWISEOR);
      } else {
        return left;
      }
    }
  }

  private Expression parseBitwiseXorExpression(boolean inFlag) throws CompilerException {
    Expression left = parseBitwiseAndExpression(inFlag);
    Expression right;

    // bitwise xor expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_BITWISEXOR) {
        readToken(Token.OPERATOR_BITWISEXOR);
        right = parseBitwiseAndExpression(inFlag);
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_BITWISEXOR);
      } else {
        return left;
      }
    }
  }

  private Expression parseBitwiseAndExpression(boolean inFlag) throws CompilerException {
    Expression left = parseEqualityExpression(inFlag);
    Expression right;

    // bitwise and expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_BITWISEAND) {
        readToken(Token.OPERATOR_BITWISEAND);
        right = parseEqualityExpression(inFlag);
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_BITWISEAND);
      } else {
        return left;
      }
    }
  }

  private Expression parseEqualityExpression(boolean inFlag) throws CompilerException {
    Expression left = parseRelationalExpression(inFlag);
    Expression right;

    // equality expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_EQUALEQUAL) {
        readToken(Token.OPERATOR_EQUALEQUAL);
        right = parseRelationalExpression(inFlag);
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_EQUALEQUAL);
      } else if (nextToken == Token.OPERATOR_NOTEQUAL) {
        readToken(Token.OPERATOR_NOTEQUAL);
        right = parseRelationalExpression(inFlag);
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_NOTEQUAL);
      } else if (nextToken == Token.OPERATOR_EQUALEQUALEQUAL) {
        readToken(Token.OPERATOR_EQUALEQUALEQUAL);
        right = parseRelationalExpression(inFlag);
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_EQUALEQUALEQUAL);
      } else if (nextToken == Token.OPERATOR_NOTEQUALEQUAL) {
        readToken(Token.OPERATOR_NOTEQUALEQUAL);
        right = parseRelationalExpression(inFlag);
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_NOTEQUALEQUAL);
      } else {
        return left;
      }
    }
  }

  private Expression parseRelationalExpression(boolean inFlag) throws CompilerException {
    Expression left = parseShiftExpression();
    Expression right;

    // relational expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_LESSTHAN) {
        readToken(Token.OPERATOR_LESSTHAN);
        right = parseShiftExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_LESSTHAN);
      } else if (nextToken == Token.OPERATOR_GREATERTHAN) {
        readToken(Token.OPERATOR_GREATERTHAN);
        right = parseShiftExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_GREATERTHAN);
      } else if (nextToken == Token.OPERATOR_LESSTHANOREQUAL) {
        readToken(Token.OPERATOR_LESSTHANOREQUAL);
        right = parseShiftExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_LESSTHANOREQUAL);
      } else if (nextToken == Token.OPERATOR_GREATERTHANOREQUAL) {
        readToken(Token.OPERATOR_GREATERTHANOREQUAL);
        right = parseShiftExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_GREATERTHANOREQUAL);
      } else if (nextToken == Token.KEYWORD_INSTANCEOF) {
        readToken(Token.KEYWORD_INSTANCEOF);
        right = parseShiftExpression();
        left = new BinaryOperatorExpression(left, right, Token.KEYWORD_INSTANCEOF);
      } else if (inFlag && nextToken == Token.KEYWORD_IN) {
        readToken(Token.KEYWORD_IN);
        right = parseShiftExpression();
        left = new BinaryOperatorExpression(left, right, Token.KEYWORD_IN);
      } else {
        return left;
      }
    }
  }

  private Expression parseShiftExpression() throws CompilerException {
    Expression left = parseAdditionExpression();
    Expression right;

    // shift expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_SHIFTLEFT) {
        readToken(Token.OPERATOR_SHIFTLEFT);
        right = parseAdditionExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_SHIFTLEFT);
      } else if (nextToken == Token.OPERATOR_SHIFTRIGHT) {
        readToken(Token.OPERATOR_SHIFTRIGHT);
        right = parseAdditionExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_SHIFTRIGHT);
      } else if (nextToken == Token.OPERATOR_SHIFTRIGHTUNSIGNED) {
        readToken(Token.OPERATOR_SHIFTRIGHTUNSIGNED);
        right = parseAdditionExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_SHIFTRIGHTUNSIGNED);
      } else {
        return left;
      }
    }
  }

  private Expression parseAdditionExpression() throws CompilerException {
    Expression left = parseMultiplyExpression();
    Expression right;

    // addition expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_PLUS) {
        readToken(Token.OPERATOR_PLUS);
        right = parseMultiplyExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_PLUS);
      } else if (nextToken == Token.OPERATOR_MINUS) {
        readToken(Token.OPERATOR_MINUS);
        right = parseMultiplyExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_MINUS);
      } else {
        return left;
      }
    }
  }

  private Expression parseMultiplyExpression() throws CompilerException {
    Expression left = parseUnaryExpression();
    Expression right;

    // multiplicative expressions are left associative
    while (true) {
      if (nextToken == Token.OPERATOR_MULTIPLY) {
        readToken(Token.OPERATOR_MULTIPLY);
        right = parseUnaryExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_MULTIPLY);
      } else if (nextToken == Token.OPERATOR_DIVIDE) {
        readToken(Token.OPERATOR_DIVIDE);
        right = parseUnaryExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_DIVIDE);
      } else if (nextToken == Token.OPERATOR_MODULO) {
        readToken(Token.OPERATOR_MODULO);
        right = parseUnaryExpression();
        left = new BinaryOperatorExpression(left, right, Token.OPERATOR_MODULO);
      } else {
        return left;
      }
    }
  }

  private Expression parseUnaryExpression() throws CompilerException {
    // TODO parse '-' numeric literal directly into literals,
    // to ensure that -0 keeps its proper value.

    // unary expressions are right associative
    if (nextToken == Token.OPERATOR_PLUSPLUS) {
      readToken(Token.OPERATOR_PLUSPLUS);
      return new IncrementExpression(parseUnaryExpression(), 1, false);
    } else if (nextToken == Token.OPERATOR_MINUSMINUS) {
      readToken(Token.OPERATOR_MINUSMINUS);
      return new IncrementExpression(parseUnaryExpression(), -1, false);
    } else if (nextToken == Token.OPERATOR_PLUS
            || nextToken == Token.OPERATOR_MINUS
            || nextToken == Token.OPERATOR_BITWISENOT
            || nextToken == Token.OPERATOR_LOGICALNOT
            || nextToken == Token.KEYWORD_VOID
            || nextToken == Token.KEYWORD_TYPEOF) {
      Token token = nextToken;
      readToken();
      UnaryOperatorExpression result = new UnaryOperatorExpression(parseUnaryExpression(), token);
      return result;
    } else if (nextToken == Token.KEYWORD_DELETE) {
      readToken(Token.KEYWORD_DELETE);
      return new DeleteExpression(parseUnaryExpression());
    } else {
      return parsePostfixExpression();
    }
  }

  private Expression parsePostfixExpression() throws CompilerException {
    // TODO this can be merged with parseUnary().

    Expression expression = parseMemberExpression(false);

    // postfix expressions aren't associative
    if (nextToken == Token.OPERATOR_PLUSPLUS) {
      readToken(Token.OPERATOR_PLUSPLUS);
      return new IncrementExpression(expression, 1, true);
    } else if (nextToken == Token.OPERATOR_MINUSMINUS) {
      readToken(Token.OPERATOR_MINUSMINUS);
      return new IncrementExpression(expression, -1, true);
    } else {
      return expression;
    }
  }

  /**
   * The grammar for the 'new' keyword is a little complicated. The keyword
   * 'new' can occur in either a NewExpression (where its not followed by
   * an argument list) or in MemberExpresison (where it is followed by an
   * argument list). The intention seems to be that an argument list should
   * bind to any unmatched 'new' keyword to the left in the same expression
   * if possible, otherwise an argument list is taken as a call expression.
   *
   * Since the rest of the productions for NewExpressions and CallExpressions
   * are similar we roll these two into one routine with a parameter to
   * indicate whether we're currently parsing a 'new' expression or not.
   *
   * @param newFlag if we're currently parsing a 'new' expression
   * @return an expression
   */
  private Expression parseMemberExpression(boolean newFlag) throws CompilerException {
    Expression expression;

    // new expressions are right associative
    if (nextToken == Token.KEYWORD_NEW) {
      Expression name;

      readToken(Token.KEYWORD_NEW);
      name = parseMemberExpression(true);

      if (nextToken == Token.OPERATOR_OPENPAREN) {
        Expression[] arguments = parseArgumentList();
        expression = new NewExpression(name, arguments);
      } else {
        expression = new NewExpression(name, null);
      }

    } else if (nextToken == Token.KEYWORD_FUNCTION) {
      expression = parseFunctionLiteral(false);

    } else {
      expression = parsePrimaryExpression();
    }

    // call expressions are left associative
    while (true) {
      if (!newFlag && nextToken == Token.OPERATOR_OPENPAREN) {
        Expression[] arguments = parseArgumentList();
        expression = new CallExpression(expression, arguments);
      } else if (nextToken == Token.OPERATOR_OPENSQUARE) {
        readToken(Token.OPERATOR_OPENSQUARE);
        Expression property = parseExpression(true);
        readToken(Token.OPERATOR_CLOSESQUARE);
        expression = new PropertyExpression(expression, property);
      } else if (nextToken == Token.OPERATOR_DOT) {
        // transform x.bar to x["bar"]
        readToken(Token.OPERATOR_DOT);
        Identifier identifier = parseIdentifier();
        expression = new PropertyExpression(expression, new StringLiteral(identifier.string));
      } else {
        return expression;
      }
    }
  }

  private Expression[] parseArgumentList() throws CompilerException {
    Vector argumentVector = new Vector();

    readToken(Token.OPERATOR_OPENPAREN);

    if (nextToken != Token.OPERATOR_CLOSEPAREN) {
      argumentVector.addElement(parseAssignmentExpression(true));
      while (nextToken == Token.OPERATOR_COMMA) {
        readToken(Token.OPERATOR_COMMA);
        argumentVector.addElement(parseAssignmentExpression(true));
      }
    }

    readToken(Token.OPERATOR_CLOSEPAREN);

    return Util.vectorToExpressionArray(argumentVector);
  }

  private Expression parsePrimaryExpression() throws CompilerException {
    if (nextToken == Token.KEYWORD_THIS) {
      readToken(Token.KEYWORD_THIS);
      return new ThisLiteral();

    } else if (nextToken == Token.KEYWORD_NULL) {
      readToken(Token.KEYWORD_NULL);
      return new NullLiteral();

    } else if (nextToken == Token.KEYWORD_TRUE) {
      readToken(Token.KEYWORD_TRUE);
      return new BooleanLiteral(true);

    } else if (nextToken == Token.KEYWORD_FALSE) {
      readToken(Token.KEYWORD_FALSE);
      return new BooleanLiteral(false);

    } else if (nextToken == Token.OPERATOR_OPENPAREN) {
      readToken(Token.OPERATOR_OPENPAREN);
      Expression expression = parseExpression(true);
      readToken(Token.OPERATOR_CLOSEPAREN);
      return expression;

    } else if (nextToken == Token.OPERATOR_OPENBRACE) {
      return parseObjectLiteral();

    } else if (nextToken == Token.OPERATOR_OPENSQUARE) {
      return parseArrayLiteral();

    } else if (nextToken.isIdentifier()) {
      return parseIdentifier();

    } else if (nextToken.isStringLiteral()) {
      return parseStringLiteral();

    } else if (nextToken.isNumericLiteral()) {
      return parseNumericLiteral();

    } else {
      throwCompilerException("identifier or literal expected at token: " + nextToken);
     
    }
   
    return null;
  }

  private ArrayLiteral parseArrayLiteral() throws CompilerException {
    Vector arrayElements = new Vector();

    readToken(Token.OPERATOR_OPENSQUARE);

    while (nextToken != Token.OPERATOR_CLOSESQUARE) {
      if (nextToken == Token.OPERATOR_COMMA) {
        arrayElements.addElement(null);
      } else {
        arrayElements.addElement(parseAssignmentExpression(true));
      }

      if (nextToken != Token.OPERATOR_CLOSESQUARE) {
        readToken(Token.OPERATOR_COMMA);
      }
    }

    readToken(Token.OPERATOR_CLOSESQUARE);

    return new ArrayLiteral(Util.vectorToExpressionArray(arrayElements));
  }

  private FunctionLiteral parseFunctionLiteral(boolean nameFlag) throws CompilerException {
    Identifier name = null;
    Vector parameterVector = new Vector();
    Vector statementVector = new Vector();

    readToken(Token.KEYWORD_FUNCTION);

    if (nameFlag || nextToken != Token.OPERATOR_OPENPAREN) {
      name = parseIdentifier();
    }

    // function literals may have zero or more parameters.

    readToken(Token.OPERATOR_OPENPAREN);

    if (nextToken != Token.OPERATOR_CLOSEPAREN) {
      parameterVector.addElement(parseIdentifier());

      while (nextToken != Token.OPERATOR_CLOSEPAREN) {
        readToken(Token.OPERATOR_COMMA);
        parameterVector.addElement(parseIdentifier());
      }
    }

    readToken(Token.OPERATOR_CLOSEPAREN);

    // function literals are required the have at least one SourceElement.

    readToken(Token.OPERATOR_OPENBRACE);

    // statementVector.addElement(parseStatement());

    while (nextToken != Token.OPERATOR_CLOSEBRACE) {
      statementVector.addElement(parseSourceElement());
    }

    readToken(Token.OPERATOR_CLOSEBRACE);

    return new FunctionLiteral(name,
        Util.vectorToIdentifierArray(parameterVector),
        Util.vectorToStatementArray(statementVector)
    );
  }

  private ObjectLiteral parseObjectLiteral() throws CompilerException {
    Vector propertyVector = new Vector();

    readToken(Token.OPERATOR_OPENBRACE);

    while (nextToken != Token.OPERATOR_CLOSEBRACE) {
      propertyVector.addElement(parseObjectLiteralProperty());

      while (nextToken == Token.OPERATOR_COMMA) {
        readToken(Token.OPERATOR_COMMA);
        propertyVector.addElement(parseObjectLiteralProperty());
      }
    }

    readToken(Token.OPERATOR_CLOSEBRACE);

    ObjectLiteralProperty[] propertyArray = new ObjectLiteralProperty[propertyVector.size()];

    propertyVector.copyInto(propertyArray);

    return new ObjectLiteral(propertyArray);
  }

  private ObjectLiteralProperty parseObjectLiteralProperty() throws CompilerException {
    Expression propertyName = null;
    Expression propertyValue = null;

    if (nextToken.isIdentifier()) {
      propertyName = new StringLiteral(parseIdentifier().string);
    } else if (nextToken.isStringLiteral()) {
      propertyName = parseStringLiteral();
    } else if (nextToken.isNumericLiteral()) {
      propertyName = parseNumericLiteral();
    } else {
      throwCompilerException("identifier or numeric literal expected");
    }

    readToken(Token.OPERATOR_COLON);

    propertyValue = parseAssignmentExpression(true);

    return new ObjectLiteralProperty(propertyName, propertyValue);
  }

  private Identifier parseIdentifier() throws CompilerException {
    Identifier identifier = null;

    if (nextToken.getType() == Token.TYPE_IDENTIFIER) {
      identifier = new Identifier(nextToken.getValue());
    } else {
      throwCompilerException("identifier or numeric literal expected");
    }

    readToken();

    return identifier;
  }

  private StringLiteral parseStringLiteral() throws CompilerException {
    String string = null;

    if (nextToken.getType() == Token.TYPE_STRING) {
      string = nextToken.getValue();
    } else {
      throwCompilerException("string literal expected");
    }

    readToken();

    return new StringLiteral(string);
  }

  private NumberLiteral parseNumericLiteral() throws CompilerException {
    double value = 0.0;

    try {
      switch (nextToken.getType()) {
        case Token.TYPE_FLOAT:
          value = Double.parseDouble(nextToken.getValue());
          break;

        case Token.TYPE_DECIMAL:
          value = Long.parseLong(nextToken.getValue());
          break;

        case Token.TYPE_OCTAL:
          value = Long.parseLong(nextToken.getValue().substring(1), 8);
          break;

        case Token.TYPE_HEXADECIMAL:
          value = Long.parseLong(nextToken.getValue().substring(2), 16);
          break;

        default:
          throwCompilerException("numeric literal expected");
      }
    } catch (NumberFormatException e) {
      value = Double.NaN;
    }

    readToken();

    return new NumberLiteral(value);
  }

  //
  // Tokens
  //

  private int getLineNumber() {
    return lexer.getLineNumber();
  }

  private void readToken() throws CompilerException {
    seenNewline = false;

    do {
      nextToken = lexer.nextToken();

      if (nextToken.isEOF() || nextToken.isNewLine()) {
        seenNewline = true;
      }
    } while (nextToken.isWhitespace());
  }

  private void readToken(Token token) throws CompilerException {
    if (nextToken == token) {
      readToken();
    } else {
      throwCompilerException("expected '" + token.getValue() + "'");
    }
  }

  private void readTokenSemicolon() throws CompilerException {
    if (nextToken == Token.OPERATOR_SEMICOLON) {
      readToken();
    } else if (nextToken == Token.OPERATOR_CLOSEBRACE) {
      // semicolon insertion
    } else if (seenNewline) {
      // semicolon insertion
    } else {
      throwCompilerException("expected '" + Token.OPERATOR_SEMICOLON.getValue() + "'");
    }
  }
 
  private void throwCompilerException(String message) throws CompilerException {
    throw new CompilerException(message, getLineNumber());
  }
}
TOP

Related Classes of com.google.minijoe.compiler.Parser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.