Beispiel #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]);
                    //
                }
            }
        }
Beispiel #2
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;
      }
Beispiel #3
0
        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;
        }