示例#1
0
 @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);
  }