/**
* Copyright (c) 2009-2011, The HATS Consortium. All rights reserved.
* This file is licensed under the terms of the Modified BSD License.
*/
package abs.backend.java.codegeneration.dynamic;
import java.io.PrintStream;
import abs.backend.java.JavaBackend;
import abs.backend.java.lib.runtime.ABSClosure;
import abs.backend.java.lib.runtime.ABSDynamicObject;
import abs.backend.java.lib.runtime.ABSDynamicRuntime;
import abs.backend.java.lib.runtime.ABSField;
import abs.backend.java.lib.runtime.ABSInitObjectCall;
import abs.backend.java.lib.runtime.ABSObject;
import abs.backend.java.lib.runtime.ABSRunMethodCall;
import abs.backend.java.lib.runtime.ABSRuntime;
import abs.backend.java.lib.runtime.ABSThread;
import abs.backend.java.lib.runtime.COG;
import abs.backend.java.lib.runtime.Task;
import abs.backend.java.lib.runtime.ABSDynamicClass;
import abs.backend.java.lib.types.ABSValue;
import abs.frontend.ast.ClassDecl;
import abs.frontend.ast.FieldDecl;
import abs.frontend.ast.MethodImpl;
import abs.frontend.ast.ParamDecl;
public class ClassDeclGenerator {
private final ClassDecl decl;
private final String className;
protected final PrintStream stream;
ClassDeclGenerator(PrintStream stream, ClassDecl decl) {
this.stream = stream;
this.decl = decl;
className = JavaBackend.getClassName(decl.getName());
}
public void generate() {
DynamicJavaGeneratorHelper.generateHelpLine(decl, stream);
generateClassHeader();
generateClassBody();
}
private void generateClassHeader() {
stream.print("public final class " + className + " ");
}
private void generateClassBody() {
// singleton() method instantiates strictly one dynamic class object and does initialisation,
// i.e. adds fields, constructor and methods.
stream.println("{");
stream.println("private static " + ABSDynamicClass.class.getName() + " instance;");
stream.println("public static void setInstance(" + ABSDynamicClass.class.getName() + " cls) { instance = cls; }");
stream.println("public static " + ABSDynamicClass.class.getName() + " singleton() {");
stream.println("if (instance == null) {");
stream.println("instance = new " + ABSDynamicClass.class.getName() + "();");
stream.println("instance.setName(\"" + decl.getName() + "\");");
// add class parameters
for (ParamDecl p : decl.getParams()) {
String name = JavaBackend.getVariableName(p.getName());
stream.println("instance.addField(\"" + name + "\", new " + ABSField.class.getName() + "());");
}
// add fields
for (FieldDecl f : decl.getFields()) {
String name = JavaBackend.getVariableName(f.getName());
stream.println("instance.addField(\"" + name + "\", " + className + ".field$" + name + ".singleton());");
}
// add constructor
stream.println("instance.setConstructor(" + className + ".CON$TRUCT.singleton());");
stream.print("instance.setParams(");
for (int i = 0; i < decl.getNumParam(); i++) {
if (i != 0)
stream.print(", ");
stream.print("\"" + JavaBackend.getVariableName(decl.getParam(i).getName()) + "\"");
}
stream.println(");");
// add methods
for (MethodImpl m : decl.getMethods()) {
String methodName = m.getMethodSig().getName();
stream.println("instance.addMethod(\"" + methodName + "\", " + className + "." + methodName + ".singleton());");
}
stream.println("}");
stream.println("return instance;");
stream.println("}");
// generate field inner classes
for (FieldDecl field : decl.getFields()) {
field.generateJavaDynamic(stream);
}
// generate CON$TRUCT inner class
generateConstructor();
// generate method inner classes
for (MethodImpl method : decl.getMethods()) {
method.generateJavaDynamic(stream);
// FIXME not sure how to handle FLI methods
if (method.isForeign()) {
stream.println("/* FLI method: not implemented yet */");
DynamicJavaGeneratorHelper.generateFLIMethod(stream, method);
}
}
generateCreateNewCOGMethod();
generateNewObjectMethods();
stream.println("}");
}
private void generateNewObjectMethods() {
// Convenience method for new C
stream.print("public static final <T extends " + ABSDynamicObject.class.getName() + "> T createNewObject");
DynamicJavaGeneratorHelper.generateParams(stream, decl.getParams());
stream.print("{ ");
stream.print("return (T)");
stream.print(className + ".__ABS_createNewObject");
DynamicJavaGeneratorHelper.generateParamArgs(stream, "null", decl.getParams());
stream.println("; }");
// static constructor method for new C
stream.print("public static final <T extends " + ABSDynamicObject.class.getName() + "> T __ABS_createNewObject");
DynamicJavaGeneratorHelper.generateParams(stream, ABSObject.class.getName() + " __ABS_source", decl.getParams());
stream.println(" {");
stream.println("final " + ABSDynamicRuntime.class.getName() + " __ABS_runtime = " + ABSDynamicRuntime.class.getName() + ".getCurrentRuntime();");
generateObjectConstruction(ABSRuntime.class.getName() + ".getCurrentRuntime()");
stream.println("__ABS_result.__ABS_init();");
if (decl.isActiveClass()) {
stream.println("final " + Task.class.getName() + " __ABS_sendingTask = " + ABSRuntime.class.getName() + ".getCurrentTask();");
stream.println(ABSRuntime.class.getName() + ".getCurrentRuntime().asyncCall(new "
+ ABSRunMethodCall.class.getName() + "(__ABS_sendingTask,__ABS_source,__ABS_result));");
}
stream.println("__ABS_runtime.registerObject((T)__ABS_result);");
stream.println("return (T)__ABS_result;");
stream.println("}");
}
private void generateCreateNewCOGMethod() {
// Convenience method for new cog C
stream.print("public static final <T extends " + ABSDynamicObject.class.getName() + "> T createNewCOG");
DynamicJavaGeneratorHelper.generateParams(stream, decl.getParams());
stream.println(" {");
stream.print("return (T)" + className + ".__ABS_createNewCOG");
DynamicJavaGeneratorHelper.generateParamArgs(stream, "null", decl.getParams());
stream.println(";");
stream.println("}");
// static constructor method for new cog C
stream.print("public static final <T extends " + ABSDynamicObject.class.getName() + "> T __ABS_createNewCOG");
DynamicJavaGeneratorHelper.generateParams(stream, ABSObject.class.getName() + " __ABS_source", decl.getParams());
stream.println(" {");
stream.println("final " + ABSDynamicRuntime.class.getName() + " __ABS_runtime = " + ABSDynamicRuntime.class.getName() + ".getCurrentRuntime();");
stream.println("final " + COG.class.getName() + " __ABS_cog = __ABS_runtime.createCOG(" + className + ".class);");
stream.println("final " + ABSThread.class.getName() + " __ABS_thread = " + ABSRuntime.class.getName() + ".getCurrentThread();");
stream.println("final " + COG.class.getName() + " __ABS_oldCOG = " + ABSRuntime.class.getName() + ".getCurrentCOG();");
stream.println("final " + Task.class.getName() + " __ABS_sendingTask = " + ABSRuntime.class.getName() + ".getCurrentTask();");
stream.println("__ABS_thread.setCOG(__ABS_cog);");
stream.println("try {");
generateObjectConstruction("__ABS_runtime");
stream.println(";");
stream.println("__ABS_runtime.cogCreated(__ABS_result);");
stream.println("__ABS_cog.getScheduler().addTask(new " + Task.class.getName() + "(new "
+ ABSInitObjectCall.class.getName() + "(__ABS_sendingTask,__ABS_source,__ABS_result)));");
if (decl.isActiveClass()) {
stream.println("__ABS_runtime.asyncCall(new " + ABSRunMethodCall.class.getName()
+ "(__ABS_sendingTask,__ABS_source,__ABS_result));");
}
stream.println("__ABS_runtime.registerObject((T)__ABS_result);");
stream.println("return (T)__ABS_result;");
stream.println("} finally {");
stream.println("__ABS_thread.setCOG(__ABS_oldCOG);");
stream.println("}");
stream.println("}");
}
private void generateObjectConstruction(String runtime) {
stream.print(ABSDynamicObject.class.getName() + " __ABS_result = ");
if (decl.isForeign()) {
stream.println("(" + className + ") " + runtime + ".getForeignObject(\"" + decl.getModuleDecl().getName() + "."
+ decl.getName() + "\");");
stream.print("if (__ABS_result == null) __ABS_result = ");
}
stream.print("new " + ABSDynamicObject.class.getName());
DynamicJavaGeneratorHelper.generateParamArgs(stream, className + ".singleton()", decl.getParams());
stream.println(";");
}
private void generateConstructor() {
// constructor
stream.println("public static class " + "CON$TRUCT" + " extends " + ABSClosure.class.getName() + " {");
stream.println("private static " + ABSClosure.class.getName() + " instance;");
stream.println("public static " + ABSClosure.class.getName() + " singleton() {");
stream.println("if (instance == null) { instance = new CON$TRUCT(); }");
stream.println("return instance;");
stream.println("}");
stream.println("public " + ABSValue.class.getName() + " exec(final " + ABSDynamicObject.class.getName() + " thisP, "
+ ABSValue.class.getName() + "... args) {");
// Fields and parameters are initialised in ABSDynamicObject::initializeFields(ABSValue[] params)
// so this whole CON$TRUCT is probably only needed for the InitBlock
// stream.println("// Initialise fields");
// stream.println("for (String f : thisP.getFieldNames()) {");
// stream.println("thisP.setFieldValue(f, thisP.getClazz().getField(f).init(thisP));");
// stream.println("}");
// initialise fields (old, static way)
// for (FieldDecl f : decl.getFields()) {
// if (f.hasInitExp()) {
// stream.print("thisP.setFieldValue(\"");
// stream.print(JavaBackend.getVariableName(f.getName()));
// stream.print("\", ");
// f.getInitExp().generateJavaDynamic(stream);
// stream.println(");");
// }
// }
if (decl.hasInitBlock()) {
decl.getInitBlock().generateJavaDynamic(stream);
}
stream.println("return null;");
stream.println("}");
stream.println("}");
}
}