Expression transformMethodCallExpression(final MethodCallExpression expr) { Expression objectExpression = expr.getObjectExpression(); if (expr.isSafe()) { MethodCallExpression notSafe = new MethodCallExpression(objectExpression, expr.getMethod(), expr.getArguments()); notSafe.copyNodeMetaData(expr); notSafe.setSpreadSafe(expr.isSpreadSafe()); notSafe.setSourcePosition(expr); notSafe.setMethodTarget(expr.getMethodTarget()); TernaryExpression texpr = new TernaryExpression( new BooleanExpression( new BinaryExpression( objectExpression, Token.newSymbol( "!=", objectExpression.getLineNumber(), objectExpression.getColumnNumber()), ConstantExpression.NULL)), notSafe, ConstantExpression.NULL); return staticCompilationTransformer.transform(texpr); } ClassNode type = staticCompilationTransformer .getTypeChooser() .resolveType(objectExpression, staticCompilationTransformer.getClassNode()); if (type != null && type.isArray()) { String method = expr.getMethodAsString(); ClassNode componentType = type.getComponentType(); if ("getAt".equals(method)) { Expression arguments = expr.getArguments(); if (arguments instanceof TupleExpression) { List<Expression> argList = ((TupleExpression) arguments).getExpressions(); if (argList.size() == 1) { Expression indexExpr = argList.get(0); ClassNode argType = staticCompilationTransformer .getTypeChooser() .resolveType(indexExpr, staticCompilationTransformer.getClassNode()); ClassNode indexType = ClassHelper.getWrapper(argType); if (componentType.isEnum() && ClassHelper.Number_TYPE == indexType) { // workaround for generated code in enums which use .next() returning a Number indexType = ClassHelper.Integer_TYPE; } if (argType != null && ClassHelper.Integer_TYPE == indexType) { BinaryExpression binaryExpression = new BinaryExpression( objectExpression, Token.newSymbol("[", indexExpr.getLineNumber(), indexExpr.getColumnNumber()), indexExpr); binaryExpression.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, componentType); return staticCompilationTransformer.transform(binaryExpression); } } } } if ("putAt".equals(method)) { Expression arguments = expr.getArguments(); if (arguments instanceof TupleExpression) { List<Expression> argList = ((TupleExpression) arguments).getExpressions(); if (argList.size() == 2) { Expression indexExpr = argList.get(0); Expression objExpr = argList.get(1); ClassNode argType = staticCompilationTransformer .getTypeChooser() .resolveType(indexExpr, staticCompilationTransformer.getClassNode()); if (argType != null && ClassHelper.Integer_TYPE == ClassHelper.getWrapper(argType)) { BinaryExpression arrayGet = new BinaryExpression( objectExpression, Token.newSymbol("[", indexExpr.getLineNumber(), indexExpr.getColumnNumber()), indexExpr); arrayGet.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, componentType); BinaryExpression assignment = new BinaryExpression( arrayGet, Token.newSymbol("=", objExpr.getLineNumber(), objExpr.getColumnNumber()), objExpr); return staticCompilationTransformer.transform(assignment); } } } } } return staticCompilationTransformer.superTransform(expr); }
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); }