public void eval(BinaryExpression expression) { switch (expression.getOperation().getType()) { case EQUAL: // = assignment evaluateEqual(expression, false); break; case COMPARE_EQUAL: // == evaluateCompareExpression(compareEqualMethod, expression); break; case COMPARE_NOT_EQUAL: evaluateCompareExpression(compareNotEqualMethod, expression); break; case COMPARE_TO: evaluateCompareTo(expression); break; case COMPARE_GREATER_THAN: evaluateCompareExpression(compareGreaterThanMethod, expression); break; case COMPARE_GREATER_THAN_EQUAL: evaluateCompareExpression(compareGreaterThanEqualMethod, expression); break; case COMPARE_LESS_THAN: evaluateCompareExpression(compareLessThanMethod, expression); break; case COMPARE_LESS_THAN_EQUAL: evaluateCompareExpression(compareLessThanEqualMethod, expression); break; case LOGICAL_AND: evaluateLogicalAndExpression(expression); break; case LOGICAL_OR: evaluateLogicalOrExpression(expression); break; case BITWISE_AND: evaluateBinaryExpression("and", expression); break; case BITWISE_AND_EQUAL: evaluateBinaryExpressionWithAssignment("and", expression); break; case BITWISE_OR: evaluateBinaryExpression("or", expression); break; case BITWISE_OR_EQUAL: evaluateBinaryExpressionWithAssignment("or", expression); break; case BITWISE_XOR: evaluateBinaryExpression("xor", expression); break; case BITWISE_XOR_EQUAL: evaluateBinaryExpressionWithAssignment("xor", expression); break; case PLUS: evaluateBinaryExpression("plus", expression); break; case PLUS_EQUAL: evaluateBinaryExpressionWithAssignment("plus", expression); break; case MINUS: evaluateBinaryExpression("minus", expression); break; case MINUS_EQUAL: evaluateBinaryExpressionWithAssignment("minus", expression); break; case MULTIPLY: evaluateBinaryExpression("multiply", expression); break; case MULTIPLY_EQUAL: evaluateBinaryExpressionWithAssignment("multiply", expression); break; case DIVIDE: evaluateBinaryExpression("div", expression); break; case DIVIDE_EQUAL: // SPG don't use divide since BigInteger implements directly // and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result evaluateBinaryExpressionWithAssignment("div", expression); break; case INTDIV: evaluateBinaryExpression("intdiv", expression); break; case INTDIV_EQUAL: evaluateBinaryExpressionWithAssignment("intdiv", expression); break; case MOD: evaluateBinaryExpression("mod", expression); break; case MOD_EQUAL: evaluateBinaryExpressionWithAssignment("mod", expression); break; case POWER: evaluateBinaryExpression("power", expression); break; case POWER_EQUAL: evaluateBinaryExpressionWithAssignment("power", expression); break; case LEFT_SHIFT: evaluateBinaryExpression("leftShift", expression); break; case LEFT_SHIFT_EQUAL: evaluateBinaryExpressionWithAssignment("leftShift", expression); break; case RIGHT_SHIFT: evaluateBinaryExpression("rightShift", expression); break; case RIGHT_SHIFT_EQUAL: evaluateBinaryExpressionWithAssignment("rightShift", expression); break; case RIGHT_SHIFT_UNSIGNED: evaluateBinaryExpression("rightShiftUnsigned", expression); break; case RIGHT_SHIFT_UNSIGNED_EQUAL: evaluateBinaryExpressionWithAssignment("rightShiftUnsigned", expression); break; case KEYWORD_INSTANCEOF: evaluateInstanceof(expression); break; case FIND_REGEX: evaluateCompareExpression(findRegexMethod, expression); break; case MATCH_REGEX: evaluateCompareExpression(matchRegexMethod, expression); break; case LEFT_SQUARE_BRACKET: if (controller.getCompileStack().isLHS()) { evaluateEqual(expression, false); } else { evaluateBinaryExpression("getAt", expression); } break; case KEYWORD_IN: evaluateCompareExpression(isCaseMethod, expression); break; case COMPARE_IDENTICAL: case COMPARE_NOT_IDENTICAL: Token op = expression.getOperation(); Throwable cause = new SyntaxException( "Operator " + op + " not supported", op.getStartLine(), op.getStartColumn(), op.getStartLine(), op.getStartColumn() + 3); throw new GroovyRuntimeException(cause); default: throw new GroovyBugError("Operation: " + expression.getOperation() + " not supported"); } }
Expression transformBinaryExpression(final BinaryExpression bin) { if (bin instanceof DeclarationExpression) { Expression optimized = transformDeclarationExpression(bin); if (optimized != null) { return optimized; } } Object[] list = bin.getNodeMetaData(BINARY_EXP_TARGET); Token operation = bin.getOperation(); int operationType = operation.getType(); Expression rightExpression = bin.getRightExpression(); Expression leftExpression = bin.getLeftExpression(); if (bin instanceof DeclarationExpression && leftExpression instanceof VariableExpression) { ClassNode declarationType = ((VariableExpression) leftExpression).getOriginType(); if (rightExpression instanceof ConstantExpression) { ClassNode unwrapper = ClassHelper.getUnwrapper(declarationType); ClassNode wrapper = ClassHelper.getWrapper(declarationType); if (!rightExpression.getType().equals(declarationType) && wrapper.isDerivedFrom(ClassHelper.Number_TYPE) && WideningCategories.isDoubleCategory(unwrapper)) { ConstantExpression constant = (ConstantExpression) rightExpression; if (constant.getValue() != null) { return optimizeConstantInitialization( bin, operation, constant, leftExpression, declarationType); } } } } if (operationType == Types.EQUAL && leftExpression instanceof PropertyExpression) { MethodNode directMCT = leftExpression.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET); if (directMCT != null) { return transformPropertyAssignmentToSetterCall( (PropertyExpression) leftExpression, rightExpression, directMCT); } } if (operationType == Types.COMPARE_EQUAL || operationType == Types.COMPARE_NOT_EQUAL) { // let's check if one of the operands is the null constant CompareToNullExpression compareToNullExpression = null; if (isNullConstant(leftExpression)) { compareToNullExpression = new CompareToNullExpression( staticCompilationTransformer.transform(rightExpression), operationType == Types.COMPARE_EQUAL); } else if (isNullConstant(rightExpression)) { compareToNullExpression = new CompareToNullExpression( staticCompilationTransformer.transform(leftExpression), operationType == Types.COMPARE_EQUAL); } if (compareToNullExpression != null) { compareToNullExpression.setSourcePosition(bin); return compareToNullExpression; } } else if (operationType == Types.KEYWORD_IN) { return convertInOperatorToTernary(bin, rightExpression, leftExpression); } if (list != null) { if (operationType == Types.COMPARE_TO) { StaticTypesTypeChooser typeChooser = staticCompilationTransformer.getTypeChooser(); ClassNode classNode = staticCompilationTransformer.getClassNode(); ClassNode leftType = typeChooser.resolveType(leftExpression, classNode); if (leftType.implementsInterface(ClassHelper.COMPARABLE_TYPE)) { ClassNode rightType = typeChooser.resolveType(rightExpression, classNode); if (rightType.implementsInterface(ClassHelper.COMPARABLE_TYPE)) { Expression left = staticCompilationTransformer.transform(leftExpression); Expression right = staticCompilationTransformer.transform(rightExpression); MethodCallExpression call = new MethodCallExpression(left, "compareTo", new ArgumentListExpression(right)); call.setImplicitThis(false); call.setMethodTarget(COMPARE_TO_METHOD); CompareIdentityExpression compareIdentity = new CompareIdentityExpression(left, right); compareIdentity.putNodeMetaData( StaticTypesMarker.INFERRED_RETURN_TYPE, ClassHelper.boolean_TYPE); TernaryExpression result = new TernaryExpression( new BooleanExpression(compareIdentity), // a==b CONSTANT_ZERO, new TernaryExpression( new BooleanExpression(new CompareToNullExpression(left, true)), // a==null CONSTANT_MINUS_ONE, new TernaryExpression( new BooleanExpression( new CompareToNullExpression(right, true)), // b==null CONSTANT_ONE, call))); compareIdentity.putNodeMetaData( StaticTypesMarker.INFERRED_RETURN_TYPE, ClassHelper.int_TYPE); result.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE); TernaryExpression expr = (TernaryExpression) result.getFalseExpression(); expr.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE); expr.getFalseExpression() .putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, ClassHelper.int_TYPE); return result; } } } boolean isAssignment = StaticTypeCheckingSupport.isAssignment(operationType); MethodCallExpression call; MethodNode node = (MethodNode) list[0]; String name = (String) list[1]; Expression left = staticCompilationTransformer.transform(leftExpression); Expression right = staticCompilationTransformer.transform(rightExpression); BinaryExpression optimized = tryOptimizeCharComparison(left, right, bin); if (optimized != null) { optimized.removeNodeMetaData(BINARY_EXP_TARGET); return transformBinaryExpression(optimized); } call = new MethodCallExpression(left, name, new ArgumentListExpression(right)); call.setImplicitThis(false); call.setMethodTarget(node); MethodNode adapter = StaticCompilationTransformer.BYTECODE_BINARY_ADAPTERS.get(operationType); if (adapter != null) { ClassExpression sba = new ClassExpression(StaticCompilationTransformer.BYTECODE_ADAPTER_CLASS); // replace with compareEquals call = new MethodCallExpression(sba, "compareEquals", new ArgumentListExpression(left, right)); call.setMethodTarget(adapter); call.setImplicitThis(false); } if (!isAssignment) return call; // case of +=, -=, /=, ... // the method represents the operation type only, and we must add an assignment return new BinaryExpression( left, Token.newSymbol("=", operation.getStartLine(), operation.getStartColumn()), call); } if (bin.getOperation().getType() == Types.EQUAL && leftExpression instanceof TupleExpression && rightExpression instanceof ListExpression) { // multiple assignment ListOfExpressionsExpression cle = new ListOfExpressionsExpression(); boolean isDeclaration = bin instanceof DeclarationExpression; List<Expression> leftExpressions = ((TupleExpression) leftExpression).getExpressions(); List<Expression> rightExpressions = ((ListExpression) rightExpression).getExpressions(); Iterator<Expression> leftIt = leftExpressions.iterator(); Iterator<Expression> rightIt = rightExpressions.iterator(); if (isDeclaration) { while (leftIt.hasNext()) { Expression left = leftIt.next(); if (rightIt.hasNext()) { Expression right = rightIt.next(); BinaryExpression bexp = new DeclarationExpression(left, bin.getOperation(), right); bexp.setSourcePosition(right); cle.addExpression(bexp); } } } else { // (next, result) = [ result, next+result ] // --> // def tmp1 = result // def tmp2 = next+result // next = tmp1 // result = tmp2 int size = rightExpressions.size(); List<Expression> tmpAssignments = new ArrayList<Expression>(size); List<Expression> finalAssignments = new ArrayList<Expression>(size); for (int i = 0; i < Math.min(size, leftExpressions.size()); i++) { Expression left = leftIt.next(); Expression right = rightIt.next(); VariableExpression tmpVar = new VariableExpression("$tmpVar$" + tmpVarCounter++); BinaryExpression bexp = new DeclarationExpression(tmpVar, bin.getOperation(), right); bexp.setSourcePosition(right); tmpAssignments.add(bexp); bexp = new BinaryExpression(left, bin.getOperation(), new VariableExpression(tmpVar)); bexp.setSourcePosition(left); finalAssignments.add(bexp); } for (Expression tmpAssignment : tmpAssignments) { cle.addExpression(tmpAssignment); } for (Expression finalAssignment : finalAssignments) { cle.addExpression(finalAssignment); } } return staticCompilationTransformer.transform(cle); } return staticCompilationTransformer.superTransform(bin); }