@Override public void visitBinaryExpression(final BinaryExpression expression) { boolean assignment = StaticTypeCheckingSupport.isAssignment(expression.getOperation().getType()); boolean isDeclaration = expression instanceof DeclarationExpression; Expression leftExpression = expression.getLeftExpression(); Expression rightExpression = expression.getRightExpression(); if (isDeclaration && leftExpression instanceof VariableExpression) { VariableExpression var = (VariableExpression) leftExpression; if (Modifier.isFinal(var.getModifiers())) { declaredFinalVariables.add(var); } } leftExpression.visit(this); inAssignment = assignment; rightExpression.visit(this); inAssignment = false; if (assignment) { if (leftExpression instanceof Variable) { boolean uninitialized = isDeclaration && rightExpression == EmptyExpression.INSTANCE; recordAssignment( (Variable) leftExpression, isDeclaration, uninitialized, false, expression); } } }
@Override protected boolean existsProperty( final PropertyExpression pexp, final boolean checkForReadOnly, final ClassCodeVisitorSupport visitor) { Expression objectExpression = pexp.getObjectExpression(); ClassNode objectExpressionType = getType(objectExpression); final Reference<ClassNode> rType = new Reference<ClassNode>(objectExpressionType); ClassCodeVisitorSupport receiverMemoizer = new ClassCodeVisitorSupport() { @Override protected SourceUnit getSourceUnit() { return null; } public void visitField(final FieldNode node) { if (visitor != null) visitor.visitField(node); ClassNode declaringClass = node.getDeclaringClass(); if (declaringClass != null) rType.set(declaringClass); } public void visitMethod(final MethodNode node) { if (visitor != null) visitor.visitMethod(node); ClassNode declaringClass = node.getDeclaringClass(); if (declaringClass != null) rType.set(declaringClass); } @Override public void visitProperty(final PropertyNode node) { if (visitor != null) visitor.visitProperty(node); ClassNode declaringClass = node.getDeclaringClass(); if (declaringClass != null) rType.set(declaringClass); } }; boolean exists = super.existsProperty(pexp, checkForReadOnly, receiverMemoizer); if (exists) { if (objectExpression.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER) == null) { objectExpression.putNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER, rType.get()); } if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf( objectExpressionType, ClassHelper.LIST_TYPE)) { objectExpression.putNodeMetaData( COMPONENT_TYPE, inferComponentType(objectExpressionType, ClassHelper.int_TYPE)); } } return exists; }
private boolean trySubscript( final Expression receiver, final String message, final Expression arguments, ClassNode rType, final ClassNode aType) { if (getWrapper(rType).isDerivedFrom(Number_TYPE) && getWrapper(aType).isDerivedFrom(Number_TYPE)) { if ("plus".equals(message) || "minus".equals(message) || "multiply".equals(message) || "div".equals(message)) { writeNumberNumberCall(receiver, message, arguments); return true; } else if ("power".equals(message)) { writePowerCall(receiver, arguments, rType, aType); return true; } else if ("mod".equals(message)) { writeModCall(receiver, arguments, rType, aType); return true; } } else if (STRING_TYPE.equals(rType) && "plus".equals(message)) { writeStringPlusCall(receiver, message, arguments); return true; } else if ("getAt".equals(message)) { if (rType.isArray() && getWrapper(aType).isDerivedFrom(Number_TYPE)) { writeArrayGet(receiver, arguments, rType, aType); return true; } else { // check if a getAt method can be found on the receiver ClassNode current = rType; MethodNode getAtNode = null; while (current != null && getAtNode == null) { getAtNode = current.getMethod("getAt", new Parameter[] {new Parameter(aType, "index")}); if (getAtNode == null && isPrimitiveType(aType)) { getAtNode = current.getMethod( "getAt", new Parameter[] {new Parameter(getWrapper(aType), "index")}); } else if (getAtNode == null && aType.isDerivedFrom(Number_TYPE)) { getAtNode = current.getMethod( "getAt", new Parameter[] {new Parameter(getUnwrapper(aType), "index")}); } current = current.getSuperClass(); } if (getAtNode != null) { MethodCallExpression call = new MethodCallExpression(receiver, "getAt", arguments); call.setSourcePosition(arguments); call.setImplicitThis(false); call.setMethodTarget(getAtNode); call.visit(controller.getAcg()); return true; } // make sure Map#getAt() and List#getAt handled with the bracket syntax are properly // compiled ClassNode[] args = {aType}; boolean acceptAnyMethod = MAP_TYPE.equals(rType) || rType.implementsInterface(MAP_TYPE) || LIST_TYPE.equals(rType) || rType.implementsInterface(LIST_TYPE); List<MethodNode> nodes = StaticTypeCheckingSupport.findDGMMethodsByNameAndArguments( controller.getSourceUnit().getClassLoader(), rType, message, args); if (nodes.isEmpty()) { // retry with raw types rType = rType.getPlainNodeReference(); nodes = StaticTypeCheckingSupport.findDGMMethodsByNameAndArguments( controller.getSourceUnit().getClassLoader(), rType, message, args); } nodes = StaticTypeCheckingSupport.chooseBestMethod(rType, nodes, args); if (nodes.size() == 1 || nodes.size() > 1 && acceptAnyMethod) { MethodNode methodNode = nodes.get(0); MethodCallExpression call = new MethodCallExpression(receiver, message, arguments); call.setSourcePosition(arguments); call.setImplicitThis(false); call.setMethodTarget(methodNode); call.visit(controller.getAcg()); return true; } if (implementsInterfaceOrIsSubclassOf(rType, MAP_TYPE)) { // fallback to Map#get MethodCallExpression call = new MethodCallExpression(receiver, "get", arguments); call.setMethodTarget(MAP_GET_METHOD); call.setSourcePosition(arguments); call.setImplicitThis(false); call.visit(controller.getAcg()); return true; } } } return false; }
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); }