private List<IdentNode> convertArrowFunctionParameterList(final Expression paramListExpr, final int functionLine) { final List<IdentNode> parameters; if (paramListExpr == null) { // empty parameter list, i.e. () => parameters = Collections.emptyList(); } else if (paramListExpr instanceof IdentNode || paramListExpr.isTokenType(ASSIGN) || isDestructuringLhs(paramListExpr)) { parameters = Collections.singletonList(verifyArrowParameter(paramListExpr, 0, functionLine)); } else if (paramListExpr instanceof BinaryNode && Token.descType(paramListExpr.getToken()) == COMMARIGHT) { parameters = new ArrayList<>(); Expression car = paramListExpr; do { final Expression cdr = ((BinaryNode) car).rhs(); parameters.add(0, verifyArrowParameter(cdr, parameters.size(), functionLine)); car = ((BinaryNode) car).lhs(); } while (car instanceof BinaryNode && Token.descType(car.getToken()) == COMMARIGHT); parameters.add(0, verifyArrowParameter(car, parameters.size(), functionLine)); } else { throw error(AbstractParser.message("expected.arrow.parameter"), paramListExpr.getToken()); } return parameters; }
private void loadASSIGN(final BinaryNode binaryNode) { final Expression lhs = binaryNode.lhs(); final Expression rhs = binaryNode.rhs(); final Type rhsType = rhs.getType(); // Detect dead assignments if(lhs instanceof IdentNode) { final Symbol symbol = ((IdentNode)lhs).getSymbol(); if(!symbol.isScope() && !symbol.hasSlotFor(rhsType) && lc.getCurrentDiscard() == binaryNode) { loadAndDiscard(rhs); lc.popDiscard(); method.markDeadLocalVariable(symbol); return; } } new Store<BinaryNode>(binaryNode, lhs) { @Override protected void evaluate() { // NOTE: we're loading with "at least as wide as" so optimistic operations on the right hand side // remain optimistic, and then explicitly convert to the required type if needed. loadExpressionAsType(rhs, rhsType); } }.store(); }
AssignmentTreeImpl(final BinaryNode node, final ExpressionTree left, final ExpressionTree right) { super(node); assert node.isAssignment() : "assignment node expected"; this.var = left; this.expr = right; this.kind = getOperator(node.tokenType()); }
private void loadASSIGN_DIV(final BinaryNode binaryNode) { new BinaryOptimisticSelfAssignment(binaryNode) { @Override protected void op(final OptimisticOperation oo) { method.div(oo.getProgramPoint()); } }.store(); }
private void loadASSIGN_BIT_XOR(final BinaryNode binaryNode) { new BinarySelfAssignment(binaryNode) { @Override protected void op() { method.xor(); } }.store(); }
private void loadBIT_OR(final BinaryNode binaryNode) { // Optimize x|0 to (int)x if (isRhsZero(binaryNode)) { loadExpressionAsType(binaryNode.lhs(), Type.INT); } else { loadBinaryOperands(binaryNode); method.or(); } }
@Override public boolean enterBinaryNode(final BinaryNode binaryNode) { if (binaryNode.isTokenType(ASSIGN)) { binaryNode.lhs().accept(this); // Initializer(rhs) can be any AssignmentExpression return false; } else { return enterDefault(binaryNode); } }
private void loadASSIGN_ADD(final BinaryNode binaryNode) { new BinaryOptimisticSelfAssignment(binaryNode) { @Override protected void op(final OptimisticOperation oo) { assert !(binaryNode.getType().isObject() && oo.isOptimistic); method.add(oo.getProgramPoint()); } }.store(); }
/** * Is this an assignment to the special variable that hosts scripting eval * results, i.e. __return__? * * @param expression expression to check whether it is $evalresult = X * @return true if an assignment to eval result, false otherwise */ private static boolean isEvalResultAssignment(final Node expression) { final Node e = expression; if (e instanceof BinaryNode) { final Node lhs = ((BinaryNode)e).lhs(); if (lhs instanceof IdentNode) { return ((IdentNode)lhs).getName().equals(RETURN.symbolName()); } } return false; }
private void loadMOD(final BinaryNode binaryNode, final TypeBounds resultBounds) { new BinaryArith() { @Override protected void op(final int programPoint) { method.rem(programPoint); } }.evaluate(binaryNode, resultBounds); }
private void loadSUB(final BinaryNode binaryNode, final TypeBounds resultBounds) { new BinaryArith() { @Override protected void op(final int programPoint) { method.sub(programPoint); } }.evaluate(binaryNode, resultBounds); }
private void loadDIV(final BinaryNode binaryNode, final TypeBounds resultBounds) { new BinaryArith() { @Override protected void op(final int programPoint) { method.div(programPoint); } }.evaluate(binaryNode, resultBounds); }
@Override public Node leaveBinaryNode(final BinaryNode binaryNode) { if (binaryNode.isAssignment() && binaryNode.lhs() instanceof IdentNode) { checkConstAssignment((IdentNode) binaryNode.lhs()); } switch (binaryNode.tokenType()) { case ASSIGN: return leaveASSIGN(binaryNode); default: return super.leaveBinaryNode(binaryNode); } }
@Override public Node leaveEQ_STRICT(final BinaryNode binaryNode) { return compareWeight(binaryNode); }
private static void enqueueChildren(final Node node, final Class<?> nodeClass, final List<Field> children) { final Deque<Class<?>> stack = new ArrayDeque<>(); /** * Here is some ugliness that can be overcome by proper ChildNode annotations * with proper orders. Right now we basically sort all classes up to Node * with super class first, as this often is the natural order, e.g. base * before index for an IndexNode. * * Also there are special cases as this is not true for UnaryNodes(lhs) and * BinaryNodes extends UnaryNode (with lhs), and TernaryNodes. * * TODO - generalize traversal with an order built on annotations and this * will go away. */ Class<?> clazz = nodeClass; do { stack.push(clazz); clazz = clazz.getSuperclass(); } while (clazz != null); if (node instanceof TernaryNode) { // HACK juggle "third" stack.push(stack.removeLast()); } // HACK change operator order for BinaryNodes to get lhs first. final Iterator<Class<?>> iter = node instanceof BinaryNode ? stack.descendingIterator() : stack.iterator(); while (iter.hasNext()) { final Class<?> c = iter.next(); for (final Field f : c.getDeclaredFields()) { try { f.setAccessible(true); final Object child = f.get(node); if (child == null) { continue; } if (child instanceof Node) { children.add(f); } else if (child instanceof Collection) { if (!((Collection<?>)child).isEmpty()) { children.add(f); } } } catch (final IllegalArgumentException | IllegalAccessException e) { return; } } } }
@Override public Node leaveBIND(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
@Override public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
@Override public Node leaveASSIGN(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
@Override public Node leaveOR(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
private void loadSAR(final BinaryNode binaryNode) { loadBinaryOperands(binaryNode); method.sar(); }
private void loadCOMMALEFT(final BinaryNode binaryNode, final TypeBounds resultBounds) { loadMaybeDiscard(binaryNode, binaryNode.lhs(), resultBounds); loadAndDiscard(binaryNode.rhs()); }
@Override public Node leaveASSIGN_SUB(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
@Override public Node leaveBinaryNode(final BinaryNode binaryNode) { return setProgramPoint(binaryNode); }
@Override public Node leaveASSIGN_ADD(final BinaryNode binaryNode) { weight += ADD_WEIGHT; return binaryNode; }
@Override public Node leaveGE(final BinaryNode binaryNode) { return compareWeight(binaryNode); }
BinarySelfAssignment(final BinaryNode node) { super(node, node.lhs()); }
@Override public Node leaveGT(final BinaryNode binaryNode) { return compareWeight(binaryNode); }
@Override public Node leaveSAR(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
@Override public Node leaveMOD(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
@Override public Node leaveDIV(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }
@Override public Node leaveNE_STRICT(final BinaryNode binaryNode) { return compareWeight(binaryNode); }
private Node compareWeight(final BinaryNode binaryNode) { weight += COMPARE_WEIGHT; return binaryNode; }
private void loadBIT_XOR(final BinaryNode binaryNode) { loadBinaryOperands(binaryNode); method.xor(); }
@Override public Node leaveINSTANCEOF(final BinaryNode binaryNode) { return new RuntimeNode(binaryNode); }
@Override public Node leaveIN(final BinaryNode binaryNode) { weight += CALL_WEIGHT; return binaryNode; }
@Override public Node leaveBIT_AND(final BinaryNode binaryNode) { return binaryNodeWeight(binaryNode); }