示例#1
0
      private AST ParseExpression(AST leftHandSide, bool single, bool bCanAssign, JSToken inToken){
        OpListItem opsStack = new OpListItem(JSToken.None, OpPrec.precNone, null); // dummy element
        AstListItem termStack = new AstListItem(leftHandSide, null);

        AST expr = null;

        try{
          for (;;){
            // if 'binary op' or 'conditional' but not 'comma'
            // inToken is a special case because of the for..in crap. When ParseExpression is called from
            // for, inToken = JSToken.In which excludes JSToken.In from the list of operators, otherwise
            // inToken = JSToken.None which is always true if the first condition is true
            if (JSScanner.IsProcessableOperator(this.currentToken.token) && inToken != this.currentToken.token){

              OpPrec prec = JSScanner.GetOperatorPrecedence(this.currentToken.token);
              bool rightAssoc = JSScanner.IsRightAssociativeOperator(this.currentToken.token);
              // the current operator has lower precedence than the operator at the top of the stack
              // or it has the same precedence and it is left associative (that is, no 'assign op' or 'conditional')
              while (prec < opsStack._prec || prec == opsStack._prec && !rightAssoc){
                //Console.Out.WriteLine("lower prec or same and left assoc");
                expr = CreateExpressionNode(opsStack._operator, termStack._prev._term, termStack._term);

                // pop the operator stack
                opsStack = opsStack._prev;
                // pop the term stack twice
                termStack = termStack._prev._prev;
                // push node onto the stack
                termStack = new AstListItem(expr, termStack);
              }

              // the current operator has higher precedence that every scanned operators on the stack, or
              // it has the same precedence as the one at the top of the stack and it is right associative

              // push operator and next term

              // special case conditional '?:'
              if (JSToken.ConditionalIf == this.currentToken.token){
                //Console.Out.WriteLine("Condition expression");

                AST condition = termStack._term;
                // pop term stack
                termStack = termStack._prev;

                GetNextToken();

                // get expr1 in logOrExpr ? expr1 : expr2
                AST operand1 = ParseExpression(true);

                if (JSToken.Colon != this.currentToken.token)
                  ReportError(JSError.NoColon);
                GetNextToken();

                // get expr2 in logOrExpr ? expr1 : expr2
                AST operand2 = ParseExpression(true, inToken);

                expr = new Conditional(condition.context.CombineWith(operand2.context), condition, operand1, operand2);
                termStack = new AstListItem(expr, termStack);
              }else{
                //Console.Out.WriteLine("higher prec or right assoc");

                if (JSScanner.IsAssignmentOperator(this.currentToken.token)){
                  if (!bCanAssign){
                    ReportError(JSError.IllegalAssignment);
                    SkipTokensAndThrow();
                  }
                }else
                  bCanAssign = false;

                // push the operator onto the operators stack
                opsStack = new OpListItem(this.currentToken.token, prec, opsStack);
                // push new term
                GetNextToken();
                if (bCanAssign)
                  termStack = new AstListItem(ParseUnaryExpression(out bCanAssign, false), termStack);
                else{
                  bool dummy;
                  termStack = new AstListItem(ParseUnaryExpression(out dummy, false), termStack);
                  dummy = dummy;
                }
              }
            }else
              break; // done, go and unwind the stack of expressions/operators
          }

          //Console.Out.WriteLine("unwinding stack");
          // there are still operators to be processed
          while (opsStack._operator != JSToken.None){
            // make the ast operator node
            expr = CreateExpressionNode(opsStack._operator, termStack._prev._term, termStack._term);

            // pop the operator stack
            opsStack = opsStack._prev;
            // pop the term stack twice
            termStack = termStack._prev._prev;

            // push node onto the stack
            termStack = new AstListItem(expr, termStack);
          }

          // if we have a ',' and we are not looking for a single expression reenter
          if (!single && JSToken.Comma == this.currentToken.token){
            //Console.Out.WriteLine("Next expr");
            GetNextToken();
            AST expr2 = ParseExpression(false, inToken);
            termStack._term = new Comma(termStack._term.context.CombineWith(expr2.context), termStack._term, expr2);
          }

          Debug.Assert(termStack._prev == null);
          return termStack._term;
        }catch(RecoveryTokenException exc){
          exc._partiallyComputedNode = leftHandSide;
          throw exc;
        }
      }
 private AST ParseExpression(AST leftHandSide, bool single, bool bCanAssign, JSToken inToken)
 {
     AST ast6;
     OpListItem prev = new OpListItem(JSToken.None, OpPrec.precNone, null);
     AstListItem item2 = new AstListItem(leftHandSide, null);
     AST term = null;
     try
     {
         while (true)
         {
             if (!JSScanner.IsProcessableOperator(this.currentToken.token) || (inToken == this.currentToken.token))
             {
                 goto Label_01E0;
             }
             OpPrec operatorPrecedence = JSScanner.GetOperatorPrecedence(this.currentToken.token);
             bool flag = JSScanner.IsRightAssociativeOperator(this.currentToken.token);
             while ((operatorPrecedence < prev._prec) || ((operatorPrecedence == prev._prec) && !flag))
             {
                 term = this.CreateExpressionNode(prev._operator, item2._prev._term, item2._term);
                 prev = prev._prev;
                 item2 = item2._prev._prev;
                 item2 = new AstListItem(term, item2);
             }
             if (JSToken.ConditionalIf == this.currentToken.token)
             {
                 AST condition = item2._term;
                 item2 = item2._prev;
                 this.GetNextToken();
                 AST ast3 = this.ParseExpression(true);
                 if (JSToken.Colon != this.currentToken.token)
                 {
                     this.ReportError(JSError.NoColon);
                 }
                 this.GetNextToken();
                 AST ast4 = this.ParseExpression(true, inToken);
                 term = new Conditional(condition.context.CombineWith(ast4.context), condition, ast3, ast4);
                 item2 = new AstListItem(term, item2);
             }
             else
             {
                 if (JSScanner.IsAssignmentOperator(this.currentToken.token))
                 {
                     if (!bCanAssign)
                     {
                         this.ReportError(JSError.IllegalAssignment);
                         this.SkipTokensAndThrow();
                     }
                 }
                 else
                 {
                     bCanAssign = false;
                 }
                 prev = new OpListItem(this.currentToken.token, operatorPrecedence, prev);
                 this.GetNextToken();
                 if (bCanAssign)
                 {
                     item2 = new AstListItem(this.ParseUnaryExpression(out bCanAssign, false), item2);
                 }
                 else
                 {
                     bool flag2;
                     item2 = new AstListItem(this.ParseUnaryExpression(out flag2, false), item2);
                     flag2 = flag2;
                 }
             }
         }
     Label_01A7:
         term = this.CreateExpressionNode(prev._operator, item2._prev._term, item2._term);
         prev = prev._prev;
         item2 = item2._prev._prev;
         item2 = new AstListItem(term, item2);
     Label_01E0:
         if (prev._operator != JSToken.None)
         {
             goto Label_01A7;
         }
         if (!single && (JSToken.Comma == this.currentToken.token))
         {
             this.GetNextToken();
             AST ast5 = this.ParseExpression(false, inToken);
             item2._term = new Comma(item2._term.context.CombineWith(ast5.context), item2._term, ast5);
         }
         ast6 = item2._term;
     }
     catch (RecoveryTokenException exception)
     {
         exception._partiallyComputedNode = leftHandSide;
         throw exception;
     }
     return ast6;
 }