/* Code generator for the Java language. Copyright (c) 2008-2014 The Regents of the University of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. PT_COPYRIGHT_VERSION_2 COPYRIGHTENDKEY */ package ptolemy.cg.kernel.generic.program.procedural.java; import java.io.BufferedReader; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; import ptolemy.actor.Actor; import ptolemy.actor.CompositeActor; import ptolemy.actor.TypedIOPort; import ptolemy.cg.adapter.generic.program.procedural.adapters.ptolemy.actor.sched.StaticSchedulingDirector; import ptolemy.cg.kernel.generic.CodeGeneratorAdapter; import ptolemy.cg.kernel.generic.GenericCodeGenerator; import ptolemy.cg.kernel.generic.program.CodeStream; import ptolemy.cg.kernel.generic.program.NamedProgramCodeGeneratorAdapter; import ptolemy.cg.kernel.generic.program.ProgramCodeGeneratorAdapter; import ptolemy.cg.kernel.generic.program.TemplateParser; import ptolemy.cg.kernel.generic.program.procedural.ProceduralCodeGenerator; import ptolemy.cg.lib.PointerToken; import ptolemy.data.BooleanToken; import ptolemy.data.expr.Variable; import ptolemy.data.type.ArrayType; import ptolemy.data.type.BaseType; import ptolemy.data.type.MatrixType; import ptolemy.data.type.Type; import ptolemy.kernel.CompositeEntity; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.InternalErrorException; import ptolemy.kernel.util.NameDuplicationException; import ptolemy.kernel.util.NamedObj; import ptolemy.util.StringUtilities; /////////////////////////////////////////////////////////////////// //// JavaCodeGenerator /** Base class for Java code generator. * * @author Gang Zhou, Contributor: Christopher Brooks * @version $Id: JavaCodeGenerator.java 70402 2014-10-23 00:52:20Z cxh $ * @since Ptolemy II 10.0 * @Pt.ProposedRating red (zgang) * @Pt.AcceptedRating red (zgang) */ public class JavaCodeGenerator extends ProceduralCodeGenerator { /** Create a new instance of the Java code generator. * @param container The container. * @param name The name of the Java code generator. * @exception IllegalActionException If the super class throws the * exception or error occurs when setting the file path. * @exception NameDuplicationException If the super class throws the * exception or an error occurs when setting the file path. */ public JavaCodeGenerator(NamedObj container, String name) throws IllegalActionException, NameDuplicationException { super(container, name, "java", "j"); // compileCommand is only used if useMake is false. if (compileCommand.getExpression().equals(_compileCommandDefault)) { compileCommand .setExpression("javac -classpath \"@PTCGLibraries@\" -J-Xmx1500M @modelName@.java"); } // runCommand is only used if useMake is false. if (runCommand.getExpression().equals(_runCommandDefault)) { runCommand .setExpression("java -classpath \"@PTCGLibraries@\" -Xmx1500M @MODELCLASS@"); } generatorPackageList.setExpression("generic.program.procedural.java"); // A list of the primitive types supported by the code generator. // FIXME: we should not have to set these each time, but // JavaCodeGenerator uses Integer, and CCodeGenerator uses Int _primitiveTypes = Arrays.asList(new String[] { "Integer", "Double", "String", "Long", "Boolean", "UnsignedByte", /*"Complex",*/"Pointer", "Object" }); } /////////////////////////////////////////////////////////////////// //// public methods //// /** * Get the corresponding type in code generation from the given Ptolemy * type. * @param type The given Ptolemy type. * @return The code generation type. */ @Override public String codeGenType(Type type) { //String ptolemyType = super.codeGenType(type); String result = type == BaseType.INT ? "Int" : type == BaseType.LONG ? "Long" : type == BaseType.STRING ? "String" : type == BaseType.DOUBLE ? "Double" : type == BaseType.BOOLEAN ? "Boolean" : type == BaseType.UNSIGNED_BYTE ? "UnsignedByte" : type == PointerToken.POINTER ? "Pointer" : type == BaseType.COMPLEX ? "Complex" // FIXME: Why do we have to use equals with BaseType.OBJECT? : type.equals(BaseType.OBJECT) ? "Object" //: type == BaseType.OBJECT ? "Object" : null; if (result == null) { if (type instanceof ArrayType) { result = "Array"; } else if (type instanceof MatrixType) { result = "Matrix"; } } if (result == null || result.length() == 0) { // if (type instanceof ptolemy.data.type.ObjectType) { // System.out.println("ObjectType: " + type + " " + BaseType.OBJECT); // ptolemy.data.type.ObjectType objectType = (ptolemy.data.type.ObjectType)type; // Class clazz = objectType.getTokenClass(); // System.out.println("ObjectType class: " + (clazz == null ? "null!" : clazz.getName())); // Class clazz2 = BaseType.OBJECT.getTokenClass(); // System.out.println("BaseType.ObjectType class: " + (clazz2 == null ? "null!" : clazz2.getName())); // boolean flag = (clazz == clazz2); // System.out.println("clazz == clazz2: " + flag); // flag = (type == BaseType.OBJECT); // System.out.println("type == BaseType.OBJECT: " + flag); // flag = (type.equals(BaseType.OBJECT)); // System.out.println("type.equals(BaseType.OBJECT): " + flag); // System.out.println("type.hashCode(): " + type.hashCode() + " BaseType.OBJECT.hashCode(): " + BaseType.OBJECT.hashCode()); // System.out.println("System.identityHashCode(type): " + System.identityHashCode(type) // + " System.identityHashCode(BaseType.OBJECT) " + System.identityHashCode(BaseType.OBJECT)); // } // It is not an error to resolve to general. See // $PTII/bin/ptcg -language java $PTII/ptolemy/cg/kernel/generic/program/procedural/java/test/auto/Display.xml System.out .println("JavaCodeGenerator.codeGenType(): Cannot resolve codegen type from Ptolemy type: " + type + ". Maybe the type of a port needs to be set from the UI or backward type inference disabled?"); } if (result == null) { return null; } return result.replace("Int", "Integer") .replace("Integerger", "Integer"); //return ptolemyType.replace("Int", "Integer").replace("Integerger", "Integer").replace("Array", "Token"); } /** * Get the corresponding type in code generation from the given Ptolemy * type. * @param type The given Ptolemy type. * @return The code generation type in primitive Java types. */ public static String codeGenType2(Type type) { // FIXME: why is this necessary? It seems to return C types (int vs Int, long vs. Long) // It is used in ./ptolemy/cg/kernel/generic/program/procedural/java/modular/ModularCodeGenerator.java // It is used in ./ptolemy/cg/kernel/generic/program/procedural/java/modular/ModularSDFCodeGenerator.java String result = type == BaseType.INT ? "int" : type == BaseType.LONG ? "long" : type == BaseType.STRING ? "String" : type == BaseType.DOUBLE ? "double" : type == BaseType.BOOLEAN ? "boolean" : type == BaseType.UNSIGNED_BYTE ? "unsigned byte" : type == PointerToken.POINTER ? "Pointer" : type == BaseType.COMPLEX ? "Complex" // FIXME: Why do we have to use equals with Object : type.equals(BaseType.OBJECT) ? "Object" //: type == BaseType.OBJECT ? "Object" : null; if (result == null) { if (type instanceof ArrayType) { result = "Array"; } else if (type instanceof MatrixType) { result = "Matrix"; } } if (result == null || result.length() == 0) { System.out .println("JavaCodeGenerator.codeGenType2: Cannot resolve codegen type from Ptolemy type: " + type); } if (result == null) { return null; } return result; } /** * Return the index of the type in the typesArray in the generated code. * @param type The given codegen type. * @return The index of the type in the typesArray * @exception IllegalActionException If the type is unsupported. */ static public Short codeGenTypeValue(String type) throws IllegalActionException { // FIXME: the typesArray should only include types used // by the model. // FIXME: why does this return a Short, but codeGenTypeToPtType() // takes an int? Short typeReturn; if (type.equals("Token")) { typeReturn = -1; } else if (type.equals("String")) { typeReturn = 0; } else if (type.equals("Array")) { typeReturn = 1; } else if (type.equals("Integer")) { typeReturn = 2; } else if (type.equals("Long")) { typeReturn = 3; } else if (type.equals("Double")) { typeReturn = 4; } else if (type.equals("Boolean")) { typeReturn = 5; } else if (type.equals("UnsignedByte")) { typeReturn = 6; } else if (type.equals("Pointer")) { typeReturn = 7; } else if (type.equals("Matrix")) { typeReturn = 8; } else if (type.equals("Complex")) { typeReturn = 9; } else if (type.equals("Object")) { typeReturn = 10; } else { throw new IllegalActionException("Unsupported type: " + type); } return typeReturn; } /** * Return the type that corresponds with an index in the typesArray in * in the generated type. * @param codeGenType The index of the codegen type. * @return The Ptolemy type that corresponds with the index. * @exception IllegalActionException If the type is unsupported. * @see #ptTypeToCodegenType(Type) */ static public Type codeGenTypeToPtType(int codeGenType) throws IllegalActionException { Type returnType; // FIXME: Add more types. // FIXME: the typesArray should only include types used // by the model. switch (codeGenType) { case 0: returnType = BaseType.STRING; break; case 2: returnType = BaseType.INT; break; case 3: returnType = BaseType.LONG; break; case 4: returnType = BaseType.DOUBLE; break; case 5: returnType = BaseType.BOOLEAN; break; case 6: returnType = BaseType.UNSIGNED_BYTE; break; case 7: returnType = PointerToken.POINTER; break; // FIXME: case 8 is Matrix case 9: returnType = BaseType.COMPLEX; break; case 10: returnType = BaseType.OBJECT; break; default: throw new IllegalActionException("Unsuported type"); } return returnType; } /** * Return the index of the type in the typesArray in the generated code. * @param type The given Ptolemy type. * @return The index of the type in the typesArray * @exception IllegalActionException If the type is unsupported. * @see #codeGenTypeToPtType(int) */ static public int ptTypeToCodegenType(Type type) throws IllegalActionException { // FIXME: the typesArray should only include types used // by the model. int result = type == BaseType.INT ? 2 : type == BaseType.LONG ? 3 : type == BaseType.STRING ? 0 : type == BaseType.DOUBLE ? 4 : type == BaseType.BOOLEAN ? 5 : type == BaseType.UNSIGNED_BYTE ? 6 : type == PointerToken.POINTER ? 7 : type == BaseType.COMPLEX ? 9 // FIXME: Why do we have to use equals with BaseType.OBJECT? : type.equals(BaseType.OBJECT) ? 10 //: type == BaseType.OBJECT ? 10 : -10; if (result == -10) { if (type instanceof ArrayType) { result = 0; } else if (type instanceof MatrixType) { result = 8; } } if (result == -10) { throw new IllegalActionException("Unsuported type: " + type); } return result; } /** Generate code that defines a constant. * In Java, generate a static final. * @param constant The name of the constant to be defined * @param type A string representing the type. In C, this * parameter is ignored. * @param value The value of the constant. * @return A static final that defines the constant. */ @Override public String generateConstantDefinition(String constant, String type, String value) { // Maybe we should keep track of these in a Set? return "static final " + type + " " + constant + " = " + value + ";" + _eol; } /** Generate the closing code for a group of fire functions common * to a Composite Actor. This method is called when the firing * code of each actor is not inlined. * * @return a curly bracket and _eol. */ @Override public String generateFireFunctionCompositeEnd() { return "}" + _eol; } /** Generate the initial code for a group of fire functions common * to a Composite Actor. This method is called when the firing * code of each actor is not inlined. * * @param className The name of the class to include in the * initial code. * @return A string that defines an inner class. */ @Override public String generateFireFunctionCompositeStart(String className) { return "class " + className + "{" + _eol; } /** Generate the fire function method invocation. This method is called * when the firing code of each actor is not inlined. * *
So as to reduce the size of classes to be compiled, this * code generator generates the fire function methods for the top * two levels of composites in separate inner classes. This * method returns a String that contains variable that refers to * an instance of the inner class followed by the name of the * method to be invoked.
* * @param namedObj The named object for which the name is generated. * @return The name of the fire function method to be invoked. * @exception IllegalActionException If thrown while generating fire code. */ @Override public String generateFireFunctionMethodInvocation(NamedObj namedObj) throws IllegalActionException { String[] results = generateFireFunctionVariableAndMethodName(namedObj); String result = "_inner" + results[0] + "." + results[1]; //System.out.println("JCG.generateFireFunctionMethodInvocation(): " + namedObj.getFullName() + " " + result); return result; } /** Generate the fire function method name. This method is called * when the firing code of each actor is not inlined. * *So as to reduce the size of classes to be compiled, this * code generator generates the fire function methods for the top * two levels of composites in separate inner classes. This * method returns a String that contains the name of the method * to be invoked.
* * @param namedObj The named object for which the name is generated. * @return The name of the fire function method. * @exception IllegalActionException If thrown while generating fire code. */ @Override public String generateFireFunctionMethodName(NamedObj namedObj) throws IllegalActionException { String[] results = generateFireFunctionVariableAndMethodName(namedObj); //System.out.println("JCG.generateFireFunctionMethodName(): " + namedObj.getFullName() + " " + results[1]); return results[1]; } /** Generate the fire function variable name and method * name. This method is called when the firing code of each actor * is not inlined. * *So as to reduce the size of classes to be compiled, this * code generator generates the fire function methods for the top * two levels of composites in separate inner classes.
* * @param namedObj The named object for which the name is generated. * @return An array of two elements. The first element is a String * that contains the variable name, the second is the name of the method. * @exception IllegalActionException If thrown while generating fire code. */ @Override public String[] generateFireFunctionVariableAndMethodName(NamedObj namedObj) throws IllegalActionException { // Get the toplevel name and the name of the composite under the // top level. // If we have Foo.Ramp, return _inner_Foo.Ramp // If we have Foo.Bar.Ramp, return _inner_Foo_Bar.Ramp // If we have Foo.Bar.Biz.Ramp, return _inner_Foo_Bar.Biz_Ramp NamedObj container = namedObj.getContainer(); String[] results = new String[2]; if (container == null) { results[0] = ""; results[1] = CodeGeneratorAdapter.generateName(namedObj); results[1] = TemplateParser.escapeName(results[1]); return results; } String fullName = namedObj.getFullName(); int firstDot = fullName.indexOf('.'); if (firstDot == -1) { throw new InternalErrorException(namedObj, null, "Could not find '.' in " + fullName); } if (firstDot == 0) { firstDot = fullName.indexOf('.', firstDot + 1); } int secondDot = fullName.indexOf('.', firstDot + 1); if (firstDot == -1) { results[0] = ""; results[1] = _javaKeywordSanitize(CodeGeneratorAdapter .generateName(namedObj)); results[1] = TemplateParser.escapeName(results[1]); return results; } if (secondDot == -1) { results[0] = _javaKeywordSanitize(StringUtilities .sanitizeName(fullName.substring(0, firstDot))); results[1] = _javaKeywordSanitize(StringUtilities .sanitizeName(fullName.substring(firstDot + 1, fullName.length()))); if (namedObj instanceof ptolemy.actor.TypedCompositeActor) { // A Hack for inline code generation. The problem is // that when we generate inline code, we want the top // few composites to be generated inside inner classes // so that we can reduce the code size for // compilation. Unfortunately, when SDFCodeGenerator // finds a TypedComposite, it generates code for the // TypedComposite and the inside of the TypedComposite // at the same time. Thus, the code needs to be // inside the same inner class. Thus, the name of the // TypedComposite has the name of the NamedObj twice. // This is a hack. results[0] += "_" + results[1]; } } else { results[0] = StringUtilities.sanitizeName(fullName.substring(0, firstDot) + "_" + fullName.substring(firstDot + 1, secondDot)); results[1] = _javaKeywordSanitize(StringUtilities .sanitizeName(fullName.substring(secondDot + 1, fullName.length()))); } //System.out.println("JCG: genVarAndMethName: " + firstDot + " " + secondDot + " " + fullName + " variableName: " + results[0] + " methodName: " + results[1]); // If an actor name has a $ in it . . . // $PTII/bin/ptcg -language java -inline false ~/ptII/ptolemy/cg/kernel/generic/program/procedural/java/test/auto/ActorWithDollarSignInName.xml results[0] = TemplateParser.escapeName(results[0]); results[1] = TemplateParser.escapeName(results[1]); return results; } /** Generate the fire function variable declaration. This method * is called when the firing code of each actor is not inlined. * *So as to reduce the size of classes the Java Code * Generator, the fire function methods for the top two levels of * composites are placed in a separate inner class.
* * @param namedObj The named object for which the name is generated. * @return If the namedObj is in a containment hierarchy that * also contains a GenericCodeGenerator, then the declaration is * returned. Otherwise, the empty string is returned. * @exception IllegalActionException If there are problems * accessing the name of the namedObj or generating the variable * declaration. */ @Override public String generateFireFunctionVariableDeclaration(NamedObj namedObj) throws IllegalActionException { // Go up the containment chain, looking for a GenericCodeGenerator. // If there is one, return the declaration. If there is not one, // return the empty string. This is needed for Composite Codegen. NamedObj container = namedObj.getContainer(); while (container != null) { List* #line lineNumber "filename" ** are generated for use by the C preprocessor. * @param lineNumber The line number of the source file or * file containing code blocks. * @param filename The name of the source file or file containing * code blocks. * @return text that is suitable for the C preprocessor. */ @Override public String generateLineInfo(int lineNumber, String filename) { return "#line " + lineNumber + " \"" + filename + "\"\n"; } /** Generate the main entry point. * @return Return the definition of the main entry point for a program. * In C, this would be defining main(). * @exception IllegalActionException Not thrown in this base class. */ @Override public String generateMainEntryCode() throws IllegalActionException { StringBuffer mainEntryCode = new StringBuffer(); // If the container is in the top level, we are generating code // for the whole model. if (_isTopLevel()) { // mainEntryCode // .append(_eol // + _eol // + "public static void main(String [] args) throws Exception {" // + _eol + _sanitizedModelName + " model = new " // + _sanitizedModelName + "();" + _eol // + "model.run();" + _eol + "}" + _eol // + "public void run() throws Exception {" + _eol); String recordStartTimeCode = ""; String printExecutionTimeCode = ""; if (((BooleanToken) measureTime.getToken()).booleanValue()) { recordStartTimeCode = _recordStartTime(); printExecutionTimeCode = _printExecutionTime(); } mainEntryCode .append(_eol + _eol + "public static void main(String [] args) throws Exception {" + _eol + _sanitizedModelName + " model = new " + _sanitizedModelName + "();" + _eol + recordStartTimeCode + _eol + "model.preinitialize();" + _eol + "model.initialize();" + _eol + "model.execute();" + _eol + "model.doWrapup();" + _eol + printExecutionTimeCode + _eol + "System.exit(0);" + _eol + "}" + _eol); } else { mainEntryCode.append(_eol + _eol + "public Object[] " + _eol + "fire (" + _eol); Iterator> inputPorts = ((Actor) getContainer()).inputPortList() .iterator(); boolean addComma = false; while (inputPorts.hasNext()) { TypedIOPort inputPort = (TypedIOPort) inputPorts.next(); if (addComma) { mainEntryCode.append(", "); } mainEntryCode.append("Object[]" + inputPort.getName()); addComma = true; } mainEntryCode.append(") throws Exception {" + _eol); } return mainEntryCode.toString(); } /** Generate the main exit point. * @return Return a string that declares the end of the main() function. * @exception IllegalActionException Not thrown in this base class. */ @Override public String generateMainExitCode() throws IllegalActionException { if (_isTopLevel()) { return "}"; } else { if (_model instanceof CompositeActor && ((CompositeActor) _model).outputPortList().isEmpty()) { return INDENT1 + "return null;" + _eol + "}" + _eol + "}" + _eol; } else { return INDENT1 + "return tokensToAllOutputPorts;" + _eol + "}" + _eol + "}" + _eol; } } } /** Generate the package statement, if any. * @return If the generateInSubdirectory parameter of * the grandparent is true, then generate a package statement with * the name of the package being the sanitized model name * @exception IllegalActionException Thrown if generateInSubdirectory * cannot be read. */ @Override public String generatePackageStatement() throws IllegalActionException { if (_generateInSubdirectory) { return "package " + _sanitizedModelName + ";" + _eol; } return ""; } /** Generate the postfire procedure entry point. * @return a string for the postfire procedure entry point. * @exception IllegalActionException Not thrown in this base class. */ @Override public String generatePostfireEntryCode() throws IllegalActionException { return _eol + _eol + "public boolean postfire() {" + _eol; } /** Generate the postfire procedure exit point. * @return a string for the postfire procedure exit point. * @exception IllegalActionException Not thrown in this base class. */ @Override public String generatePostfireExitCode() throws IllegalActionException { return INDENT1 + "return true;" + _eol + "}" + _eol; } /** Generate the postfire procedure name. * @return a string for the postfire procedure name. * @exception IllegalActionException Not thrown in this base class. */ @Override public String generatePostfireProcedureName() throws IllegalActionException { return INDENT1 + "postfire();" + _eol; } /** * Generate type conversion code. * Determine the proper code put into the source to support dynamic type * resolution. First, find out the different types used in the model. * Second, find out the different polymorphic functions used. (note: types * and functions are independent of each other). Third, append code blocks * according to the functions used, and read from files according to the * types referenced. Fourth, generate type resolution code, which consists * of constants (MAX_NUM_TYPE, MAX_NUM_FUNC), the type map, the function * map, function definitions read from the files, and function table. * @return The type resolution code. * @exception IllegalActionException If an error occurs when generating * the type resolution code, or if the adapter class for the model * director cannot be found, or if an error occurs when the adapter * actor generates the type resolution code. */ @Override public String generateTypeConvertCode() throws IllegalActionException { StringBuffer code = new StringBuffer(); code.append(_eol + comment("Generate type resolution code for " + getContainer().getFullName())); // Include the constantsBlock at the top so that sharedBlocks from // actors can use true and false etc. StringMatches needs this. CodeStream sharedStream = new CodeStream( "$CLASSPATH/ptolemy/cg/kernel/generic/program/procedural/java/SharedCode.j", this); sharedStream.appendCodeBlock("constantsBlock"); code.append(sharedStream.toString()); HashSet
For Java, if the code consists of
* linesPerMethod or fewer lines, then the the first
* element will be the empty string and the second element will
* consist of the value of the code argument. If the code
* consists of more than linesPerMethod then the first
* element will consist of one or more "import static" statements
* and the second and possibly successive element will consist of
* Java classes that should be written out by
* {@link #_writeVariableDeclarations(List)}.
*
* @param linesPerMethod The number of lines that should go into
* each method.
* @param prefix The prefix to use when naming functions that
* are created
* @param code The variable declarations to be split.
* @return A list of at least two elements. If the code has less than
* _LINES_PER_METHOD lines, then the first element is empty, the
* second element contains the contents of the code parameter. If
* the code has more lines than _LINES_PER_METHOD, then the first
* element contains the declarations necessary for the include files
* section and the second element and successive elements contain the
* declarations. Each declaration should be placed into a file
* that corresponds with the include or import listed in the first
* element.
* @exception IOException If thrown while reading the code.
*/
@Override
public List Typically, the preinitialize code consists of variable
* declarations. However, AutoAdapter generates method calls
* that instantiate wrapper TypedCompositeActors, so we need
* to invoke those method calls. If a If no The makefile is written to a directory named by the
* codeDirectory parameter, with a file name that is a
* sanitized version of the model name, and a ".mk" extension.
* Thus, for a model named "Foo", we might generate a makefile in
* "$HOME/codegen/Foo.mk".
* Under Java under Windows, your The following variables are substituted
* If the first element is the empty String, then the second
* element contains all of the variable declarations and this method
* does not create files and the value of the second element is returned.
* If the first element is not the empty string, then the second
* and successive elements are written to a file whos name is
* created by parsing the first element. The first element must
* consist of strings like "import static variables.foo;", the file name
* will be "variables/foo.java".
* @param variableDeclarations A List of two or more elements.
* first element is not empty, then it contains the language
* specific declarations for the variable declarations. In Java,
* the first element may consist of one or more "import"
* statements. The second and successive elements contain the
* code to be written to separate files or to be returned as one
* String.
* @return If the first element is empty, then return the value
* of the second element. If the first element is not empty, then
* files are created and the empty string is returned.
* @exception IllegalActionException Thrown if there is a problem
* writing the files.
*/
@Override
protected String _writeVariableDeclarations(
List.mk.in
file with the name of the sanitized model
* name, then that file is used as a template. For example, if the
* model name is Foo
and the file Foo.mk.in
* exists, then the file Foo.mk.in
is used as a makefile
* template.
*
* .mk.in
file is found, then the makefile
* template can be found by looking up a resource name
* makefile.in in the package named by the
* generatorPackage parameter. Thus, if the
* generatorPackage has the value "ptolemy.codegen.c",
* then we look for the resource "ptolemy.codegen.c.makefile.in", which
* is usually found as $PTII/ptolemy/codegen/c/makefile.in
.
*
* $HOME
variable
* is set to the value of the user.home
System property,
* which is usually something like
* C:\Documents and Settings\yourlogin
, thus
* for user mrptolemy
the makefile would be
* C:\Documents and Settings\mrptolemy\codegen\Foo.mk
.
*
*
*
* @param container The composite actor for which we generate the makefile
* @param currentDirectory The director in which the makefile is to be written.
* @exception IllegalActionException If there is a problem reading
* a parameter, if there is a problem creating the codeDirectory directory
* or if there is a problem writing the code to a file.
*/
@Override
protected void _writeMakefile(CompositeEntity container,
String currentDirectory) throws IllegalActionException {
if (!_libraries.isEmpty()) {
// Loop through the path elements in java.class.path and add
// them as libraries. We need this so that we can find the
// JavaScope.zip code coverage file in the nightly build
_addClassPathLibraries();
}
String root = ".";
String modelClass = _sanitizedModelName;
if (((BooleanToken) generateInSubdirectory.getToken()).booleanValue()) {
root = "..";
modelClass = _sanitizedModelName + "." + _sanitizedModelName;
addLibraryIfNecessary("..");
}
_substituteMap.put("@ROOT@", root);
if (_libraries.size() == 0) {
addLibraryIfNecessary(".");
}
String ptcgLibraries = _concatenateClasspath(_libraries);
// Remove any trailing : and avoid having ".::.." in the makefile.
if (ptcgLibraries.endsWith(":")) {
ptcgLibraries = ptcgLibraries.substring(0,
ptcgLibraries.length() - 1);
}
_substituteMap.put("@PTCGLibraries@", ptcgLibraries);
_substituteMap.put("@MODELCLASS@", modelClass);
super._writeMakefile(container, currentDirectory);
}
/** Write the variable declaration code.
* @modelName@
* @PTCGIncludes@
* @PTCGLibraries@
*