JavaTypeName.OBJECT,
PUBLIC_STATIC_FINAL,
EMPTY_TYPE_NAME_ARRAY);
// Add the class JavaDoc
JavaDocComment jdc = new JavaDocComment("This inner class (" + FUNCTION_CLASS_NAME + ") contains constants");
jdc.addLine("and methods related to binding to CAL functions in the " + moduleTypeInfo.getModuleName() + " module.");
functionsClass.setJavaDoc(jdc);
// Build up and sort the list of function names.
Map<String, FunctionalAgent> nameToFuncInfo = new TreeMap<String, FunctionalAgent>();
for (int i = 0, n = moduleTypeInfo.getNFunctions(); i < n; ++i) {
Function fe = moduleTypeInfo.getNthFunction(i);
if (fe.getScope().isPublic() != publicEntities) {
continue;
}
nameToFuncInfo.put(fe.getName().getUnqualifiedName(), fe);
}
for (int i = 0, n = moduleTypeInfo.getNTypeClasses(); i < n; ++i) {
TypeClass tc = moduleTypeInfo.getNthTypeClass(i);
for (int j = 0, k = tc.getNClassMethods(); j < k; ++j) {
ClassMethod cm = tc.getNthClassMethod(j);
if (cm.getScope().isPublic() == publicEntities) {
nameToFuncInfo.put(cm.getName().getUnqualifiedName(), cm);
}
}
}
if (nameToFuncInfo.size() == 0) {
return;
}
bindingClass.addInnerClass(functionsClass);
// Now go over the function names and generate the helper functions and
// QualifiedName constant.
for (final Map.Entry<String, FunctionalAgent> entry : nameToFuncInfo.entrySet()) {
String calFuncName = entry.getKey();
FunctionalAgent functionalAgent = entry.getValue();
CALDocComment cdc = functionalAgent.getCALDocComment();
// We need to make sure the name for the helper function/qualified name field is
// a valid java name.
String javaFuncName = fixupVarName(calFuncName);
// Add a binding method for the CAL function.
// Essentially this method builds an application
// of the function to the supplied arguments using our
// source model.
// Build up the argument names and types.
TypeExpr te = functionalAgent.getTypeExpr();
int nArgs = te.getArity();
int nNamedArgs = functionalAgent.getNArgumentNames();
String paramNames[] = CALDocToJavaDocUtilities.getArgumentNamesFromCALDocComment(cdc, functionalAgent);
if (paramNames.length != nArgs) {
throw new NullPointerException ("Mismatch between arity and number of arguments for " + calFuncName);
}
String origParamNames[] = new String[paramNames.length];
System.arraycopy(paramNames, 0, origParamNames, 0, origParamNames.length);
JavaTypeName paramTypes[] = new JavaTypeName [paramNames.length];
// If we have named arguments we should use those names.
Set<String> paramNamesSet = new HashSet<String>();
for (int i = 0; i < paramNames.length; ++i) {
String name = paramNames[i];
if (name == null) {
if (i < nNamedArgs) {
name = functionalAgent.getArgumentName(i);
}
if (name == null || name.equals("")) {
name = null;
// There is no name for this argument in the functional entity. This
// usually occurs with foreign functions and class methods because
// you don't have to explicitly name the arguments.
// Check to see if there was a CALDoc comment that named the arguments.
if (cdc != null && cdc.getNArgBlocks() == paramNames.length) {
name = cdc.getNthArgBlock(i).getArgName().getCalSourceForm();
}
// If we still don't have an argument name just build one.
if (name == null) {
name = "arg_" + (i+1);
}
}
// Make sure name is unique.
String baseName = name;
int suffix = 0;
while (paramNamesSet.contains(name)) {
name = baseName + "_" + suffix++;
}
}
origParamNames[i] = name;
paramNames[i] = fixupVarName(name);
paramTypes[i] = SOURCE_MODEL_EXPR_TYPE_NAME;
}
// Get the JavaDoc for the helper function. If there is CALDoc
// for the function we translate it to JavaDoc.
JavaDocComment funcComment;
if (cdc != null) {
funcComment = new JavaDocComment(calDocCommentToJavaComment(cdc, functionalAgent, false));
funcComment = fixupJavaDoc(funcComment, origParamNames, paramNames);
} else {
funcComment = new JavaDocComment("Helper binding method for function: " + calFuncName + ". ");
for (int iName = 0; iName < paramNames.length; ++iName) {
funcComment.addLine("@param " + paramNames[iName]);
}
funcComment.addLine("@return the SourceModule.expr representing an application of " + calFuncName);
}
// Create the method.
JavaMethod bindingMethod =
new JavaMethod(PUBLIC_STATIC_FINAL,
SOURCE_MODEL_EXPR_TYPE_NAME,
paramNames,
paramTypes,
null, javaFuncName);
functionsClass.addMethod(bindingMethod);
// Add the JavaDoc
bindingMethod.setJavaDocComment(funcComment);
// Build up the body of the method.
// We want to us the QualifiedName field.
JavaField nameField = new JavaField.Static(functionsClassTypeName, javaFuncName, QUALIFIED_NAME_TYPE_NAME);
// Create an instance of SourceModel.Expr.Var for the CAL function.
JavaExpression sourceModelVarCreation =
new MethodInvocation.Static(
SOURCE_MODEL_EXPR_VAR_TYPE_NAME,
"make",
nameField,
QUALIFIED_NAME_TYPE_NAME,
SOURCE_MODEL_EXPR_VAR_TYPE_NAME);
// For the comment for this method we want an @see referring to the previous method.
String atSee = "@see #" + javaFuncName + "(";
for (int iArg = 0; iArg < paramNames.length; ++iArg) {
if (iArg == 0) {
atSee = atSee + paramTypes[iArg].getFullJavaSourceName();
} else {
atSee = atSee + ", " + paramTypes[iArg].getFullJavaSourceName();
}
}
atSee = atSee + ")";
if (paramNames.length == 0) {
// Simply return the Expr.Var
bindingMethod.addStatement(new ReturnStatement(sourceModelVarCreation));
} else {
// Need to create an application.
// Create an array of SourceModel.Expr. The first element is the SourceModel.Expr.Var
// for the CAL function the remaining elements are the function arguments.
JavaExpression arrayElements[] = new JavaExpression[paramNames.length + 1];
arrayElements[0] = sourceModelVarCreation;
for (int i = 1; i <= paramNames.length; ++i) {
arrayElements[i] = new JavaExpression.MethodVariable(paramNames[i-1]);
}
// Build the array creation expression.
JavaExpression arrayCreation =
new JavaExpression.ArrayCreationExpression(SOURCE_MODEL_EXPR_TYPE_NAME, arrayElements);
// Invoke SourceModel.Expr.Application.make()
MethodInvocation makeApply =
new MethodInvocation.Static(
SOURCE_MODEL_EXPR_APPLICATION_TYPE_NAME,
"make",
arrayCreation,
JavaTypeName.makeArrayType(SOURCE_MODEL_EXPR_TYPE_NAME),
SOURCE_MODEL_EXPR_APPLICATION_TYPE_NAME);
bindingMethod.addStatement(new ReturnStatement (makeApply));
// If any of the argument types correspond to a Java type.
// (eg. Prelude.Int, Prelude.Long, etc. we can generate a version
// of the binding function that takes these argument types.
boolean primArgs = false;
TypeExpr[] pieces = te.getTypePieces();
for (int i = 0; i < paramNames.length; ++i) {
if (canTypeBeUnboxed(pieces[i])) {
primArgs = true;
// Change the param type.
paramTypes[i] = typeExprToTypeName(pieces[i]);
// Since the parameter will now be an int, boolean, long, etc. we
// need to create the appropriate SourceModel wrapper around the
// value.
arrayElements[i+1] = wrapArgument(paramNames[i], pieces[i]);
}
}
if (primArgs) {
// Create the alternate helper method.
bindingMethod =
new JavaMethod(PUBLIC_STATIC_FINAL,
SOURCE_MODEL_EXPR_TYPE_NAME,
paramNames,
paramTypes,
null, javaFuncName);
functionsClass.addMethod(bindingMethod);
JavaStatement.JavaDocComment comment = new JavaStatement.JavaDocComment(atSee);
for (int iArg = 0; iArg < paramNames.length; ++iArg) {
comment.addLine("@param " + paramNames[iArg]);
}
comment.addLine("@return the SourceModel.Expr representing an application of " + calFuncName);
bindingMethod.setJavaDocComment(comment);
arrayCreation =
new JavaExpression.ArrayCreationExpression(SOURCE_MODEL_EXPR_TYPE_NAME, arrayElements);
makeApply =
new MethodInvocation.Static(
SOURCE_MODEL_EXPR_APPLICATION_TYPE_NAME,
"make",
arrayCreation,
JavaTypeName.makeArrayType(SOURCE_MODEL_EXPR_TYPE_NAME),
SOURCE_MODEL_EXPR_APPLICATION_TYPE_NAME);
bindingMethod.addStatement(new ReturnStatement (makeApply));
}
}
// Add a field for the function name.
// 'static final QualifiedName functionName = "functionName";'
// We need to check for conflict between the functionName
// and java keywords. It is valid to have a CAL
// function called assert but not valid to have java code
// 'static final Qualifiedname assert = ...
JavaFieldDeclaration jfd =
makeQualifiedNameDeclaration(javaFuncName, calFuncName);
JavaDocComment qfComment = new JavaDocComment("Name binding for function: " + calFuncName + ".");
qfComment.addLine(atSee);
jfd.setJavaDoc(qfComment);
functionsClass.addFieldDeclaration(jfd);
}