private JCTree makeCallMethod(List<JCStatement> body, int numParams) {
    MethodDefinitionBuilder callMethod = MethodDefinitionBuilder.callable(gen);
    callMethod.isOverride(true);
    callMethod.modifiers(Flags.PUBLIC);
    ProducedType returnType = gen.getReturnTypeOfCallable(typeModel);
    callMethod.resultType(gen.makeJavaType(returnType, JT_NO_PRIMITIVES), null);
    // Now append formal parameters
    switch (numParams) {
      case 3:
        callMethod.parameter(makeCallableCallParam(0, numParams - 3));
        // fall through
      case 2:
        callMethod.parameter(makeCallableCallParam(0, numParams - 2));
        // fall through
      case 1:
        callMethod.parameter(makeCallableCallParam(0, numParams - 1));
        break;
      case 0:
        break;
      default: // use varargs
        callMethod.parameter(makeCallableCallParam(Flags.VARARGS, 0));
    }

    // Return the call result, or null if a void method
    callMethod.body(body);
    return callMethod.build();
  }
 private ParameterDefinitionBuilder makeCallableCallParam(long flags, int ii) {
   JCExpression type = gen.makeIdent(gen.syms().objectType);
   if ((flags & Flags.VARARGS) != 0) {
     type = gen.make().TypeArray(type);
   }
   ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.instance(gen, getParamName(ii));
   pdb.modifiers(Flags.FINAL | flags);
   pdb.type(type, null);
   return pdb;
   /*
   return gen.make().VarDef(gen.make().Modifiers(Flags.FINAL | Flags.PARAMETER | flags),
           makeParamName(gen, ii), type, null);
           */
 }
 private JCExpression makeDefaultValueCall(Parameter defaultedParam, int i) {
   // add the default value
   List<JCExpression> defaultMethodArgs = List.nil();
   // pass all the previous values
   for (int a = i - 1; a >= 0; a--) {
     Parameter param = paramLists.getParameters().get(a);
     JCExpression previousValue = gen.makeUnquotedIdent(getCallableTempVarName(param));
     defaultMethodArgs = defaultMethodArgs.prepend(previousValue);
   }
   // now call the default value method
   return gen.make()
       .Apply(
           null,
           gen.makeUnquotedIdent(Naming.getDefaultedParamMethodName(null, defaultedParam)),
           defaultMethodArgs);
 }
  public JCNewClass build() {
    // Generate a subclass of Callable
    ListBuffer<JCTree> classBody = new ListBuffer<JCTree>();
    int numParams = paramLists.getParameters().size();
    int minimumParams = 0;
    for (Parameter p : paramLists.getParameters()) {
      if (p.isDefaulted() || p.isSequenced()) break;
      minimumParams++;
    }
    boolean isVariadic = minimumParams != numParams;
    if (parameterListTree != null) {
      // generate a method for each defaulted param
      for (Tree.Parameter p : parameterListTree.getParameters()) {
        if (p.getDefaultArgument() != null || p.getDeclarationModel().isSequenced()) {
          MethodDefinitionBuilder methodBuilder =
              gen.classGen().makeParamDefaultValueMethod(false, null, parameterListTree, p);
          classBody.append(methodBuilder.build());
        }
      }
    }

    // collect each parameter type from the callable type model rather than the declarations to get
    // them all bound
    java.util.List<ProducedType> parameterTypes = new ArrayList<ProducedType>(numParams);
    if (forwardCallTo != null) {
      for (int i = 0; i < numParams; i++)
        parameterTypes.add(gen.getParameterTypeOfCallable(typeModel, i));
    } else {
      // get them from our declaration
      for (Parameter p : paramLists.getParameters()) parameterTypes.add(p.getType());
    }

    // now generate a method for each supported minimum number of parameters below 4
    // which delegates to the $call$typed method if required
    for (int i = minimumParams, max = Math.min(numParams, 4); i < max; i++) {
      classBody.append(makeDefaultedCall(i, isVariadic, parameterTypes));
    }
    // generate the $call method for the max number of parameters,
    // which delegates to the $call$typed method if required
    classBody.append(makeDefaultedCall(numParams, isVariadic, parameterTypes));
    // generate the $call$typed method if required
    if (isVariadic && forwardCallTo == null)
      classBody.append(makeCallTypedMethod(body, parameterTypes));

    JCClassDecl classDef =
        gen.make().AnonymousClassDef(gen.make().Modifiers(0), classBody.toList());

    JCNewClass instance =
        gen.make()
            .NewClass(
                null,
                null,
                gen.makeJavaType(typeModel, JT_EXTENDS | JT_CLASS_NEW),
                List.<JCExpression>of(gen.make().Literal(typeModel.getProducedTypeName(true))),
                classDef);
    return instance;
  }
 private JCExpression getTypedParameter(
     Parameter param, int argIndex, boolean varargs, java.util.List<ProducedType> parameterTypes) {
   JCExpression argExpr;
   if (!varargs) {
     // The Callable has overridden one of the non-varargs call()
     // methods
     argExpr = gen.make().Ident(makeParamName(gen, argIndex));
   } else {
     // The Callable has overridden the varargs call() method
     // so we need to index into the varargs array
     argExpr =
         gen.make().Indexed(gen.make().Ident(makeParamName(gen, 0)), gen.make().Literal(argIndex));
   }
   // make sure we unbox it if required
   argExpr =
       gen.expressionGen()
           .applyErasureAndBoxing(
               argExpr,
               gen.typeFact().getObjectDeclaration().getType(), // it came in as Object
               true, // it's completely erased
               true, // it came in boxed
               CodegenUtil.getBoxingStrategy(param), // see if we need to box
               parameterTypes.get(argIndex), // see what type we need
               0); // no flags
   return argExpr;
 }
 private JCTree makeCallTypedMethod(
     List<JCStatement> body, java.util.List<ProducedType> parameterTypes) {
   // make the method
   MethodDefinitionBuilder methodBuilder =
       MethodDefinitionBuilder.method(gen, false, Naming.getCallableTypedMethodName());
   methodBuilder.modifiers(Flags.PRIVATE);
   ProducedType returnType = gen.getReturnTypeOfCallable(typeModel);
   methodBuilder.resultType(gen.makeJavaType(returnType, JT_NO_PRIMITIVES), null);
   // add all parameters
   int i = 0;
   for (Parameter param : paramLists.getParameters()) {
     ParameterDefinitionBuilder parameterBuilder =
         ParameterDefinitionBuilder.instance(gen, param.getName());
     JCExpression paramType = gen.makeJavaType(parameterTypes.get(i));
     parameterBuilder.type(paramType, null);
     methodBuilder.parameter(parameterBuilder);
     i++;
   }
   // Return the call result, or null if a void method
   methodBuilder.body(body);
   return methodBuilder.build();
 }
 private static Name makeParamName(AbstractTransformer gen, int paramIndex) {
   return gen.names().fromString(getParamName(paramIndex));
 }
 private JCTree makeDefaultedCall(
     int i, boolean isVariadic, java.util.List<ProducedType> parameterTypes) {
   // collect every parameter
   int a = 0;
   ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
   for (Parameter param : paramLists.getParameters()) {
     // don't read default parameter values for forwarded calls
     if (forwardCallTo != null && i == a) break;
     // read the value
     JCExpression paramExpression = getTypedParameter(param, a, i > 3, parameterTypes);
     JCExpression varInitialExpression;
     if (param.isDefaulted() || param.isSequenced()) {
       if (i > 3) {
         // must check if it's defined
         JCExpression test =
             gen.make()
                 .Binary(JCTree.GT, gen.makeSelect(getParamName(0), "length"), gen.makeInteger(a));
         JCExpression elseBranch = makeDefaultValueCall(param, a);
         varInitialExpression = gen.make().Conditional(test, paramExpression, elseBranch);
       } else if (a >= i) {
         // get its default value because we don't have it
         varInitialExpression = makeDefaultValueCall(param, a);
       } else {
         // we must have it
         varInitialExpression = paramExpression;
       }
     } else {
       varInitialExpression = paramExpression;
     }
     // store it in a local var
     JCStatement var =
         gen.make()
             .VarDef(
                 gen.make().Modifiers(Flags.FINAL),
                 gen.naming.makeUnquotedName(getCallableTempVarName(param)),
                 gen.makeJavaType(
                     parameterTypes.get(a),
                     CodegenUtil.isUnBoxed(param) ? 0 : gen.JT_NO_PRIMITIVES),
                 varInitialExpression);
     stmts.append(var);
     a++;
   }
   if (forwardCallTo != null) {
     InvocationBuilder invocationBuilder =
         InvocationBuilder.forCallableInvocation(gen, forwardCallTo, paramLists, i);
     boolean prevCallableInv = gen.expressionGen().withinCallableInvocation(true);
     try {
       stmts.append(gen.make().Return(invocationBuilder.build()));
     } finally {
       gen.expressionGen().withinCallableInvocation(prevCallableInv);
     }
   } else if (isVariadic) {
     // chain to n param typed method
     List<JCExpression> args = List.nil();
     // pass along the parameters
     for (a = paramLists.getParameters().size() - 1; a >= 0; a--) {
       Parameter param = paramLists.getParameters().get(a);
       args = args.prepend(gen.makeUnquotedIdent(getCallableTempVarName(param)));
     }
     JCMethodInvocation chain =
         gen.make().Apply(null, gen.makeUnquotedIdent(Naming.getCallableTypedMethodName()), args);
     stmts.append(gen.make().Return(chain));
   } else {
     // insert the method body directly
     stmts.appendList(this.body);
   }
   List<JCStatement> body = stmts.toList();
   return makeCallMethod(body, i);
 }