📄 nodetransformer.java
字号:
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 boolean createWith = tree.getType() != Token.FUNCTION || ((FunctionNode)tree).requiresActivation(); node = visitLet(createWith, parent, previous, node); break; } else { // fall through to process let declaration... } } /* fall through */ case Token.CONST: case Token.VAR: { 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: { Node.Scope defining = scope.getDefiningScope(node.getString()); if (defining != null) { node.setScope(defining); } } break; case Token.TYPEOF: case Token.IFNE: { /* We want to suppress warnings for undefined property o.p * for the following constructs: typeof o.p, if (o.p), * if (!o.p), if (o.p == undefined), if (undefined == o.p) */ 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.NAME: case Token.SETNAME: 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(); Node.Scope defining = scope.getDefiningScope(name); if (defining != null) { nameSource.setScope(defining); if (type == Token.NAME) { node.setType(Token.GETVAR); } else if (type == Token.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 instanceof Node.Scope ? (Node.Scope)node : scope, createScopeObjects); } } protected void visitNew(Node node, ScriptOrFnNode tree) { } protected void visitCall(Node node, ScriptOrFnNode tree) { } protected Node visitLet(boolean createWith, Node parent, Node previous, Node scopeNode) { Node vars = scopeNode.getFirstChild(); Node body = vars.getNext(); scopeNode.removeChild(vars); scopeNode.removeChild(body); boolean isExpression = scopeNode.getType() == Token.LETEXPR; Node result; Node newVars; if (createWith) { result = new Node(isExpression ? Token.WITHEXPR : Token.BLOCK); result = replaceCurrent(parent, previous, scopeNode, result); ArrayList<Object> list = new ArrayList<Object>(); Node objectLiteral = new Node(Token.OBJECTLIT); for (Node v=vars.getFirstChild(); v != null; v = v.getNext()) { Node current = v; if (current.getType() == Token.LETEXPR) { // destructuring in let expr, e.g. let ([x, y] = [3, 4]) {} List<?> destructuringNames = (List<?>) current.getProp(Node.DESTRUCTURING_NAMES); Node c = current.getFirstChild(); if (c.getType() != Token.LET) throw Kit.codeBug(); // Add initialization code to front of body if (isExpression) { body = new Node(Token.COMMA, c.getNext(), body); } else { body = new Node(Token.BLOCK, new Node(Token.EXPR_VOID, c.getNext()), body); } // Update "list" and "objectLiteral" for the variables // defined in the destructuring assignment if (destructuringNames != null) { list.addAll(destructuringNames); for (int i=0; i < destructuringNames.size(); i++) { objectLiteral.addChildToBack( new Node(Token.VOID, Node.newNumber(0.0))); } } current = c.getFirstChild(); // should be a NAME, checked below } if (current.getType() != Token.NAME) throw Kit.codeBug(); list.add(ScriptRuntime.getIndexObject(current.getString())); Node init = current.getFirstChild(); if (init == null) { init = new Node(Token.VOID, Node.newNumber(0.0)); } objectLiteral.addChildToBack(init); } objectLiteral.putProp(Node.OBJECT_IDS_PROP, list.toArray()); newVars = new Node(Token.ENTERWITH, objectLiteral); result.addChildToBack(newVars); result.addChildToBack(new Node(Token.WITH, body)); result.addChildToBack(new Node(Token.LEAVEWITH)); } else { result = new Node(isExpression ? Token.COMMA : Token.BLOCK); result = replaceCurrent(parent, previous, scopeNode, result); newVars = new Node(Token.COMMA); for (Node v=vars.getFirstChild(); v != null; v = v.getNext()) { Node current = v; if (current.getType() == Token.LETEXPR) { // destructuring in let expr, e.g. let ([x, y] = [3, 4]) {} Node c = current.getFirstChild(); if (c.getType() != Token.LET) throw Kit.codeBug(); // Add initialization code to front of body if (isExpression) { body = new Node(Token.COMMA, c.getNext(), body); } else { body = new Node(Token.BLOCK, new Node(Token.EXPR_VOID, c.getNext()), body); } // We're removing the LETEXPR, so move the symbols Node.Scope.joinScopes((Node.Scope)current, (Node.Scope)scopeNode); current = c.getFirstChild(); // should be a NAME, checked below } if (current.getType() != Token.NAME) throw Kit.codeBug(); Node stringNode = Node.newString(current.getString()); stringNode.setScope((Node.Scope)scopeNode); Node init = current.getFirstChild(); if (init == null) { init = new Node(Token.VOID, Node.newNumber(0.0)); } newVars.addChildToBack(new Node(Token.SETVAR, stringNode, init)); } if (isExpression) { result.addChildToBack(newVars); scopeNode.setType(Token.COMMA); result.addChildToBack(scopeNode); scopeNode.addChildToBack(body); } else { result.addChildToBack(new Node(Token.EXPR_VOID, newVars)); scopeNode.setType(Token.BLOCK); result.addChildToBack(scopeNode); scopeNode.addChildrenToBack(body); } } return result; } private static Node addBeforeCurrent(Node parent, Node previous, Node current, Node toAdd) { if (previous == null) { if (!(current == parent.getFirstChild())) Kit.codeBug(); parent.addChildToFront(toAdd); } else { if (!(current == previous.getNext())) Kit.codeBug(); parent.addChildAfter(toAdd, previous); } return toAdd; } private static Node replaceCurrent(Node parent, Node previous, Node current, Node replacement) { if (previous == null) { if (!(current == parent.getFirstChild())) Kit.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; } private ObjArray loops; private ObjArray loopEnds; private boolean hasFinally;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -