/* * 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(); } }