📄 irfactory.java
字号:
/** * Add a child to the back of the given node. This function * breaks the Factory abstraction, but it removes a requirement * from implementors of Node. */ void addChildToBack(Node parent, Node child) { parent.addChildToBack(child); } /** * Create a node that can be used to hold lexically scoped variable * definitions (via let declarations). * * @param token the token of the node to create * @param lineno line number of source * @return the created node */ Node createScopeNode(int token, int lineno) { return new Node.Scope(token, lineno); } /** * Create loop node. The parser will later call * createWhile|createDoWhile|createFor|createForIn * to finish loop generation. */ Node createLoopNode(Node loopLabel, int lineno) { Node.Jump result = new Node.Scope(Token.LOOP, lineno); if (loopLabel != null) { ((Node.Jump)loopLabel).setLoop(result); } return result; } /** * While */ Node createWhile(Node loop, Node cond, Node body) { return createLoop((Node.Jump)loop, LOOP_WHILE, body, cond, null, null); } /** * DoWhile */ Node createDoWhile(Node loop, Node body, Node cond) { return createLoop((Node.Jump)loop, LOOP_DO_WHILE, body, cond, null, null); } /** * For */ Node createFor(Node 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. Node.Scope let = Node.Scope.splitScope((Node.Scope)loop); let.setType(Token.LET); let.addChildrenToBack(init); let.addChildToBack(createLoop((Node.Jump)loop, LOOP_FOR, body, test, new Node(Token.EMPTY), incr)); return let; } return createLoop((Node.Jump)loop, LOOP_FOR, body, test, init, incr); } 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.getType() == 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.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; } /** * For .. In * */ Node createForIn(int declType, Node loop, Node lhs, Node obj, Node body, boolean isForEach) { int destructuring = -1; int destructuringLen = 0; Node lvalue; int type = lhs.getType(); if (type == Token.VAR || type == Token.LET) { Node lastChild = lhs.getLastChild(); if (lhs.getFirstChild() != lastChild) { /* * check that there was only one variable given. * we can't do this in the parser, because then the * parser would have to know something about the * 'init' node of the for-in loop. */ parser.reportError("msg.mult.index"); } if (lastChild.getType() == Token.ARRAYLIT || lastChild.getType() == Token.OBJECTLIT) { type = destructuring = lastChild.getType(); lvalue = lastChild; destructuringLen = lastChild.getIntProp( Node.DESTRUCTURING_ARRAY_LENGTH, 0); } else if (lastChild.getType() == Token.NAME) { lvalue = Node.newString(Token.NAME, lastChild.getString()); } else { parser.reportError("msg.bad.for.in.lhs"); return obj; } } else if (type == Token.ARRAYLIT || type == Token.OBJECTLIT) { destructuring = type; lvalue = lhs; destructuringLen = lhs.getIntProp(Node.DESTRUCTURING_ARRAY_LENGTH, 0); } else { lvalue = makeReference(lhs); if (lvalue == null) { parser.reportError("msg.bad.for.in.lhs"); return obj; } } Node localBlock = new Node(Token.LOCAL_BLOCK); int initType = (isForEach) ? Token.ENUM_INIT_VALUES : (destructuring != -1) ? Token.ENUM_INIT_ARRAY : Token.ENUM_INIT_KEYS; Node init = new Node(initType, obj); init.putProp(Node.LOCAL_BLOCK_PROP, localBlock); Node cond = new Node(Token.ENUM_NEXT); cond.putProp(Node.LOCAL_BLOCK_PROP, localBlock); Node id = new Node(Token.ENUM_ID); id.putProp(Node.LOCAL_BLOCK_PROP, localBlock); Node newBody = new Node(Token.BLOCK); Node assign; if (destructuring != -1) { assign = createDestructuringAssignment(declType, lvalue, id); if (!isForEach && (destructuring == Token.OBJECTLIT || destructuringLen != 2)) { // destructuring assignment is only allowed in for..each or // with an array type of length 2 (to hold key and value) parser.reportError("msg.bad.for.in.destruct"); } } else { assign = simpleAssignment(lvalue, id); } newBody.addChildToBack(new Node(Token.EXPR_VOID, assign)); newBody.addChildToBack(body); loop = createWhile(loop, cond, newBody); loop.addChildToFront(init); if (type == Token.VAR || type == Token.LET) loop.addChildToFront(lhs); localBlock.addChildToBack(loop); return localBlock; } /** * 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. */ Node createTryCatchFinally(Node tryBlock, Node catchBlocks, Node finallyBlock, int lineno) { boolean hasFinally = (finallyBlock != null) && (finallyBlock.getType() != Token.BLOCK || finallyBlock.hasChildren()); // short circuit if (tryBlock.getType() == Token.BLOCK && !tryBlock.hasChildren() && !hasFinally) { return tryBlock; } boolean 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.getFirstChild(); boolean 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; } /** * Throw, Return, Label, Break and Continue are defined in ASTFactory. */ /** * With */ Node createWith(Node obj, Node body, int lineno)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -