public boolean addGeneratedClosureConstructorCall(ConstructorCallExpression call) {
    ClassNode classNode = controller.getClassNode();
    if (!classNode.declaresInterface(ClassHelper.GENERATED_CLOSURE_Type)) return false;

    AsmClassGenerator acg = controller.getAcg();
    OperandStack operandStack = controller.getOperandStack();

    MethodVisitor mv = controller.getMethodVisitor();
    mv.visitVarInsn(ALOAD, 0);
    ClassNode callNode = classNode.getSuperClass();
    TupleExpression arguments = (TupleExpression) call.getArguments();
    if (arguments.getExpressions().size() != 2)
      throw new GroovyBugError(
          "expected 2 arguments for closure constructor super call, but got"
              + arguments.getExpressions().size());
    arguments.getExpression(0).visit(acg);
    operandStack.box();
    arguments.getExpression(1).visit(acg);
    operandStack.box();
    // TODO: replace with normal String, p not needed
    Parameter p = new Parameter(ClassHelper.OBJECT_TYPE, "_p");
    String descriptor =
        BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, new Parameter[] {p, p});
    mv.visitMethodInsn(
        INVOKESPECIAL, BytecodeHelper.getClassInternalName(callNode), "<init>", descriptor, false);
    operandStack.remove(2);
    return true;
  }
 public void visitMethodCallExpression(MethodCallExpression mce) {
   super.visitMethodCallExpression(mce);
   Expression aexp = mce.getArguments();
   if (aexp instanceof TupleExpression) {
     TupleExpression arguments = (TupleExpression) aexp;
     for (Expression e : arguments.getExpressions()) {
       checkForInvalidDeclaration(e);
     }
   } else {
     checkForInvalidDeclaration(aexp);
   }
 }
 private void checkFinalFieldAccess(Expression expression) {
   // currently not looking for PropertyExpression: dealt with at runtime using
   // ReadOnlyPropertyException
   if (!(expression instanceof VariableExpression) && !(expression instanceof TupleExpression))
     return;
   if (expression instanceof TupleExpression) {
     TupleExpression list = (TupleExpression) expression;
     for (Expression e : list.getExpressions()) {
       checkForFinal(expression, (VariableExpression) e);
     }
   } else {
     checkForFinal(expression, (VariableExpression) expression);
   }
 }
  public void visitDeclarationExpression(DeclarationExpression expression) {
    // visit right side first to avoid the usage of a
    // variable before its declaration
    expression.getRightExpression().visit(this);

    if (expression.isMultipleAssignmentDeclaration()) {
      TupleExpression list = expression.getTupleExpression();
      for (Expression e : list.getExpressions()) {
        declare((VariableExpression) e);
      }
    } else {
      declare(expression.getVariableExpression());
    }
  }
 /**
  * If constructor does not define a call to super, then transform constructor to get String,int
  * parameters at beginning and add call super(String,int).
  */
 private void transformConstructor(ConstructorNode ctor, boolean isAic) {
   boolean chainedThisConstructorCall = false;
   ConstructorCallExpression cce = null;
   if (ctor.firstStatementIsSpecialConstructorCall()) {
     Statement code = ctor.getFirstStatement();
     cce = (ConstructorCallExpression) ((ExpressionStatement) code).getExpression();
     if (cce.isSuperCall()) return;
     // must be call to this(...)
     chainedThisConstructorCall = true;
   }
   // we need to add parameters
   Parameter[] oldP = ctor.getParameters();
   Parameter[] newP = new Parameter[oldP.length + 2];
   String stringParameterName = getUniqueVariableName("__str", ctor.getCode());
   newP[0] = new Parameter(ClassHelper.STRING_TYPE, stringParameterName);
   String intParameterName = getUniqueVariableName("__int", ctor.getCode());
   newP[1] = new Parameter(ClassHelper.int_TYPE, intParameterName);
   System.arraycopy(oldP, 0, newP, 2, oldP.length);
   ctor.setParameters(newP);
   VariableExpression stringVariable = new VariableExpression(newP[0]);
   VariableExpression intVariable = new VariableExpression(newP[1]);
   if (chainedThisConstructorCall) {
     TupleExpression args = (TupleExpression) cce.getArguments();
     List<Expression> argsExprs = args.getExpressions();
     argsExprs.add(0, stringVariable);
     argsExprs.add(1, intVariable);
   } else {
     // add a super call
     List<Expression> args = new ArrayList<Expression>();
     args.add(stringVariable);
     args.add(intVariable);
     if (isAic) {
       for (Parameter parameter : oldP) {
         args.add(new VariableExpression(parameter.getName()));
       }
     }
     cce = new ConstructorCallExpression(ClassNode.SUPER, new ArgumentListExpression(args));
     BlockStatement code = new BlockStatement();
     code.addStatement(new ExpressionStatement(cce));
     Statement oldCode = ctor.getCode();
     if (oldCode != null) code.addStatement(oldCode);
     ctor.setCode(code);
   }
 }
  public MethodNode tryFindPossibleMethod(String name, Expression arguments) {
    int count = 0;

    if (arguments instanceof TupleExpression) {
      TupleExpression tuple = (TupleExpression) arguments;
      // TODO this won't strictly be true when using list expansion in argument calls
      count = tuple.getExpressions().size();
    } else return null;

    MethodNode res = null;
    ClassNode node = this;
    TupleExpression args = (TupleExpression) arguments;
    do {
      for (MethodNode method : node.getMethods(name)) {
        if (method.getParameters().length == count) {
          boolean match = true;
          for (int i = 0; i != count; ++i)
            if (!args.getType().isDerivedFrom(method.getParameters()[i].getType())) {
              match = false;
              break;
            }

          if (match) {
            if (res == null) res = method;
            else {
              if (res.getParameters().length != count) return null;
              if (node.equals(this)) return null;

              match = true;
              for (int i = 0; i != count; ++i)
                if (!res.getParameters()[i].getType().equals(method.getParameters()[i].getType())) {
                  match = false;
                  break;
                }
              if (!match) return null;
            }
          }
        }
      }
      node = node.getSuperClass();
    } while (node != null);

    return res;
  }
  /**
   * Returns true if the given method has a possibly matching instance method with the given name
   * and arguments.
   *
   * @param name the name of the method of interest
   * @param arguments the arguments to match against
   * @return true if a matching method was found
   */
  public boolean hasPossibleMethod(String name, Expression arguments) {
    int count = 0;

    if (arguments instanceof TupleExpression) {
      TupleExpression tuple = (TupleExpression) arguments;
      // TODO this won't strictly be true when using list expansion in argument calls
      count = tuple.getExpressions().size();
    }
    ClassNode node = this;
    do {
      for (MethodNode method : getMethods(name)) {
        if (method.getParameters().length == count && !method.isStatic()) {
          return true;
        }
      }
      node = node.getSuperClass();
    } while (node != null);
    return false;
  }
 protected Expression transformConstructorCallExpression(ConstructorCallExpression cce) {
   inSpecialConstructorCall = cce.isSpecialCall();
   Expression expression = cce.getArguments();
   if (expression instanceof TupleExpression) {
     TupleExpression tuple = (TupleExpression) expression;
     if (tuple.getExpressions().size() == 1) {
       expression = tuple.getExpression(0);
       if (expression instanceof NamedArgumentListExpression) {
         NamedArgumentListExpression namedArgs = (NamedArgumentListExpression) expression;
         List<MapEntryExpression> entryExpressions = namedArgs.getMapEntryExpressions();
         for (int i = 0; i < entryExpressions.size(); i++) {
           entryExpressions.set(
               i,
               (MapEntryExpression)
                   transformMapEntryExpression(entryExpressions.get(i), cce.getType()));
         }
       }
     }
   }
   Expression ret = cce.transformExpression(this);
   inSpecialConstructorCall = false;
   return ret;
 }
  /**
   * Returns true if the given method has a possibly matching static method with the given name and
   * arguments.
   *
   * @param name the name of the method of interest
   * @param arguments the arguments to match against
   * @return true if a matching method was found
   */
  public boolean hasPossibleStaticMethod(String name, Expression arguments) {
    int count = 0;

    if (arguments instanceof TupleExpression) {
      TupleExpression tuple = (TupleExpression) arguments;
      // TODO this won't strictly be true when using list expansion in argument calls
      count = tuple.getExpressions().size();
    } else if (arguments instanceof MapExpression) {
      count = 1;
    }

    for (MethodNode method : getMethods(name)) {
      if (method.isStatic()) {
        Parameter[] parameters = method.getParameters();
        if (parameters.length == count) return true;

        // handle varargs case
        if (parameters.length > 0 && parameters[parameters.length - 1].getType().isArray()) {
          if (count >= parameters.length - 1) return true;
        }

        // handle parameters with default values
        int nonDefaultParameters = 0;
        for (Parameter parameter : parameters) {
          if (!parameter.hasInitialExpression()) {
            nonDefaultParameters++;
          }
        }

        if (count < parameters.length && nonDefaultParameters <= count) {
          return true;
        }
      }
    }
    return false;
  }
    @Override
    public void visitTupleExpression(TupleExpression expression) {
      // LOG.debug "Transforming expression '${expression}':"

      if (expression.getLineNumber() >= 0 && expression.getLineNumber() < lineNumbers.length) {
        // LOG.debug "   start from ${expression.lineNumber} to ${lineNumbers[expression.lineNumber
        // - 1]}"
        expression.setLineNumber(lineNumbers[expression.getLineNumber() - 1]);
      }

      if (expression.getLastLineNumber() > 0
          && expression.getLastLineNumber() < lineNumbers.length) {
        // LOG.debug "   end from ${expression.lastLineNumber} to
        // ${lineNumbers[expression.lastLineNumber - 1]}"
        expression.setLastLineNumber(lineNumbers[expression.getLastLineNumber() - 1]);
      }
      super.visitTupleExpression(expression);
    }
 public void visitTupleExpression(TupleExpression expression) {
   visitListOfExpressions(expression.getExpressions());
 }
  public void evaluateEqual(BinaryExpression expression, boolean defineVariable) {
    AsmClassGenerator acg = controller.getAcg();
    CompileStack compileStack = controller.getCompileStack();
    OperandStack operandStack = controller.getOperandStack();
    Expression rightExpression = expression.getRightExpression();
    Expression leftExpression = expression.getLeftExpression();
    ClassNode lhsType =
        controller.getTypeChooser().resolveType(leftExpression, controller.getClassNode());

    if (defineVariable
        && rightExpression instanceof EmptyExpression
        && !(leftExpression instanceof TupleExpression)) {
      VariableExpression ve = (VariableExpression) leftExpression;
      BytecodeVariable var =
          compileStack.defineVariable(
              ve, controller.getTypeChooser().resolveType(ve, controller.getClassNode()), false);
      operandStack.loadOrStoreVariable(var, false);
      return;
    }

    // let's evaluate the RHS and store the result
    ClassNode rhsType;
    if (rightExpression instanceof ListExpression && lhsType.isArray()) {
      ListExpression list = (ListExpression) rightExpression;
      ArrayExpression array =
          new ArrayExpression(lhsType.getComponentType(), list.getExpressions());
      array.setSourcePosition(list);
      array.visit(acg);
    } else if (rightExpression instanceof EmptyExpression) {
      rhsType = leftExpression.getType();
      loadInitValue(rhsType);
    } else {
      rightExpression.visit(acg);
    }
    rhsType = operandStack.getTopOperand();

    boolean directAssignment = defineVariable && !(leftExpression instanceof TupleExpression);
    int rhsValueId;
    if (directAssignment) {
      VariableExpression var = (VariableExpression) leftExpression;
      if (var.isClosureSharedVariable() && ClassHelper.isPrimitiveType(rhsType)) {
        // GROOVY-5570: if a closure shared variable is a primitive type, it must be boxed
        rhsType = ClassHelper.getWrapper(rhsType);
        operandStack.box();
      }

      // ensure we try to unbox null to cause a runtime NPE in case we assign
      // null to a primitive typed variable, even if it is used only in boxed
      // form as it is closure shared
      if (var.isClosureSharedVariable()
          && ClassHelper.isPrimitiveType(var.getOriginType())
          && isNull(rightExpression)) {
        operandStack.doGroovyCast(var.getOriginType());
        // these two are never reached in bytecode and only there
        // to avoid verifyerrors and compiler infrastructure hazzle
        operandStack.box();
        operandStack.doGroovyCast(lhsType);
      }
      // normal type transformation
      if (!ClassHelper.isPrimitiveType(lhsType) && isNull(rightExpression)) {
        operandStack.replace(lhsType);
      } else {
        operandStack.doGroovyCast(lhsType);
      }
      rhsType = lhsType;
      rhsValueId = compileStack.defineVariable(var, lhsType, true).getIndex();
    } else {
      rhsValueId = compileStack.defineTemporaryVariable("$rhs", rhsType, true);
    }
    // TODO: if rhs is VariableSlotLoader already, then skip crating a new one
    BytecodeExpression rhsValueLoader = new VariableSlotLoader(rhsType, rhsValueId, operandStack);

    // assignment for subscript
    if (leftExpression instanceof BinaryExpression) {
      BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
      if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
        assignToArray(
            expression,
            leftBinExpr.getLeftExpression(),
            leftBinExpr.getRightExpression(),
            rhsValueLoader);
      }
      compileStack.removeVar(rhsValueId);
      return;
    }

    compileStack.pushLHS(true);

    // multiple declaration
    if (leftExpression instanceof TupleExpression) {
      TupleExpression tuple = (TupleExpression) leftExpression;
      int i = 0;
      for (Expression e : tuple.getExpressions()) {
        VariableExpression var = (VariableExpression) e;
        MethodCallExpression call =
            new MethodCallExpression(
                rhsValueLoader, "getAt", new ArgumentListExpression(new ConstantExpression(i)));
        call.visit(acg);
        i++;
        if (defineVariable) {
          operandStack.doGroovyCast(var);
          compileStack.defineVariable(var, true);
          operandStack.remove(1);
        } else {
          acg.visitVariableExpression(var);
        }
      }
    }
    // single declaration
    else if (defineVariable) {
      rhsValueLoader.visit(acg);
      operandStack.remove(1);
      compileStack.popLHS();
      return;
    }
    // normal assignment
    else {
      int mark = operandStack.getStackLength();
      // to leave a copy of the rightExpression value on the stack after the assignment.
      rhsValueLoader.visit(acg);
      TypeChooser typeChooser = controller.getTypeChooser();
      ClassNode targetType = typeChooser.resolveType(leftExpression, controller.getClassNode());
      operandStack.doGroovyCast(targetType);
      leftExpression.visit(acg);
      operandStack.remove(operandStack.getStackLength() - mark);
    }
    compileStack.popLHS();

    // return value of assignment
    rhsValueLoader.visit(acg);
    compileStack.removeVar(rhsValueId);
  }