📄 irfactory.java
字号:
double ld = left.getDouble(); if (right.type == Token.NUMBER) { //both numbers left.setDouble(ld * right.getDouble()); return left; } else if (ld == 1.0) { // first 1: 1 * x -> +x return new Node(Token.POS, right); } } else if (right.type == Token.NUMBER) { if (right.getDouble() == 1.0) { //second 1: x * 1 -> +x // can not make simply x because x - 0 must be number return new Node(Token.POS, left); } } // can't do x*0: Infinity * 0 gives NaN, not 0 break; case Token.DIV: // number division if (right.type == Token.NUMBER) { double rd = right.getDouble(); if (left.type == Token.NUMBER) { // both constants -- just divide, trust Java to handle x/0 left.setDouble(left.getDouble() / rd); return left; } else if (rd == 1.0) { // second 1: x/1 -> +x // not simply x to force number convertion return new Node(Token.POS, left); } } break; case Token.AND: { // Since x && y gives x, not false, when Boolean(x) is false, // and y, not Boolean(y), when Boolean(x) is true, x && y // can only be simplified if x is defined. See bug 309957. int leftStatus = isAlwaysDefinedBoolean(left); if (leftStatus == ALWAYS_FALSE_BOOLEAN) { // if the first one is false, just return it return left; } else if (leftStatus == ALWAYS_TRUE_BOOLEAN) { // if first is true, set to second return right; } break; } case Token.OR: { // Since x || y gives x, not true, when Boolean(x) is true, // and y, not Boolean(y), when Boolean(x) is false, x || y // can only be simplified if x is defined. See bug 309957. int leftStatus = isAlwaysDefinedBoolean(left); if (leftStatus == ALWAYS_TRUE_BOOLEAN) { // if the first one is true, just return it return left; } else if (leftStatus == ALWAYS_FALSE_BOOLEAN) { // if first is false, set to second return right; } break; } } return new Node(nodeType, left, right); } private Node simpleAssignment(Node left, Node right) { int nodeType = left.getType(); switch (nodeType) { case Token.NAME: left.setType(Token.BINDNAME); return new Node(Token.SETNAME, left, right); case Token.GETPROP: case Token.GETELEM: { Node obj = left.getFirstChild(); Node id = left.getLastChild(); int type; if (nodeType == Token.GETPROP) { type = Token.SETPROP; } else { type = Token.SETELEM; } return new Node(type, obj, id, right); } case Token.GET_REF: { Node ref = left.getFirstChild(); checkMutableReference(ref); return new Node(Token.SET_REF, ref, right); } } throw Kit.codeBug(); } private void checkMutableReference(Node n) { int memberTypeFlags = n.getIntProp(Node.MEMBER_TYPE_PROP, 0); if ((memberTypeFlags & Node.DESCENDANTS_FLAG) != 0) { parser.reportError("msg.bad.assign.left"); } } Node createAssignment(int assignType, Node left, Node right) { Node ref = makeReference(left); if (ref == null) { if (left.getType() == Token.ARRAYLIT || left.getType() == Token.OBJECTLIT) { if (assignType != Token.ASSIGN) { parser.reportError("msg.bad.destruct.op"); return right; } return createDestructuringAssignment(-1, left, right); } parser.reportError("msg.bad.assign.left"); return right; } left = ref; int assignOp; switch (assignType) { case Token.ASSIGN: return simpleAssignment(left, right); case Token.ASSIGN_BITOR: assignOp = Token.BITOR; break; case Token.ASSIGN_BITXOR: assignOp = Token.BITXOR; break; case Token.ASSIGN_BITAND: assignOp = Token.BITAND; break; case Token.ASSIGN_LSH: assignOp = Token.LSH; break; case Token.ASSIGN_RSH: assignOp = Token.RSH; break; case Token.ASSIGN_URSH: assignOp = Token.URSH; break; case Token.ASSIGN_ADD: assignOp = Token.ADD; break; case Token.ASSIGN_SUB: assignOp = Token.SUB; break; case Token.ASSIGN_MUL: assignOp = Token.MUL; break; case Token.ASSIGN_DIV: assignOp = Token.DIV; break; case Token.ASSIGN_MOD: assignOp = Token.MOD; break; default: throw Kit.codeBug(); } int nodeType = left.getType(); switch (nodeType) { case Token.NAME: { Node op = new Node(assignOp, left, right); Node lvalueLeft = Node.newString(Token.BINDNAME, left.getString()); return new Node(Token.SETNAME, lvalueLeft, op); } case Token.GETPROP: case Token.GETELEM: { Node obj = left.getFirstChild(); Node id = left.getLastChild(); int type = nodeType == Token.GETPROP ? Token.SETPROP_OP : Token.SETELEM_OP; Node opLeft = new Node(Token.USE_STACK); Node op = new Node(assignOp, opLeft, right); return new Node(type, obj, id, op); } case Token.GET_REF: { ref = left.getFirstChild(); checkMutableReference(ref); Node opLeft = new Node(Token.USE_STACK); Node op = new Node(assignOp, opLeft, right); return new Node(Token.SET_REF_OP, ref, op); } } throw Kit.codeBug(); } /** * Given a destructuring assignment with a left hand side parsed * as an array or object literal and a right hand side expression, * rewrite as a series of assignments to the variables defined in * left from property accesses to the expression on the right. * @param type declaration type: Token.VAR or Token.LET or -1 * @param left array or object literal containing NAME nodes for * variables to assign * @param right expression to assign from * @return expression that performs a series of assignments to * the variables defined in left */ Node createDestructuringAssignment(int type, Node left, Node right) { String tempName = parser.currentScriptOrFn.getNextTempName(); Node result = destructuringAssignmentHelper(type, left, right, tempName); Node comma = result.getLastChild(); comma.addChildToBack(createName(tempName)); return result; } private Node destructuringAssignmentHelper(int variableType, Node left, Node right, String tempName) { Node result = createScopeNode(Token.LETEXPR, parser.getCurrentLineNumber()); result.addChildToFront(new Node(Token.LET, createName(Token.NAME, tempName, right))); try { parser.pushScope(result); parser.defineSymbol(Token.LET, tempName); } finally { parser.popScope(); } Node comma = new Node(Token.COMMA); result.addChildToBack(comma); final int setOp = variableType == Token.CONST ? Token.SETCONST : Token.SETNAME; List<String> destructuringNames = new ArrayList<String>(); boolean empty = true; int type = left.getType(); if (type == Token.ARRAYLIT) { int index = 0; int[] skipIndices = (int[])left.getProp(Node.SKIP_INDEXES_PROP); int skip = 0; Node n = left.getFirstChild(); for (;;) { if (skipIndices != null) { while (skip < skipIndices.length && skipIndices[skip] == index) { skip++; index++; } } if (n == null) break; Node rightElem = new Node(Token.GETELEM, createName(tempName), createNumber(index)); if (n.getType() == Token.NAME) { String name = n.getString(); comma.addChildToBack(new Node(setOp, createName(Token.BINDNAME, name, null), rightElem)); if (variableType != -1) { parser.defineSymbol(variableType, name); destructuringNames.add(name); } } else { comma.addChildToBack( destructuringAssignmentHelper(variableType, n, rightElem, parser.currentScriptOrFn.getNextTempName())); } index++; empty = false; n = n.getNext(); } } else if (type == Token.OBJECTLIT) { int index = 0; Object[] propertyIds = (Object[]) left.getProp(Node.OBJECT_IDS_PROP); for (Node n = left.getFirstChild(); n != null; n = n.getNext()) { Object id = propertyIds[index]; Node rightElem = id instanceof String ? new Node(Token.GETPROP, createName(tempName), createString((String)id)) : new Node(Token.GETELEM, createName(tempName), createNumber(((Number)id).intValue())); if (n.getType() == Token.NAME) { String name = n.getString(); comma.addChildToBack(new Node(setOp, createName(Token.BINDNAME, name, null), rightElem)); if (variableType != -1) { parser.defineSymbol(variableType, name); destructuringNames.add(name); } } else { comma.addChildToBack( destructuringAssignmentHelper(variableType, n, rightElem, parser.currentScriptOrFn.getNextTempName())); } index++; empty = false; } } else if (type == Token.GETPROP || type == Token.GETELEM) { comma.addChildToBack(simpleAssignment(left, createName(tempName))); } else { parser.reportError("msg.bad.assign.left"); } if (empty) { // Don't want a COMMA node with no children. Just add a zero. comma.addChildToBack(createNumber(0)); } result.putProp(Node.DESTRUCTURING_NAMES, destructuringNames); return result; } Node createUseLocal(Node localBlock) { if (Token.LOCAL_BLOCK != localBlock.getType()) throw Kit.codeBug(); Node result = new Node(Token.LOCAL_LOAD); result.putProp(Node.LOCAL_BLOCK_PROP, localBlock); return result; } private Node.Jump makeJump(int type, Node target) { Node.Jump n = new Node.Jump(type); n.target = target; return n; } private Node makeReference(Node node) { int type = node.getType(); switch (type) { case Token.NAME: case Token.GETPROP: case Token.GETELEM: case Token.GET_REF: return node; case Token.CALL: node.setType(Token.REF_CALL); return new Node(Token.GET_REF, node); } // Signal caller to report error return null; } // Check if Node always mean true or false in boolean context private static int isAlwaysDefinedBoolean(Node node) { switch (node.getType()) { case Token.FALSE: case Token.NULL: return ALWAYS_FALSE_BOOLEAN; case Token.TRUE: return ALWAYS_TRUE_BOOLEAN; case Token.NUMBER: { double num = node.getDouble(); if (num == num && num != 0.0) { return ALWAYS_TRUE_BOOLEAN; } else { return ALWAYS_FALSE_BOOLEAN; } } } return 0; } private void checkActivationName(String name, int token) { if (parser.insideFunction()) { boolean activation = false; if ("arguments".equals(name) || (parser.compilerEnv.activationNames != null && parser.compilerEnv.activationNames.containsKey(name))) { activation = true; } else if ("length".equals(name)) { if (token == Token.GETPROP && parser.compilerEnv.getLanguageVersion() == Context.VERSION_1_2) { // Use of "length" in 1.2 requires an activation object. activation = true; } } if (activation) { setRequiresActivation(); } } } private void setRequiresActivation() { if (parser.insideFunction()) { ((FunctionNode)parser.currentScriptOrFn).itsNeedsActivation = true; } } private void setIsGenerator() { if (parser.insideFunction()) { ((FunctionNode)parser.currentScriptOrFn).itsIsGenerator = true; } } private Parser parser; private static final int LOOP_DO_WHILE = 0; private static final int LOOP_WHILE = 1; private static final int LOOP_FOR = 2; private static final int ALWAYS_TRUE_BOOLEAN = 1; private static final int ALWAYS_FALSE_BOOLEAN = -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -