/// <summary> Script (for associating file/url names with toplevel scripts.)</summary> internal void initScript (ScriptOrFnNode scriptNode, Node body) { Node children = body.FirstChild; if (children != null) { scriptNode.addChildrenToBack (children); } }
private static Node addBeforeCurrent(Node parent, Node previous, Node current, Node toAdd) { if (previous == null) { if (!(current == parent.FirstChild)) Context.CodeBug (); parent.addChildToFront (toAdd); } else { if (!(current == previous.Next)) Context.CodeBug (); parent.addChildAfter (toAdd, previous); } return toAdd; }
/// <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; }
private static Node replaceCurrent(Node parent, Node previous, Node current, Node replacement) { if (previous == null) { if (!(current == parent.FirstChild)) Context.CodeBug (); parent.replaceChild (current, replacement); } else if (previous.next == current) { // Check cachedPrev.next == current is necessary due to possible // tree mutations parent.replaceChildAfter (previous, replacement); } else { parent.replaceChild (current, replacement); } return replacement; }
/// <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); }
protected internal virtual void visitCall (Node node, ScriptOrFnNode tree) { }
public Node(int nodeType, Node child) { Type = nodeType; first = last = child; child.next = null; }
internal Jump(int Type, Node child) : base(Type, child) { }
private static void generatePrintIds(Node n, ObjToIntMap map) { if (Token.printTrees) { map.put (n, map.size ()); for (Node cursor = n.FirstChild; cursor != null; cursor = cursor.Next) { generatePrintIds (cursor, map); } } }
public void replaceChildAfter(Node prevChild, Node newChild) { Node child = prevChild.next; newChild.next = child.next; prevChild.next = newChild; if (child == last) last = newChild; child.next = null; }
public void removeChild(Node child) { Node prev = getChildBefore (child); if (prev == null) first = first.next; else prev.next = child.next; if (child == last) last = prev; child.next = null; }
void VisitExpression (Node node, int contextFlags) { if (VisitExpressionOptimized (node, contextFlags)) return; int type = node.Type; Node child = node.FirstChild; int savedStackDepth = itsStackDepth; switch (type) { case Token.FUNCTION: { int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP); FunctionNode fn = scriptOrFn.getFunctionNode (fnIndex); // See comments in visitStatement for Token.FUNCTION case switch (fn.FunctionType) { case FunctionNode.FUNCTION_EXPRESSION: addIndexOp (Icode_CLOSURE_EXPR, fnIndex); break; default: throw Context.CodeBug (); } stackChange (1); } break; case Token.LOCAL_LOAD: { int localIndex = getLocalBlockRef (node); addIndexOp (Token.LOCAL_LOAD, localIndex); stackChange (1); } break; case Token.COMMA: { Node lastChild = node.LastChild; while (child != lastChild) { VisitExpression (child, 0); addIcode (Icode_POP); stackChange (-1); child = child.Next; } // Preserve tail context flag if any VisitExpression (child, contextFlags & ECF_TAIL); } break; case Token.USE_STACK: // Indicates that stack was modified externally, // like placed catch object stackChange (1); break; case Token.REF_CALL: case Token.CALL: case Token.NEW: { if (type == Token.NEW) { VisitExpression (child, 0); } else { generateCallFunAndThis (child); } int argCount = 0; while ((child = child.Next) != null) { VisitExpression (child, 0); ++argCount; } int callType = node.getIntProp (Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL); if (callType != Node.NON_SPECIALCALL) { // embed line number and source filename addIndexOp (Icode_CALLSPECIAL, argCount); addUint8 (callType); addUint8 (type == Token.NEW ? 1 : 0); addUint16 (itsLineNumber & 0xFFFF); } else { if (type == Token.CALL) { if ((contextFlags & ECF_TAIL) != 0) { type = Icode_TAIL_CALL; } } addIndexOp (type, argCount); } // adjust stack if (type == Token.NEW) { // new: f, args -> result stackChange (-argCount); } else { // call: f, thisObj, args -> result // ref_call: f, thisObj, args -> ref stackChange (-1 - argCount); } if (argCount > itsData.itsMaxCalleeArgs) { itsData.itsMaxCalleeArgs = argCount; } } break; case Token.AND: case Token.OR: { VisitExpression (child, 0); addIcode (Icode_DUP); stackChange (1); int afterSecondJumpStart = itsICodeTop; int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ; addGotoOp (jump); stackChange (-1); addIcode (Icode_POP); stackChange (-1); child = child.Next; // Preserve tail context flag if any VisitExpression (child, contextFlags & ECF_TAIL); resolveForwardGoto (afterSecondJumpStart); } break; case Token.HOOK: { Node ifThen = child.Next; Node ifElse = ifThen.Next; VisitExpression (child, 0); int elseJumpStart = itsICodeTop; addGotoOp (Token.IFNE); ; stackChange (-1); // Preserve tail context flag if any VisitExpression (ifThen, contextFlags & ECF_TAIL); int afterElseJumpStart = itsICodeTop; addGotoOp (Token.GOTO); resolveForwardGoto (elseJumpStart); itsStackDepth = savedStackDepth; // Preserve tail context flag if any VisitExpression (ifElse, contextFlags & ECF_TAIL); resolveForwardGoto (afterElseJumpStart); } break; case Token.GETPROP: VisitExpression (child, 0); child = child.Next; addStringOp (Token.GETPROP, child.String); break; case Token.ADD: case Token.GETELEM: case Token.DELPROP: case Token.BITAND: case Token.BITOR: case Token.BITXOR: case Token.LSH: case Token.RSH: case Token.URSH: case Token.SUB: case Token.MOD: case Token.DIV: case Token.MUL: case Token.EQ: case Token.NE: case Token.SHEQ: case Token.SHNE: case Token.IN: case Token.INSTANCEOF: case Token.LE: case Token.LT: case Token.GE: case Token.GT: VisitExpression (child, 0); VisitExpression (child.Next, 0); addToken (type); stackChange (-1); break; case Token.POS: case Token.NEG: case Token.NOT: case Token.BITNOT: case Token.TYPEOF: case Token.VOID: VisitExpression (child, 0); if (type == Token.VOID) { addIcode (Icode_POP); addIcode (Icode_UNDEF); } else { addToken (type); } break; case Token.GET_REF: case Token.DEL_REF: VisitExpression (child, 0); addToken (type); break; case Token.SETPROP: case Token.SETPROP_OP: case Token.SETPROP_GETTER: case Token.SETPROP_SETTER: { VisitExpression (child, 0); child = child.Next; string property = child.String; child = child.Next; if (type == Token.SETPROP_OP) { addIcode (Icode_DUP); stackChange (1); addStringOp (Token.GETPROP, property); // Compensate for the following USE_STACK stackChange (-1); } VisitExpression (child, 0); addStringOp ((type == Token.SETPROP_OP) ? Token.SETPROP : type, property); stackChange (-1); } break; case Token.SETELEM: case Token.SETELEM_OP: VisitExpression (child, 0); child = child.Next; VisitExpression (child, 0); child = child.Next; if (type == Token.SETELEM_OP) { addIcode (Icode_DUP2); stackChange (2); addToken (Token.GETELEM); stackChange (-1); // Compensate for the following USE_STACK stackChange (-1); } VisitExpression (child, 0); addToken (Token.SETELEM); stackChange (-2); break; case Token.SET_REF: case Token.SET_REF_OP: VisitExpression (child, 0); child = child.Next; if (type == Token.SET_REF_OP) { addIcode (Icode_DUP); stackChange (1); addToken (Token.GET_REF); // Compensate for the following USE_STACK stackChange (-1); } VisitExpression (child, 0); addToken (Token.SET_REF); stackChange (-1); break; case Token.SETNAME: { string name = child.String; VisitExpression (child, 0); child = child.Next; VisitExpression (child, 0); addStringOp (Token.SETNAME, name); stackChange (-1); } break; case Token.TYPEOFNAME: { string name = node.String; int index = -1; // use typeofname if an activation frame exists // since the vars all exist there instead of in jregs if (itsInFunctionFlag && !itsData.itsNeedsActivation) index = scriptOrFn.getParamOrVarIndex (name); if (index == -1) { addStringOp (Icode_TYPEOFNAME, name); stackChange (1); } else { addVarOp (Token.GETVAR, index); stackChange (1); addToken (Token.TYPEOF); } } break; case Token.BINDNAME: case Token.NAME: case Token.STRING: addStringOp (type, node.String); stackChange (1); break; case Token.INC: case Token.DEC: VisitIncDec (node, child); break; case Token.NUMBER: { double num = node.Double; int inum = (int)num; if (inum == num) { if (inum == 0) { addIcode (Icode_ZERO); // Check for negative zero if (1.0 / num < 0.0) { addToken (Token.NEG); } } else if (inum == 1) { addIcode (Icode_ONE); } else if ((short)inum == inum) { addIcode (Icode_SHORTNUMBER); // write short as uin16 bit pattern addUint16 (inum & 0xFFFF); } else { addIcode (Icode_INTNUMBER); addInt (inum); } } else { int index = GetDoubleIndex (num); addIndexOp (Token.NUMBER, index); } stackChange (1); } break; case Token.GETVAR: { if (itsData.itsNeedsActivation) Context.CodeBug (); string name = node.String; int index = scriptOrFn.getParamOrVarIndex (name); addVarOp (Token.GETVAR, index); stackChange (1); } break; case Token.SETVAR: { if (itsData.itsNeedsActivation) Context.CodeBug (); string name = child.String; child = child.Next; VisitExpression (child, 0); int index = scriptOrFn.getParamOrVarIndex (name); addVarOp (Token.SETVAR, index); } break; case Token.NULL: case Token.THIS: case Token.THISFN: case Token.FALSE: case Token.TRUE: addToken (type); stackChange (1); break; case Token.ENUM_NEXT: case Token.ENUM_ID: addIndexOp (type, getLocalBlockRef (node)); stackChange (1); break; case Token.REGEXP: { int index = node.getExistingIntProp (Node.REGEXP_PROP); addIndexOp (Token.REGEXP, index); stackChange (1); } break; case Token.ARRAYLIT: case Token.OBJECTLIT: VisitLiteral (node, child); break; case Token.REF_SPECIAL: VisitExpression (child, 0); addStringOp (type, (string)node.getProp (Node.NAME_PROP)); break; case Token.REF_MEMBER: case Token.REF_NS_MEMBER: case Token.REF_NAME: case Token.REF_NS_NAME: { int memberTypeFlags = node.getIntProp (Node.MEMBER_TYPE_PROP, 0); // generate possible target, possible namespace and member int childCount = 0; do { VisitExpression (child, 0); ++childCount; child = child.Next; } while (child != null); addIndexOp (type, memberTypeFlags); stackChange (1 - childCount); } break; case Token.DOTQUERY: { int queryPC; updateLineNumber (node); VisitExpression (child, 0); addIcode (Icode_ENTERDQ); stackChange (-1); queryPC = itsICodeTop; VisitExpression (child.Next, 0); addBackwardGoto (Icode_LEAVEDQ, queryPC); } break; case Token.DEFAULTNAMESPACE: case Token.ESCXMLATTR: case Token.ESCXMLTEXT: VisitExpression (child, 0); addToken (type); break; default: throw badTree (node); } //if (savedStackDepth + 1 != itsStackDepth) { // EcmaScriptHelper.CodeBug(); //} }
bool VisitExpressionOptimized (Node node, int contextFlags) { return false; #if FALKSE if (node.Type == Token.ADD) { Node next = node.Next; if (next == null) return false; switch (next.Type) { case Token.NAME: case Token.STRING: return true; } } return false; #endif }
void VisitStatement (Node node) { int type = node.Type; Node child = node.FirstChild; switch (type) { case Token.FUNCTION: { int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP); int fnType = scriptOrFn.getFunctionNode (fnIndex).FunctionType; // Only function expressions or function expression // statements needs closure code creating new function // object on stack as function statements are initialized // at script/function start // In addition function expression can not present here // at statement level, they must only present as expressions. if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { addIndexOp (Icode_CLOSURE_STMT, fnIndex); } else { if (fnType != FunctionNode.FUNCTION_STATEMENT) { throw Context.CodeBug (); } } } break; case Token.SCRIPT: case Token.LABEL: case Token.LOOP: case Token.BLOCK: case Token.EMPTY: case Token.WITH: updateLineNumber (node); while (child != null) { VisitStatement (child); child = child.Next; } break; case Token.ENTERWITH: VisitExpression (child, 0); addToken (Token.ENTERWITH); stackChange (-1); break; case Token.LEAVEWITH: addToken (Token.LEAVEWITH); break; case Token.LOCAL_BLOCK: { int local = allocLocal (); node.putIntProp (Node.LOCAL_PROP, local); updateLineNumber (node); while (child != null) { VisitStatement (child); child = child.Next; } addIndexOp (Icode_LOCAL_CLEAR, local); releaseLocal (local); } break; case Token.DEBUGGER: updateLineNumber (node); addIcode (Icode_DEBUGGER); break; case Token.SWITCH: updateLineNumber (node); { // See comments in IRFactory.createSwitch() for description // of SWITCH node Node switchNode = (Node.Jump)node; VisitExpression (child, 0); for (Node.Jump caseNode = (Node.Jump)child.Next; caseNode != null; caseNode = (Node.Jump)caseNode.Next) { if (caseNode.Type != Token.CASE) throw badTree (caseNode); Node test = caseNode.FirstChild; addIcode (Icode_DUP); stackChange (1); VisitExpression (test, 0); addToken (Token.SHEQ); stackChange (-1); // If true, Icode_IFEQ_POP will jump and remove case // value from stack addGoto (caseNode.target, Icode_IFEQ_POP); stackChange (-1); } addIcode (Icode_POP); stackChange (-1); } break; case Token.TARGET: markTargetLabel (node); break; case Token.IFEQ: case Token.IFNE: { Node target = ((Node.Jump)node).target; VisitExpression (child, 0); addGoto (target, type); stackChange (-1); } break; case Token.GOTO: { Node target = ((Node.Jump)node).target; addGoto (target, type); } break; case Token.JSR: { Node target = ((Node.Jump)node).target; addGoto (target, Icode_GOSUB); } break; case Token.FINALLY: { // Account for incomming GOTOSUB address stackChange (1); int finallyRegister = getLocalBlockRef (node); addIndexOp (Icode_STARTSUB, finallyRegister); stackChange (-1); while (child != null) { VisitStatement (child); child = child.Next; } addIndexOp (Icode_RETSUB, finallyRegister); } break; case Token.EXPR_VOID: case Token.EXPR_RESULT: updateLineNumber (node); VisitExpression (child, 0); addIcode ((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT); stackChange (-1); break; case Token.TRY: { Node.Jump tryNode = (Node.Jump)node; int exceptionObjectLocal = getLocalBlockRef (tryNode); int scopeLocal = allocLocal (); addIndexOp (Icode_SCOPE_SAVE, scopeLocal); int tryStart = itsICodeTop; while (child != null) { VisitStatement (child); child = child.Next; } Node catchTarget = tryNode.target; if (catchTarget != null) { int catchStartPC = itsLabelTable [getTargetLabel (catchTarget)]; addExceptionHandler (tryStart, catchStartPC, catchStartPC, false, exceptionObjectLocal, scopeLocal); } Node finallyTarget = tryNode.Finally; if (finallyTarget != null) { int finallyStartPC = itsLabelTable [getTargetLabel (finallyTarget)]; addExceptionHandler (tryStart, finallyStartPC, finallyStartPC, true, exceptionObjectLocal, scopeLocal); } addIndexOp (Icode_LOCAL_CLEAR, scopeLocal); releaseLocal (scopeLocal); } break; case Token.CATCH_SCOPE: { int localIndex = getLocalBlockRef (node); int scopeIndex = node.getExistingIntProp (Node.CATCH_SCOPE_PROP); string name = child.String; child = child.Next; VisitExpression (child, 0); // load expression object addStringPrefix (name); addIndexPrefix (localIndex); addToken (Token.CATCH_SCOPE); addUint8 (scopeIndex != 0 ? 1 : 0); stackChange (-1); } break; case Token.THROW: updateLineNumber (node); VisitExpression (child, 0); addToken (Token.THROW); addUint16 (itsLineNumber & 0xFFFF); stackChange (-1); break; case Token.RETHROW: updateLineNumber (node); addIndexOp (Token.RETHROW, getLocalBlockRef (node)); break; case Token.RETURN: updateLineNumber (node); if (child != null) { VisitExpression (child, ECF_TAIL); addToken (Token.RETURN); stackChange (-1); } else { addIcode (Icode_RETUNDEF); } break; case Token.RETURN_RESULT: updateLineNumber (node); addToken (Token.RETURN_RESULT); break; case Token.ENUM_INIT_KEYS: case Token.ENUM_INIT_VALUES: VisitExpression (child, 0); addIndexOp (type, getLocalBlockRef (node)); stackChange (-1); break; default: throw badTree (node); } if (itsStackDepth != 0) { throw Context.CodeBug (); } }
ApplicationException badTree (Node node) { throw new ApplicationException (node.ToString ()); }
public void addChildToFront(Node child) { child.next = first; first = child; if (last == null) { last = child; } }
public Node getChildBefore(Node child) { if (child == first) return null; Node n = first; while (n.next != child) { n = n.next; if (n == null) throw new ApplicationException ("node is not a child"); } return n; }
public Node(int nodeType, Node child, int line) : this(nodeType, child) { lineno = line; }
public void replaceChild(Node child, Node newChild) { newChild.next = child.next; if (child == first) { first = newChild; } else { Node prev = getChildBefore (child); prev.next = newChild; } if (child == last) last = newChild; child.next = null; }
public Node(int nodeType, Node left, Node mid, Node right, int line) : this(nodeType, left, mid, right) { lineno = line; }
private static void appendPrintId(Node n, ObjToIntMap printIds, System.Text.StringBuilder sb) { if (Token.printTrees) { if (n != null) { int id = printIds.Get (n, -1); sb.Append ('#'); if (id != -1) { sb.Append (id + 1); } else { sb.Append ("<not_available>"); } } } }
/// <summary> Add 'child' after 'node'.</summary> public void addChildAfter(Node newChild, Node node) { if (newChild.next != null) throw new ApplicationException ("newChild had siblings in addChildAfter"); newChild.next = node.next; node.next = newChild; if (last == node) last = newChild; }
private static void toStringTreeHelper(ScriptOrFnNode treeTop, Node n, ObjToIntMap printIds, int level, System.Text.StringBuilder sb) { if (Token.printTrees) { if (printIds == null) { printIds = new ObjToIntMap (); generatePrintIds (treeTop, printIds); } for (int i = 0; i != level; ++i) { sb.Append (" "); } n.toString (printIds, sb); sb.Append ('\n'); for (Node cursor = n.FirstChild; cursor != null; cursor = cursor.Next) { if (cursor.Type == Token.FUNCTION) { int fnIndex = cursor.getExistingIntProp (Node.FUNCTION_PROP); FunctionNode fn = treeTop.getFunctionNode (fnIndex); toStringTreeHelper (fn, fn, null, level + 1, sb); } else { toStringTreeHelper (treeTop, cursor, printIds, level + 1, sb); } } } }
/// <summary> Add 'child' before 'node'.</summary> public void addChildBefore(Node newChild, Node node) { if (newChild.next != null) throw new ApplicationException ("newChild had siblings in addChildBefore"); if (first == node) { newChild.next = first; first = newChild; return; } Node prev = getChildBefore (node); addChildAfter (newChild, prev); }
internal Jump(int Type, Node child, int lineno) : base(Type, child, lineno) { }
public void addChildrenToBack(Node children) { if (last != null) { last.next = children; } last = children.LastSibling; if (first == null) { first = children; } }
public Node(int nodeType, Node left, Node right) { Type = nodeType; first = left; last = right; left.next = right; right.next = null; }
public void addChildrenToFront(Node children) { Node lastSib = children.LastSibling; lastSib.next = first; first = children; if (last == null) { last = lastSib; } }
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: ; } } }
public void addChildToBack(Node child) { child.next = null; if (last == null) { first = last = child; return; } last.next = child; last = child; }