internal AstListItem(AST term, AstListItem prev){ _prev = prev; _term = term; }
internal AstListItem(AST term, AstListItem prev) { this._prev = prev; this._term = term; }
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; }