/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.bytecode.util;
import java.util.Date;
import org.objectweb.asm.*;
import org.whole.lang.builders.BuilderConstants;
import org.whole.lang.builders.IBuilder;
import org.whole.lang.builders.IBuilderOperation;
import org.whole.lang.contexts.IBuilderContext;
import org.whole.lang.contexts.IEntityContext;
import org.whole.lang.model.EnumValue;
import org.whole.lang.reflect.EntityDescriptor;
import org.whole.lang.reflect.FeatureDescriptor;
import org.whole.lang.reflect.ILanguageKit;
import org.whole.lang.templates.AbstractTemplateFactory;
import org.whole.lang.templates.ITemplate;
/**
* @author Riccardo Solmi
*/
public class BytecodeStoreProducerBuilder implements IBuilder, Opcodes {
// private List<ClassWriter> cwList = new ArrayList<ClassWriter>();
private ClassWriter cw;
private MethodVisitor mv;
private String builderInterfaceInternalName;
private int varNum = 2;
public byte[] getResult() {
return cw.toByteArray();
}
public static void visitIntInsn(MethodVisitor mv, int value) {
switch (value) {
case -1:
mv.visitInsn(ICONST_M1);
break;
case 0:
mv.visitInsn(ICONST_0);
break;
case 1:
mv.visitInsn(ICONST_1);
break;
case 2:
mv.visitInsn(ICONST_2);
break;
case 3:
mv.visitInsn(ICONST_3);
break;
case 4:
mv.visitInsn(ICONST_4);
break;
case 5:
mv.visitInsn(ICONST_5);
break;
default:
if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
mv.visitIntInsn(BIPUSH, value);
else
mv.visitIntInsn(SIPUSH, value);
}
}
public static String getInternalName(String type) {
return Type.getType(type).getInternalName();
}
public static String getMethodDescriptor(final Class<?> res, final Class<?> arg0) {
final StringBuffer buf = new StringBuffer();
buf.append('(');
buf.append(Type.getDescriptor(arg0));
buf.append(')');
buf.append(Type.getDescriptor(res));
return buf.toString();
}
public void buildStartCompilationUnit(String packageName, String className) {
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
String classInternalName = Type.getType(packageName.length()>0 ? packageName+'.'+className : className).getInternalName();
String superInternalName = Type.getInternalName(AbstractTemplateFactory.class);
cw.visit(V1_4, ACC_PUBLIC+ACC_SUPER,
classInternalName, null, superInternalName, null);
cw.visitSource(className+".java", null);
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, superInternalName, "<init>", "()V");
mv.visitInsn(RETURN);
mv.visitEnd();
mv = cw.visitMethod(ACC_PUBLIC, "apply", getMethodDescriptor(Void.TYPE, IBuilderOperation.class), null, null);
mv.visitCode();
}
public void buildEndCompilationUnit() {
mv.visitInsn(RETURN);
mv.visitEnd();
}
public void ensureBuilder(ILanguageKit languageKit) {
//TODO
}
protected void buildGetBuilder(ILanguageKit languageKit, String builderType) {
builderInterfaceInternalName = getInternalName(builderType);
mv.visitVarInsn(ALOAD, 1);
mv.visitLdcInsn(languageKit.getClass().getName());
mv.visitMethodInsn(INVOKEINTERFACE,
Type.getInternalName(IBuilderOperation.class),
"wGetBuilder",
getMethodDescriptor(IBuilder.class, String.class));
mv.visitTypeInsn(CHECKCAST, builderInterfaceInternalName);
mv.visitVarInsn(ASTORE, varNum);
}
public void wEntity_(EntityDescriptor<?> entityDesc) {
ensureBuilder(entityDesc.getLanguageKit());
mv.visitVarInsn(ALOAD, varNum);
mv.visitMethodInsn(INVOKEINTERFACE,
builderInterfaceInternalName,
BuilderConstants.startBuildName(entityDesc),
"()V");
}
public void wEntity_(EntityDescriptor<?> entityDesc, int initialCapacity) {
ensureBuilder(entityDesc.getLanguageKit());
mv.visitVarInsn(ALOAD, varNum);
visitIntInsn(mv, initialCapacity);
mv.visitMethodInsn(INVOKEINTERFACE,
builderInterfaceInternalName,
BuilderConstants.startBuildName(entityDesc),
"(I)V");
}
public void _wEntity(EntityDescriptor<?> entityDesc) {
ensureBuilder(entityDesc.getLanguageKit());
mv.visitVarInsn(ALOAD, varNum);
mv.visitMethodInsn(INVOKEINTERFACE,
builderInterfaceInternalName,
BuilderConstants.endBuildName(entityDesc),
"()V");
}
public void wEntity(EntityDescriptor<?> entityDesc) {
ensureBuilder(entityDesc.getLanguageKit());
mv.visitVarInsn(ALOAD, varNum);
mv.visitMethodInsn(INVOKEINTERFACE,
builderInterfaceInternalName,
BuilderConstants.buildName(entityDesc),
"()V");
}
public void wEntity(EntityDescriptor<?> entityDesc, boolean value) {
ensureBuilder(entityDesc.getLanguageKit());
mv.visitVarInsn(ALOAD, varNum);
mv.visitInsn(value ? ICONST_1 : ICONST_0);
mv.visitMethodInsn(INVOKEINTERFACE,
builderInterfaceInternalName,
BuilderConstants.buildName(entityDesc),
"(Z)V");
}
public void wEntity(EntityDescriptor<?> entityDesc, byte value) {
ensureBuilder(entityDesc.getLanguageKit());
wEntity(entityDesc, value);
}
public void wEntity(EntityDescriptor<?> entityDesc, char value) {
ensureBuilder(entityDesc.getLanguageKit());
}
public void wEntity(EntityDescriptor<?> entityDesc, double value) {
ensureBuilder(entityDesc.getLanguageKit());
}
public void wEntity(EntityDescriptor<?> entityDesc, float value) {
ensureBuilder(entityDesc.getLanguageKit());
}
public void wEntity(EntityDescriptor<?> entityDesc, int value) {
ensureBuilder(entityDesc.getLanguageKit());
mv.visitVarInsn(ALOAD, varNum);
visitIntInsn(mv, value);
mv.visitMethodInsn(INVOKEINTERFACE,
builderInterfaceInternalName,
BuilderConstants.buildName(entityDesc),
"(I)V");
}
public void wEntity(EntityDescriptor<?> entityDesc, long value) {
ensureBuilder(entityDesc.getLanguageKit());
}
public void wEntity(EntityDescriptor<?> entityDesc, short value) {
ensureBuilder(entityDesc.getLanguageKit());
}
public void wEntity(EntityDescriptor<?> entityDesc, String value) {
ensureBuilder(entityDesc.getLanguageKit());
mv.visitVarInsn(ALOAD, varNum);
mv.visitLdcInsn(value);
mv.visitMethodInsn(INVOKEINTERFACE,
builderInterfaceInternalName,
BuilderConstants.buildName(entityDesc),
"(Ljava/lang/String;)V");
}
public void wEntity(EntityDescriptor<?> entityDesc, Date value) {
ensureBuilder(entityDesc.getLanguageKit());
}
public void wEntity(EntityDescriptor<?> entityDesc, EnumValue value) {
ensureBuilder(entityDesc.getLanguageKit());
}
public void wEntity(EntityDescriptor<?> entityDesc, Object value) {
}
public void wSetBuilderContext(IBuilderContext context) {
}
public void wSetEntityContext(IEntityContext context) {
}
public void wDefault() {
// TODO
throw new UnsupportedOperationException();
}
public void wEntity() {
// TODO
throw new UnsupportedOperationException();
}
public void wEntity_() {
// TODO
throw new UnsupportedOperationException();
}
public void _wEntity() {
// TODO
throw new UnsupportedOperationException();
}
public void wFeature(int index) {
// TODO
throw new UnsupportedOperationException();
}
public void wFeature(FeatureDescriptor feature) {
// TODO
throw new UnsupportedOperationException();
}
public void wFeature(ITemplate template) {
// TODO
throw new UnsupportedOperationException();
}
}