package nebula.simpletemplate;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import nebula.lang.NebulaClassLoader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import util.NamesEncoding;
public class ActionComplier implements Opcodes {
private static final String SUPER_NAME = Action.class.getName().replace('.', '/');
Log log = LogFactory.getLog(getClass());
private Action noop;
static ActionComplier DEFAULT = new ActionComplier();
private ActionComplier() {
}
/*
* Returns the byte code of an Expression class corresponding to this
* expression.
*/
<T> byte[] doCompile(final String clzInternalName, final CompiledST template, CompilerContext context) {
// class header
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
MethodVisitor mv;
// Class define
cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, clzInternalName, null, "java/lang/Object", new String[] { SUPER_NAME });
// Init method
{
// default public constructor
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
// if (template.implicitlyDefinedTemplates != null) {
// List<TemplateImpl> list = template.implicitlyDefinedTemplates;
// for (int i = 0; i < list.size(); i++) {
// {
// String templateClzFieldName = "clz" + i;
// fv = cw.visitField(ACC_PRIVATE, templateClzFieldName,
// "Ljava/lang/Class;", "Ljava/lang/Class<*>;", null);
// fv.visitEnd();
// }
// {
// String templateActionFieldName = "temp" + i;
// fv = cw.visitField(ACC_PRIVATE, templateActionFieldName,
// Type.getDescriptor(Action.class), null, null);
// fv.visitEnd();
// }
// }
// }
{
mv = cw.visitMethod(ACC_PUBLIC, "exec",
"(" + Type.getDescriptor(STGroup.class) + "" + Type.getDescriptor(CompiledST.class) + "" + Type.getDescriptor(StringBuilder.class)
+ "[Ljava/lang/Object;)V", null, new String[] { "java/io/IOException" });
mv.visitCode();
template.code.compile(clzInternalName, cw, mv, context);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
static long count = 0;
public Action compileAndGetInstance(CompilerContext context, String actionName, final CompiledST template) {
try {
if (template.code instanceof Compiler.Block && ((Compiler.Block) template.code).statements.size() == 0) {
if (this.noop != null) {
return this.noop;
} else {
Class<Action> action = compile(context, actionName, template);
// instantiates this compiled expression class...
this.noop = (Action) action.newInstance();
return this.noop;
}
}
Class<Action> action = compile(context, actionName, template);
// instantiates this compiled expression class...
Action expr = (Action) action.newInstance();
return expr;
} catch (InstantiationException e) {
log.error(e);
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
log.error(e);
throw new RuntimeException(e);
}
}
public Class<Action> compile(CompilerContext context, String actionName, final CompiledST template) {
actionName = actionName.replace('.', '_');
String name = Action.class.getSimpleName() + "_" + NamesEncoding.encode(actionName, false) + "_" + String.valueOf(count++);
try {
byte[] b = this.doCompile(name, template, context);
if (log.isDebugEnabled()) {
try {
FileOutputStream fos = new FileOutputStream("tmp/" + name + ".class");
fos.write(b);
fos.close();
} catch (FileNotFoundException e) {
log.error(e);
throw new RuntimeException(e);
} catch (IOException e) {
log.error(e);
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
Class<Action> action = (Class<Action>) NebulaClassLoader.defineClass(name, b);
NebulaClassLoader.doResolveClass(action);
return action;
} catch (ClassFormatError e) {
throw new RuntimeException(e);
}
}
}