//--------------------------------------------------------------------------------------- // ParseTryStatement // // TryStatement : // 'try' Block CatchList Finally // // CatchList : // <empty> | // CatchList Catch // // Catch : // 'catch' '(' Identifier Type ')' Block // // Finally : // <empty> | // 'finally' Block //--------------------------------------------------------------------------------------- private AST ParseTryStatement(){ Context tryCtx = this.currentToken.Clone(); Context tryEndContext = null; AST body = null; AST id = null; AST handler = null; AST finally_block = null; RecoveryTokenException excInFinally = null; TypeExpression type = null; this.blockType.Add(BlockType.Block); try{ bool catchOrFinally = false; bool foundCatchAll = false; GetNextToken(); if (JSToken.LeftCurly != this.currentToken.token) ReportError(JSError.NoLeftCurly); this.noSkipTokenSet.Add(NoSkipTokenSet.s_NoTrySkipTokenSet); try{ body = ParseBlock(out tryEndContext); }catch(RecoveryTokenException exc){ if (IndexOfToken(NoSkipTokenSet.s_NoTrySkipTokenSet, exc) == -1) // do nothing and just return the containing block, if any throw exc; else body = exc._partiallyComputedNode; }finally{ this.noSkipTokenSet.Remove(NoSkipTokenSet.s_NoTrySkipTokenSet); } while (JSToken.Catch == this.currentToken.token){ this.noSkipTokenSet.Add(NoSkipTokenSet.s_NoTrySkipTokenSet); try{ if (handler != null){ body = new Try(tryCtx, body, id, type, handler, null, false, tryEndContext); id = null; type = null; handler = null; } catchOrFinally = true; GetNextToken(); if (JSToken.LeftParen != this.currentToken.token) ReportError(JSError.NoLeftParen); GetNextToken(); if (JSToken.Identifier != this.currentToken.token){ string identifier = JSKeyword.CanBeIdentifier(this.currentToken.token); if (null != identifier){ ForceReportInfo(JSError.KeywordUsedAsIdentifier); id = new Lookup(identifier, this.currentToken.Clone()); }else{ ReportError(JSError.NoIdentifier); id = new Lookup("##Exc##" + s_cDummyName++, CurrentPositionContext()); } }else id = new Lookup(this.scanner.GetIdentifier(), this.currentToken.Clone()); GetNextToken(); this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try{ if (JSToken.Colon == this.currentToken.token) type = ParseTypeExpression(); else{ if (foundCatchAll) //no point in having another ForceReportInfo(id.context, JSError.UnreachableCatch); foundCatchAll = true; } if (JSToken.RightParen != this.currentToken.token) ReportError(JSError.NoRightParen); GetNextToken(); }catch(RecoveryTokenException exc){ if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1){ exc._partiallyComputedNode = null; // rethrow throw exc; }else{ type = (TypeExpression)exc._partiallyComputedNode; if (this.currentToken.token == JSToken.RightParen) GetNextToken(); } }finally{ this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } if (JSToken.LeftCurly != this.currentToken.token) ReportError(JSError.NoLeftCurly); handler = ParseBlock(); tryCtx.UpdateWith(handler.context); }catch(RecoveryTokenException exc){ if (exc._partiallyComputedNode == null) handler = new Block(CurrentPositionContext()); else handler = exc._partiallyComputedNode; if (IndexOfToken(NoSkipTokenSet.s_NoTrySkipTokenSet, exc) == -1){ Debug.Assert((type == null) ? exc._partiallyComputedNode == null : true); if (type != null) exc._partiallyComputedNode = new Try(tryCtx, body, id, type, handler, null, false, tryEndContext); throw exc; } }finally{ this.noSkipTokenSet.Remove(NoSkipTokenSet.s_NoTrySkipTokenSet); } } try{ if (JSToken.Finally == this.currentToken.token){ GetNextToken(); this.blockType.Add(BlockType.Finally); try{ finally_block = ParseBlock(); catchOrFinally = true; }finally{ this.blockType.RemoveAt(this.blockType.Count - 1); } tryCtx.UpdateWith(finally_block.context); } }catch(RecoveryTokenException exc){ excInFinally = exc; // thrown later so we can execute code below } if (!catchOrFinally){ ReportError(JSError.NoCatch, true); finally_block = new Block(CurrentPositionContext()); // make a dummy empty block } }finally{ this.blockType.RemoveAt(this.blockType.Count - 1); } bool isFinallyEscaped = false; if (this.finallyEscaped > 0){ this.finallyEscaped--; isFinallyEscaped = true; } if (excInFinally != null){ excInFinally._partiallyComputedNode = new Try(tryCtx, body, id, type, handler, finally_block, isFinallyEscaped, tryEndContext); throw excInFinally; }else return new Try(tryCtx, body, id, type, handler, finally_block, isFinallyEscaped, tryEndContext); }
/** * 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 ParseTryStatement() { Context context = this.currentToken.Clone(); Context closingBraceContext = null; AST body = null; AST identifier = null; AST handler = null; AST ast4 = null; RecoveryTokenException exception = null; TypeExpression type = null; this.blockType.Add(BlockType.Block); try { bool flag = false; bool flag2 = false; this.GetNextToken(); if (JSToken.LeftCurly != this.currentToken.token) { this.ReportError(JSError.NoLeftCurly); } this.noSkipTokenSet.Add(NoSkipTokenSet.s_NoTrySkipTokenSet); try { try { body = this.ParseBlock(out closingBraceContext); } catch (RecoveryTokenException exception2) { if (this.IndexOfToken(NoSkipTokenSet.s_NoTrySkipTokenSet, exception2) == -1) { throw exception2; } body = exception2._partiallyComputedNode; } goto Label_02E5; } finally { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_NoTrySkipTokenSet); } Label_00A6: this.noSkipTokenSet.Add(NoSkipTokenSet.s_NoTrySkipTokenSet); try { if (handler != null) { body = new Try(context, body, identifier, type, handler, null, false, closingBraceContext); identifier = null; type = null; handler = null; } flag = true; this.GetNextToken(); if (JSToken.LeftParen != this.currentToken.token) { this.ReportError(JSError.NoLeftParen); } this.GetNextToken(); if (JSToken.Identifier != this.currentToken.token) { string name = JSKeyword.CanBeIdentifier(this.currentToken.token); if (name != null) { this.ForceReportInfo(JSError.KeywordUsedAsIdentifier); identifier = new Lookup(name, this.currentToken.Clone()); } else { this.ReportError(JSError.NoIdentifier); identifier = new Lookup("##Exc##" + s_cDummyName++, this.CurrentPositionContext()); } } else { identifier = new Lookup(this.scanner.GetIdentifier(), this.currentToken.Clone()); } this.GetNextToken(); this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try { if (JSToken.Colon == this.currentToken.token) { type = this.ParseTypeExpression(); } else { if (flag2) { this.ForceReportInfo(identifier.context, JSError.UnreachableCatch); } flag2 = true; } if (JSToken.RightParen != this.currentToken.token) { this.ReportError(JSError.NoRightParen); } this.GetNextToken(); } catch (RecoveryTokenException exception3) { if (this.IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exception3) == -1) { exception3._partiallyComputedNode = null; throw exception3; } type = (TypeExpression) exception3._partiallyComputedNode; if (this.currentToken.token == JSToken.RightParen) { this.GetNextToken(); } } finally { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } if (JSToken.LeftCurly != this.currentToken.token) { this.ReportError(JSError.NoLeftCurly); } handler = this.ParseBlock(); context.UpdateWith(handler.context); } catch (RecoveryTokenException exception4) { if (exception4._partiallyComputedNode == null) { handler = new Block(this.CurrentPositionContext()); } else { handler = exception4._partiallyComputedNode; } if (this.IndexOfToken(NoSkipTokenSet.s_NoTrySkipTokenSet, exception4) == -1) { if (type != null) { exception4._partiallyComputedNode = new Try(context, body, identifier, type, handler, null, false, closingBraceContext); } throw exception4; } } finally { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_NoTrySkipTokenSet); } Label_02E5: if (JSToken.Catch == this.currentToken.token) { goto Label_00A6; } try { if (JSToken.Finally == this.currentToken.token) { this.GetNextToken(); this.blockType.Add(BlockType.Finally); try { ast4 = this.ParseBlock(); flag = true; } finally { this.blockType.RemoveAt(this.blockType.Count - 1); } context.UpdateWith(ast4.context); } } catch (RecoveryTokenException exception5) { exception = exception5; } if (!flag) { this.ReportError(JSError.NoCatch, true); ast4 = new Block(this.CurrentPositionContext()); } } finally { this.blockType.RemoveAt(this.blockType.Count - 1); } bool finallyHasControlFlowOutOfIt = false; if (this.finallyEscaped > 0) { this.finallyEscaped--; finallyHasControlFlowOutOfIt = true; } if (exception != null) { exception._partiallyComputedNode = new Try(context, body, identifier, type, handler, ast4, finallyHasControlFlowOutOfIt, closingBraceContext); throw exception; } return new Try(context, body, identifier, type, handler, ast4, finallyHasControlFlowOutOfIt, closingBraceContext); }