Inheritance: AST, ICanModifyContext
Exemplo n.º 1
0
        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]);
                    //
                }
            }
        }
Exemplo n.º 2
0
        /**
         * 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;
        }