in src/main/java/net/hydromatic/linq4j/expressions/FunctionExpression.java [104:197]
void accept(ExpressionWriter writer, int lprec, int rprec) {
// "new Function1() {
// public Result apply(T1 p1, ...) {
// <body>
// }
// // bridge method
// public Object apply(Object p1, ...) {
// return apply((T1) p1, ...);
// }
// }
//
// if any arguments are primitive there is an extra bridge method:
//
// new Function1() {
// public double apply(double p1, int p2) {
// <body>
// }
// // box bridge method
// public Double apply(Double p1, Integer p2) {
// return apply(p1.doubleValue(), p2.intValue());
// }
// // bridge method
// public Object apply(Object p1, Object p2) {
// return apply((Double) p1, (Integer) p2);
// }
List<String> params = new ArrayList<String>();
List<String> bridgeParams = new ArrayList<String>();
List<String> bridgeArgs = new ArrayList<String>();
List<String> boxBridgeParams = new ArrayList<String>();
List<String> boxBridgeArgs = new ArrayList<String>();
for (ParameterExpression parameterExpression : parameterList) {
final Type parameterType = parameterExpression.getType();
final Type parameterBoxType = Types.box(parameterType);
final String parameterBoxTypeName = Types.className(parameterBoxType);
params.add(parameterExpression.declString());
bridgeParams.add(parameterExpression.declString(Object.class));
bridgeArgs.add("(" + parameterBoxTypeName + ") "
+ parameterExpression.name);
boxBridgeParams.add(parameterExpression.declString(parameterBoxType));
boxBridgeArgs.add(parameterExpression.name
+ (Primitive.is(parameterType)
? "." + Primitive.of(parameterType).primitiveName + "Value()"
: ""));
}
Type bridgeResultType = Functions.FUNCTION_RESULT_TYPES.get(this.type);
if (bridgeResultType == null) {
bridgeResultType = body.getType();
}
Type resultType2 = bridgeResultType;
if (bridgeResultType == Object.class
&& !params.equals(bridgeParams)
&& !(body.getType() instanceof TypeVariable)) {
resultType2 = body.getType();
}
String methodName = getAbstractMethodName();
writer.append("new ")
.append(type)
.append("()")
.begin(" {\n")
.append("public ")
.append(Types.className(resultType2))
.list(" " + methodName + "(", ", ", ") ", params)
.append(Blocks.toFunctionBlock(body));
// Generate an intermediate bridge method if at least one parameter is
// primitive.
if (!boxBridgeParams.equals(params)) {
writer
.append("public ")
.append(Types.boxClassName(bridgeResultType))
.list(" " + methodName + "(", ", ", ") ", boxBridgeParams)
.begin("{\n")
.list("return " + methodName + "(\n", ",\n", ");\n", boxBridgeArgs)
.end("}\n");
}
// Generate a bridge method. Argument types are looser (as if every
// type parameter is set to 'Object').
//
// Skip the bridge method if there are no arguments. It would have the
// same overload as the regular method.
if (!bridgeParams.equals(params)) {
writer
.append("public ")
.append(Types.boxClassName(bridgeResultType))
.list(" " + methodName + "(", ", ", ") ", bridgeParams)
.begin("{\n")
.list("return " + methodName + "(\n", ",\n", ");\n", bridgeArgs)
.end("}\n");
}
writer.end("}\n");
}