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]); // } } }
AST MulExpr(AST parent) { AST pn = UnaryExpr (parent); for (;;) { int tt = ts.PeekToken (); if (tt == Token.MUL || tt == Token.DIV || tt == Token.MOD) { ts.GetToken (); decompiler.AddToken (tt); pn = new Binary (parent, pn, UnaryExpr (parent), ToJSToken (tt), new Location (ts.SourceName, ts.LineNumber)); continue; } break; } return pn; }
AST MemberExprTail(AST parent, bool allow_call_syntax, AST pn) { int tt; while ((tt = ts.GetToken ()) > Token.EOF) { if (tt == Token.DOT) { decompiler.AddToken (Token.DOT); MustMatchToken (Token.NAME, "msg.no.name.after.dot"); string s = ts.GetString; decompiler.AddName (s); // FIXME: is 'new Identifier' appropriate here? pn = new Binary (parent, pn, new Identifier (parent, ts.GetString, new Location (ts.SourceName, ts.LineNumber)), JSToken.AccessField, new Location (ts.SourceName, ts.LineNumber)); } else if (tt == Token.LB) { decompiler.AddToken (Token.LB); Binary b = new Binary (parent, pn, JSToken.LeftBracket, new Location (ts.SourceName, ts.LineNumber)); b.right = Expr (b, false); pn = b; MustMatchToken (Token.RB, "msg.no.bracket.index"); decompiler.AddToken (Token.RB); } else if (allow_call_syntax && tt == Token.LP) { /* make a call node */ decompiler.AddToken (Token.LP); pn = new Call (parent, pn, new Location (ts.SourceName, ts.LineNumber)); /* Add the arguments to pn, if any are supplied. */ ArgumentList (parent, (ICallable) pn); } else { ts.UnGetToken (tt); break; } } return pn; }
AST BitXorExpr(AST parent, bool in_for_init) { AST pn = BitAndExpr (parent, in_for_init); while (ts.MatchToken (Token.BITXOR)) { decompiler.AddToken (Token.BITXOR); pn = new Binary (parent, pn, BitAndExpr (parent, in_for_init), JSToken.BitwiseXor, new Location (ts.SourceName, ts.LineNumber)); } return pn; }
AST ShiftExpr(AST parent) { AST pn = AddExpr (parent); for (;;) { int tt = ts.PeekToken (); if (tt == Token.LSH || tt == Token.URSH || tt == Token.RSH) { ts.GetToken (); decompiler.AddToken (tt); JSToken op = JSToken.LeftShift; if (tt == Token.RSH) op = JSToken.RightShift; else if (tt == Token.URSH) op = JSToken.UnsignedRightShift; pn = new Binary (parent, pn, AddExpr (parent), op, new Location (ts.SourceName, ts.LineNumber)); continue; } break; } return pn; }
internal override void Emit(EmitContext ec) { if (oper == JSToken.None) operand.Emit (ec); else { ILGenerator ig = ec.ig; Type post_prefix = typeof (PostOrPrefixOperator); LocalBuilder post_prefix_local = ig.DeclareLocal (post_prefix); LocalBuilder tmp_obj = ig.DeclareLocal (typeof (object)); switch (this.oper) { case JSToken.Increment: if (prefix) ig.Emit (OpCodes.Ldc_I4_3); else ig.Emit (OpCodes.Ldc_I4_1); break; case JSToken.Decrement: if (prefix) ig.Emit (OpCodes.Ldc_I4_2); else ig.Emit (OpCodes.Ldc_I4_0); break; } ig.Emit (OpCodes.Newobj, post_prefix.GetConstructor (new Type [] { typeof (int) })); ig.Emit (OpCodes.Stloc, post_prefix_local); Binary assign = null; if (operand is Identifier) ((Identifier) operand).EmitLoad (ec); else if (operand is Binary) { Binary binary = operand as Binary; binary.no_effect = false; binary.assign = false; assign = new Binary (binary.parent, binary.left, binary.right, binary.op, binary.location); assign.assign = true; assign.late_bind = true; assign.no_effect = false; if (binary.op == JSToken.LeftBracket || binary.op == JSToken.AccessField) { binary.Emit (ec); ig.Emit (OpCodes.Box, typeof (object)); } else throw new NotImplementedException (String.Format ("Unhandled binary op {0}", operand)); } else { Console.WriteLine ("PostOrPrefixOperator: prefix = {0}, oper = {1}, operand = {2}", prefix, oper, operand.GetType ()); throw new NotImplementedException (); } ig.Emit (OpCodes.Stloc, tmp_obj); ig.Emit (OpCodes.Ldloc, post_prefix_local); ig.Emit (OpCodes.Ldloca_S, tmp_obj); ig.Emit (OpCodes.Call, post_prefix.GetMethod ("EvaluatePostOrPrefix")); // // if does not appear as a global expression // if (prefix && !(parent is ScriptBlock)) { ig.Emit (OpCodes.Dup); ig.Emit (OpCodes.Stloc, tmp_obj); } if (operand is Identifier) ((Identifier) operand).EmitStore (ec); else if (operand is Binary) assign.Emit (ec); else throw new NotImplementedException (); // // If value will be used, load the // temp var that holded the value // before inc/dec was evaluated // if (!(parent is ScriptBlock || parent is FunctionDeclaration || parent is FunctionExpression || parent is Block)) ig.Emit (OpCodes.Ldloc, tmp_obj); } }