Exemplo n.º 1
0
        /// <summary> If caseExpression argument is null it indicate default label.</summary>
        internal void addSwitchCase(Node switchBlock, Node caseExpression, Node statements)
        {
            if (switchBlock.Type != Token.BLOCK)
                throw Context.CodeBug ();
            Node.Jump switchNode = (Node.Jump)switchBlock.FirstChild;
            if (switchNode.Type != Token.SWITCH)
                throw Context.CodeBug ();

            Node gotoTarget = Node.newTarget ();
            if (caseExpression != null) {
                Node.Jump caseNode = new Node.Jump (Token.CASE, caseExpression);
                caseNode.target = gotoTarget;
                switchNode.addChildToBack (caseNode);
            }
            else {
                switchNode.Default = gotoTarget;
            }
            switchBlock.addChildToBack (gotoTarget);
            switchBlock.addChildToBack (statements);
        }
Exemplo n.º 2
0
        private void transformCompilationUnit_r (ScriptOrFnNode tree, Node parent)
        {
            Node node = null;

            using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (1024)) {
                for (; ; ) {
                    Node previous = null;
                    if (node == null) {
                        node = parent.FirstChild;
                    }
                    else {
                        previous = node;
                        node = node.Next;
                    }
                    if (node == null) {
                        break;
                    }

                    int type = node.Type;

                    switch (type) {


                        case Token.LABEL:
                        case Token.SWITCH:
                        case Token.LOOP:
                            loops.push (node);
                            loopEnds.push (((Node.Jump)node).target);
                            break;


                        case Token.WITH: {
                                loops.push (node);
                                Node leave = node.Next;
                                if (leave.Type != Token.LEAVEWITH) {
                                    Context.CodeBug ();
                                }
                                loopEnds.push (leave);
                                break;
                            }


                        case Token.TRY: {
                                Node.Jump jump = (Node.Jump)node;
                                Node finallytarget = jump.Finally;
                                if (finallytarget != null) {
                                    hasFinally = true;
                                    loops.push (node);
                                    loopEnds.push (finallytarget);
                                }
                                break;
                            }


                        case Token.TARGET:
                        case Token.LEAVEWITH:
                            if (!loopEnds.Empty && loopEnds.peek () == node) {
                                loopEnds.pop ();
                                loops.pop ();
                            }
                            break;


                        case Token.RETURN: {
                                /* If we didn't support try/finally, it wouldn't be
                                * necessary to put LEAVEWITH nodes here... but as
                                * we do need a series of JSR FINALLY nodes before
                                * each RETURN, we need to ensure that each finally
                                * block gets the correct scope... which could mean
                                * that some LEAVEWITH nodes are necessary.
                                */
                                if (!hasFinally)
                                    break; // skip the whole mess.
                                Node unwindBlock = null;
                                for (int i = loops.size () - 1; i >= 0; i--) {
                                    Node n = (Node)loops.Get (i);
                                    int elemtype = n.Type;
                                    if (elemtype == Token.TRY || elemtype == Token.WITH) {
                                        Node unwind;
                                        if (elemtype == Token.TRY) {
                                            Node.Jump jsrnode = new Node.Jump (Token.JSR);
                                            Node jsrtarget = ((Node.Jump)n).Finally;
                                            jsrnode.target = jsrtarget;
                                            unwind = jsrnode;
                                        }
                                        else {
                                            unwind = new Node (Token.LEAVEWITH);
                                        }
                                        if (unwindBlock == null) {
                                            unwindBlock = new Node (Token.BLOCK, node.Lineno);
                                        }
                                        unwindBlock.addChildToBack (unwind);
                                    }
                                }
                                if (unwindBlock != null) {
                                    Node returnNode = node;
                                    Node returnExpr = returnNode.FirstChild;
                                    node = replaceCurrent (parent, previous, node, unwindBlock);
                                    if (returnExpr == null) {
                                        unwindBlock.addChildToBack (returnNode);
                                    }
                                    else {
                                        Node store = new Node (Token.EXPR_RESULT, returnExpr);
                                        unwindBlock.addChildToFront (store);
                                        returnNode = new Node (Token.RETURN_RESULT);
                                        unwindBlock.addChildToBack (returnNode);
                                        // transform return expression
                                        transformCompilationUnit_r (tree, store);
                                    }
                                    // skip transformCompilationUnit_r to avoid infinite loop

                                    goto siblingLoop;
                                }
                                break;
                            }


                        case Token.BREAK:
                        case Token.CONTINUE: {
                                Node.Jump jump = (Node.Jump)node;
                                Node.Jump jumpStatement = jump.JumpStatement;
                                if (jumpStatement == null)
                                    Context.CodeBug ();

                                for (int i = loops.size (); ; ) {
                                    if (i == 0) {
                                        // Parser/IRFactory ensure that break/continue
                                        // always has a jump statement associated with it
                                        // which should be found
                                        throw Context.CodeBug ();
                                    }
                                    --i;
                                    Node n = (Node)loops.Get (i);
                                    if (n == jumpStatement) {
                                        break;
                                    }

                                    int elemtype = n.Type;
                                    if (elemtype == Token.WITH) {
                                        Node leave = new Node (Token.LEAVEWITH);
                                        previous = addBeforeCurrent (parent, previous, node, leave);
                                    }
                                    else if (elemtype == Token.TRY) {
                                        Node.Jump tryNode = (Node.Jump)n;
                                        Node.Jump jsrFinally = new Node.Jump (Token.JSR);
                                        jsrFinally.target = tryNode.Finally;
                                        previous = addBeforeCurrent (parent, previous, node, jsrFinally);
                                    }
                                }

                                if (type == Token.BREAK) {
                                    jump.target = jumpStatement.target;
                                }
                                else {
                                    jump.target = jumpStatement.Continue;
                                }
                                jump.Type = Token.GOTO;

                                break;
                            }


                        case Token.CALL:
                            visitCall (node, tree);
                            break;


                        case Token.NEW:
                            visitNew (node, tree);
                            break;


                        case Token.CONST:
                        case Token.VAR: {
                                Node result = new Node (Token.BLOCK);
                                for (Node cursor = node.FirstChild; cursor != null; ) {
                                    // Move cursor to next before createAssignment get chance
                                    // to change n.next
                                    Node n = cursor;
                                    if (n.Type != Token.NAME)
                                        Context.CodeBug ();
                                    cursor = cursor.Next;
                                    if (!n.hasChildren ())
                                        continue;
                                    Node init = n.FirstChild;
                                    n.removeChild (init);
                                    n.Type = Token.BINDNAME;
                                    n = new Node ((node.Type == Token.VAR) ? Token.SETNAME : Token.SETNAME_CONST, n, init);
                                    Node pop = new Node (Token.EXPR_VOID, n, node.Lineno);
                                    result.addChildToBack (pop);
                                }
                                node = replaceCurrent (parent, previous, node, result);
                                break;
                            }


                        case Token.NAME:
                        case Token.SETNAME:
                        case Token.DELPROP: {
                                // Turn name to var for faster access if possible
                                if (tree.Type != Token.FUNCTION || ((FunctionNode)tree).RequiresActivation) {
                                    break;
                                }
                                Node nameSource;
                                if (type == Token.NAME) {
                                    nameSource = node;
                                }
                                else {
                                    nameSource = node.FirstChild;
                                    if (nameSource.Type != Token.BINDNAME) {
                                        if (type == Token.DELPROP) {
                                            break;
                                        }
                                        throw Context.CodeBug ();
                                    }
                                }
                                string name = nameSource.String;
                                if (tree.hasParamOrVar (name)) {
                                    if (type == Token.NAME) {
                                        node.Type = Token.GETVAR;
                                    }
                                    else if (type == Token.SETNAME) {
                                        node.Type = Token.SETVAR;
                                        nameSource.Type = Token.STRING;
                                    }
                                    else if (type == Token.DELPROP) {
                                        // Local variables are by definition permanent
                                        Node n = new Node (Token.FALSE);
                                        node = replaceCurrent (parent, previous, node, n);
                                    }
                                    else {
                                        throw Context.CodeBug ();
                                    }
                                }
                                break;
                            }
                    }

                    transformCompilationUnit_r (tree, node);

                siblingLoop:
                    ;
                }
            }
        }
Exemplo n.º 3
0
        /// <summary> Try/Catch/Finally
        /// 
        /// The IRFactory tries to express as much as possible in the tree;
        /// the responsibilities remaining for Codegen are to add the Java
        /// handlers: (Either (but not both) of TARGET and FINALLY might not
        /// be defined)
        /// - a catch handler for javascript exceptions that unwraps the
        /// exception onto the stack and GOTOes to the catch target
        /// - a finally handler
        /// ... and a goto to GOTO around these handlers.
        /// </summary>
        internal Node CreateTryCatchFinally(Node tryBlock, Node catchBlocks, Node finallyBlock, int lineno)
        {
            bool hasFinally = (finallyBlock != null) && (finallyBlock.Type != Token.BLOCK || finallyBlock.hasChildren ());

            // short circuit
            if (tryBlock.Type == Token.BLOCK && !tryBlock.hasChildren () && !hasFinally) {
                return tryBlock;
            }

            bool hasCatch = catchBlocks.hasChildren ();

            // short circuit
            if (!hasFinally && !hasCatch) {
                // bc finally might be an empty block...
                return tryBlock;
            }

            Node handlerBlock = new Node (Token.LOCAL_BLOCK);
            Node.Jump pn = new Node.Jump (Token.TRY, tryBlock, lineno);
            pn.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);

            if (hasCatch) {
                // jump around catch code
                Node endCatch = Node.newTarget ();
                pn.addChildToBack (makeJump (Token.GOTO, endCatch));

                // make a TARGET for the catch that the tcf node knows about
                Node catchTarget = Node.newTarget ();
                pn.target = catchTarget;
                // mark it
                pn.addChildToBack (catchTarget);

                //
                //  Given
                //
                //   try {
                //       tryBlock;
                //   } catch (e if condition1) {
                //       something1;
                //   ...
                //
                //   } catch (e if conditionN) {
                //       somethingN;
                //   } catch (e) {
                //       somethingDefault;
                //   }
                //
                //  rewrite as
                //
                //   try {
                //       tryBlock;
                //       goto after_catch:
                //   } catch (x) {
                //       with (newCatchScope(e, x)) {
                //           if (condition1) {
                //               something1;
                //               goto after_catch;
                //           }
                //       }
                //   ...
                //       with (newCatchScope(e, x)) {
                //           if (conditionN) {
                //               somethingN;
                //               goto after_catch;
                //           }
                //       }
                //       with (newCatchScope(e, x)) {
                //           somethingDefault;
                //           goto after_catch;
                //       }
                //   }
                // after_catch:
                //
                // If there is no default catch, then the last with block
                // arround  "somethingDefault;" is replaced by "rethrow;"

                // It is assumed that catch handler generation will store
                // exeception object in handlerBlock register

                // Block with local for exception scope objects
                Node catchScopeBlock = new Node (Token.LOCAL_BLOCK);

                // expects catchblocks children to be (cond block) pairs.
                Node cb = catchBlocks.FirstChild;
                bool hasDefault = false;
                int scopeIndex = 0;
                while (cb != null) {
                    int catchLineNo = cb.Lineno;

                    Node name = cb.FirstChild;
                    Node cond = name.Next;
                    Node catchStatement = cond.Next;
                    cb.removeChild (name);
                    cb.removeChild (cond);
                    cb.removeChild (catchStatement);

                    // Add goto to the catch statement to jump out of catch
                    // but prefix it with LEAVEWITH since try..catch produces
                    // "with"code in order to limit the scope of the exception
                    // object.
                    catchStatement.addChildToBack (new Node (Token.LEAVEWITH));
                    catchStatement.addChildToBack (makeJump (Token.GOTO, endCatch));

                    // Create condition "if" when present
                    Node condStmt;
                    if (cond.Type == Token.EMPTY) {
                        condStmt = catchStatement;
                        hasDefault = true;
                    }
                    else {
                        condStmt = CreateIf (cond, catchStatement, null, catchLineNo);
                    }

                    // Generate code to Create the scope object and store
                    // it in catchScopeBlock register
                    Node catchScope = new Node (Token.CATCH_SCOPE, name, CreateUseLocal (handlerBlock));
                    catchScope.putProp (Node.LOCAL_BLOCK_PROP, catchScopeBlock);
                    catchScope.putIntProp (Node.CATCH_SCOPE_PROP, scopeIndex);
                    catchScopeBlock.addChildToBack (catchScope);

                    // Add with statement based on catch scope object
                    catchScopeBlock.addChildToBack (CreateWith (CreateUseLocal (catchScopeBlock), condStmt, catchLineNo));

                    // move to next cb
                    cb = cb.Next;
                    ++scopeIndex;
                }
                pn.addChildToBack (catchScopeBlock);
                if (!hasDefault) {
                    // Generate code to rethrow if no catch clause was executed
                    Node rethrow = new Node (Token.RETHROW);
                    rethrow.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);
                    pn.addChildToBack (rethrow);
                }

                pn.addChildToBack (endCatch);
            }

            if (hasFinally) {
                Node finallyTarget = Node.newTarget ();
                pn.Finally = finallyTarget;

                // add jsr finally to the try block
                pn.addChildToBack (makeJump (Token.JSR, finallyTarget));

                // jump around finally code
                Node finallyEnd = Node.newTarget ();
                pn.addChildToBack (makeJump (Token.GOTO, finallyEnd));

                pn.addChildToBack (finallyTarget);
                Node fBlock = new Node (Token.FINALLY, finallyBlock);
                fBlock.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);
                pn.addChildToBack (fBlock);

                pn.addChildToBack (finallyEnd);
            }
            handlerBlock.addChildToBack (pn);
            return handlerBlock;
        }
Exemplo n.º 4
0
        /// <summary> Statement leaf nodes.</summary>
        internal Node CreateSwitch(Node expr, int lineno)
        {
            //
            // The switch will be rewritten from:
            //
            // switch (expr) {
            //   case test1: statements1;
            //   ...
            //   default: statementsDefault;
            //   ...
            //   case testN: statementsN;
            // }
            //
            // to:
            //
            // {
            //     switch (expr) {
            //       case test1: goto label1;
            //       ...
            //       case testN: goto labelN;
            //     }
            //     goto labelDefault;
            //   label1:
            //     statements1;
            //   ...
            //   labelDefault:
            //     statementsDefault;
            //   ...
            //   labelN:
            //     statementsN;
            //   breakLabel:
            // }
            //
            // where inside switch each "break;" without label will be replaced
            // by "goto breakLabel".
            //
            // If the original switch does not have the default label, then
            // the transformed code would contain after the switch instead of
            //     goto labelDefault;
            // the following goto:
            //     goto breakLabel;
            //

            Node.Jump switchNode = new Node.Jump (Token.SWITCH, expr, lineno);
            Node block = new Node (Token.BLOCK, switchNode);
            return block;
        }
Exemplo n.º 5
0
 /// <summary> Create loop node. The parser will later call
 /// CreateWhile|CreateDoWhile|CreateFor|CreateForIn
 /// to finish loop generation.
 /// </summary>
 internal Node CreateLoopNode(Node loopLabel, int lineno)
 {
     Node.Jump result = new Node.Jump (Token.LOOP, lineno);
     if (loopLabel != null) {
         ((Node.Jump)loopLabel).Loop = result;
     }
     return result;
 }
Exemplo n.º 6
0
        /// <summary> If statement</summary>
        internal Node CreateIf(Node cond, Node ifTrue, Node ifFalse, int lineno)
        {
            int condStatus = isAlwaysDefinedBoolean (cond);
            if (condStatus == ALWAYS_TRUE_BOOLEAN) {
                return ifTrue;
            }
            else if (condStatus == ALWAYS_FALSE_BOOLEAN) {
                if (ifFalse != null) {
                    return ifFalse;
                }
                return new Node (Token.BLOCK, lineno);
            }

            Node result = new Node (Token.BLOCK, lineno);
            Node ifNotTarget = Node.newTarget ();
            Node.Jump IFNE = new Node.Jump (Token.IFNE, cond);
            IFNE.target = ifNotTarget;

            result.addChildToBack (IFNE);
            result.addChildrenToBack (ifTrue);

            if (ifFalse != null) {
                Node endTarget = Node.newTarget ();
                result.addChildToBack (makeJump (Token.GOTO, endTarget));
                result.addChildToBack (ifNotTarget);
                result.addChildrenToBack (ifFalse);
                result.addChildToBack (endTarget);
            }
            else {
                result.addChildToBack (ifNotTarget);
            }

            return result;
        }
Exemplo n.º 7
0
 /// <summary> Continue (possibly labeled)</summary>
 internal Node CreateContinue(Node loop, int lineno)
 {
     if (loop.Type != Token.LOOP)
         Context.CodeBug ();
     Node.Jump n = new Node.Jump (Token.CONTINUE, lineno);
     n.JumpStatement = (Node.Jump)loop;
     return n;
 }
Exemplo n.º 8
0
 /// <summary> Break (possibly labeled)</summary>
 internal Node CreateBreak(Node breakStatement, int lineno)
 {
     Node.Jump n = new Node.Jump (Token.BREAK, lineno);
     Node.Jump jumpStatement;
     int t = breakStatement.Type;
     if (t == Token.LOOP || t == Token.LABEL) {
         jumpStatement = (Node.Jump)breakStatement;
     }
     else if (t == Token.BLOCK && breakStatement.FirstChild.Type == Token.SWITCH) {
         jumpStatement = (Node.Jump)breakStatement.FirstChild;
     }
     else {
         throw Context.CodeBug ();
     }
     n.JumpStatement = jumpStatement;
     return n;
 }
Exemplo n.º 9
0
 private Node.Jump makeJump(int type, Node target)
 {
     Node.Jump n = new Node.Jump (type);
     n.target = target;
     return n;
 }
Exemplo n.º 10
0
        private Node CreateLoop(Node.Jump loop, int loopType, Node body, Node cond, Node init, Node incr)
        {
            Node bodyTarget = Node.newTarget ();
            Node condTarget = Node.newTarget ();
            if (loopType == LOOP_FOR && cond.Type == Token.EMPTY) {
                cond = new Node (Token.TRUE);
            }
            Node.Jump IFEQ = new Node.Jump (Token.IFEQ, cond);
            IFEQ.target = bodyTarget;
            Node breakTarget = Node.newTarget ();

            loop.addChildToBack (bodyTarget);
            loop.addChildrenToBack (body);
            if (loopType == LOOP_WHILE || loopType == LOOP_FOR) {
                // propagate lineno to condition
                loop.addChildrenToBack (new Node (Token.EMPTY, loop.Lineno));
            }
            loop.addChildToBack (condTarget);
            loop.addChildToBack (IFEQ);
            loop.addChildToBack (breakTarget);

            loop.target = breakTarget;
            Node continueTarget = condTarget;

            if (loopType == LOOP_WHILE || loopType == LOOP_FOR) {
                // Just add a GOTO to the condition in the do..while
                loop.addChildToFront (makeJump (Token.GOTO, condTarget));

                if (loopType == LOOP_FOR) {
                    if (init.Type != Token.EMPTY) {
                        if (init.Type != Token.VAR) {
                            init = new Node (Token.EXPR_VOID, init);
                        }
                        loop.addChildToFront (init);
                    }
                    Node incrTarget = Node.newTarget ();
                    loop.addChildAfter (incrTarget, body);
                    if (incr.Type != Token.EMPTY) {
                        incr = new Node (Token.EXPR_VOID, incr);
                        loop.addChildAfter (incr, incrTarget);
                    }
                    continueTarget = incrTarget;
                }
            }

            loop.Continue = continueTarget;

            return loop;
        }
Exemplo n.º 11
0
        private void transformCompilationUnit_r(ScriptOrFnNode tree, Node parent)
        {
            Node node = null;

            using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(1024)) {
                for (; ;)
                {
                    Node previous = null;
                    if (node == null)
                    {
                        node = parent.FirstChild;
                    }
                    else
                    {
                        previous = node;
                        node     = node.Next;
                    }
                    if (node == null)
                    {
                        break;
                    }

                    int type = node.Type;

                    switch (type)
                    {
                    case Token.LABEL:
                    case Token.SWITCH:
                    case Token.LOOP:
                        loops.push(node);
                        loopEnds.push(((Node.Jump)node).target);
                        break;


                    case Token.WITH: {
                        loops.push(node);
                        Node leave = node.Next;
                        if (leave.Type != Token.LEAVEWITH)
                        {
                            Context.CodeBug();
                        }
                        loopEnds.push(leave);
                        break;
                    }


                    case Token.TRY: {
                        Node.Jump jump          = (Node.Jump)node;
                        Node      finallytarget = jump.Finally;
                        if (finallytarget != null)
                        {
                            hasFinally = true;
                            loops.push(node);
                            loopEnds.push(finallytarget);
                        }
                        break;
                    }


                    case Token.TARGET:
                    case Token.LEAVEWITH:
                        if (!loopEnds.Empty && loopEnds.peek() == node)
                        {
                            loopEnds.pop();
                            loops.pop();
                        }
                        break;


                    case Token.RETURN: {
                        /* If we didn't support try/finally, it wouldn't be
                         * necessary to put LEAVEWITH nodes here... but as
                         * we do need a series of JSR FINALLY nodes before
                         * each RETURN, we need to ensure that each finally
                         * block gets the correct scope... which could mean
                         * that some LEAVEWITH nodes are necessary.
                         */
                        if (!hasFinally)
                        {
                            break;         // skip the whole mess.
                        }
                        Node unwindBlock = null;
                        for (int i = loops.size() - 1; i >= 0; i--)
                        {
                            Node n        = (Node)loops.Get(i);
                            int  elemtype = n.Type;
                            if (elemtype == Token.TRY || elemtype == Token.WITH)
                            {
                                Node unwind;
                                if (elemtype == Token.TRY)
                                {
                                    Node.Jump jsrnode   = new Node.Jump(Token.JSR);
                                    Node      jsrtarget = ((Node.Jump)n).Finally;
                                    jsrnode.target = jsrtarget;
                                    unwind         = jsrnode;
                                }
                                else
                                {
                                    unwind = new Node(Token.LEAVEWITH);
                                }
                                if (unwindBlock == null)
                                {
                                    unwindBlock = new Node(Token.BLOCK, node.Lineno);
                                }
                                unwindBlock.addChildToBack(unwind);
                            }
                        }
                        if (unwindBlock != null)
                        {
                            Node returnNode = node;
                            Node returnExpr = returnNode.FirstChild;
                            node = replaceCurrent(parent, previous, node, unwindBlock);
                            if (returnExpr == null)
                            {
                                unwindBlock.addChildToBack(returnNode);
                            }
                            else
                            {
                                Node store = new Node(Token.EXPR_RESULT, returnExpr);
                                unwindBlock.addChildToFront(store);
                                returnNode = new Node(Token.RETURN_RESULT);
                                unwindBlock.addChildToBack(returnNode);
                                // transform return expression
                                transformCompilationUnit_r(tree, store);
                            }
                            // skip transformCompilationUnit_r to avoid infinite loop

                            goto siblingLoop;
                        }
                        break;
                    }


                    case Token.BREAK:
                    case Token.CONTINUE: {
                        Node.Jump jump          = (Node.Jump)node;
                        Node.Jump jumpStatement = jump.JumpStatement;
                        if (jumpStatement == null)
                        {
                            Context.CodeBug();
                        }

                        for (int i = loops.size(); ;)
                        {
                            if (i == 0)
                            {
                                // Parser/IRFactory ensure that break/continue
                                // always has a jump statement associated with it
                                // which should be found
                                throw Context.CodeBug();
                            }
                            --i;
                            Node n = (Node)loops.Get(i);
                            if (n == jumpStatement)
                            {
                                break;
                            }

                            int elemtype = n.Type;
                            if (elemtype == Token.WITH)
                            {
                                Node leave = new Node(Token.LEAVEWITH);
                                previous = addBeforeCurrent(parent, previous, node, leave);
                            }
                            else if (elemtype == Token.TRY)
                            {
                                Node.Jump tryNode    = (Node.Jump)n;
                                Node.Jump jsrFinally = new Node.Jump(Token.JSR);
                                jsrFinally.target = tryNode.Finally;
                                previous          = addBeforeCurrent(parent, previous, node, jsrFinally);
                            }
                        }

                        if (type == Token.BREAK)
                        {
                            jump.target = jumpStatement.target;
                        }
                        else
                        {
                            jump.target = jumpStatement.Continue;
                        }
                        jump.Type = Token.GOTO;

                        break;
                    }


                    case Token.CALL:
                        visitCall(node, tree);
                        break;


                    case Token.NEW:
                        visitNew(node, tree);
                        break;


                    case Token.VAR: {
                        Node result = new Node(Token.BLOCK);
                        for (Node cursor = node.FirstChild; cursor != null;)
                        {
                            // Move cursor to next before createAssignment get chance
                            // to change n.next
                            Node n = cursor;
                            if (n.Type != Token.NAME)
                            {
                                Context.CodeBug();
                            }
                            cursor = cursor.Next;
                            if (!n.hasChildren())
                            {
                                continue;
                            }
                            Node init = n.FirstChild;
                            n.removeChild(init);
                            n.Type = Token.BINDNAME;
                            n      = new Node(Token.SETNAME, n, init);
                            Node pop = new Node(Token.EXPR_VOID, n, node.Lineno);
                            result.addChildToBack(pop);
                        }
                        node = replaceCurrent(parent, previous, node, result);
                        break;
                    }


                    case Token.NAME:
                    case Token.SETNAME:
                    case Token.DELPROP: {
                        // Turn name to var for faster access if possible
                        if (tree.Type != Token.FUNCTION || ((FunctionNode)tree).RequiresActivation)
                        {
                            break;
                        }
                        Node nameSource;
                        if (type == Token.NAME)
                        {
                            nameSource = node;
                        }
                        else
                        {
                            nameSource = node.FirstChild;
                            if (nameSource.Type != Token.BINDNAME)
                            {
                                if (type == Token.DELPROP)
                                {
                                    break;
                                }
                                throw Context.CodeBug();
                            }
                        }
                        string name = nameSource.String;
                        if (tree.hasParamOrVar(name))
                        {
                            if (type == Token.NAME)
                            {
                                node.Type = Token.GETVAR;
                            }
                            else if (type == Token.SETNAME)
                            {
                                node.Type       = Token.SETVAR;
                                nameSource.Type = Token.STRING;
                            }
                            else if (type == Token.DELPROP)
                            {
                                // Local variables are by definition permanent
                                Node n = new Node(Token.FALSE);
                                node = replaceCurrent(parent, previous, node, n);
                            }
                            else
                            {
                                throw Context.CodeBug();
                            }
                        }
                        break;
                    }
                    }

                    transformCompilationUnit_r(tree, node);

siblingLoop:
                    ;
                }
            }
        }