public Expression transform(UnaryMinusExpression exp, CompilerTransformer compiler) {
    final BytecodeExpr inner = (BytecodeExpr) compiler.transform(exp.getExpression());
    final ClassNode type = ClassHelper.getUnwrapper(inner.getType());
    if (type == ClassHelper.byte_TYPE
        || type == ClassHelper.short_TYPE
        || type == ClassHelper.int_TYPE
        || type == ClassHelper.long_TYPE
        || type == ClassHelper.float_TYPE
        || type == ClassHelper.double_TYPE) {
      return new BytecodeExpr(exp, type) {
        protected void compile(MethodVisitor mv) {
          inner.visit(mv);
          if (!ClassHelper.isPrimitiveType(inner.getType())) unbox(type, mv);

          if (type == ClassHelper.int_TYPE
              || type == ClassHelper.short_TYPE
              || type == ClassHelper.byte_TYPE) mv.visitInsn(INEG);
          else if (type == ClassHelper.long_TYPE) mv.visitInsn(LNEG);
          else if (type == ClassHelper.float_TYPE) mv.visitInsn(FNEG);
          else if (type == ClassHelper.double_TYPE) mv.visitInsn(DNEG);
        }
      };
    } else {
      MethodCallExpression negate =
          new MethodCallExpression(inner, "negate", new ArgumentListExpression());
      negate.setSourcePosition(exp);
      return compiler.transform(negate);
    }
  }
 private Expression transformMethodCallExpression(final MethodCallExpression exp) {
   Expression objectExpression = transform(exp.getObjectExpression());
   ClassNode traitReceiver = objectExpression.getNodeMetaData(SuperCallTraitTransformer.class);
   if (traitReceiver != null) {
     TraitHelpersTuple helpers = Traits.findHelpers(traitReceiver);
     // (SomeTrait.super).foo() --> SomeTrait$Helper.foo(this)
     ClassExpression receiver = new ClassExpression(helpers.getHelper());
     ArgumentListExpression newArgs = new ArgumentListExpression();
     Expression arguments = exp.getArguments();
     newArgs.addExpression(new VariableExpression("this"));
     if (arguments instanceof TupleExpression) {
       List<Expression> expressions = ((TupleExpression) arguments).getExpressions();
       for (Expression expression : expressions) {
         newArgs.addExpression(transform(expression));
       }
     } else {
       newArgs.addExpression(arguments);
     }
     MethodCallExpression result = new MethodCallExpression(receiver, exp.getMethod(), newArgs);
     result.setImplicitThis(false);
     result.setSpreadSafe(exp.isSpreadSafe());
     result.setSafe(exp.isSafe());
     result.setSourcePosition(exp);
     return result;
   }
   return super.transform(exp);
 }
  public static BytecodeExpr transformLogicalExpression(
      Expression exp, CompilerTransformer compiler, Label label, boolean onTrue) {
    if (exp instanceof StaticMethodCallExpression) {
      StaticMethodCallExpression smce = (StaticMethodCallExpression) exp;
      MethodCallExpression mce =
          new MethodCallExpression(
              new ClassExpression(smce.getOwnerType()), smce.getMethod(), smce.getArguments());
      mce.setSourcePosition(smce);
      return transformLogicalExpression(mce, compiler, label, onTrue);
    }

    ExprTransformer t = transformers.get(exp.getClass());
    return t.transformLogical(exp, compiler, label, onTrue);
  }
 private Expression convertInOperatorToTernary(
     final BinaryExpression bin,
     final Expression rightExpression,
     final Expression leftExpression) {
   MethodCallExpression call = new MethodCallExpression(rightExpression, "isCase", leftExpression);
   call.setMethodTarget(
       (MethodNode) bin.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET));
   call.setSourcePosition(bin);
   call.copyNodeMetaData(bin);
   TernaryExpression tExp =
       new TernaryExpression(
           new BooleanExpression(
               new BinaryExpression(
                   rightExpression, Token.newSymbol("==", -1, -1), new ConstantExpression(null))),
           new BinaryExpression(
               leftExpression, Token.newSymbol("==", -1, -1), new ConstantExpression(null)),
           call);
   return staticCompilationTransformer.transform(tExp);
 }
 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);
 }
  @Override
  public void makeGetPropertySite(
      Expression receiver,
      final String methodName,
      final boolean safe,
      final boolean implicitThis) {
    Object dynamic =
        receiver.getNodeMetaData(StaticCompilationMetadataKeys.RECEIVER_OF_DYNAMIC_PROPERTY);
    if (dynamic != null) {
      MethodNode target =
          safe ? INVOKERHELPER_GETPROPERTYSAFE_METHOD : INVOKERHELPER_GETPROPERTY_METHOD;
      MethodCallExpression mce =
          new MethodCallExpression(
              new ClassExpression(INVOKERHELPER_TYPE),
              target.getName(),
              new ArgumentListExpression(receiver, new ConstantExpression(methodName)));
      mce.setSafe(false);
      mce.setImplicitThis(false);
      mce.setMethodTarget(target);
      mce.visit(controller.getAcg());
      return;
    }
    TypeChooser typeChooser = controller.getTypeChooser();
    ClassNode classNode = controller.getClassNode();
    ClassNode receiverType =
        (ClassNode) receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
    if (receiverType == null) {
      receiverType = typeChooser.resolveType(receiver, classNode);
    }
    Object type = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
    if (type == null && receiver instanceof VariableExpression) {
      Variable variable = ((VariableExpression) receiver).getAccessedVariable();
      if (variable instanceof Expression) {
        type = ((Expression) variable).getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
      }
    }
    if (type != null) {
      // in case a "flow type" is found, it is preferred to use it instead of
      // the declaration type
      receiverType = (ClassNode) type;
    }
    boolean isClassReceiver = false;
    if (isClassClassNodeWrappingConcreteType(receiverType)) {
      isClassReceiver = true;
      receiverType = receiverType.getGenericsTypes()[0].getType();
    }
    MethodVisitor mv = controller.getMethodVisitor();

    if (receiverType.isArray() && methodName.equals("length")) {
      receiver.visit(controller.getAcg());
      ClassNode arrayGetReturnType = typeChooser.resolveType(receiver, classNode);
      controller.getOperandStack().doGroovyCast(arrayGetReturnType);
      mv.visitInsn(ARRAYLENGTH);
      controller.getOperandStack().replace(int_TYPE);
      return;
    } else if ((receiverType.implementsInterface(COLLECTION_TYPE)
            || COLLECTION_TYPE.equals(receiverType))
        && ("size".equals(methodName) || "length".equals(methodName))) {
      MethodCallExpression expr =
          new MethodCallExpression(receiver, "size", ArgumentListExpression.EMPTY_ARGUMENTS);
      expr.setMethodTarget(COLLECTION_SIZE_METHOD);
      expr.setImplicitThis(implicitThis);
      expr.setSafe(safe);
      expr.visit(controller.getAcg());
      return;
    }
    if (makeGetPropertyWithGetter(receiver, receiverType, methodName, safe, implicitThis)) return;
    if (makeGetField(
        receiver,
        receiverType,
        methodName,
        implicitThis,
        samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;
    if (receiverType.isEnum()) {
      mv.visitFieldInsn(
          GETSTATIC,
          BytecodeHelper.getClassInternalName(receiverType),
          methodName,
          BytecodeHelper.getTypeDescription(receiverType));
      controller.getOperandStack().push(receiverType);
      return;
    }
    if (receiver instanceof ClassExpression) {
      if (makeGetField(
          receiver,
          receiver.getType(),
          methodName,
          implicitThis,
          samePackages(receiver.getType().getPackageName(), classNode.getPackageName()))) return;
      if (makeGetPropertyWithGetter(receiver, receiver.getType(), methodName, safe, implicitThis))
        return;
      if (makeGetPrivateFieldWithBridgeMethod(
          receiver, receiver.getType(), methodName, safe, implicitThis)) return;
    }
    if (isClassReceiver) {
      // we are probably looking for a property of the class
      if (makeGetPropertyWithGetter(receiver, CLASS_Type, methodName, safe, implicitThis)) return;
      if (makeGetField(receiver, CLASS_Type, methodName, false, true)) return;
    }
    if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, methodName, safe, implicitThis))
      return;

    // GROOVY-5580, it is still possible that we're calling a superinterface property
    String getterName = "get" + MetaClassHelper.capitalize(methodName);
    if (receiverType.isInterface()) {
      Set<ClassNode> allInterfaces = receiverType.getAllInterfaces();
      MethodNode getterMethod = null;
      for (ClassNode anInterface : allInterfaces) {
        getterMethod = anInterface.getGetterMethod(getterName);
        if (getterMethod != null) break;
      }
      // GROOVY-5585
      if (getterMethod == null) {
        getterMethod = OBJECT_TYPE.getGetterMethod(getterName);
      }

      if (getterMethod != null) {
        MethodCallExpression call =
            new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
        call.setMethodTarget(getterMethod);
        call.setImplicitThis(false);
        call.setSourcePosition(receiver);
        call.visit(controller.getAcg());
        return;
      }
    }

    // GROOVY-5568, we would be facing a DGM call, but instead of foo.getText(), have foo.text
    List<MethodNode> methods =
        findDGMMethodsByNameAndArguments(
            controller.getSourceUnit().getClassLoader(),
            receiverType,
            getterName,
            ClassNode.EMPTY_ARRAY);
    if (!methods.isEmpty()) {
      List<MethodNode> methodNodes = chooseBestMethod(receiverType, methods, ClassNode.EMPTY_ARRAY);
      if (methodNodes.size() == 1) {
        MethodNode getter = methodNodes.get(0);
        MethodCallExpression call =
            new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
        call.setMethodTarget(getter);
        call.setImplicitThis(false);
        call.setSourcePosition(receiver);
        call.visit(controller.getAcg());
        return;
      }
    }

    boolean isStaticProperty =
        receiver instanceof ClassExpression
            && (receiverType.isDerivedFrom(receiver.getType())
                || receiverType.implementsInterface(receiver.getType()));

    if (!isStaticProperty) {
      if (receiverType.implementsInterface(MAP_TYPE) || MAP_TYPE.equals(receiverType)) {
        // for maps, replace map.foo with map.get('foo')
        writeMapDotProperty(receiver, methodName, mv, safe);
        return;
      }
      if (receiverType.implementsInterface(LIST_TYPE) || LIST_TYPE.equals(receiverType)) {
        writeListDotProperty(receiver, methodName, mv, safe);
        return;
      }
    }

    controller
        .getSourceUnit()
        .addError(
            new SyntaxException(
                "Access to "
                    + (receiver instanceof ClassExpression ? receiver.getType() : receiverType)
                        .toString(false)
                    + "#"
                    + methodName
                    + " is forbidden",
                receiver.getLineNumber(),
                receiver.getColumnNumber(),
                receiver.getLastLineNumber(),
                receiver.getLastColumnNumber()));
    controller.getMethodVisitor().visitInsn(ACONST_NULL);
    controller.getOperandStack().push(OBJECT_TYPE);
  }
  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;
  }
  private boolean makeGetPropertyWithGetter(
      final Expression receiver,
      final ClassNode receiverType,
      final String methodName,
      final boolean safe,
      final boolean implicitThis) {
    // does a getter exists ?
    String getterName = "get" + MetaClassHelper.capitalize(methodName);
    MethodNode getterNode = receiverType.getGetterMethod(getterName);
    if (getterNode == null) {
      getterName = "is" + MetaClassHelper.capitalize(methodName);
      getterNode = receiverType.getGetterMethod(getterName);
    }
    if (getterNode != null
        && receiver instanceof ClassExpression
        && !CLASS_Type.equals(receiverType)
        && !getterNode.isStatic()) {
      return false;
    }

    // GROOVY-5561: if two files are compiled in the same source unit
    // and that one references the other, the getters for properties have not been
    // generated by the compiler yet (generated by the Verifier)
    PropertyNode propertyNode = receiverType.getProperty(methodName);
    if (propertyNode != null) {
      // it is possible to use a getter
      String prefix = "get";
      if (boolean_TYPE.equals(propertyNode.getOriginType())) {
        prefix = "is";
      }
      getterName = prefix + MetaClassHelper.capitalize(methodName);
      getterNode =
          new MethodNode(
              getterName,
              ACC_PUBLIC,
              propertyNode.getOriginType(),
              Parameter.EMPTY_ARRAY,
              ClassNode.EMPTY_ARRAY,
              EmptyStatement.INSTANCE);
      getterNode.setDeclaringClass(receiverType);
      if (propertyNode.isStatic()) getterNode.setModifiers(ACC_PUBLIC + ACC_STATIC);
    }
    if (getterNode != null) {
      MethodCallExpression call =
          new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
      call.setSourcePosition(receiver);
      call.setMethodTarget(getterNode);
      call.setImplicitThis(implicitThis);
      call.setSafe(safe);
      call.visit(controller.getAcg());
      return true;
    }

    if (receiverType instanceof InnerClassNode && !receiverType.isStaticClass()) {
      if (makeGetPropertyWithGetter(
          receiver, receiverType.getOuterClass(), methodName, safe, implicitThis)) {
        return true;
      }
    }

    // go upper level
    ClassNode superClass = receiverType.getSuperClass();
    if (superClass != null) {
      return makeGetPropertyWithGetter(receiver, superClass, methodName, safe, implicitThis);
    }
    return false;
  }
  public BytecodeExpr transformLogical(
      T exp, CompilerTransformer compiler, final Label label, final boolean onTrue) {
    final BytecodeExpr be;
    be = (BytecodeExpr) transform(exp, compiler);
    final ClassNode type = be.getType();

    if (type == ClassHelper.VOID_TYPE) {
      return be;
    }

    if (ClassHelper.isPrimitiveType(type)) {
      return new BytecodeExpr(exp, ClassHelper.VOID_TYPE) {
        protected void compile(MethodVisitor mv) {
          be.visit(mv);
          if (type == ClassHelper.byte_TYPE
              || type == ClassHelper.short_TYPE
              || type == ClassHelper.char_TYPE
              || type == ClassHelper.boolean_TYPE
              || type == ClassHelper.int_TYPE) {
          } else if (type == ClassHelper.long_TYPE) {
            mv.visitInsn(L2I);
          } else if (type == ClassHelper.float_TYPE) {
            mv.visitInsn(F2I);
          } else if (type == ClassHelper.double_TYPE) {
            mv.visitInsn(D2I);
          }
          mv.visitJumpInsn(onTrue ? IFNE : IFEQ, label);
        }
      };
    } else {
      MethodCallExpression safeCall =
          new MethodCallExpression(
              new BytecodeExpr(exp, be.getType()) {
                protected void compile(MethodVisitor mv) {}
              },
              "asBoolean",
              ArgumentListExpression.EMPTY_ARGUMENTS);
      safeCall.setSourcePosition(exp);

      final ResolvedMethodBytecodeExpr call =
          (ResolvedMethodBytecodeExpr) compiler.transform(safeCall);

      if (!call.getType().equals(ClassHelper.boolean_TYPE))
        compiler.addError("asBoolean should return 'boolean'", exp);

      if (call.getMethodNode().getDeclaringClass().equals(ClassHelper.OBJECT_TYPE)) {
        // fast path
        return new BytecodeExpr(exp, ClassHelper.VOID_TYPE) {
          protected void compile(MethodVisitor mv) {
            be.visit(mv);
            mv.visitJumpInsn(onTrue ? IFNONNULL : IFNULL, label);
          }
        };
      } else {
        return new BytecodeExpr(exp, ClassHelper.VOID_TYPE) {
          protected void compile(MethodVisitor mv) {
            be.visit(mv);
            mv.visitInsn(DUP);
            Label nullLabel = new Label(), endLabel = new Label();

            mv.visitJumpInsn(IFNULL, nullLabel);

            call.visit(mv);

            if (onTrue) {
              mv.visitJumpInsn(IFEQ, endLabel);
              mv.visitJumpInsn(GOTO, label);

              mv.visitLabel(nullLabel);
              mv.visitInsn(POP);
            } else {
              mv.visitJumpInsn(IFNE, endLabel);
              mv.visitJumpInsn(GOTO, label);

              mv.visitLabel(nullLabel);
              mv.visitInsn(POP);
              mv.visitJumpInsn(GOTO, label);
            }

            mv.visitLabel(endLabel);
          }
        };
      }
    }
  }