/// <summary> /// Set the /// <see cref="Scope">Scope</see> /// associated with this node. This method does not /// set the scope's ast-node field to this node. The field exists only /// for temporary storage by the code generator. Not every name has an /// associated scope - typically only function and variable names (but not /// property names) are registered in a scope. /// </summary> /// <param name="s"> /// the scope. Can be null. Doesn't set any fields in the /// scope. /// </param> public override void SetScope(Scope s) { scope = s; }
/// <summary>Sets this symbol's Scope</summary> public virtual void SetContainingTable(Scope containingTable) { this.containingTable = containingTable; }
/// <summary>Used only for code generation.</summary> /// <remarks>Used only for code generation.</remarks> public virtual void ClearParentScope() { this.parentScope = null; }
/// <summary>Sets parent scope</summary> public virtual void SetParentScope(Rhino.Ast.Scope parentScope) { this.parentScope = parentScope; this.top = parentScope == null ? (ScriptNode)this : parentScope.top; }
/// <summary> /// Creates a new scope node, moving symbol table information /// from "scope" to the new node, and making "scope" a nested /// scope contained by the new node. /// </summary> /// <remarks> /// Creates a new scope node, moving symbol table information /// from "scope" to the new node, and making "scope" a nested /// scope contained by the new node. /// Useful for injecting a new scope in a scope chain. /// </remarks> public static Rhino.Ast.Scope SplitScope(Rhino.Ast.Scope scope) { Rhino.Ast.Scope result = new Rhino.Ast.Scope(scope.GetType()); result.symbolTable = scope.symbolTable; scope.symbolTable = null; result.parent = scope.parent; result.SetParentScope(scope.GetParentScope()); result.SetParentScope(result); scope.parent = result; result.top = scope.top; return result; }
private Node CreateFor(Scope loop, Node init, Node test, Node incr, Node body) { if (init.GetType() == Token.LET) { // rewrite "for (let i=s; i < N; i++)..." as // "let (i=s) { for (; i < N; i++)..." so that "s" is evaluated // outside the scope of the for. Scope let = Scope.SplitScope(loop); let.SetType(Token.LET); let.AddChildrenToBack(init); let.AddChildToBack(CreateLoop(loop, LOOP_FOR, body, test, new Node(Token.EMPTY), incr)); return let; } return CreateLoop(loop, LOOP_FOR, body, test, init, incr); }
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: ; }