/// Build up the chain of .apply(...) calls, with each argument marshalled properly
/// We use the multi-argument apply() variants as much as possible
/// Then build up the evaluation of the application chain.
//
final MachineFunction functionalAgentMachineFunction = module.getFunction(functionalAgent.getName());
final JavaExpression executionContextArg = new JavaExpression.CastExpression(
JavaTypeNames.RTEXECUTION_CONTEXT,
new JavaExpression.MethodVariable(executionContextArgName));
final List<JavaExpression> marshalledArgs = new ArrayList<JavaExpression>();
for (int i = 0; i < nFunctionalAgentArgs; i++) {
marshalledArgs.add(makeRTValueMarshallingExpr(
argTypes.get(i), new JavaExpression.MethodVariable(methodArgNames.get(i))));
}
final JavaExpression resultExpr;
final boolean isLiteralResult;
// Special handling for literal value is required, because it may represent either an actual literal value
// or an enum data cons, or an alias to an enum data cons
final Object literalValue = functionalAgentMachineFunction.getLiteralValue();
if (literalValue != null) {
final Class<?> unboxedLiteralType = supportedLiteralTypesBoxedToUnboxedClassMap.get(literalValue.getClass());
if (unboxedLiteralType == null) {
throw new IllegalStateException("Unsupported literal type in machine function: " + literalValue.getClass());
}
isLiteralResult = true;
if (returnType.getExposedTypeName().equals(JavaTypeName.CAL_VALUE)) {
// an alias of a data constructor, which should be in an enumeration algebraic type
// so we just marshall the literal as the opaque representation of the enum value
if (unboxedLiteralType != int.class) {
throw new IllegalStateException("Unboxed literal type " + unboxedLiteralType + " is not the primitive type int.");
}
if (!LECCMachineConfiguration.TREAT_ENUMS_AS_INTS) {
throw new IllegalStateException("Enums are not treated as ints, but there is a MachineFunction with a literal value whose return type is CalValue");
}
resultExpr = makeRTValueMarshallingExpr(ClassTypeInfo.make(unboxedLiteralType), JavaExpression.LiteralWrapper.make(literalValue));
} else {
// not an aliased data constructor
if (!returnType.getExposedTypeName().equals(JavaTypeName.make(unboxedLiteralType))) {
throw new IllegalStateException("Unboxed literal type " + unboxedLiteralType + " does not match return type " + returnType.getExposedTypeName());
}
// emit a literal value directly
resultExpr = JavaExpression.LiteralWrapper.make(literalValue);
}
} else if (functionalAgentMachineFunction.isDataConstructor() && isEnumDataConsRepresentedAsPrimitiveInt((DataConstructor)functionalAgent)) {
// ***Optional optimization***
// a data constructor in an enumeration algebraic type
// so we just marshall the literal as the opaque representation of the enum value
if (!returnType.getExposedTypeName().equals(JavaTypeName.CAL_VALUE)) {