private void ParseAst(JS.AST ast, string sp) { if (ast == null) { return; } if (CheckWorker()) { return; } //_logView.LogStr("JSM->" + sp + ast.ToString() + "\t\t" + ast.GetType().Name); if (ast is JS.FunctionDeclaration) { JS.Function func = ast as JS.Function; ParseAstList(func.func_obj.body.elems, sp + " "); } else if (ast is JS.Assign) { JS.Assign ass = ast as JS.Assign; ParseAst(ass.left, sp + "l "); ParseAst(ass.right, sp + "r "); } else if (ast is JS.Binary) { JS.Binary bin = ast as JS.Binary; string[] parts = bin.ToString().Split('.'); if (parts.Length > 1) { if (parts[parts.Length - 2] == "This") { string calledId = parts[parts.Length - 1] + "()"; //dup // If we have a method of this name in this file/class if (_addedNodes.ContainsKey(calledId)) { // Create an edge. // A definite functional assignment link. AddEdge(_methodNodeId, calledId, EdgeStyle.NormalArrow, Color.Aqua); } else { // It's a call to a method outside this class/file. // //_logView.LogStr("skipped assign ref -->" + _methodNodeId + " --------> " + calledId); // } } else if (parts[parts.Length - 2] == "self") { string calledId = parts[parts.Length - 1] + "()"; //dup // If we have a method of this name in this file/class if (_addedNodes.ContainsKey(calledId)) { // Get the graph node that we're linking to. //Node calledNode = _addedNodes[calledId]; // Create an edge. // A definite functional assignment link. AddEdge(_methodNodeId, calledId, EdgeStyle.NormalArrow, Color.Aqua); } else { // It's a call to a method outside this class/file. _logView.LogStr("skipped assign ref -->" + _methodNodeId + " --------> " + calledId); } } } } else if (ast is JS.Expression) { JS.Expression expr = ast as JS.Expression; ParseAstList(expr.exprs, sp + " "); } else if (ast is JS.FunctionExpression) { JS.FunctionExpression expr = ast as JS.FunctionExpression; ParseAstList(expr.func_obj.body.elems, sp + " "); } else if (ast is JS.For) { JS.For fr = ast as JS.For; ParseAst(fr.stms, sp + " "); } else if (ast is JS.If) { JS.If iff = ast as JS.If; ParseAst(iff.false_stm, sp + "f "); ParseAst(iff.true_stm, sp + "t "); } else if (ast is JS.Block) { JS.Block block = ast as JS.Block; ParseAstList(block.elems, sp + " "); } else if (ast is JS.VariableStatement) { JS.VariableStatement var = ast as JS.VariableStatement; //var. ParseAstList(var.var_decls, sp + " "); } else if (ast is JS.Return) { JS.Return ret = ast as JS.Return; ParseAst(ret.expression, sp + " "); } else if (ast is JS.VariableDeclaration) { JS.VariableDeclaration var = ast as JS.VariableDeclaration; Microsoft.JScript.New newval = var.val as Microsoft.JScript.New; if (newval != null && newval.exp != null) { //_logView.LogStr("new:" + newval.exp.ToString()); string[] parts = newval.exp.ToString().Split('.'); if (parts.Length > 0) { string calledId = parts[parts.Length - 1] + "()"; // If we have a method of this name in this file/class, then // we have a possible constructor link. if (_addedNodes.ContainsKey(calledId)) { // Create an edge. AddEdge(_methodNodeId, calledId, EdgeStyle.NormalArrow, Color.Green); } } } else { if (var.val != null) { string valStr = var.val.ToString(); string[] parts = valStr.Split('.'); if (parts.Length > 1 && parts[0] == "self") { // dup.. string calledId = parts[parts.Length - 1] + "()"; // If we have a method of this name in this file/class, then // we have a possible constructor link. if (_addedNodes.ContainsKey(calledId)) { // Create an edge. AddEdge(_methodNodeId, calledId, EdgeStyle.NormalArrow, Color.Green); } } } } //ParseAstList(var.var_decls, sp + " "); } else if (ast is JS.Call) { JS.Call call = ast as JS.Call; string[] parts = call.ToString().Split(' '); string[] bits = parts[0].Split('.'); string calledId = bits[bits.Length - 1] + "()"; bool methodInThisClass = true; if (bits.Length > 1) { if ((bits[bits.Length - 2] != "This") && (bits[bits.Length - 2] != "self")) { methodInThisClass = false; } } // If we have a method of this name in this file/class if (_addedNodes.ContainsKey(calledId)) { // Create an edge. if (methodInThisClass) { // A definite link. AddEdge(_methodNodeId, calledId, EdgeStyle.NormalArrow, Color.Black); } else { // A tentative link. AddEdge(_methodNodeId, calledId, EdgeStyle.NormalArrow, Color.Gray); } } else { // It's a call to a method outside this class/file. // //_logView.LogStr("skipped -------->" + _methodNodeId + " --------> " + parts[0]); // } } }
//--------------------------------------------------------------------------------------- // ParseForStatement // // ForStatement : // 'for' '(' OptionalExpressionNoIn ';' OptionalExpression ';' OptionalExpression ')' // 'for' '(' 'var' VariableDeclarationListNoIn ';' OptionalExpression ';' OptionalExpression ')' // 'for' '(' LeftHandSideExpression 'in' Expression')' // 'for' '(' 'var' Identifier OptionalInitializerNoIn 'in' Expression')' // // OptionalExpressionNoIn : // <empty> | // ExpressionNoIn // same as Expression but does not process 'in' as an operator // // OptionalInitializerNoIn : // <empty> | // InitializerNoIn // same as initializer but does not process 'in' as an operator //--------------------------------------------------------------------------------------- private AST ParseForStatement(){ this.blockType.Add(BlockType.Loop); AST forNode = null; try{ Context forCtx = this.currentToken.Clone(); GetNextToken(); if (JSToken.LeftParen != this.currentToken.token) ReportError(JSError.NoLeftParen); GetNextToken(); bool isForIn = false, recoveryInForIn = false; AST lhs = null, initializer = null, condOrColl = null, increment = null; try{ if (JSToken.Var == this.currentToken.token){ isForIn = true; initializer = ParseIdentifierInitializer(JSToken.In, (FieldAttributes)0, null, JSToken.Var); // a list of variable initializers is allowed only in a for(;;) AST var = null; while (JSToken.Comma == this.currentToken.token){ isForIn = false; var = ParseIdentifierInitializer(JSToken.In, (FieldAttributes)0, null, JSToken.Var); initializer = new Comma(initializer.context.CombineWith(var.context), initializer, var); } // if it could still be a for..in, now it's time to get the 'in' if (isForIn){ if (JSToken.In == this.currentToken.token){ GetNextToken(); condOrColl = ParseExpression(); }else isForIn = false; } }else{ if (JSToken.Semicolon != this.currentToken.token){ bool isLHS; initializer = ParseUnaryExpression(out isLHS, false); if (isLHS && JSToken.In == this.currentToken.token){ isForIn = true; lhs = initializer; initializer = null; GetNextToken(); this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try{ condOrColl = ParseExpression(); }catch(RecoveryTokenException exc){ if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1){ exc._partiallyComputedNode = null; throw exc; }else{ if (exc._partiallyComputedNode == null) condOrColl = new ConstantWrapper(true, CurrentPositionContext()); // what could we put here? else condOrColl = exc._partiallyComputedNode; } if (exc._token == JSToken.RightParen){ GetNextToken(); recoveryInForIn = true; } }finally{ this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } }else initializer = ParseExpression(initializer, false, isLHS, JSToken.In); }else initializer = new EmptyLiteral(CurrentPositionContext()); } }catch(RecoveryTokenException exc){ // error is too early abort for exc._partiallyComputedNode = null; throw exc; } // at this point we know whether or not is a for..in if (isForIn){ if (!recoveryInForIn){ if (JSToken.RightParen != this.currentToken.token) ReportError(JSError.NoRightParen); forCtx.UpdateWith(this.currentToken); GetNextToken(); } AST body = null; try{ body = ParseStatement(); }catch(RecoveryTokenException exc){ if (exc._partiallyComputedNode == null) body = new Block(CurrentPositionContext()); else body = exc._partiallyComputedNode; exc._partiallyComputedNode = new ForIn(forCtx, lhs, initializer, condOrColl, body); throw exc; } forNode = new ForIn(forCtx, lhs, initializer, condOrColl, body); }else{ this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try{ if (JSToken.Semicolon != this.currentToken.token){ ReportError(JSError.NoSemicolon); if (JSToken.Colon == this.currentToken.token){ this.noSkipTokenSet.Add(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); try{ SkipTokensAndThrow(); }catch(RecoveryTokenException exc){ if (JSToken.Semicolon == this.currentToken.token) this.errorToken = null; else throw exc; }finally{ this.noSkipTokenSet.Remove(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); } } } GetNextToken(); if (JSToken.Semicolon != this.currentToken.token){ condOrColl = ParseExpression(); if (JSToken.Semicolon != this.currentToken.token) ReportError(JSError.NoSemicolon); }else condOrColl = new ConstantWrapper(true, CurrentPositionContext()); GetNextToken(); if (JSToken.RightParen != this.currentToken.token) increment = ParseExpression(); else increment = new EmptyLiteral(CurrentPositionContext()); if (JSToken.RightParen != this.currentToken.token) ReportError(JSError.NoRightParen); forCtx.UpdateWith(this.currentToken); GetNextToken(); }catch(RecoveryTokenException exc){ if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1){ exc._partiallyComputedNode = null; throw exc; }else{ // discard any partial info, just genrate empty condition and increment and keep going exc._partiallyComputedNode = null; if (condOrColl == null) condOrColl = new ConstantWrapper(true, CurrentPositionContext()); if (increment == null) increment = new EmptyLiteral(CurrentPositionContext()); } if (exc._token == JSToken.RightParen){ GetNextToken(); } }finally{ this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } AST body = null; try{ body = ParseStatement(); }catch(RecoveryTokenException exc){ if (exc._partiallyComputedNode == null) body = new Block(CurrentPositionContext()); else body = exc._partiallyComputedNode; exc._partiallyComputedNode = new For(forCtx, initializer, condOrColl, increment, body); throw exc; } forNode = new For(forCtx, initializer, condOrColl, increment, body); } }finally{ this.blockType.RemoveAt(this.blockType.Count - 1); } return forNode; }
/** * Whether the "catch (e: e instanceof Exception) { ... }" syntax * is implemented. */ AST StatementHelper(AST parent) { AST pn = null; // If skipsemi == true, don't add SEMI + EOL to source at the // end of this statment. For compound statements, IF/FOR etc. bool skip_semi = false; int tt; tt = ts.GetToken (); if (tt == Token.IF) { skip_semi = true; decompiler.AddToken (Token.IF); AST cond = Condition (parent); decompiler.AddEOL (Token.LC); AST if_true = Statement (parent); AST if_false = null; if (ts.MatchToken (Token.ELSE)) { decompiler.AddToken (Token.RC); decompiler.AddToken (Token.ELSE); decompiler.AddEOL (Token.LC); if_false = Statement (parent); } decompiler.AddEOL (Token.RC); pn = new If (parent, cond, if_true, if_false, new Location (ts.SourceName, ts.LineNumber)); } else if (tt == Token.SWITCH) { skip_semi = true; decompiler.AddToken (Token.SWITCH); pn = new Switch (parent, new Location (ts.SourceName, ts.LineNumber)); Clause cur_case; MustMatchToken (Token.LP, "msg.no.paren.switch"); decompiler.AddToken (Token.LP); ((Switch) pn).exp = Expr (parent, false); MustMatchToken (Token.RP, "msg.no.paren.after.switch"); decompiler.AddToken (Token.RP); MustMatchToken (Token.LC, "msg.no.brace.switch"); decompiler.AddEOL (Token.LC); ClauseType clause_type = ClauseType.Case; while ((tt = ts.GetToken ()) != Token.RC && tt != Token.EOF) { if (tt == Token.CASE) { decompiler.AddToken (Token.CASE); cur_case = new Clause (pn, new Location (ts.SourceName, ts.LineNumber)); cur_case.exp = Expr (pn, false); decompiler.AddEOL (Token.COLON); if (clause_type == ClauseType.Default) clause_type = ClauseType.CaseAfterDefault; } else if (tt == Token.DEFAULT) { cur_case = null; clause_type = ClauseType.Default; decompiler.AddToken (Token.DEFAULT); decompiler.AddEOL (Token.COLON); } else { cur_case = null; ReportError ("msg.bad.switch"); } MustMatchToken (Token.COLON, "msg.no.colon.case"); while ((tt = ts.PeekToken ()) != Token.RC && tt != Token.CASE && tt != Token.DEFAULT && tt != Token.EOF) { if (clause_type == ClauseType.Case || clause_type == ClauseType.CaseAfterDefault) cur_case.AddStm (Statement (pn)); else if (clause_type == ClauseType.Default) ((Switch) pn).default_clauses.Add (Statement (pn)); } ((Switch) pn).AddClause (cur_case, clause_type); } decompiler.AddEOL (Token.RC); } else if (tt == Token.WHILE) { skip_semi = true; decompiler.AddToken (Token.WHILE); While w = new While (new Location (ts.SourceName, ts.LineNumber)); AST cond = Condition (w); decompiler.AddEOL (Token.LC); AST body = Statement (w); decompiler.AddEOL (Token.RC); w.Init (parent, cond, body); pn = w; } else if (tt == Token.DO) { decompiler.AddToken (Token.DO); decompiler.AddEOL (Token.LC); int line_number = ts.LineNumber; DoWhile do_while = new DoWhile (new Location (ts.SourceName, line_number)); AST body = Statement (do_while); decompiler.AddToken (Token.RC); MustMatchToken (Token.WHILE, "msg.no.while.do"); decompiler.AddToken (Token.WHILE); AST cond = Condition (do_while); do_while.Init (parent, body, cond); pn = do_while; } else if (tt == Token.FOR) { skip_semi = true; decompiler.AddToken (Token.FOR); AST init, cond, incr = null, body; MustMatchToken (Token.LP, "msg.no.paren.for"); decompiler.AddToken (Token.LP); tt = ts.PeekToken (); if (tt == Token.SEMI) init = new EmptyAST (); else { if (tt == Token.VAR) { // set init to a var list or initial ts.GetToken (); // throw away the 'var' token init = Variables (parent, true); } else init = Expr (parent, true); } if (ts.MatchToken (Token.IN)) { decompiler.AddToken (Token.IN); cond = Expr (parent, false); // 'cond' is the object over which we're iterating } else { // ordinary for loop MustMatchToken (Token.SEMI, "msg.no.semi.for"); decompiler.AddToken (Token.SEMI); if (ts.PeekToken () == Token.SEMI) cond = new EmptyAST (); // no loop condition else cond = Expr (parent, false); MustMatchToken (Token.SEMI, "msg.no.semi.for.cond"); decompiler.AddToken (Token.SEMI); if (ts.PeekToken () == Token.RP) incr = new EmptyAST (); else incr = Expr (parent, false); } MustMatchToken (Token.RP, "msg.no.paren.for.ctrl"); decompiler.AddToken (Token.RP); decompiler.AddEOL (Token.LC); body = Statement (pn); decompiler.AddEOL (Token.RC); if (incr == null) // cond could be null if 'in obj' got eaten by the init node. pn = new ForIn (parent, init, cond, body, new Location (ts.SourceName, ts.LineNumber)); else pn = new For (parent, init, cond, incr, body, new Location (ts.SourceName, ts.LineNumber)); body.PropagateParent (pn); } else if (tt == Token.TRY) { int line_number = ts.LineNumber; AST try_block; ArrayList catch_blocks = null; AST finally_block = null; skip_semi = true; decompiler.AddToken (Token.TRY); decompiler.AddEOL (Token.LC); try_block = Statement (parent); decompiler.AddEOL (Token.RC); catch_blocks = new ArrayList (); bool saw_default_catch = false; int peek = ts.PeekToken (); if (peek == Token.CATCH) { while (ts.MatchToken (Token.CATCH)) { if (saw_default_catch) ReportError ("msg.catch.unreachable"); decompiler.AddToken (Token.CATCH); MustMatchToken (Token.LP, "msg.no.paren.catch"); decompiler.AddToken (Token.LP); MustMatchToken (Token.NAME, "msg.bad.catchcond"); string var_name = ts.GetString; decompiler.AddName (var_name); AST catch_cond = null; if (ts.MatchToken (Token.IF)) { decompiler.AddToken (Token.IF); catch_cond = Expr (parent, false); } else saw_default_catch = true; MustMatchToken (Token.RP, "msg.bad.catchcond"); decompiler.AddToken (Token.RP); MustMatchToken (Token.LC, "msg.no.brace.catchblock"); decompiler.AddEOL (Token.LC); catch_blocks.Add (new Catch (var_name, catch_cond, Statements (null), parent, new Location (ts.SourceName, line_number))); MustMatchToken (Token.RC, "msg.no.brace.after.body"); decompiler.AddEOL (Token.RC); } } else if (peek != Token.FINALLY) MustMatchToken (Token.FINALLY, "msg.try.no.catchfinally"); if (ts.MatchToken (Token.FINALLY)) { decompiler.AddToken (Token.FINALLY); decompiler.AddEOL (Token.LC); finally_block = Statement (parent); decompiler.AddEOL (Token.RC); } pn = new Try (try_block, catch_blocks, finally_block, parent, new Location (ts.SourceName, ts.LineNumber)); } else if (tt == Token.THROW) { int line_number = ts.LineNumber; decompiler.AddToken (Token.THROW); pn = new Throw (Expr (parent, false), new Location (ts.SourceName, ts.LineNumber)); if (line_number == ts.LineNumber) CheckWellTerminated (); } else if (tt == Token.BREAK) { decompiler.AddToken (Token.BREAK); // MatchLabel only matches if there is one string label = MatchLabel (); if (label != null) decompiler.AddName (label); pn = new Break (parent, label, new Location (ts.SourceName, ts.LineNumber)); } else if (tt == Token.CONTINUE) { decompiler.AddToken (Token.CONTINUE); // MatchLabel only matches if there is one string label = MatchLabel (); if (label != null) decompiler.AddName (label); pn = new Continue (parent, label, new Location (ts.SourceName, ts.LineNumber)); } else if (tt == Token.WITH) { skip_semi = true; decompiler.AddToken (Token.WITH); MustMatchToken (Token.LP, "msg.no.paren.with"); decompiler.AddToken (Token.LP); AST obj = Expr (parent, false); MustMatchToken (Token.RP, "msg.no.paren.after.with"); decompiler.AddToken (Token.RP); decompiler.AddToken (Token.LC); ++nesting_of_with; AST body; try { body = Statement (parent); } finally { --nesting_of_with; } decompiler.AddEOL (Token.RC); pn = new With (parent, obj, body, new Location (ts.SourceName, ts.LineNumber)); } else if (tt == Token.VAR) { int line_number = ts.LineNumber; pn = Variables (parent, false); if (ts.LineNumber == line_number) CheckWellTerminated (); } else if (tt == Token.RETURN) { AST ret_expr = null; decompiler.AddToken (Token.RETURN); pn = new Return (new Location (ts.SourceName, ts.LineNumber)); if (!InsideFunction) ReportError ("msg.bad.return"); /* This is ugly, but we don't want to require a semicolon. */ ts.allow_reg_exp = true; tt = ts.PeekTokenSameLine (); ts.allow_reg_exp = false; int line_number = ts.LineNumber; if (tt != Token.EOF && tt != Token.EOL && tt != Token.SEMI && tt != Token.RC) { ret_expr = Expr (pn, false); if (ts.LineNumber == line_number) CheckWellTerminated (); } ((Return) pn).Init (parent, ret_expr); } else if (tt == Token.LC) { skip_semi = true; pn = Statements (parent); MustMatchToken (Token.RC, "msg.no.brace.block"); } else if (tt == Token.ERROR || tt == Token.EOL || tt == Token.SEMI) { pn = new EmptyAST (); skip_semi = true; } else if (tt == Token.FUNCTION) { pn = Function (parent, FunctionType.ExpressionStatement); } else if (tt == Token.IMPORT) { decompiler.AddToken (Token.IMPORT); pn = Import (parent); } else { int last_expr_type = tt; int token_number = ts.TokenNumber; ts.UnGetToken (tt); int line_number = ts.LineNumber; pn = Expr (parent, false); if (ts.PeekToken () == Token.COLON) { /* check that the last thing the tokenizer returned was a * NAME and that only one token was consumed. */ if (last_expr_type != Token.NAME || (ts.TokenNumber != token_number)) ReportError ("msg.bad.label"); ts.GetToken (); // eat the colon string name = ts.GetString; // bind 'Statement (pn)' to the label Labelled labelled = new Labelled (parent, new Location (ts.SourceName, ts.LineNumber)); labelled.Init (parent, name, Statement (labelled), new Location (ts.SourceName, ts.LineNumber)); pn = labelled; // depend on decompiling lookahead to guess that that // last name was a label. decompiler.AddEOL (Token.COLON); return pn; } // FIXME: // pn = nf.createExprStatement(pn, lineno); if (ts.LineNumber == line_number) CheckWellTerminated (); } ts.MatchToken (Token.SEMI); if (!skip_semi) decompiler.AddEOL (Token.SEMI); return pn; }
private AST ParseForStatement() { this.blockType.Add(BlockType.Loop); AST ast = null; try { Context context = this.currentToken.Clone(); this.GetNextToken(); if (JSToken.LeftParen != this.currentToken.token) { this.ReportError(JSError.NoLeftParen); } this.GetNextToken(); bool flag = false; bool flag2 = false; AST var = null; AST ast3 = null; AST collection = null; AST incrementer = null; try { if (JSToken.Var == this.currentToken.token) { flag = true; ast3 = this.ParseIdentifierInitializer(JSToken.In, FieldAttributes.PrivateScope, null, JSToken.Var); AST ast6 = null; while (JSToken.Comma == this.currentToken.token) { flag = false; ast6 = this.ParseIdentifierInitializer(JSToken.In, FieldAttributes.PrivateScope, null, JSToken.Var); ast3 = new Comma(ast3.context.CombineWith(ast6.context), ast3, ast6); } if (flag) { if (JSToken.In == this.currentToken.token) { this.GetNextToken(); collection = this.ParseExpression(); } else { flag = false; } } } else if (JSToken.Semicolon != this.currentToken.token) { bool flag3; ast3 = this.ParseUnaryExpression(out flag3, false); if (flag3 && (JSToken.In == this.currentToken.token)) { flag = true; var = ast3; ast3 = null; this.GetNextToken(); this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try { try { collection = this.ParseExpression(); } catch (RecoveryTokenException exception) { if (this.IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exception) == -1) { exception._partiallyComputedNode = null; throw exception; } if (exception._partiallyComputedNode == null) { collection = new ConstantWrapper(true, this.CurrentPositionContext()); } else { collection = exception._partiallyComputedNode; } if (exception._token == JSToken.RightParen) { this.GetNextToken(); flag2 = true; } } goto Label_01E1; } finally { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } } ast3 = this.ParseExpression(ast3, false, flag3, JSToken.In); } else { ast3 = new EmptyLiteral(this.CurrentPositionContext()); } } catch (RecoveryTokenException exception2) { exception2._partiallyComputedNode = null; throw exception2; } Label_01E1: if (flag) { if (!flag2) { if (JSToken.RightParen != this.currentToken.token) { this.ReportError(JSError.NoRightParen); } context.UpdateWith(this.currentToken); this.GetNextToken(); } AST ast7 = null; try { ast7 = this.ParseStatement(); } catch (RecoveryTokenException exception3) { if (exception3._partiallyComputedNode == null) { ast7 = new Block(this.CurrentPositionContext()); } else { ast7 = exception3._partiallyComputedNode; } exception3._partiallyComputedNode = new ForIn(context, var, ast3, collection, ast7); throw exception3; } return new ForIn(context, var, ast3, collection, ast7); } this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try { if (JSToken.Semicolon != this.currentToken.token) { this.ReportError(JSError.NoSemicolon); if (JSToken.Colon == this.currentToken.token) { this.noSkipTokenSet.Add(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); try { this.SkipTokensAndThrow(); } catch (RecoveryTokenException exception4) { if (JSToken.Semicolon != this.currentToken.token) { throw exception4; } this.errorToken = null; } finally { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); } } } this.GetNextToken(); if (JSToken.Semicolon != this.currentToken.token) { collection = this.ParseExpression(); if (JSToken.Semicolon != this.currentToken.token) { this.ReportError(JSError.NoSemicolon); } } else { collection = new ConstantWrapper(true, this.CurrentPositionContext()); } this.GetNextToken(); if (JSToken.RightParen != this.currentToken.token) { incrementer = this.ParseExpression(); } else { incrementer = new EmptyLiteral(this.CurrentPositionContext()); } if (JSToken.RightParen != this.currentToken.token) { this.ReportError(JSError.NoRightParen); } context.UpdateWith(this.currentToken); this.GetNextToken(); } catch (RecoveryTokenException exception5) { if (this.IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exception5) == -1) { exception5._partiallyComputedNode = null; throw exception5; } exception5._partiallyComputedNode = null; if (collection == null) { collection = new ConstantWrapper(true, this.CurrentPositionContext()); } if (incrementer == null) { incrementer = new EmptyLiteral(this.CurrentPositionContext()); } if (exception5._token == JSToken.RightParen) { this.GetNextToken(); } } finally { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } AST body = null; try { body = this.ParseStatement(); } catch (RecoveryTokenException exception6) { if (exception6._partiallyComputedNode == null) { body = new Block(this.CurrentPositionContext()); } else { body = exception6._partiallyComputedNode; } exception6._partiallyComputedNode = new For(context, ast3, collection, incrementer, body); throw exception6; } ast = new For(context, ast3, collection, incrementer, body); } finally { this.blockType.RemoveAt(this.blockType.Count - 1); } return ast; }