/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* PartialAppNodeGenerator.java
* Creation date: Mar 9, 2006
* By: rcypher
*/
package org.openquark.cal.internal.machine.lecc;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
/**
* This is a helper class to generate the source code for the RTPartialApp
* sub-classes.
* It simply generates the source for the static inner classes of RTPartialApp
* and dumps it to the file specified in the arguments to main.
* @author rcypher
*/
public final class PartialAppNodeGenerator {
public static void main(String[] args) {
try {
// Set up the file for i/o.
File f = new File (args[0]);
FileOutputStream fs = new FileOutputStream(f);
PrintStream ps = new PrintStream (fs);
// There is a static inner class derived from RTPartialApp for
// each arity from 2 to 15 (you can't have a partial application
// of a function with only one argument).
for (int scArity = 2; scArity <= 15; ++scArity) {
println(ps, 1, "/**");
println(ps, 1, " * WARNING- this class was automatically generated by PartialAppNodeGenerator. DO NOT MANUALLY EDIT THIS CLASS.");
println(ps, 1, " * This class is used to represent a function created by");
println(ps, 1, " * partial application of an arity " + scArity + " function.");
println(ps, 1, " */");
println(ps, 1, "public static abstract class _" + scArity + " extends RTPartialApp {");
ps.println();
// The arity class has a static inner class for each possible number of arguments.
// i.e. 1 to (arity-1).
for (int nAppliedArgs = 1; nAppliedArgs < scArity; ++nAppliedArgs) {
final int partialAppArity = scArity - nAppliedArgs;
println(ps, 2, "/**");
println(ps, 2, " * WARNING- this class was automatically generated by PartialAppNodeGenerator. DO NOT MANUALLY EDIT THIS CLASS.");
println(ps, 2, " * Represents an application of an arity " + scArity + " function to " + nAppliedArgs + " argument(s).");
println(ps, 2, " */");
println(ps, 2, "public static final class _" + nAppliedArgs + " extends _" + scArity + " {");
ps.println();
// There will be a final RTSupercombinator field for the supercombinator that is being
// partially applied.
println(ps, 3, "private final RTSupercombinator function;");
// There will be an RTValue field for each applied argument.
for (int k = 1; k <= nAppliedArgs; ++k) {
println(ps, 3, "private final RTValue arg" + k + ";");
}
ps.println();
// Create the constructor. It takes the supercombinator and arguments.
print(ps, 3, "public _" + nAppliedArgs + " (final RTSupercombinator function");
for (int k = 1; k <= nAppliedArgs; ++k) {
ps.print (", final RTValue arg" + k);
}
ps.println(") {");
// Assert that the arguments are non-null.
print(ps, 4, "assert (function != null ");
for (int k = 1; k <= nAppliedArgs; ++k) {
ps.print("&& arg" + k + " != null ");
}
ps.println(") : \"Invalid argument value in RTPartialApp._" + scArity + "._" + nAppliedArgs + "\";");
println(ps, 4, "this.function = function;");
for (int k = 1; k <= nAppliedArgs; ++k) {
println(ps, 4, "this.arg" + k + " = arg" + k + ";");
}
println(ps, 3, "}");
ps.println();
println(ps, 3, "/** {@inheritDoc} */");
println(ps, 3, "@Override");
println(ps, 3, "public final int getArity() {");
println(ps, 3, " return " + partialAppArity + ";");
println(ps, 3, "}");
ps.println();
// Now create the f method. It will extract enough arguments to fill
// the application and then invoke the fnL method of the supercombinator.
println(ps, 3, "/** {@inheritDoc} */");
println(ps, 3, "@Override");
println(ps, 3, "protected final RTValue f(final RTResultFunction rootNode, final RTExecutionContext ec) throws CALExecutorException {");
for (int k = scArity; k > nAppliedArgs; --k) {
if (k == scArity) {
println(ps, 4, "RTValue arg" + k + " = rootNode.getArgValue();");
} else if (k == scArity - 1) {
if (partialAppArity > 2) {
println(ps, 4, "RTValue currentRootNode;");
println(ps, 4, "RTValue arg" + k + " = (currentRootNode = rootNode.prevArg()).getArgValue();");
} else {
println(ps, 4, "RTValue arg" + k + " = rootNode.prevArg().getArgValue();");
}
} else if (k == nAppliedArgs+1) {
println(ps, 4, "RTValue arg" + k + " = currentRootNode.prevArg().getArgValue();");
} else {
println(ps, 4, "RTValue arg" + k + " = (currentRootNode = currentRootNode.prevArg()).getArgValue();");
}
}
// Uncomment this code to allow collapsing of indirection chains.
// currently we don't do this because of the associated performance hit.
// for (int k = 1; k <= nAppliedArgs; ++k) {
// println(ps, 3, " if (arg" + k + " instanceof RTResultFunction){");
// println(ps, 3, " arg" + k + " = arg" + k + ".getValue();");
// println(ps, 3, " }");
// }
print(ps, 4, "return function.f" + scArity + "L(");
for (int k = 1; k <= scArity; ++k) {
if (k > nAppliedArgs) {
ps.print("RTValue.lastRef(arg" + k + ", (arg" + k + " = null)), ");
} else {
ps.print("arg" + k + ", ");
}
}
println(ps, 0, "ec);");
println(ps, 3, "}");
ps.println();
// Now create the fnL method. It will take as arguments enough values to complete
// the partial application and then will invoke the fnL method of the supercombinator.
// Note that we try to collapse indirection chains for the argument fields.
println(ps, 3, "@Override");
print(ps, 3, "public RTValue f" + partialAppArity + "L(");
for(int k = nAppliedArgs+1; k <= scArity; k++) {
ps.print("RTValue arg" + k + ", ");
}
ps.println("final RTExecutionContext ec) throws CALExecutorException {");
// Uncomment this code to allow collapsing of indirection chains.
// currently we don't do this because of the associated performance hit.
// for (int k = 1; k <= nAppliedArgs; ++k) {
// println(ps, 3, " if (arg" + k + " instanceof RTResultFunction){");
// println(ps, 3, " arg" + k + " = arg" + k + ".getValue();");
// println(ps, 3, " }");
// }
print(ps, 4, "return function.f" + scArity + "L(");
for (int k = 1; k <= scArity; ++k) {
if (k > nAppliedArgs) {
ps.print("RTValue.lastRef(arg" + k + ", (arg" + k + " = null)), ");
} else {
ps.print("arg" + k + ", ");
}
}
println(ps, 0, "ec);");
println(ps, 3, "}");
ps.println();
// Now create the debug functions used to examine the node classes for
// tracing etc.
// debug_getNChildren should simply return the number of applied arguments.
println(ps, 3, "/** {@inheritDoc} */");
println(ps, 3, "@Override");
println(ps, 3, "public final int debug_getNChildren() {");
println(ps, 3, " return " + nAppliedArgs + ";");
println(ps, 3, "}");
ps.println();
// debug_getChild() will return the appropriate applied argument.
println(ps, 3, "/** {@inheritDoc} */");
println(ps, 3, "@Override");
println(ps, 3, "public final CalValue debug_getChild(final int childN) {");
println(ps, 3, " switch (childN) {");
for (int k = 0; k < nAppliedArgs; ++k) {
println(ps, 3, " case " + k + ":");
println(ps, 3, " return arg" + (k+1) + ";");
}
println(ps, 3, " default:");
println(ps, 3, " throw new IndexOutOfBoundsException();");
println(ps, 3, " }");
println(ps, 3, "}");
ps.println();
// debug_getNodeStartText should return the qualified name of the
// supercombinator that is partially applied.
println(ps, 3, "/** {@inheritDoc} */");
println(ps, 3, "@Override");
println(ps, 3, "public final String debug_getNodeStartText() {");
println(ps, 3, " return \"(\" + function.getQualifiedName();");
println(ps, 3, "}");
ps.println();
// debug_getNodeEndText simply returns ")".
println(ps, 3, "/** {@inheritDoc} */");
println(ps, 3, "@Override");
println(ps, 3, "public final String debug_getNodeEndText() {");
println(ps, 3, " return \")\";");
println(ps, 3, "}");
ps.println();
// debug_getChildPrefixText returns a space.
println(ps, 3, "/** {@inheritDoc} */");
println(ps, 3, "@Override");
println(ps, 3, "public final String debug_getChildPrefixText(final int childN) {");
println(ps, 3, " if (childN >= 0 && childN < " + nAppliedArgs + ") {");
println(ps, 3, " return \" \";");
println(ps, 3, " }");
println(ps, 3, " throw new IndexOutOfBoundsException();");
println(ps, 3, "}");
ps.println();
// Create the getSupercombinator() override.
println(ps, 3, "/** {@inheritDoc} */");
println(ps, 3, "@Override");
println(ps, 3, "RTSupercombinator getSupercombinator () {");
println(ps, 3, " return function;");
println(ps, 3, "}");
println(ps, 2, "}");
ps.println();
}
println(ps, 1, "}");
ps.println();
}
} catch (Exception e) {
System.out.println("Exception generating code for partial application classes. " + e);
}
System.out.println("Generated source text sent to " + args[0]);
}
private static void print(final PrintStream ps, final int nTabs, final String text) {
StringBuilder indentedText = new StringBuilder();
for (int i = 0; i < nTabs; ++i) {
indentedText.append(" ");
}
indentedText.append(text);
ps.print(indentedText.toString());
}
private static void println(final PrintStream ps, final int nTabs, final String text) {
print(ps, nTabs, text);
ps.println();
}
}