public virtual void SetJumpStatement(Rhino.Ast.Jump jumpStatement) { if (type != Token.BREAK && type != Token.CONTINUE) { CodeBug(); } if (jumpStatement == null) { CodeBug(); } if (this.jumpNode != null) { CodeBug(); } //only once this.jumpNode = jumpStatement; }
private void VisitSwitch(Jump switchNode, Node child) { // See comments in IRFactory.createSwitch() for description // of SWITCH node GenerateExpression(child, switchNode); // save selector value short selector = GetNewWordLocal(); cfw.AddAStore(selector); for (Jump caseNode = (Jump)child.GetNext(); caseNode != null; caseNode = (Jump)caseNode.GetNext()) { if (caseNode.GetType() != Token.CASE) { throw Codegen.BadTree(); } Node test = caseNode.GetFirstChild(); GenerateExpression(test, caseNode); cfw.AddALoad(selector); AddScriptRuntimeInvoke("shallowEq", "(Ljava/lang/Object;" + "Ljava/lang/Object;" + ")Z"); AddGoto(caseNode.target, ByteCode.IFNE); } ReleaseWordLocal(selector); }
public virtual void SetLoop(Rhino.Ast.Jump loop) { if (type != Token.LABEL) { CodeBug(); } if (loop == null) { CodeBug(); } if (jumpNode != null) { CodeBug(); } //only once jumpNode = loop; }
/// <summary>Push a new try block onto the exception information stack.</summary> /// <remarks>Push a new try block onto the exception information stack.</remarks> /// <param name="node"> /// an exception handling node (node.getType() == /// Token.TRY) /// </param> internal virtual void PushExceptionInfo(Jump node) { Node fBlock = this._enclosing.GetFinallyAtTarget(node.GetFinally()); BodyCodegen.ExceptionManager.ExceptionInfo ei = new BodyCodegen.ExceptionManager.ExceptionInfo(this, node, fBlock); this.exceptionInfo.Add(ei); }
internal ExceptionInfo(ExceptionManager _enclosing, Jump node, Node finallyBlock) { this._enclosing = _enclosing; this.node = node; this.finallyBlock = finallyBlock; this.handlerLabels = new int[BodyCodegen.EXCEPTION_MAX]; this.exceptionStarts = new int[BodyCodegen.EXCEPTION_MAX]; this.currentFinally = null; }
private void VisitGoto(Jump node, int type, Node child) { Node target = node.target; if (type == Token.IFEQ || type == Token.IFNE) { if (child == null) { throw Codegen.BadTree(); } int targetLabel = GetTargetLabel(target); int fallThruLabel = cfw.AcquireLabel(); if (type == Token.IFEQ) { GenerateIfJump(child, node, targetLabel, fallThruLabel); } else { GenerateIfJump(child, node, fallThruLabel, targetLabel); } cfw.MarkLabel(fallThruLabel); } else { if (type == Token.JSR) { if (isGenerator) { AddGotoWithReturn(target); } else { // This assumes that JSR is only ever used for finally InlineFinally(target); } } else { AddGoto(target, ByteCode.GOTO); } } }
private void VisitTryCatchFinally(Jump node, Node child) { // OPT we only need to do this if there are enclosed WITH // statements; could statically check and omit this if there aren't any. // XXX OPT Maybe instead do syntactic transforms to associate // each 'with' with a try/finally block that does the exitwith. short savedVariableObject = GetNewWordLocal(); cfw.AddALoad(variableObjectLocal); cfw.AddAStore(savedVariableObject); int startLabel = cfw.AcquireLabel(); cfw.MarkLabel(startLabel, (short)0); Node catchTarget = node.target; Node finallyTarget = node.GetFinally(); int[] handlerLabels = new int[EXCEPTION_MAX]; exceptionManager.PushExceptionInfo(node); if (catchTarget != null) { handlerLabels[JAVASCRIPT_EXCEPTION] = cfw.AcquireLabel(); handlerLabels[EVALUATOR_EXCEPTION] = cfw.AcquireLabel(); handlerLabels[ECMAERROR_EXCEPTION] = cfw.AcquireLabel(); Context cx = Context.GetCurrentContext(); if (cx != null && cx.HasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)) { handlerLabels[THROWABLE_EXCEPTION] = cfw.AcquireLabel(); } } if (finallyTarget != null) { handlerLabels[FINALLY_EXCEPTION] = cfw.AcquireLabel(); } exceptionManager.SetHandlers(handlerLabels, startLabel); // create a table for the equivalent of JSR returns if (isGenerator && finallyTarget != null) { BodyCodegen.FinallyReturnPoint ret = new BodyCodegen.FinallyReturnPoint(); if (finallys == null) { finallys = new Dictionary<Node, BodyCodegen.FinallyReturnPoint>(); } // add the finally target to hashtable finallys.Put(finallyTarget, ret); // add the finally node as well to the hash table finallys.Put(finallyTarget.GetNext(), ret); } while (child != null) { if (child == catchTarget) { int catchLabel = GetTargetLabel(catchTarget); exceptionManager.RemoveHandler(JAVASCRIPT_EXCEPTION, catchLabel); exceptionManager.RemoveHandler(EVALUATOR_EXCEPTION, catchLabel); exceptionManager.RemoveHandler(ECMAERROR_EXCEPTION, catchLabel); exceptionManager.RemoveHandler(THROWABLE_EXCEPTION, catchLabel); } GenerateStatement(child); child = child.GetNext(); } // control flow skips the handlers int realEnd = cfw.AcquireLabel(); cfw.Add(ByteCode.GOTO, realEnd); int exceptionLocal = GetLocalBlockRegister(node); // javascript handler; unwrap exception and GOTO to javascript // catch area. if (catchTarget != null) { // get the label to goto int catchLabel = catchTarget.LabelId(); // If the function is a generator, then handlerLabels will consist // of zero labels. generateCatchBlock will create its own label // in this case. The extra parameter for the label is added for // the case of non-generator functions that inline finally blocks. GenerateCatchBlock(JAVASCRIPT_EXCEPTION, savedVariableObject, catchLabel, exceptionLocal, handlerLabels[JAVASCRIPT_EXCEPTION]); GenerateCatchBlock(EVALUATOR_EXCEPTION, savedVariableObject, catchLabel, exceptionLocal, handlerLabels[EVALUATOR_EXCEPTION]); GenerateCatchBlock(ECMAERROR_EXCEPTION, savedVariableObject, catchLabel, exceptionLocal, handlerLabels[ECMAERROR_EXCEPTION]); Context cx = Context.GetCurrentContext(); if (cx != null && cx.HasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)) { GenerateCatchBlock(THROWABLE_EXCEPTION, savedVariableObject, catchLabel, exceptionLocal, handlerLabels[THROWABLE_EXCEPTION]); } } // finally handler; catch all exceptions, store to a local; JSR to // the finally, then re-throw. if (finallyTarget != null) { int finallyHandler = cfw.AcquireLabel(); int finallyEnd = cfw.AcquireLabel(); cfw.MarkHandler(finallyHandler); if (!isGenerator) { cfw.MarkLabel(handlerLabels[FINALLY_EXCEPTION]); } cfw.AddAStore(exceptionLocal); // reset the variable object local cfw.AddALoad(savedVariableObject); cfw.AddAStore(variableObjectLocal); // get the label to JSR to int finallyLabel = finallyTarget.LabelId(); if (isGenerator) { AddGotoWithReturn(finallyTarget); } else { InlineFinally(finallyTarget, handlerLabels[FINALLY_EXCEPTION], finallyEnd); } // rethrow cfw.AddALoad(exceptionLocal); if (isGenerator) { cfw.Add(ByteCode.CHECKCAST, "java/lang/Throwable"); } cfw.Add(ByteCode.ATHROW); cfw.MarkLabel(finallyEnd); // mark the handler if (isGenerator) { cfw.AddExceptionHandler(startLabel, finallyLabel, finallyHandler, null); } } // catch any ReleaseWordLocal(savedVariableObject); cfw.MarkLabel(realEnd); if (!isGenerator) { exceptionManager.PopExceptionInfo(); } }
private Jump MakeJump(int type, Node target) { Jump n = new Jump(type); n.target = target; return n; }
/// <summary>Sets the statement to break to.</summary> /// <remarks>Sets the statement to break to.</remarks> /// <param name="target">the statement to break to</param> /// <exception cref="System.ArgumentException"> /// if target is /// <code>null</code> /// </exception> public virtual void SetBreakTarget(Jump target) { AssertNotNull(target); this.target = target; SetJumpStatement(target); }
private 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; } // Replace if (false) xxx by empty block return new Node(Token.BLOCK, lineno); } } Node result = new Node(Token.BLOCK, lineno); Node ifNotTarget = Node.NewTarget(); Jump IFNE = new 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; }
/// <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 /// ... /// </summary> /// <remarks> /// 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. /// </remarks> private Node CreateTryCatchFinally(Node tryBlock, Node catchBlocks, Node finallyBlock, int lineno) { bool hasFinally = (finallyBlock != null) && (finallyBlock.GetType() != Token.BLOCK || finallyBlock.HasChildren()); // short circuit if (tryBlock.GetType() == 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); Jump pn = new 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.GetFirstChild(); bool hasDefault = false; int scopeIndex = 0; while (cb != null) { int catchLineNo = cb.GetLineno(); Node name = cb.GetFirstChild(); Node cond = name.GetNext(); Node catchStatement = cond.GetNext(); 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.GetType() == 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.GetNext(); ++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.SetFinally(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; }
private Node CreateLoop(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.GetType() == Token.EMPTY) { cond = new Node(Token.TRUE); } Jump IFEQ = new 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.GetLineno())); } 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) { int initType = init.GetType(); if (initType != Token.EMPTY) { if (initType != Token.VAR && initType != Token.LET) { init = new Node(Token.EXPR_VOID, init); } loop.AddChildToFront(init); } Node incrTarget = Node.NewTarget(); loop.AddChildAfter(incrTarget, body); if (incr.GetType() != Token.EMPTY) { incr = new Node(Token.EXPR_VOID, incr); loop.AddChildAfter(incr, incrTarget); } continueTarget = incrTarget; } } loop.SetContinue(continueTarget); return loop; }
/// <summary>If caseExpression argument is null it indicates a default label.</summary> /// <remarks>If caseExpression argument is null it indicates a default label.</remarks> private void AddSwitchCase(Node switchBlock, Node caseExpression, Node statements) { if (switchBlock.GetType() != Token.BLOCK) { throw Kit.CodeBug(); } Jump switchNode = (Jump)switchBlock.GetFirstChild(); if (switchNode.GetType() != Token.SWITCH) { throw Kit.CodeBug(); } Node gotoTarget = Node.NewTarget(); if (caseExpression != null) { Jump caseNode = new Jump(Token.CASE, caseExpression); caseNode.target = gotoTarget; switchNode.AddChildToBack(caseNode); } else { switchNode.SetDefault(gotoTarget); } switchBlock.AddChildToBack(gotoTarget); switchBlock.AddChildToBack(statements); }
private void TransformCompilationUnit_r(ScriptNode tree, Node parent, Scope scope, bool createScopeObjects, bool inStrictMode) { Node node = null; for (; ; ) { Node previous = null; if (node == null) { node = parent.GetFirstChild(); } else { previous = node; node = node.GetNext(); } if (node == null) { break; } int type = node.GetType(); if (createScopeObjects && (type == Token.BLOCK || type == Token.LOOP || type == Token.ARRAYCOMP) && (node is Scope)) { Scope newScope = (Scope)node; if (newScope.GetSymbolTable() != null) { // transform to let statement so we get a with statement // created to contain scoped let variables Node let = new Node(type == Token.ARRAYCOMP ? Token.LETEXPR : Token.LET); Node innerLet = new Node(Token.LET); let.AddChildToBack(innerLet); foreach (string name in newScope.GetSymbolTable().Keys) { innerLet.AddChildToBack(Node.NewString(Token.NAME, name)); } newScope.SetSymbolTable(null); // so we don't transform again Node oldNode = node; node = ReplaceCurrent(parent, previous, node, let); type = node.GetType(); let.AddChildToBack(oldNode); } } switch (type) { case Token.LABEL: case Token.SWITCH: case Token.LOOP: { loops.Push(node); loopEnds.Push(((Jump)node).target); break; } case Token.WITH: { loops.Push(node); Node leave = node.GetNext(); if (leave.GetType() != Token.LEAVEWITH) { Kit.CodeBug(); } loopEnds.Push(leave); break; } case Token.TRY: { Jump jump = (Jump)node; Node finallytarget = jump.GetFinally(); if (finallytarget != null) { hasFinally = true; loops.Push(node); loopEnds.Push(finallytarget); } break; } case Token.TARGET: case Token.LEAVEWITH: { if (!loopEnds.IsEmpty() && loopEnds.Peek() == node) { loopEnds.Pop(); loops.Pop(); } break; } case Token.YIELD: { ((FunctionNode)tree).AddResumptionPoint(node); break; } case Token.RETURN: { bool isGenerator = tree.GetType() == Token.FUNCTION && ((FunctionNode)tree).IsGenerator(); if (isGenerator) { node.PutIntProp(Node.GENERATOR_END_PROP, 1); } 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.GetType(); if (elemtype == Token.TRY || elemtype == Token.WITH) { Node unwind; if (elemtype == Token.TRY) { Jump jsrnode = new Jump(Token.JSR); Node jsrtarget = ((Jump)n).GetFinally(); jsrnode.target = jsrtarget; unwind = jsrnode; } else { unwind = new Node(Token.LEAVEWITH); } if (unwindBlock == null) { unwindBlock = new Node(Token.BLOCK, node.GetLineno()); } unwindBlock.AddChildToBack(unwind); } } if (unwindBlock != null) { Node returnNode = node; Node returnExpr = returnNode.GetFirstChild(); node = ReplaceCurrent(parent, previous, node, unwindBlock); if (returnExpr == null || isGenerator) { 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, scope, createScopeObjects, inStrictMode); } // skip transformCompilationUnit_r to avoid infinite loop goto siblingLoop_continue; } break; } case Token.BREAK: case Token.CONTINUE: { Jump jump = (Jump)node; Jump jumpStatement = jump.GetJumpStatement(); if (jumpStatement == null) { Kit.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 Kit.CodeBug(); } --i; Node n = (Node)loops.Get(i); if (n == jumpStatement) { break; } int elemtype = n.GetType(); if (elemtype == Token.WITH) { Node leave = new Node(Token.LEAVEWITH); previous = AddBeforeCurrent(parent, previous, node, leave); } else { if (elemtype == Token.TRY) { Jump tryNode = (Jump)n; Jump jsrFinally = new Jump(Token.JSR); jsrFinally.target = tryNode.GetFinally(); previous = AddBeforeCurrent(parent, previous, node, jsrFinally); } } } if (type == Token.BREAK) { jump.target = jumpStatement.target; } else { jump.target = jumpStatement.GetContinue(); } jump.SetType(Token.GOTO); break; } case Token.CALL: { VisitCall(node, tree); break; } case Token.NEW: { VisitNew(node, tree); break; } case Token.LETEXPR: case Token.LET: { Node child = node.GetFirstChild(); if (child.GetType() == Token.LET) { // We have a let statement or expression rather than a // let declaration bool createWith = tree.GetType() != Token.FUNCTION || ((FunctionNode)tree).RequiresActivation(); node = VisitLet(createWith, parent, previous, node); break; } goto case Token.CONST; } case Token.CONST: case Token.VAR: { // fall through to process let declaration... Node result = new Node(Token.BLOCK); for (Node cursor = node.GetFirstChild(); cursor != null; ) { // Move cursor to next before createAssignment gets chance // to change n.next Node n = cursor; cursor = cursor.GetNext(); if (n.GetType() == Token.NAME) { if (!n.HasChildren()) { continue; } Node init = n.GetFirstChild(); n.RemoveChild(init); n.SetType(Token.BINDNAME); n = new Node(type == Token.CONST ? Token.SETCONST : Token.SETNAME, n, init); } else { // May be a destructuring assignment already transformed // to a LETEXPR if (n.GetType() != Token.LETEXPR) { throw Kit.CodeBug(); } } Node pop = new Node(Token.EXPR_VOID, n, node.GetLineno()); result.AddChildToBack(pop); } node = ReplaceCurrent(parent, previous, node, result); break; } case Token.TYPEOFNAME: { Scope defining = scope.GetDefiningScope(node.GetString()); if (defining != null) { node.SetScope(defining); } break; } case Token.TYPEOF: case Token.IFNE: { Node child = node.GetFirstChild(); if (type == Token.IFNE) { while (child.GetType() == Token.NOT) { child = child.GetFirstChild(); } if (child.GetType() == Token.EQ || child.GetType() == Token.NE) { Node first = child.GetFirstChild(); Node last = child.GetLastChild(); if (first.GetType() == Token.NAME && first.GetString().Equals("undefined")) { child = last; } else { if (last.GetType() == Token.NAME && last.GetString().Equals("undefined")) { child = first; } } } } if (child.GetType() == Token.GETPROP) { child.SetType(Token.GETPROPNOWARN); } break; } case Token.SETNAME: { if (inStrictMode) { node.SetType(Token.STRICT_SETNAME); } goto case Token.NAME; } case Token.NAME: case Token.SETCONST: case Token.DELPROP: { // Turn name to var for faster access if possible if (createScopeObjects) { break; } Node nameSource; if (type == Token.NAME) { nameSource = node; } else { nameSource = node.GetFirstChild(); if (nameSource.GetType() != Token.BINDNAME) { if (type == Token.DELPROP) { break; } throw Kit.CodeBug(); } } if (nameSource.GetScope() != null) { break; } // already have a scope set string name = nameSource.GetString(); Scope defining = scope.GetDefiningScope(name); if (defining != null) { nameSource.SetScope(defining); if (type == Token.NAME) { node.SetType(Token.GETVAR); } else { if (type == Token.SETNAME || type == Token.STRICT_SETNAME) { node.SetType(Token.SETVAR); nameSource.SetType(Token.STRING); } else { if (type == Token.SETCONST) { node.SetType(Token.SETCONSTVAR); nameSource.SetType(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 Kit.CodeBug(); } } } } } break; } } TransformCompilationUnit_r(tree, node, node is Scope ? (Scope)node : scope, createScopeObjects, inStrictMode); siblingLoop_continue: ; } siblingLoop_break: ; }