/** * 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; }
internal void AddClause (Clause clause, ClauseType clause_type) { if (clause_type == ClauseType.Case) case_clauses.Add (clause); else if (clause_type == ClauseType.CaseAfterDefault) sec_case_clauses.Add (clause); }