// the ordinal fields.
Set<String> javaNames = new HashSet<String>();
for (final String typeConstructorName : typeConstructorNames) {
TypeConstructor typeCons = moduleTypeInfo.getTypeConstructor(typeConstructorName);
for (int i = 0, n = typeCons.getNDataConstructors(); i < n; ++i) {
DataConstructor dc = typeCons.getNthDataConstructor(i);
// If we are showing public entities we only car about public data constructors.
if (dc.getScope().isPublic() != publicEntities) {
continue;
}
// This is the name used to name the java function and the QualfiedName field
// associated with this data constructor.
String javaFuncName = fixupVarName(dc.getName().getUnqualifiedName());
javaNames.add(javaFuncName);
}
}
for (final String typeConstructorName : typeConstructorNames) {
TypeConstructor typeCons = moduleTypeInfo.getTypeConstructor(typeConstructorName);
boolean commentAdded = false;
for (int i = 0, n = typeCons.getNDataConstructors(); i < n; ++i) {
DataConstructor dc = typeCons.getNthDataConstructor(i);
// If we are showing public entities we only car about public data constructors.
if (dc.getScope().isPublic() != publicEntities) {
continue;
}
addClass = true;
// If this is the first DC for the data type we want a non JavaDoc comment
// indicating the data type.
if (!commentAdded) {
MultiLineComment mlc = new MultiLineComment("DataConstructors for the " + typeCons.getName().getQualifiedName() + " data type.");
dataConstructorsClass.addComment(mlc);
commentAdded = true;
}
// Get the types of the data constructor fields.
TypeExpr[] fieldTypes = getFieldTypesForDC(dc);
String javaFuncName = fixupVarName(dc.getName().getUnqualifiedName());
// Since data constructors are capitalized its possible to have a conflict between the name
// of our field/helper function and the name of the containing class.
if (javaFuncName.equals(this.bindingClassName)) {
javaFuncName = javaFuncName + "_";
}
// First generate a method that takes SourceModel.Expr instances for
// each field value.
// Build up the argument names and types.
int nArgs = dc.getArity();
JavaTypeName argTypes[] = new JavaTypeName[nArgs];
Arrays.fill(argTypes, SOURCE_MODEL_EXPR_TYPE_NAME);
String argNames[] = new String[nArgs];
String origArgNames[] = new String[nArgs];
for (int j = 0, k = argNames.length; j < k; ++j) {
argNames[j] = fixupVarName(dc.getArgumentName(j));
origArgNames[j] = dc.getArgumentName(j);
}
// Create the method.
JavaMethod bindingFunction =
new JavaMethod(PUBLIC_STATIC_FINAL,
SOURCE_MODEL_EXPR_TYPE_NAME,
argNames,
argTypes,
null, javaFuncName);
dataConstructorsClass.addMethod(bindingFunction);
// Add JavaDoc for the method.
JavaDocComment funcComment;
CALDocComment cdc = dc.getCALDocComment();
if (cdc != null) {
funcComment = new JavaDocComment(calDocCommentToJavaComment(cdc, dc, false, argNames));
funcComment = fixupJavaDoc(funcComment, origArgNames, argNames);
} else {
funcComment = new JavaDocComment("Binding for DataConstructor: " + dc.getName().getQualifiedName() + ".");
for (int iName = 0; iName < argNames.length; ++iName) {
funcComment.addLine("@param " + argNames[iName]);
}
funcComment.addLine("@return the SourceModule.Expr representing an application of " + dc.getName().getQualifiedName());
}
bindingFunction.setJavaDocComment(funcComment);
// Now we need to fill in the body.
// Create an instance of SourceModel.Expr.DataCons for the data constructor.
JavaField nameField = new JavaField.Static(dataConstructorsClassTypeName, javaFuncName, QUALIFIED_NAME_TYPE_NAME);
JavaExpression sourceModelDataConsCreation =
new MethodInvocation.Static(
SOURCE_MODEL_EXPR_DATA_CONS_TYPE_NAME,
"make",
nameField,
QUALIFIED_NAME_TYPE_NAME,
SOURCE_MODEL_EXPR_DATA_CONS_TYPE_NAME);
// Build up an @see tag for the function just created.
String atSee = "@see #" + javaFuncName + "(";
for (int iArg = 0; iArg < argNames.length; ++iArg) {
if (iArg == 0) {
atSee = atSee + argTypes[iArg].getFullJavaSourceName();
} else {
atSee = atSee + ", " + argTypes[iArg].getFullJavaSourceName();
}
}
atSee = atSee + ")";
if (dc.getArity() == 0) {
// Simply return the Expr.DataCons.
bindingFunction.addStatement(new ReturnStatement(sourceModelDataConsCreation));
} else {
// Need to build up an application.
// Create an array of SourceModel.Expr where the first element is the
// SourceModel.Expr.DataCons instance and the following elements are
// the function arguments.
JavaExpression arrayElements[] = new JavaExpression[dc.getArity() + 1];
arrayElements[0] = sourceModelDataConsCreation;
for (int j = 1; j <= argNames.length; ++j) {
arrayElements[j] = new JavaExpression.MethodVariable(argNames[j-1]);
}
JavaExpression arrayCreation =
new JavaExpression.ArrayCreationExpression(SOURCE_MODEL_EXPR_TYPE_NAME, arrayElements);
// Invoke SourceModle.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);
bindingFunction.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;
for (int j = 0, k = fieldTypes.length; j < k; ++j) {
if (canTypeBeUnboxed(fieldTypes[j])) {
primArgs = true;
// Update the type of the argument.
argTypes[j] = typeExprToTypeName(fieldTypes[j]);
// The argument to Application.make needs to be updated.
// We need to wrap the raw value (i.e. int, boolean, etc.)
// in the appropriate SourceModel construct.
arrayElements[j+1] = wrapArgument(argNames[j], fieldTypes[j]);
}
}
if (primArgs) {
bindingFunction =
new JavaMethod(PUBLIC_STATIC_FINAL,
SOURCE_MODEL_EXPR_TYPE_NAME,
argNames,
argTypes,
null, javaFuncName);
dataConstructorsClass.addMethod(bindingFunction);
// For the comment for this method we want an @see referring to the previous method.
JavaStatement.JavaDocComment comment = new JavaStatement.JavaDocComment(atSee);
for (int iArg = 0; iArg < argNames.length; ++iArg) {
comment.addLine("@param " + argNames[iArg]);
}
comment.addLine("@return " + SOURCE_MODEL_EXPR_TYPE_NAME.getFullJavaSourceName());
bindingFunction.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);
bindingFunction.addStatement(new ReturnStatement (makeApply));
}
}
// Create a field declaration for the QualifiedName field.
JavaFieldDeclaration jfd =
makeQualifiedNameDeclaration(javaFuncName, dc.getName().getUnqualifiedName());
// If there is CALDoc for the DC add it as JavaDoc.
JavaDocComment comment = new JavaDocComment("Name binding for DataConstructor: " + dc.getName().getQualifiedName() + ".");
comment.addLine(atSee);
jfd.setJavaDoc(comment);
dataConstructorsClass.addFieldDeclaration(jfd);
// Now add an int field which is the ordinal of the data constructor.
String ordinalFieldName = javaFuncName + "_ordinal";
while (javaNames.contains(ordinalFieldName)) {
ordinalFieldName = ordinalFieldName + "_";
}
JavaFieldDeclaration ordinalFieldDec =
new JavaFieldDeclaration(PUBLIC_STATIC_FINAL, JavaTypeName.INT, ordinalFieldName, JavaExpression.LiteralWrapper.make(Integer.valueOf(dc.getOrdinal())));
javaNames.add(ordinalFieldName);
JavaDocComment ordinalComment = new JavaDocComment("Ordinal of DataConstructor " + dc.getName().getQualifiedName() + ".");
ordinalComment.addLine(atSee);
ordinalFieldDec.setJavaDoc(ordinalComment);
dataConstructorsClass.addFieldDeclaration(ordinalFieldDec);
}