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]); // } } }
//--------------------------------------------------------------------------------------- // ParseStatement // // OptionalStatement: // Statement | // <empty> // // Statement : // Block | // VariableStatement | // EmptyStatement | // ExpressionStatement | // IfStatement | // IterationStatement | // ContinueStatement | // BreakStatement | // ReturnStatement | // WithStatement | // LabeledStatement | // SwitchStatement | // ThrowStatement | // TryStatement | // QualifiedDeclaration | // Class | // FunctionDeclaration // // IterationStatement : // 'for' '(' ForLoopControl ')' | ===> ForStatement // 'do' Statement 'while' '(' Expression ')' | ===> DoStatement // 'while' '(' Expression ')' Statement ===> WhileStatement // //--------------------------------------------------------------------------------------- // ParseStatement deals with the end of statement issue (EOL vs ';') so if any of the // ParseXXX routine does it as well, it should return directly from the switch statement // without any further execution in the ParseStatement private AST ParseStatement(){ AST statement = null; String id = null; switch (this.currentToken.token){ case JSToken.EndOfFile: EOFError(JSError.ErrEOF); throw new EndOfFile(); // abort parsing, get back to the main parse routine case JSToken.Debugger: statement = new DebugBreak(this.currentToken.Clone()); GetNextToken(); break; case JSToken.Semicolon: // make an empty statement statement = new Block(this.currentToken.Clone()); GetNextToken(); return statement; case JSToken.RightCurly: ReportError(JSError.SyntaxError); SkipTokensAndThrow(); break; case JSToken.LeftCurly: return ParseBlock(); case JSToken.Var: case JSToken.Const: return ParseVariableStatement((FieldAttributes)0, null, this.currentToken.token); case JSToken.If: return ParseIfStatement(); case JSToken.For: return ParseForStatement(); case JSToken.Do: return ParseDoStatement(); case JSToken.While: return ParseWhileStatement(); case JSToken.Continue: statement = ParseContinueStatement(); if (null == statement) return new Block(CurrentPositionContext()); else return statement; case JSToken.Break: statement = ParseBreakStatement(); if (null == statement) return new Block(CurrentPositionContext()); else return statement; case JSToken.Return: statement = ParseReturnStatement(); if (null == statement) return new Block(CurrentPositionContext()); else return statement; case JSToken.With: return ParseWithStatement(); case JSToken.Switch: return ParseSwitchStatement(); case JSToken.Super: case JSToken.This: Context superCtx = this.currentToken.Clone(); if (JSToken.LeftParen == this.scanner.PeekToken()) statement = ParseConstructorCall(superCtx); else goto default; break; case JSToken.Throw: statement = ParseThrowStatement(); if (statement == null) return new Block(CurrentPositionContext()); else break; case JSToken.Try: return ParseTryStatement(); case JSToken.Internal: case JSToken.Public: case JSToken.Static: case JSToken.Private: case JSToken.Protected: case JSToken.Abstract: case JSToken.Final: bool parsedOK; statement = ParseAttributes(null, false, false, out parsedOK); if (!parsedOK){ statement = ParseExpression(statement, false, true, JSToken.None); statement = new Expression(statement.context.Clone(), statement); break; }else return statement; case JSToken.Package: Context packageContext = this.currentToken.Clone(); statement = ParsePackage(packageContext); if (statement is Package){ // handle common error of using import in function ReportError(JSError.PackageInWrongContext, packageContext, true); // make an empty statement statement = new Block(packageContext); } break; case JSToken.Interface: case JSToken.Class: return ParseClass((FieldAttributes)0, false, this.currentToken.Clone(), false, false, null); case JSToken.Enum: return ParseEnum((FieldAttributes)0, this.currentToken.Clone(), null); case JSToken.Function: return ParseFunction((FieldAttributes)0, false, this.currentToken.Clone(), false, false, false, false, null); //Parse a function as a statement case JSToken.Else: ReportError(JSError.InvalidElse); SkipTokensAndThrow(); break; case JSToken.Import: // handle common error of using import in function ReportError(JSError.InvalidImport, true); // make an empty statement statement = new Block(this.currentToken.Clone()); try{ ParseImportStatement(); }catch(RecoveryTokenException){ } break; default: this.noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet); bool exprError = false; try{ bool bAssign, canBeAttribute = true; statement = ParseUnaryExpression(out bAssign, ref canBeAttribute, false); if (canBeAttribute){ // look for labels if (statement is Lookup){ if (JSToken.Colon == this.currentToken.token){ // can be a label id = statement.ToString(); if (null != this.labelTable[id]){ // there is already a label with that name. Ignore the current label ReportError(JSError.BadLabel, statement.context.Clone(), true); id = null; GetNextToken(); // skip over ':' return new Block(CurrentPositionContext()); }else{ GetNextToken(); this.labelTable[id] = this.blockType.Count; if (JSToken.EndOfFile != this.currentToken.token) statement = ParseStatement(); else statement = new Block(CurrentPositionContext()); this.labelTable.Remove(id); return statement; } } } // look for custom attributes if (JSToken.Semicolon != this.currentToken.token && !this.scanner.GotEndOfLine()){ bool parsed; statement = ParseAttributes(statement, false, false, out parsed); if (parsed) return statement; } } statement = ParseExpression(statement, false, bAssign, JSToken.None); statement = new Expression(statement.context.Clone(), statement); }catch(RecoveryTokenException exc){ if (exc._partiallyComputedNode != null) statement = exc._partiallyComputedNode; if (statement == null){ this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet); exprError = true; SkipTokensAndThrow(); } if (IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exc) == -1){ exc._partiallyComputedNode = statement; throw exc; } }finally{ if (!exprError) this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet); } break; } if (JSToken.Semicolon == this.currentToken.token){ statement.context.UpdateWith(this.currentToken); GetNextToken(); }else if (!this.scanner.GotEndOfLine() && JSToken.RightCurly != this.currentToken.token && JSToken.EndOfFile != this.currentToken.token) ReportError(JSError.NoSemicolon, true); return statement; }
AST Expr(AST parent, bool in_for_init) { Expression pn = new Expression (parent, new Location (ts.SourceName, ts.LineNumber)); AST init = AssignExpr (parent, in_for_init); pn.Add (init); if (init == null) throw new Exception ("Expr, L680, AST is null"); while (ts.MatchToken (Token.COMMA)) { decompiler.AddToken (Token.COMMA); pn.Add (AssignExpr (parent, in_for_init)); } return pn; }
private AST ParseStatement() { AST leftHandSide = null; string key = null; switch (this.currentToken.token) { case JSToken.Super: case JSToken.This: { Context superCtx = this.currentToken.Clone(); if (JSToken.LeftParen != this.scanner.PeekToken()) { break; } leftHandSide = this.ParseConstructorCall(superCtx); goto Label_04B0; } case JSToken.RightCurly: this.ReportError(JSError.SyntaxError); this.SkipTokensAndThrow(); goto Label_04B0; case JSToken.Enum: return this.ParseEnum(FieldAttributes.PrivateScope, this.currentToken.Clone(), null); case JSToken.Interface: case JSToken.Class: return this.ParseClass(FieldAttributes.PrivateScope, false, this.currentToken.Clone(), false, false, null); case JSToken.EndOfFile: this.EOFError(JSError.ErrEOF); throw new EndOfFile(); case JSToken.If: return this.ParseIfStatement(); case JSToken.For: return this.ParseForStatement(); case JSToken.Do: return this.ParseDoStatement(); case JSToken.While: return this.ParseWhileStatement(); case JSToken.Continue: leftHandSide = this.ParseContinueStatement(); if (leftHandSide != null) { return leftHandSide; } return new Block(this.CurrentPositionContext()); case JSToken.Break: leftHandSide = this.ParseBreakStatement(); if (leftHandSide != null) { return leftHandSide; } return new Block(this.CurrentPositionContext()); case JSToken.Return: leftHandSide = this.ParseReturnStatement(); if (leftHandSide != null) { return leftHandSide; } return new Block(this.CurrentPositionContext()); case JSToken.Import: this.ReportError(JSError.InvalidImport, true); leftHandSide = new Block(this.currentToken.Clone()); try { this.ParseImportStatement(); } catch (RecoveryTokenException) { } goto Label_04B0; case JSToken.With: return this.ParseWithStatement(); case JSToken.Switch: return this.ParseSwitchStatement(); case JSToken.Throw: leftHandSide = this.ParseThrowStatement(); if (leftHandSide != null) { goto Label_04B0; } return new Block(this.CurrentPositionContext()); case JSToken.Try: return this.ParseTryStatement(); case JSToken.Package: { Context packageContext = this.currentToken.Clone(); leftHandSide = this.ParsePackage(packageContext); if (leftHandSide is Package) { this.ReportError(JSError.PackageInWrongContext, packageContext, true); leftHandSide = new Block(packageContext); } goto Label_04B0; } case JSToken.Internal: case JSToken.Abstract: case JSToken.Public: case JSToken.Static: case JSToken.Private: case JSToken.Protected: case JSToken.Final: bool flag; leftHandSide = this.ParseAttributes(null, false, false, out flag); if (flag) { return leftHandSide; } leftHandSide = this.ParseExpression(leftHandSide, false, true, JSToken.None); leftHandSide = new Expression(leftHandSide.context.Clone(), leftHandSide); goto Label_04B0; case JSToken.Var: case JSToken.Const: return this.ParseVariableStatement(FieldAttributes.PrivateScope, null, this.currentToken.token); case JSToken.Function: return this.ParseFunction(FieldAttributes.PrivateScope, false, this.currentToken.Clone(), false, false, false, false, null); case JSToken.LeftCurly: return this.ParseBlock(); case JSToken.Semicolon: leftHandSide = new Block(this.currentToken.Clone()); this.GetNextToken(); return leftHandSide; case JSToken.Debugger: leftHandSide = new DebugBreak(this.currentToken.Clone()); this.GetNextToken(); goto Label_04B0; case JSToken.Else: this.ReportError(JSError.InvalidElse); this.SkipTokensAndThrow(); goto Label_04B0; } this.noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet); bool flag2 = false; try { bool flag3; bool canBeAttribute = true; leftHandSide = this.ParseUnaryExpression(out flag3, ref canBeAttribute, false); if (canBeAttribute) { if ((leftHandSide is Lookup) && (JSToken.Colon == this.currentToken.token)) { key = leftHandSide.ToString(); if (this.labelTable[key] != null) { this.ReportError(JSError.BadLabel, leftHandSide.context.Clone(), true); key = null; this.GetNextToken(); return new Block(this.CurrentPositionContext()); } this.GetNextToken(); this.labelTable[key] = this.blockType.Count; if (this.currentToken.token != JSToken.EndOfFile) { leftHandSide = this.ParseStatement(); } else { leftHandSide = new Block(this.CurrentPositionContext()); } this.labelTable.Remove(key); return leftHandSide; } if ((JSToken.Semicolon != this.currentToken.token) && !this.scanner.GotEndOfLine()) { bool flag5; leftHandSide = this.ParseAttributes(leftHandSide, false, false, out flag5); if (flag5) { return leftHandSide; } } } leftHandSide = this.ParseExpression(leftHandSide, false, flag3, JSToken.None); leftHandSide = new Expression(leftHandSide.context.Clone(), leftHandSide); } catch (RecoveryTokenException exception) { if (exception._partiallyComputedNode != null) { leftHandSide = exception._partiallyComputedNode; } if (leftHandSide == null) { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet); flag2 = true; this.SkipTokensAndThrow(); } if (this.IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exception) == -1) { exception._partiallyComputedNode = leftHandSide; throw exception; } } finally { if (!flag2) { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet); } } Label_04B0: if (JSToken.Semicolon == this.currentToken.token) { leftHandSide.context.UpdateWith(this.currentToken); this.GetNextToken(); return leftHandSide; } if ((!this.scanner.GotEndOfLine() && (JSToken.RightCurly != this.currentToken.token)) && (this.currentToken.token != JSToken.EndOfFile)) { this.ReportError(JSError.NoSemicolon, true); } return leftHandSide; }