diff --git a/README.md b/README.md
index c3fe852..914a57f 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
-# beejava
-Beejava is a code creation library, somewhat comparable to javassist or bytebuddy.
-* It let's you compile java 'opcode' to bytecode.
+# bejava
+Bejava (backend java compiler) is a code creation library, somewhat comparable to javassist or bytebuddy.
+* It let's you compile bejava-lang' to bytecode.
* It does not inspect or enhance existing bytecode, though it could be part of such functionality.
-What is 'opcode'?
+What is 'bejava lang'?
The goal of the project is to let developers dynamically create classes, using a simplified version of standard java opcodes. For instance:
instead of having to choose between:
diff --git a/pom.xml b/pom.xml
index d984146..6c3b898 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,21 +2,21 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- beejava
+ bejava
org.apache.maven.plugins
maven-compiler-plugin
+ 3.8.0
- 15
- 15
+ 15
nl.sander
- beejava
+ bejava
0.1-SNAPSHOT
jar
diff --git a/src/main/java/nl/sander/beejava/Compiler.java b/src/main/java/nl/sander/beejava/Compiler.java
index 59fb1c5..c34ad5f 100644
--- a/src/main/java/nl/sander/beejava/Compiler.java
+++ b/src/main/java/nl/sander/beejava/Compiler.java
@@ -1,14 +1,11 @@
package nl.sander.beejava;
-import nl.sander.beejava.api.BeeMethod;
-import nl.sander.beejava.api.BeeSource;
-import nl.sander.beejava.api.CodeContainer;
-import nl.sander.beejava.api.CodeLine;
+import nl.sander.beejava.api.*;
+import nl.sander.beejava.classinfo.FieldInfo;
import nl.sander.beejava.classinfo.MethodInfo;
import nl.sander.beejava.constantpool.ConstantPool;
-import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
+import nl.sander.beejava.constantpool.entry.ClassEntry;
import nl.sander.beejava.constantpool.entry.FieldRefEntry;
-import nl.sander.beejava.constantpool.entry.MethodRefEntry;
import nl.sander.beejava.constantpool.entry.Utf8Entry;
/**
@@ -22,7 +19,6 @@ import nl.sander.beejava.constantpool.entry.Utf8Entry;
*/
public class Compiler {
private final CompiledClass compiledClass;
- private final ConstantPoolEntryCreator constantPoolEntryCreator;
private final ConstantPoolCreator constantPoolCreator = new ConstantPoolCreator();
private Utf8Entry codeAttributeNameEntry;
@@ -34,7 +30,6 @@ public class Compiler {
*/
public Compiler(CompiledClass compiledClass) {
this.compiledClass = compiledClass;
- this.constantPoolEntryCreator = new ConstantPoolEntryCreator(compiledClass);
}
/**
@@ -51,26 +46,57 @@ public class Compiler {
* construct a CompiledClass object that contains all information for generating the bytecode
*/
public CompiledClass compile() {
- compiledClass.setConstantPool(createConstantPool());
+ compiledClass.getSource().getFields().forEach(this::addToConstantPool);
+ compiledClass.getSource().getConstructors().forEach(this::addToConstantPool);
+ compiledClass.getSource().getMethods().forEach(this::addToConstantPool); // compiledClass.getSource() ?
+
+ addClassAndSuperClassEntriesToCompiledClass();
+
+ ConstantPool constantPool = constantPoolCreator.createConstantPool(compiledClass.getConstantTree());
+
+ compiledClass.setConstantPool(constantPool);
+
+ // add refs to super interfaces to class descriptor and constantpool
+ compiledClass.getSource().getInterfaces().forEach(interfase -> {
+ ClassEntry interfaceEntry = ConstantPoolEntryCreator.getOrCreateClassEntry(interfase);
+ compiledClass.addInterface(interfaceEntry);
+ compiledClass.addConstantPoolEntry(interfaceEntry);
+ });
+
+ // add refs to fields to class descriptor
+ compiledClass.getSource().getFields().stream()
+ .map(field ->
+ new FieldInfo(ConstantPoolEntryCreator.getOrCreateUtf8(field.getName()),
+ ConstantPoolEntryCreator.getOrCreateUtf8(internalName(field.getType().getName())))
+ .addAccessFlags(field.getAccessFlags())
+ )
+ .forEach(compiledClass::addField);
- constantPoolEntryCreator.addInterfaces();
- constantPoolEntryCreator.addFields();
addConstructors();
addMethods();
return compiledClass;
}
- private ConstantPool createConstantPool() {
- compiledClass.getSource().getConstructors().forEach(this::updateConstantPool);
- compiledClass.getSource().getMethods().forEach(this::updateConstantPool); // compiledClass.getSource() ?
+ // why not put this everywhere, it's not like it's ever going to change
+ private String internalName(String name) {
+ return name.replaceAll("\\.", "/");
+ }
- compiledClass.setThisClass(constantPoolEntryCreator.addThisClass());
- this.codeAttributeNameEntry = constantPoolEntryCreator.getOrCreateUtf8("Code");
+
+ private void addClassAndSuperClassEntriesToCompiledClass() {
+ ClassEntry classEntry = ConstantPoolEntryCreator.getOrCreateClassEntry(compiledClass.getSource().getName());
+ compiledClass.setThisClass(classEntry);
+ compiledClass.addConstantPoolEntry(classEntry);
+
+ ClassEntry superClass = ConstantPoolEntryCreator.getOrCreateClassEntry(compiledClass.getSource().getSuperClass());
+ compiledClass.addConstantPoolEntry(superClass);
+ compiledClass.setSuperClass(superClass);
+
+
+ this.codeAttributeNameEntry = ConstantPoolEntryCreator.getOrCreateUtf8("Code");
compiledClass.addConstantPoolEntry(codeAttributeNameEntry);
-
- return constantPoolCreator.createConstantPool(compiledClass.getConstantTree());
}
public void addConstructors() {
@@ -79,8 +105,7 @@ public class Compiler {
.forEach(compiledClass::addMethod);
}
-
- /*
+ /**
* maps methods from the source to a MethodInfo and adds that to the CompiledClass.
*/
public void addMethods() {
@@ -88,34 +113,34 @@ public class Compiler {
for (BeeMethod method : compiledClass.getSource().getMethods()) {
compiledClass.addMethod(createMethod(method));
}
-
-// compiledClass.getSource().getMethods().stream()
-// .map(this::createMethod)
-// .forEach(compiledClass::addMethod);
}
- /*
- * create bytecode for method
+ /**
* create methodInfo object for classfile
*/
private MethodInfo createMethod(CodeContainer method) {
return new MethodInfo(
- constantPoolEntryCreator.getOrCreateUtf8(method.getName()),
- constantPoolEntryCreator.getOrCreateUtf8(method.getSignature()))
+ ConstantPoolEntryCreator.getOrCreateUtf8(method.getName()),
+ ConstantPoolEntryCreator.getOrCreateUtf8(method.getSignature()))
.addAccessFlags(method.getAccessFlags())
- .addAttribute(MethodCodeCreator.createCodeAttribute(codeAttributeNameEntry, method));
+ .addAttribute(MethodCodeAttributeCreator.createCodeAttribute(codeAttributeNameEntry, method));
}
- /*
+ private void addToConstantPool(BeeField field) {
+ FieldRefEntry fieldRefEntry = ConstantPoolEntryCreator.getOrCreateFieldRefEntry(compiledClass.getSource().getName(), field.getName(), field.getType());
+ compiledClass.addConstantPoolEntry(fieldRefEntry);
+ }
+
+ /**
* inspect a method or constructor, extract items that need to be added, and add them to the constant pool
*/
- private void updateConstantPool(CodeContainer codeContainer) {
- compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateUtf8(codeContainer.getName()));
- compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateUtf8(codeContainer.getSignature()));
- codeContainer.getCode().forEach(this::updateConstantPool);
+ private void addToConstantPool(CodeContainer codeContainer) {
+ compiledClass.addConstantPoolEntry(ConstantPoolEntryCreator.getOrCreateUtf8(codeContainer.getName()));
+ compiledClass.addConstantPoolEntry(ConstantPoolEntryCreator.getOrCreateUtf8(codeContainer.getSignature()));
+ codeContainer.getExpandedCode().forEach(this::updateConstantPool);
}
- /*
+ /**
* Scan code line for items that need adding to the constant pool
*
* Constantpool uniqueness is maintained in two ways:
@@ -124,23 +149,17 @@ public class Compiler {
* 2. the root node (also in aforementioned cache) is not symmetric because it is the only one that can be added to The compiledClass.
* So Compiled class also contains a set of unique root nodes.
*/
- private void updateConstantPool(CodeLine codeline) {
- if (codeline.hasMethodCall()) {
- MethodRefEntry methodRefEntry = constantPoolEntryCreator.getOrCreateMethodRefEntry(codeline);
- codeline.setAssignedEntry(methodRefEntry);
- compiledClass.addConstantPoolEntry(methodRefEntry);
+ private void updateConstantPool(JavaInstruction instruction) {
+ if (instruction.hasMethodRef()) {
+ compiledClass.addConstantPoolEntry(instruction.getMethodRef());
}
- if (codeline.hasRefToOwnField() || codeline.hasRefToExternalField()) {
- FieldRefEntry fieldRefEntry = constantPoolEntryCreator.getOrCreateFieldRefEntry(codeline);
- codeline.setAssignedEntry(fieldRefEntry);
- compiledClass.addConstantPoolEntry(fieldRefEntry);
+ if (instruction.hasFieldRef()) {
+ compiledClass.addConstantPoolEntry(instruction.getFieldRef());
}
- if (codeline.hasConstValue()) {
- ConstantPoolEntry primitiveEntry = constantPoolEntryCreator.getOrCreatePrimitiveEntry(codeline);
- codeline.setAssignedEntry(primitiveEntry);
- compiledClass.addConstantPoolEntry(primitiveEntry);
+ if (instruction.hasConstantRef()) {
+ compiledClass.addConstantPoolEntry(instruction.getConstantEntry());
}
}
}
diff --git a/src/main/java/nl/sander/beejava/ConstantPoolEntryCreator.java b/src/main/java/nl/sander/beejava/ConstantPoolEntryCreator.java
index 53e746d..2edafd7 100644
--- a/src/main/java/nl/sander/beejava/ConstantPoolEntryCreator.java
+++ b/src/main/java/nl/sander/beejava/ConstantPoolEntryCreator.java
@@ -1,10 +1,7 @@
package nl.sander.beejava;
-import nl.sander.beejava.api.CodeLine;
-import nl.sander.beejava.api.Ref;
-import nl.sander.beejava.classinfo.FieldInfo;
-import nl.sander.beejava.classinfo.attributes.CodeAttribute;
import nl.sander.beejava.constantpool.entry.*;
+import nl.sander.beejava.operands.ConstantOperand;
import java.util.HashMap;
import java.util.Map;
@@ -14,147 +11,84 @@ import java.util.Map;
* Responsible for creating unique constant pool entries
*/
class ConstantPoolEntryCreator {
- private final Map cache = new HashMap<>();
- private final CompiledClass compiledClass;
- public ConstantPoolEntryCreator(CompiledClass compiledClass) {
- this.compiledClass = compiledClass;
+ private static final Map cache = new HashMap<>();
+
+ private ConstantPoolEntryCreator() {
}
/*
* creates a FieldRefEntry when not found in cache, otherwise gets it from there
*/
- FieldRefEntry getOrCreateFieldRefEntry(CodeLine codeLine) {
- return cache(new FieldRefEntry(getOrCreateClassEntry(codeLine), getOrCreateFieldNameAndType(codeLine)));
+ static FieldRefEntry getOrCreateFieldRefEntry(String declaringClassName, String fieldName, Class> fieldType) {
+ return cache(new FieldRefEntry(getOrCreateClassEntry(declaringClassName), getOrCreateFieldNameAndType(fieldName, fieldType)));
}
/*
* creates a MethodRefEntry when not found in cache, otherwise gets it from there
*/
- MethodRefEntry getOrCreateMethodRefEntry(CodeLine codeline) {
- ClassEntry classEntry = getOrCreateClassEntry(codeline);
- return cache(new MethodRefEntry(classEntry, getOrCreateMethodNameAndType(codeline)));
+ static MethodRefEntry getOrCreateMethodRefEntry(String className, String methodName, String signature) {
+ ClassEntry classEntry = getOrCreateClassEntry(className);
+ return cache(new MethodRefEntry(classEntry, getOrCreateMethodNameAndType(methodName, signature)));
}
/*
* creates a NamAndTypeEntry for a field when not found in cache, otherwise gets it from there
*/
- private NameAndTypeEntry getOrCreateFieldNameAndType(CodeLine codeline) {
- if (codeline.hasRefToOwnField()) {
- return cache(new NameAndTypeEntry(
- cache(new Utf8Entry(codeline.getOwnfield().getName())),
- cache(new Utf8Entry(TypeMapper.map(codeline.getOwnfield().getType()))))); // is actually a shortcut
- } else {//TODO this method may need some work
- return cache(new NameAndTypeEntry(
- cache(new Utf8Entry(codeline.getExternalfield().getName())),
- cache(new Utf8Entry(TypeMapper.map(codeline.getExternalfield().getType())))
- ));
- }
+ private static NameAndTypeEntry getOrCreateFieldNameAndType(String name, Class> type) {
+ return cache(new NameAndTypeEntry(
+ cache(new Utf8Entry(name)),
+ cache(new Utf8Entry(TypeMapper.map(type)))));
}
/*
* creates a NamAndTypeEntry for a method when not found in cache, otherwise gets it from there
*/
- private NameAndTypeEntry getOrCreateMethodNameAndType(CodeLine codeline) {
+ private static NameAndTypeEntry getOrCreateMethodNameAndType(String methodName, String methodSignature) {
return new NameAndTypeEntry(
- cache(new Utf8Entry(codeline.getMethodName())),
- cache(new Utf8Entry(codeline.getMethodSignature())));
- }
-
- /*
- * creates a ClassEntry when not found in cache, otherwise gets it from there
- */
- private ClassEntry getOrCreateClassEntry(CodeLine codeline) {
- if (codeline.hasRef()) {
- if (codeline.getRef() == Ref.SUPER) { // this and super are rather special
- ClassEntry superClass = getClassEntry(compiledClass.getSource().getSuperClass().getName());
- compiledClass.setSuperClass(superClass);
- return superClass;
-
- } else if (codeline.getRef() == Ref.THIS) {
- return addThisClass();
- }
- } else if (codeline.hasClassName()) {
- return getClassEntry(codeline.getClassName());
- }
-
- throw new RuntimeException("shouldn't be here");
- }
-
- /*
- * this method gives me a headache. It adds, but also creates a classEntry for the this class
- */
- ClassEntry addThisClass() {
- ClassEntry classEntry = getClassEntry(compiledClass.getSource().getName());
- compiledClass.addConstantPoolEntry(classEntry);
- return classEntry;
+ cache(new Utf8Entry(methodName)),
+ cache(new Utf8Entry(methodSignature)));
}
/*
* get or create a ClassEntry
*/
- private ClassEntry getClassEntry(String externalClassName) {
+ public static ClassEntry getOrCreateClassEntry(String externalClassName) {
return cache(new ClassEntry(cache(new Utf8Entry(internalName(externalClassName)))));
}
- /*
- * Adds interfaces to the constant pool as well as the class.
- *
- * interfaces[] in the class file is an array of cp entries
- */
- public void addInterfaces() {
- compiledClass.getSource().getInterfaces().forEach(interfase -> {
- ClassEntry interfaceEntry = cache(new ClassEntry(cache(new Utf8Entry(internalName(interfase.getName())))));
- compiledClass.addInterface(interfaceEntry);
- compiledClass.addConstantPoolEntry(interfaceEntry);
- });
+ public static ClassEntry getOrCreateClassEntry(Class> type) {
+ return getOrCreateClassEntry(type.getName());
}
/*
* If a constant is in the codeline, it needs to be added to the constant pool.
*/
- public ConstantPoolEntry getOrCreatePrimitiveEntry(CodeLine codeline) {
- Object v = codeline.getConstValue();
-
- if (v instanceof String) {
- return cache(new StringEntry(cache(new Utf8Entry((String) v))));
- } else if (v instanceof Integer) {
- return cache(new IntegerEntry((Integer) v));
- } else if (v instanceof Long) {
- return cache(new LongEntry((Long) v));
- } else if (v instanceof Float) {
- return cache(new FloatEntry((Float) v));
- } else if (v instanceof Double) {
- return cache(new DoubleEntry((Double) v));
- }
- throw new IllegalStateException("shouldn't be here"); // TODO find out why are you here
+ public static ConstantPoolEntry getOrCreatePrimitiveConstantEntry(ConstantOperand operand) {
+ return cache(switch (operand.getType()) {
+ case STRING -> new StringEntry(cache(new Utf8Entry(operand.getValue())));
+ case INT, BYTE, SHORT -> new IntegerEntry(operand.getValue());
+ case LONG -> new LongEntry(Long.parseLong(operand.getValue()));
+ case FLOAT -> new FloatEntry(operand.getValue());
+ case DOUBLE -> new DoubleEntry(Double.parseDouble(operand.getValue()));
+ case CHAR -> new IntegerEntry(Character.codePointAt(operand.getValue(), 0));
+ case BOOLEAN -> new IntegerEntry(Boolean.parseBoolean(operand.getValue()) ? 1 : 0);
+ });
}
- /*
- * maps a field from the source to a FieldInfo and adds that to the CompiledClass.
- */
- public void addFields() {
- compiledClass.getSource().getFields().stream()
- .map(field -> new FieldInfo(
- cache(new Utf8Entry(field.getName())),
- cache(new Utf8Entry(internalName(field.getType().getName())))
- ).addAccessFlags(field.getAccessFlags())
- )
- .forEach(compiledClass::addField);
- }
-
- public Utf8Entry getOrCreateUtf8(String utf8) {
+ public static Utf8Entry getOrCreateUtf8(String utf8) {
return cache(new Utf8Entry(utf8));
}
// why not put this everywhere, it's not like it's ever going to change
- private String internalName(String name) {
+ private static String internalName(String name) {
return name.replaceAll("\\.", "/");
}
@SuppressWarnings("unchecked")
- T cache(T newEntry) {
- // First create an object using the supplier, but if it's found in cache, return the cached entry and discard the first.
+ static T cache(T newEntry) {
+ // if the argument newEntry is found in cache, return the cached entry and discard the argument
+ // Otherwise store it.
// Can't check for equality unless you create a potential new entry first
int hash = newEntry.hashCode();
return (T) cache.computeIfAbsent(hash, k -> newEntry);
diff --git a/src/main/java/nl/sander/beejava/FieldWrapper.java b/src/main/java/nl/sander/beejava/FieldWrapper.java
new file mode 100644
index 0000000..d79ce43
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/FieldWrapper.java
@@ -0,0 +1,51 @@
+package nl.sander.beejava;
+
+import nl.sander.beejava.api.BeeField;
+import nl.sander.beejava.flags.AccessFlags;
+
+import java.lang.reflect.Field;
+
+/**
+ * Union type for an existing standard java field (already loaded) or a field for the class that is being compiled
+ */
+public class FieldWrapper {
+ private final Field reflectField;
+ private final BeeField beefield;
+
+ public FieldWrapper(Field reflectField, BeeField beefield) {
+ this.reflectField = reflectField;
+ this.beefield = beefield;
+ }
+
+ public Class> getType() {
+ if (reflectField != null) {
+ return reflectField.getType();
+ } else {
+ return beefield.getType();
+ }
+ }
+
+ public String getName() {
+ if (reflectField != null) {
+ return reflectField.getName();
+ } else {
+ return beefield.getName();
+ }
+ }
+
+ public int getModifiers() {
+ if (reflectField != null) {
+ return reflectField.getModifiers();
+ } else {
+ return AccessFlags.combine(beefield.getAccessFlags());
+ }
+ }
+
+ public String getOwner() {
+ if (reflectField != null) {
+ return reflectField.getDeclaringClass().getName();
+ } else {
+ return beefield.getDeclaringClass();
+ }
+ }
+}
diff --git a/src/main/java/nl/sander/beejava/JavaInstruction.java b/src/main/java/nl/sander/beejava/JavaInstruction.java
new file mode 100644
index 0000000..f7ac201
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/JavaInstruction.java
@@ -0,0 +1,81 @@
+package nl.sander.beejava;
+
+import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
+import nl.sander.beejava.constantpool.entry.FieldRefEntry;
+import nl.sander.beejava.constantpool.entry.MethodRefEntry;
+
+public class JavaInstruction {
+ private final JavaOpcode opcode;
+ private final MethodRefEntry methodRefEntry;
+ private final FieldRefEntry fieldRefEntry;
+ private final ConstantPoolEntry constantEntry;
+ private Integer localVariableIndex;
+
+ public JavaInstruction(JavaOpcode opcode) {
+ this(opcode, null, null, null, null);
+ }
+
+ public JavaInstruction(JavaOpcode opcode, int localVariableIndex) {
+ this(opcode, localVariableIndex, null, null, null);
+ }
+
+ public JavaInstruction(JavaOpcode opcode, ConstantPoolEntry constantEntry) {
+ this(opcode, null, null, null, constantEntry);
+ }
+
+ public JavaInstruction(JavaOpcode opcode, MethodRefEntry methodRefEntry) {
+ this(opcode, null, methodRefEntry, null, null);
+ }
+
+ public JavaInstruction(JavaOpcode opcode, FieldRefEntry fieldRefEntry) {
+ this(opcode, null, null, fieldRefEntry, null);
+ }
+
+ private JavaInstruction(JavaOpcode opcode, Integer localVariableIndex, MethodRefEntry methodRefEntry, FieldRefEntry fieldRefEntry, ConstantPoolEntry constantEntry) {
+ this.opcode = opcode;
+ this.localVariableIndex = localVariableIndex;
+ this.methodRefEntry = methodRefEntry;
+ this.fieldRefEntry = fieldRefEntry;
+ this.constantEntry = constantEntry;
+ }
+
+ public JavaOpcode getOpcode() {
+ return opcode;
+ }
+
+ public MethodRefEntry getMethodRef() {
+ return methodRefEntry;
+ }
+
+ public FieldRefEntry getFieldRef() {
+ return fieldRefEntry;
+ }
+
+ public boolean hasMethodRef() {
+ return methodRefEntry != null;
+ }
+
+ public boolean hasFieldRef() {
+ return fieldRefEntry != null;
+ }
+
+ public ConstantPoolEntry getEntry() {
+ if (methodRefEntry != null) {
+ return methodRefEntry;
+ } else if (fieldRefEntry != null) {
+ return fieldRefEntry;
+ } else if (constantEntry!=null){
+ return constantEntry;
+ } else {
+ return null; // Not sure yet what to do here.
+ }
+ }
+
+ public boolean hasConstantRef() {
+ return constantEntry !=null;
+ }
+
+ public ConstantPoolEntry getConstantEntry() {
+ return constantEntry;
+ }
+}
diff --git a/src/main/java/nl/sander/beejava/JavaOpcode.java b/src/main/java/nl/sander/beejava/JavaOpcode.java
index dc8bdf1..4519907 100644
--- a/src/main/java/nl/sander/beejava/JavaOpcode.java
+++ b/src/main/java/nl/sander/beejava/JavaOpcode.java
@@ -5,8 +5,20 @@ public enum JavaOpcode {
LDC_W(0x13,true, +1),
LDC2_W ( 0x14, true, +2),
+ ALOAD ( 0x19, false, +1),
ALOAD_0 ( 0x2a, false, +1),
+ ALOAD_1 ( 0x2b, false, +1),
+ ALOAD_2 ( 0x2c, false, +1),
+ ALOAD_3 ( 0x2d, false, +1),
+
+ IRETURN ( 0xac,false, -1),
+ LRETURN(0xad, false, -2),
+ FRETURN(0xae,false,-1),
+ DRETURN(0xaf,false,-2),
+ ARETURN ( 0xb0,false, -1),
+
RETURN ( 0xb1,false, 0),
+
GETSTATIC ( 0xb2,true, +1),
GETFIELD ( 0xb4,true, +1),
diff --git a/src/main/java/nl/sander/beejava/MethodCodeCreator.java b/src/main/java/nl/sander/beejava/MethodCodeAttributeCreator.java
similarity index 76%
rename from src/main/java/nl/sander/beejava/MethodCodeCreator.java
rename to src/main/java/nl/sander/beejava/MethodCodeAttributeCreator.java
index 5a63edf..91714a2 100644
--- a/src/main/java/nl/sander/beejava/MethodCodeCreator.java
+++ b/src/main/java/nl/sander/beejava/MethodCodeAttributeCreator.java
@@ -8,7 +8,7 @@ import nl.sander.beejava.constantpool.entry.MethodRefEntry;
import nl.sander.beejava.constantpool.entry.Utf8Entry;
import nl.sander.beejava.util.ByteBuf;
-public class MethodCodeCreator {
+public class MethodCodeAttributeCreator {
public static CodeAttribute createCodeAttribute(Utf8Entry codeAttributeNameEntry, CodeContainer codeContainer) {
CodeAttribute codeAttribute = new CodeAttribute(codeAttributeNameEntry);
@@ -16,10 +16,10 @@ public class MethodCodeCreator {
codeAttribute.setMaxLocals(codeContainer.getFormalParameters().size() + 1);
ByteBuf byteBuf = new ByteBuf();
- codeContainer.getCode().forEach(codeLine -> {
- JavaOpcode javaOpcode = codeLine.getJavaOpcode(); // the opcode we determined in calculateMaxStack
+ codeContainer.getExpandedCode().forEach(instruction -> {
+ JavaOpcode javaOpcode = instruction.getOpcode();
byteBuf.addU8(javaOpcode.getByteCode());
- ConstantPoolEntry constantPoolEntry = codeLine.getAssignedEntry();
+ ConstantPoolEntry constantPoolEntry = instruction.getEntry();
if (constantPoolEntry != null) {
if (javaOpcode.isWide()) {
byteBuf.addU16(constantPoolEntry.getIndex());
@@ -37,11 +37,9 @@ public class MethodCodeCreator {
private static int calculateMaxStack(CodeContainer codeContainer) {
int stackSize = 0;
int maxStackSize = 0;
- for (CodeLine codeLine : codeContainer.getCode()) {
- JavaOpcode javaOpcode = OpcodeMapper.mapOpcode(codeLine);
- codeLine.setJavaOpcode(javaOpcode); //not really nice that we mutate codeLine, but this way we don't have to calculate the JavaOpcode twice
- stackSize += javaOpcode.getStackDif();
- ConstantPoolEntry assignedEntry = codeLine.getAssignedEntry();
+ for (JavaInstruction instruction : codeContainer.getExpandedCode()) {
+ stackSize += instruction.getOpcode().getStackDif();
+ ConstantPoolEntry assignedEntry = instruction.getEntry();
if (assignedEntry instanceof MethodRefEntry) {
MethodRefEntry methodRefEntry = (MethodRefEntry) assignedEntry;
String argumentTypes = methodRefEntry.getNameAndType().getType();
diff --git a/src/main/java/nl/sander/beejava/OpcodeMapper.java b/src/main/java/nl/sander/beejava/OpcodeMapper.java
deleted file mode 100644
index 6ca6cb7..0000000
--- a/src/main/java/nl/sander/beejava/OpcodeMapper.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package nl.sander.beejava;
-
-import nl.sander.beejava.api.BeeSource;
-import nl.sander.beejava.api.CodeLine;
-import nl.sander.beejava.api.Opcode;
-import nl.sander.beejava.flags.ClassAccessFlags;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-
-import static nl.sander.beejava.JavaOpcode.*;
-
-public class OpcodeMapper {
-
- public static JavaOpcode mapOpcode(CodeLine codeLine) {
- Opcode opcode = codeLine.getOpcode();
- return switch (opcode) {
- case GET -> isStatic(codeLine.getExternalfield()) ? GETSTATIC : GETFIELD;
- case LD_VAR -> ALOAD_0;
- case LD_CONST -> loadConst(codeLine);
- case INVOKE -> invoke(codeLine);
- case RETURN -> JavaOpcode.RETURN; //TODO not complete yet
- case PUT -> JavaOpcode.PUTFIELD;
- default -> throw new IllegalStateException("something not implemented");
- };
- }
-
- /* TODO cover more cases */
- private static JavaOpcode invoke(CodeLine codeLine) {
- BeeSource source = codeLine.getOwner().getOwner();
- if (source.getAccessFlags().contains(ClassAccessFlags.SUPER) && codeLine.getOwner().isConstructor()) {
- return INVOKESPECIAL;
- } else {
- return INVOKEVIRTUAL;
- }
- }
-
- private static JavaOpcode loadConst(CodeLine codeLine) {
- Object constValue = codeLine.getConstValue();
- int index = codeLine.getAssignedEntry().getIndex();
- if (constValue instanceof Double || constValue instanceof Long) {
- return LDC2_W;
- } else {
- if (index > 0xff) {
- return LDC_W;
- } else {
- return LDC;
- }
- }
- }
-
- private static boolean isStatic(Field field) {
- return (field.getModifiers() & Modifier.STATIC) == Modifier.STATIC;
- }
-}
diff --git a/src/main/java/nl/sander/beejava/OpcodeTranslator.java b/src/main/java/nl/sander/beejava/OpcodeTranslator.java
new file mode 100644
index 0000000..c565622
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/OpcodeTranslator.java
@@ -0,0 +1,214 @@
+package nl.sander.beejava;
+
+import nl.sander.beejava.api.*;
+import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
+import nl.sander.beejava.operands.*;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.stream.Collectors;
+
+enum Primitives {
+ INT, SHORT, BYTE, LONG, FLOAT, DOUBLE, CHAR, BOOLEAN;
+
+ public static Primitives from(String value) {
+ return Arrays.stream(values()).filter(e -> e.toString().equals(value)).findFirst().orElse(null);
+ }
+}
+
+/**
+ * Translates from BeeJava opcodes to actual java opcodes.
+ */
+public class OpcodeTranslator {
+ private final static OpcodeTranslator instance = new OpcodeTranslator();
+ private final Parser parser = new Parser();
+ private BeeSource beeSource;
+
+ /*
+ * trying to make SourceExpander reusable.
+ * @not_multithreaded.
+ * //TODO should not mutate beesource
+ */
+ public static void translate(BeeSource beeSource) {
+ instance.init(beeSource);
+ instance.doExpand();
+ }
+
+ private void init(BeeSource beeSource) {
+ this.beeSource = beeSource;
+ }
+
+ private void doExpand() {
+ beeSource.getConstructors().forEach(this::translate);
+ beeSource.getMethods().forEach(this::translate);
+ }
+
+ private void translate(CodeContainer codeContainer) {
+ var methodInstructions = codeContainer.getCode().stream()
+ .flatMap(o -> translate(codeContainer, o).stream())
+ .collect(Collectors.toList());
+ codeContainer.setExpandedCode(methodInstructions);
+ }
+
+ private List translate(CodeContainer codeContainer, CodeLine codeLine) {
+ var operand = parser.parse(codeLine);
+ return eval(codeContainer, codeLine.getOpcode(), operand);
+ }
+
+ private List eval(CodeContainer codeContainer, Opcode opcode, Operand operand) {
+ final List instructions = new ArrayList<>();
+ if (operand instanceof MethodOperand) {
+ var mo = (MethodOperand) operand;
+ if ("this".equals(mo.className)) {
+ instructions.add(new JavaInstruction(JavaOpcode.ALOAD_0));
+ }
+ }
+ if (opcode == Opcode.LOAD) {
+ if (operand instanceof ConstantOperand) {
+ ConstantPoolEntry constantEntry = ConstantPoolEntryCreator.getOrCreatePrimitiveConstantEntry((ConstantOperand) operand);
+ instructions.add(new JavaInstruction(JavaOpcode.LDC, constantEntry));
+ }
+ } else if (opcode == Opcode.RETURN && operand instanceof VoidOperand) {
+ instructions.add(new JavaInstruction(JavaOpcode.RETURN));
+ } else if (opcode == Opcode.GET) {
+ assert operand instanceof FieldOperand;
+
+ var fieldOperand = (FieldOperand) operand;
+ FieldWrapper field = getField(codeContainer, fieldOperand);
+ instructions.add(new JavaInstruction(getJavaOpcodeForGet(field),
+ ConstantPoolEntryCreator.getOrCreateFieldRefEntry(getType(codeContainer, fieldOperand), field.getName(), field.getType())));
+ } else if (opcode == Opcode.INVOKE) {
+ assert operand instanceof MethodOperand;
+ var mo = (MethodOperand) operand;
+ if ("super".equals(mo.methodName)) {
+ instructions.add(new JavaInstruction(JavaOpcode.INVOKESPECIAL,
+ ConstantPoolEntryCreator.getOrCreateMethodRefEntry(beeSource.getSuperClass().getName(), "", "()V")));
+ } else {
+ instructions.add(new JavaInstruction(JavaOpcode.INVOKEVIRTUAL, ConstantPoolEntryCreator.getOrCreateMethodRefEntry(mo.className, mo.methodName, mo.signature)));
+ }
+ System.out.println(operand);
+ } else if (operand instanceof FieldOperand) {
+ var fieldOperand = (FieldOperand) operand;
+ if (fieldOperand.className.equals("this")) {
+ instructions.add(new JavaInstruction(JavaOpcode.ALOAD_0));
+ }
+
+ if (opcode == Opcode.RETURN) {
+ instructions.add(getReturnInstruction(codeContainer, fieldOperand));
+ }
+ } else if (operand instanceof LocalVariableOperand) {
+ var localVariable = (LocalVariableOperand) operand;
+ instructions.add(codeContainer.getParameter(localVariable.name).map(this::getJavaLoadInstruction).orElse(null)); //else case
+ }
+
+ // TODO continue here. finish simpleBean
+ return instructions;
+ }
+
+ private JavaOpcode getJavaOpcodeForGet(FieldWrapper field) {
+ JavaOpcode get;
+ if (Modifier.isStatic(field.getModifiers())) {
+ get = JavaOpcode.GETSTATIC;
+ } else {
+ get = JavaOpcode.GETFIELD;
+ }
+ return get;
+ }
+
+ private JavaInstruction getReturnInstruction(CodeContainer codeContainer, FieldOperand fo) {
+ FieldWrapper field = getField(codeContainer, fo);
+
+ JavaOpcode javaOpcode = switch (field.getName()) {
+ case "int", "byte", "boolean", "short" -> JavaOpcode.IRETURN;
+ case "long" -> JavaOpcode.LRETURN;
+ case "float" -> JavaOpcode.FRETURN;
+ case "double" -> JavaOpcode.DRETURN;
+ default -> JavaOpcode.ARETURN;
+ };
+ return new JavaInstruction(javaOpcode);
+
+ }
+
+ private String getType(CodeContainer codeContainer, FieldOperand fo) {
+ if (fo.className.equals("this")) {
+ return codeContainer.getName();
+ } else {
+ return fo.className;
+ }
+ }
+
+
+ private FieldWrapper getField(CodeContainer codeContainer, FieldOperand fo) {
+ try {
+ Field javaField = null;
+ BeeField beeField = null;
+ if (fo.className.equals("this")) {
+ beeField = codeContainer.getOwner().getField(fo.fieldName);
+ } else {
+ Class> type = Class.forName(fo.className);
+ javaField = type.getDeclaredField(fo.fieldName);
+ }
+ return new FieldWrapper(javaField, beeField);
+ } catch (ClassNotFoundException | NoSuchFieldException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private JavaInstruction getJavaLoadInstruction(BeeParameter parameter) {
+ return switch (parameter.getIndex()) {
+ case 0 -> new JavaInstruction(JavaOpcode.ALOAD_0);
+ case 1 -> new JavaInstruction(JavaOpcode.ALOAD_1);
+ case 2 -> new JavaInstruction(JavaOpcode.ALOAD_2);
+ case 3 -> new JavaInstruction(JavaOpcode.ALOAD_3);
+ default -> new JavaInstruction(JavaOpcode.ALOAD, parameter.getIndex());
+ };
+ }
+}
+
+class Parser {
+
+ Operand parse(CodeLine codeLine) {
+ var operand = codeLine.getOperand();
+ if (operand == null) {
+ return VoidOperand.INSTANCE;
+ } else {
+ if (operand.contains("(")) {
+ var parenIndex = operand.indexOf('(');
+ var signature = operand.substring(parenIndex);
+ var classAndMethodeName = operand.substring(0, parenIndex);
+ int lastDotIndex = classAndMethodeName.lastIndexOf('.');
+ var className = classAndMethodeName.substring(0, lastDotIndex);
+ var methodName = classAndMethodeName.substring(lastDotIndex + 1);
+ return new MethodOperand(className, methodName, signature);
+ } else {
+ int index = operand.lastIndexOf('.');
+ if (index < 0) {
+ var constantOperandOrNull = asConstantOperand(operand);
+ return Objects.requireNonNullElseGet(constantOperandOrNull, () -> new LocalVariableOperand(operand));
+ } else if (index < operand.length() - 1) {
+ var className = operand.substring(0, index);
+ var fieldName = operand.substring(index + 1);
+ return new FieldOperand(className, fieldName);
+ }
+ }
+ }
+ throw new IllegalArgumentException("compile error");
+ }
+
+ ConstantOperand asConstantOperand(String value) {
+ //TODO add boxed types
+ var tokens = value.split(" ");
+ var type = Primitive.from(tokens[0].toUpperCase(Locale.ROOT));
+ if (tokens.length == 2 && type != null) {
+ return new ConstantOperand(type, tokens[1]);
+ } else if (value.startsWith("\"")) {
+ if (value.endsWith("\"")) {
+ return new ConstantOperand(Primitive.STRING, value.substring(1, value.length() - 1));
+ } else {
+ throw new IllegalArgumentException("Unterminated String value");
+ }
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/nl/sander/beejava/OverallCompiler.java b/src/main/java/nl/sander/beejava/OverallCompiler.java
new file mode 100644
index 0000000..52c13d8
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/OverallCompiler.java
@@ -0,0 +1,17 @@
+package nl.sander.beejava;
+
+import nl.sander.beejava.api.BeeSource;
+
+public final class OverallCompiler {
+
+ private OverallCompiler(){
+ //
+ }
+
+ public static byte[] compile(String sourcecode){
+ BeeSource beeSource = SourceCompiler.compile(sourcecode);
+ OpcodeTranslator.translate(beeSource);
+ CompiledClass compiledClass = Compiler.compile(beeSource);
+ return BytecodeGenerator.generate(compiledClass);
+ }
+}
diff --git a/src/main/java/nl/sander/beejava/Primitive.java b/src/main/java/nl/sander/beejava/Primitive.java
new file mode 100644
index 0000000..31a2cbf
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/Primitive.java
@@ -0,0 +1,14 @@
+package nl.sander.beejava;
+
+import java.util.Arrays;
+
+public enum Primitive {
+ INT, SHORT, BYTE, LONG, FLOAT, DOUBLE, CHAR, BOOLEAN, STRING;
+
+ public static Primitive from(String value) {
+ return Arrays.stream(values())
+ .filter(e -> e.toString().equals(value))
+ .findFirst()
+ .orElse(null);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/nl/sander/beejava/apiv2/SourceCompiler.java b/src/main/java/nl/sander/beejava/SourceCompiler.java
similarity index 67%
rename from src/main/java/nl/sander/beejava/apiv2/SourceCompiler.java
rename to src/main/java/nl/sander/beejava/SourceCompiler.java
index a75ff1f..683e1c8 100644
--- a/src/main/java/nl/sander/beejava/apiv2/SourceCompiler.java
+++ b/src/main/java/nl/sander/beejava/SourceCompiler.java
@@ -1,6 +1,6 @@
-package nl.sander.beejava.apiv2;
+package nl.sander.beejava;
-import nl.sander.beejava.api.Version;
+import nl.sander.beejava.api.*;
import nl.sander.beejava.flags.ClassAccessFlags;
import nl.sander.beejava.flags.FieldAccessFlag;
import nl.sander.beejava.flags.MethodAccessFlag;
@@ -30,9 +30,11 @@ public class SourceCompiler {
}
public BeeSource doCompile() {
- Arrays.stream(sourcecode.split("\n")).map(this::compileLine).forEach(instructions::add);
+ Arrays.stream(sourcecode.split("\n"))
+ .map(this::compileLine)
+ .forEach(instructions::add);
- BeeSource beeSource = new nl.sander.beejava.apiv2.BeeSource();
+ BeeSource beeSource = new BeeSource();
for (currentLine = 0; currentLine < instructions.size(); ) {
Instruction ins = instructions.get(currentLine);
@@ -51,15 +53,15 @@ public class SourceCompiler {
ClassInstruction classInstruction = (ClassInstruction) instruction;
String operand = classInstruction.getOperand();
switch (classInstruction.getOperation()) {
- case FIELD -> beeSource.addFields(parseField(operand));
- case CONSTRUCTOR -> beeSource.addConstructors(parseConstructor(operand));
- case METHOD -> beeSource.addMethods(parseMethod(operand));
+ case FIELD -> beeSource.addFields(parseField(beeSource, operand));
+ case CONSTRUCTOR -> beeSource.addConstructors(parseConstructor(beeSource, operand));
+ case METHOD -> beeSource.addMethods(parseMethod(beeSource, operand));
default -> throw new IllegalArgumentException("Not allowed here");
}
}
}
- private BeeMethod parseMethod(String text) {
+ private nl.sander.beejava.api.BeeMethod parseMethod(BeeSource beeSource, String text) {
String[] tokens = returntypesplitter.split(text);
final String first;
final Class> returnType;
@@ -83,42 +85,41 @@ public class SourceCompiler {
}
String[] nameParams = split(flagsNameParameters[i], parensplitter);
- Set parameters = new HashSet<>();
- String methodName=null;
+ Set parameters = new HashSet<>();
+ String methodName = null;
if (nameParams.length > 0) {
methodName = nameParams[0];
if (nameParams[1].length() > 0) {
-
+ int index = 0;
String params = nameParams[1];
String[] paramTokens = params.split(",");
for (String paramToken : paramTokens) {
String[] declaration = paramToken.trim().split(" ");
String type = declaration[0];
String name = declaration[1];
- parameters.add(new BeeParameter(getType(type), name));
+ parameters.add(new nl.sander.beejava.api.BeeParameter(getType(type), name, index++));
}
}
}
- if (methodName==null){
+ if (methodName == null) {
throw new IllegalArgumentException("method name not found");
}
currentLine += 1;
- List lines = new ArrayList<>();
+ List lines = new ArrayList<>();
Instruction nextInstruction = instructions.get(currentLine);
- while (nextInstruction instanceof CodeLine) {
- lines.add((CodeLine) nextInstruction);
- currentLine += 1;
- if (currentLine >= instructions.size()) {
- break; // too tired to think
- }
+ while (currentLine < instructions.size() && nextInstruction instanceof CodeLine) {
nextInstruction = instructions.get(currentLine);
+ if (nextInstruction instanceof CodeLine) {
+ lines.add((CodeLine) nextInstruction);
+ currentLine += 1;
+ }
}
- return new BeeMethod(methodName, flags, parameters, returnType, lines);
+ return new BeeMethod(beeSource, methodName, flags, parameters, returnType, lines);
}
- private BeeConstructor parseConstructor(String text) {
+ private nl.sander.beejava.api.BeeConstructor parseConstructor(BeeSource beeSource, String text) {
String[] tokens = split(text, parensplitter);
String flag = tokens[0];
MethodAccessFlag methodAccessFlag = MethodAccessFlag.get(flag.toUpperCase()).orElseThrow(illegalArgument("Not a valid flag " + flag));
@@ -127,30 +128,29 @@ public class SourceCompiler {
Set parameters = new HashSet<>();
if (params.length() > 0) {
String[] paramTokens = params.split(",");
+ int index = 0;
for (String paramToken : paramTokens) {
String[] declaration = paramToken.trim().split(" ");
String type = declaration[0];
String name = declaration[1];
- try {
- parameters.add(new BeeParameter(Class.forName(type), name));
- } catch (ClassNotFoundException e) {
- throw new IllegalArgumentException("field type " + type + " not found");
- }
+ parameters.add(new BeeParameter(getType(type), name, index++));
}
}
currentLine += 1;
List lines = new ArrayList<>();
Instruction nextInstruction = instructions.get(currentLine);
- while (nextInstruction instanceof CodeLine) {
- lines.add((CodeLine) nextInstruction);
- currentLine += 1;
+ while (currentLine < instructions.size() && nextInstruction instanceof CodeLine) {
nextInstruction = instructions.get(currentLine);
-
+ if (nextInstruction instanceof CodeLine) {
+ lines.add((CodeLine) nextInstruction);
+ currentLine += 1;
+ }
}
- return new BeeConstructor(Set.of(methodAccessFlag), parameters, lines);
+
+ return new BeeConstructor(beeSource, Set.of(methodAccessFlag), parameters, lines);
}
- private BeeField parseField(String operand) {
+ private nl.sander.beejava.api.BeeField parseField(BeeSource beeSource, String operand) {
String[] tokens = operand.split(" ");
Set flags = new HashSet<>();
String type = null;
@@ -168,19 +168,29 @@ public class SourceCompiler {
}
}
currentLine += 1;
- return new BeeField(flags, getType(type), name);
+ return new BeeField(beeSource.getName(), flags, getType(type), name);
}
- private void parseClassDeclaration(Instruction firstLine, BeeSource beeSource) {
- if (firstLine instanceof ClassInstruction) {
- ClassInstruction classDeclaration = (ClassInstruction) firstLine;
+ private void parseClassDeclaration(Instruction instruction, BeeSource beeSource) {
+ if (instruction instanceof ClassInstruction) {
+ ClassInstruction classDeclaration = (ClassInstruction) instruction;
ClassOperation operation = classDeclaration.getOperation();
switch (operation) {
case CLASS -> {
+ beeSource.addAccessFlags(ClassAccessFlags.SUPER);
+ beeSource.setClassFileVersion(getVersion(classDeclaration));
+
String[] tokens = split(classDeclaration.getOperand(), parensplitter);
- beeSource.addAccessFlags(ClassAccessFlags.PUBLIC, ClassAccessFlags.SUPER);
- beeSource.setName(tokens[0]);
- beeSource.setClassFileVersion(Version.get(tokens[1]).orElseThrow(illegalArgument(tokens[1])));
+ String rightHand = classDeclaration.getOperand();
+ if (tokens.length > 0) { // has Version tag
+ rightHand = tokens[0];
+ }
+ tokens = rightHand.split(" ");
+
+ if (tokens.length == 2) { // has access flag
+ beeSource.addAccessFlags(ClassAccessFlags.valueOf(tokens[0].toUpperCase()));
+ }
+ beeSource.setName(getClassName(tokens));
}
case INTERFACE -> {
}//TODO
@@ -194,6 +204,23 @@ public class SourceCompiler {
currentLine += 1;
}
+ private Version getVersion(ClassInstruction classDeclaration) {
+ String[] tokens2 = split(classDeclaration.getOperand(), parensplitter);
+ if (tokens2.length == 0) {
+ return Version.V8;
+ } else {
+ return Version.get(tokens2[1]).orElseThrow(illegalArgument(tokens2[1]));
+ }
+ }
+
+ private String getClassName(String[] tokens) {
+ if (tokens.length == 2) {
+ return tokens[1];
+ } else {
+ return tokens[0];
+ }
+ }
+
private Instruction compileLine(String line) {
if (!line.startsWith(" ")) {
String[] tokens = split(line, firstBlanksplitter);
@@ -203,6 +230,9 @@ public class SourceCompiler {
return new ClassInstruction(classOperation, operand);
} else {
line = line.substring(2);
+ if (line.startsWith(" ")) {
+ throw new IllegalArgumentException("Illegal indent -> must be 2 spaces");
+ }
String operation;
String operand;
if (line.indexOf(' ') > -1) {
@@ -236,7 +266,13 @@ public class SourceCompiler {
try {
return switch (type) {
case "int" -> int.class;
+ case "short" -> short.class;
+ case "byte" -> byte.class;
+ case "long" -> long.class;
+ case "float" -> float.class;
case "double" -> double.class;
+ case "boolean" -> boolean.class;
+ case "char" -> char.class;
default -> Class.forName(type);
};
} catch (ClassNotFoundException e) {
diff --git a/src/main/java/nl/sander/beejava/TypeMapper.java b/src/main/java/nl/sander/beejava/TypeMapper.java
index cbd5aee..aed69a8 100644
--- a/src/main/java/nl/sander/beejava/TypeMapper.java
+++ b/src/main/java/nl/sander/beejava/TypeMapper.java
@@ -16,8 +16,7 @@ public class TypeMapper {
MAP.put(long.class, "J");
MAP.put(short.class, "S");
MAP.put(boolean.class, "Z");
- MAP.put(Void.class, "V");
-
+ MAP.put(void.class, "V");
}
//TODO something with arrays
diff --git a/src/main/java/nl/sander/beejava/api/BeeConstructor.java b/src/main/java/nl/sander/beejava/api/BeeConstructor.java
index e195c1a..feda15f 100644
--- a/src/main/java/nl/sander/beejava/api/BeeConstructor.java
+++ b/src/main/java/nl/sander/beejava/api/BeeConstructor.java
@@ -9,19 +9,15 @@ import java.util.*;
*/
public final class BeeConstructor extends CodeContainer {
- public BeeConstructor(Set accessFlags,
- Set formalParameters,
- List code) {
+ public BeeConstructor(BeeSource beeSource, Set accessFlags,
+ Set formalParameters,
+ List code) {
this.formalParameters.addAll(formalParameters);
this.accessFlags.addAll(accessFlags);
super.code.addAll(code);
+ setOwner(beeSource);
}
- public static Builder builder() {
- return new Builder();
- }
-
-
public String getName() {
return "";
}
@@ -34,7 +30,7 @@ public final class BeeConstructor extends CodeContainer {
}
public Class> getReturnType() {
- return Void.class;
+ return void.class;
}
@Override
@@ -55,34 +51,4 @@ public final class BeeConstructor extends CodeContainer {
return Objects.hash(formalParameters);
}
- public static class Builder {
- private final Set accessFlags = new HashSet<>();
- private final Set formalParameters = new HashSet<>();
- private final List code = new LinkedList<>();
-
- private Builder() {
-
- }
-
- public Builder withFormalParameters(BeeParameter... formalParameters) {
- this.formalParameters.addAll(Arrays.asList(formalParameters));
- return this;
- }
-
- public Builder withAccessFlags(MethodAccessFlag... accessFlags) {
- this.accessFlags.addAll(Arrays.asList(accessFlags));
- return this;
- }
-
- public Builder withCode(CodeLine... lines) {
- this.code.addAll(Arrays.asList(lines));
- return this;
- }
-
- public BeeConstructor build() {
- BeeConstructor beeConstructor = new BeeConstructor(accessFlags, formalParameters, code);
- code.forEach(line -> line.setOwner(beeConstructor));
- return beeConstructor;
- }
- }
}
diff --git a/src/main/java/nl/sander/beejava/api/BeeField.java b/src/main/java/nl/sander/beejava/api/BeeField.java
index 3683b9d..09eea60 100644
--- a/src/main/java/nl/sander/beejava/api/BeeField.java
+++ b/src/main/java/nl/sander/beejava/api/BeeField.java
@@ -2,7 +2,6 @@ package nl.sander.beejava.api;
import nl.sander.beejava.flags.FieldAccessFlag;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@@ -12,20 +11,25 @@ import java.util.Set;
*/
public final class BeeField {
+ private final String declaringClass;
private final Set accessFlags = new HashSet<>();
private final Class> type;
private final String name;
- public BeeField(Set accessFlags, Class> type, String name) {
+ /**
+ *
+ * @param declaringClass class that declares the field. Can be existing class, or the one that is under construction
+ * @param accessFlags
+ * @param type field type. Must be existing type.
+ * @param name
+ */
+ public BeeField(String declaringClass, Set accessFlags, Class> type, String name) {
+ this.declaringClass = declaringClass;
this.accessFlags.addAll(accessFlags);
this.type = type;
this.name = name;
}
- public static BeeField.Builder builder(){
- return new Builder();
- }
-
public Set getAccessFlags() {
return accessFlags;
}
@@ -38,6 +42,10 @@ public final class BeeField {
return name;
}
+ public String getDeclaringClass() {
+ return declaringClass;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -51,32 +59,5 @@ public final class BeeField {
return Objects.hash(name);
}
- public static class Builder {
- private final Set accessFlags = new HashSet<>();
- private Class> type;
- private String name;
- private Builder(){
-
- }
-
- public BeeField.Builder withAccessFlags(FieldAccessFlag... accessFlags) {
- this.accessFlags.addAll(Arrays.asList(accessFlags));
- return this;
- }
-
- public BeeField.Builder withType(Class> type) {
- this.type=type;
- return this;
- }
-
- public BeeField.Builder withName(String name) {
- this.name=name;
- return this;
- }
-
- public BeeField build() {
- return new BeeField(accessFlags, type, name);
- }
- }
}
diff --git a/src/main/java/nl/sander/beejava/api/BeeMethod.java b/src/main/java/nl/sander/beejava/api/BeeMethod.java
index 0454bdf..fa5c406 100644
--- a/src/main/java/nl/sander/beejava/api/BeeMethod.java
+++ b/src/main/java/nl/sander/beejava/api/BeeMethod.java
@@ -12,18 +12,15 @@ public final class BeeMethod extends CodeContainer {
private final Class> returnType;
- private BeeMethod(String name, Set accessFlags,
- List formalParameters,
- Class> returnType, List code) {
+ public BeeMethod(BeeSource beeSource, String name, Set accessFlags,
+ Set formalParameters,
+ Class> returnType, List code) {
this.name = name;
this.accessFlags.addAll(accessFlags);
this.formalParameters.addAll(formalParameters);
this.returnType = returnType;
super.code.addAll(code);
- }
-
- public static Builder builder() {
- return new Builder();
+ setOwner(beeSource);
}
public String getName() {
@@ -48,45 +45,18 @@ public final class BeeMethod extends CodeContainer {
*/
}
- public static class Builder {
- private final Set accessFlags = new HashSet<>();
- private final List formalParameters = new LinkedList<>();
- private final List code = new LinkedList<>();
- private String name;
- private Class> returnType = Void.class;
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
+ BeeMethod beeMethod = (BeeMethod) o;
+ return name.equals(beeMethod.name) &&
+ returnType.equals(beeMethod.returnType);
+ }
- private Builder() {
- }
-
- public Builder withName(String name) {
- this.name = name;
- return this;
- }
-
- public Builder withAccessFlags(MethodAccessFlag... accessFlags) {
- this.accessFlags.addAll(Arrays.asList(accessFlags));
- return this;
- }
-
- public Builder withFormalParameters(BeeParameter... formalParameters) {
- this.formalParameters.addAll(Arrays.asList(formalParameters));
- return this;
- }
-
- public Builder withReturnType(Class> returnType) {
- this.returnType = returnType;
- return this;
- }
-
- public Builder withCode(CodeLine... lines) {
- this.code.addAll(Arrays.asList(lines));
- return this;
- }
-
- public BeeMethod build() {
- BeeMethod beeMethod = new BeeMethod(name, accessFlags, formalParameters, returnType, code);
- code.forEach(line -> line.setOwner(beeMethod));
- return beeMethod;
- }
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), name, returnType);
}
}
diff --git a/src/main/java/nl/sander/beejava/api/BeePackage.java b/src/main/java/nl/sander/beejava/api/BeePackage.java
deleted file mode 100644
index 9638a22..0000000
--- a/src/main/java/nl/sander/beejava/api/BeePackage.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package nl.sander.beejava.api;
-
-/**
- * Contains the name of the package for a class
- */
-public final class BeePackage {
-
- private final String name;
-
- BeePackage(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-}
diff --git a/src/main/java/nl/sander/beejava/api/BeeParameter.java b/src/main/java/nl/sander/beejava/api/BeeParameter.java
index c4dd604..1533c8e 100644
--- a/src/main/java/nl/sander/beejava/api/BeeParameter.java
+++ b/src/main/java/nl/sander/beejava/api/BeeParameter.java
@@ -8,14 +8,18 @@ import java.util.Objects;
public final class BeeParameter {
private final Class> type;
private final String name;
+ private final int index;
public BeeParameter(Class> type, String name) {
this.type = type;
this.name = name;
+ this.index = -1;
}
- public static BeeParameter create(Class> type, String name) {
- return new BeeParameter(type, Objects.requireNonNull(name));
+ public BeeParameter(Class> type, String name, int index) {
+ this.type = type;
+ this.name = name;
+ this.index = index;
}
public Class> getType() {
@@ -34,6 +38,10 @@ public final class BeeParameter {
return name.equals(that.name);
}
+ public int getIndex() {
+ return index;
+ }
+
@Override
public int hashCode() {
return Objects.hash(name);
diff --git a/src/main/java/nl/sander/beejava/api/BeeSource.java b/src/main/java/nl/sander/beejava/api/BeeSource.java
index 410de1e..83df8cc 100644
--- a/src/main/java/nl/sander/beejava/api/BeeSource.java
+++ b/src/main/java/nl/sander/beejava/api/BeeSource.java
@@ -2,50 +2,22 @@ package nl.sander.beejava.api;
import nl.sander.beejava.flags.ClassAccessFlags;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
- * Contains all information needed for compilation
- *
- * End users need to create an instance of this class (using the Builder) and add all fields, methods etc.
- * Once created the BeeSource object is immutable.
+ * Contains parsed class elements like constructors and methods, but the opcode is not compiled to bytecode yet.
*/
public final class BeeSource {
- private final Version classFileVersion;
- private final BeePackage beePackage;
private final Set accessFlags = new HashSet<>();
- private final String simpleName;
- private final Class> superClass;
private final Set> interfaces = new HashSet<>();
private final Set fields = new HashSet<>();
private final Set constructors = new HashSet<>();
private final Set methods = new HashSet<>();
-
- private BeeSource(Version classFileVersion,
- BeePackage beePackage, Set accessFlags, String simpleName, Class> superClass,
- Set> interfaces, Set fields, Set constructors, Set methods) {
- this.classFileVersion = classFileVersion;
- this.beePackage = beePackage;
- this.accessFlags.addAll(accessFlags);
- this.simpleName = simpleName;
- this.superClass = superClass;
- this.interfaces.addAll(interfaces);
- this.fields.addAll(fields);
- this.constructors.addAll(constructors);
- this.methods.addAll(methods);
- }
-
- /**
- * Create a new BeeSource Builder class.
- *
- * @return a new instance of a Builder
- */
- public static BeeSource.Builder builder() {
- return new Builder();
- }
+ private Version classFileVersion;
+ private String name;
+ private Class> superClass = Object.class;
/**
* @return The classfile version
@@ -54,18 +26,8 @@ public final class BeeSource {
return classFileVersion;
}
- /**
- * @return The package in which the compiled class will reside.
- */
- public BeePackage getPackage() {
- return beePackage;
- }
-
- /**
- * returns the unqualified name, like java.lang.Class
- */
- public String getSimpleName() {
- return simpleName;
+ public void setClassFileVersion(Version classFileVersion) {
+ this.classFileVersion = classFileVersion;
}
/**
@@ -75,6 +37,10 @@ public final class BeeSource {
return Collections.unmodifiableSet(constructors);
}
+ public void addConstructors(BeeConstructor... constructors) {
+ this.constructors.addAll(Set.of(constructors));
+ }
+
/**
* @return all methods that are provided with the class
*/
@@ -82,6 +48,10 @@ public final class BeeSource {
return methods;
}
+ public void addMethods(BeeMethod... methods) {
+ this.methods.addAll(Set.of(methods));
+ }
+
/**
* @return The access flags for the class
*/
@@ -89,11 +59,19 @@ public final class BeeSource {
return Collections.unmodifiableSet(accessFlags);
}
+ public void addAccessFlags(ClassAccessFlags... classAccessFlags) {
+ this.accessFlags.addAll(Set.of(classAccessFlags));
+ }
+
/**
* @return The full name, like java.lang.Class
*/
public String getName() {
- return beePackage.getName() + "." + simpleName;
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
}
/**
@@ -103,6 +81,10 @@ public final class BeeSource {
return superClass;
}
+ public void setSuperClass(Class> superClass) {
+ this.superClass = superClass;
+ }
+
/**
* @return a list of unique interfaces that the class will implements
*/
@@ -110,6 +92,10 @@ public final class BeeSource {
return Collections.unmodifiableSet(interfaces);
}
+ public void addInterfaces(Class>... interfaces) {
+ this.interfaces.addAll(Set.of(interfaces));
+ }
+
/**
* @return a list of unique fields that the class will contain
*/
@@ -117,74 +103,14 @@ public final class BeeSource {
return Collections.unmodifiableSet(fields);
}
- /**
- * Helper class for creating BeeSource classes
- */
- public static class Builder {
- private final Set accessFlags = new HashSet<>();
- private final Set> interfaces = new HashSet<>();
- private final Set fields = new HashSet<>();
- private Version version;
- private BeePackage beePackage;
- private Class> superClass = Object.class;
- private String simpleName;
- private final Set constructors = new HashSet<>();
- private final Set methods = new HashSet<>();
-
- private Builder() {
- }
-
- public Builder withClassFileVersion(Version version) {
- this.version = version;
- return this;
- }
-
- public BeeSource.Builder withPackage(String beePackage) {
- this.beePackage = new BeePackage(beePackage);
- return this;
- }
-
- public BeeSource.Builder withAccessFlags(ClassAccessFlags... accessFlags) {
- this.accessFlags.addAll(Arrays.asList(accessFlags));
- return this;
- }
-
- public BeeSource.Builder withSimpleName(String simpleName) {
- this.simpleName = simpleName;
- return this;
- }
-
- public Builder withSuperClass(Class> superClass) {
- this.superClass = superClass;
- return this;
- }
-
- public Builder withInterfaces(Class>... interfaces) {
- this.interfaces.addAll(Arrays.asList(interfaces));
- return this;
- }
-
- public Builder withFields(BeeField... fields) {
- this.fields.addAll(Arrays.asList(fields));
- return this;
- }
-
- public Builder withConstructors(BeeConstructor... constructors) {
- this.constructors.addAll(Arrays.asList(constructors));
- return this;
- }
-
- public Builder withMethods(BeeMethod... methods) {
- this.methods.addAll(Arrays.asList(methods));
- return this;
- }
-
- public BeeSource build() {
- BeeSource beeSource = new BeeSource(version, beePackage, accessFlags, simpleName, superClass, interfaces, fields, constructors, methods);
- constructors.forEach(c -> c.setOwner(beeSource));
- methods.forEach(m -> m.setOwner(beeSource));
- return beeSource;
- }
+ public void addFields(BeeField... fields) {
+ this.fields.addAll(Set.of(fields));
+ }
+ public BeeField getField(String fieldName) {
+ return fields.stream()
+ .filter(f -> f.getName().equals(fieldName))
+ .findAny()
+ .orElseThrow(() -> new IllegalArgumentException("field " + fieldName + " not found in " + getName()));
}
}
diff --git a/src/main/java/nl/sander/beejava/apiv2/ClassInstruction.java b/src/main/java/nl/sander/beejava/api/ClassInstruction.java
similarity index 92%
rename from src/main/java/nl/sander/beejava/apiv2/ClassInstruction.java
rename to src/main/java/nl/sander/beejava/api/ClassInstruction.java
index f16e12a..ce1f574 100644
--- a/src/main/java/nl/sander/beejava/apiv2/ClassInstruction.java
+++ b/src/main/java/nl/sander/beejava/api/ClassInstruction.java
@@ -1,4 +1,4 @@
-package nl.sander.beejava.apiv2;
+package nl.sander.beejava.api;
public class ClassInstruction extends Instruction {
private final ClassOperation classOperation;
diff --git a/src/main/java/nl/sander/beejava/apiv2/ClassOperation.java b/src/main/java/nl/sander/beejava/api/ClassOperation.java
similarity index 80%
rename from src/main/java/nl/sander/beejava/apiv2/ClassOperation.java
rename to src/main/java/nl/sander/beejava/api/ClassOperation.java
index 793562c..35f5168 100644
--- a/src/main/java/nl/sander/beejava/apiv2/ClassOperation.java
+++ b/src/main/java/nl/sander/beejava/api/ClassOperation.java
@@ -1,4 +1,4 @@
-package nl.sander.beejava.apiv2;
+package nl.sander.beejava.api;
import java.util.Optional;
@@ -10,7 +10,7 @@ public enum ClassOperation {
CONSTRUCTOR,
METHOD;
- static Optional get(String text){
+ public static Optional get(String text){
String upper = text.toUpperCase();
for (ClassOperation val: ClassOperation.values()){
if (val.toString().equals(upper)){
diff --git a/src/main/java/nl/sander/beejava/api/CodeContainer.java b/src/main/java/nl/sander/beejava/api/CodeContainer.java
index deea548..8110d5b 100644
--- a/src/main/java/nl/sander/beejava/api/CodeContainer.java
+++ b/src/main/java/nl/sander/beejava/api/CodeContainer.java
@@ -1,9 +1,7 @@
package nl.sander.beejava.api;
+import nl.sander.beejava.JavaInstruction;
import nl.sander.beejava.TypeMapper;
-import nl.sander.beejava.api.BeeParameter;
-import nl.sander.beejava.api.BeeSource;
-import nl.sander.beejava.api.CodeLine;
import nl.sander.beejava.flags.MethodAccessFlag;
import java.util.*;
@@ -17,6 +15,7 @@ public abstract class CodeContainer {
protected final List code = new LinkedList<>();
protected final Set formalParameters = new HashSet<>();
protected final Set accessFlags = new HashSet<>();
+ private final List expandedCode = new ArrayList<>();
private BeeSource owner;
public List getCode() {
@@ -53,9 +52,35 @@ public abstract class CodeContainer {
this.owner = beeSource;
}
+ public List getExpandedCode() {
+ return Collections.unmodifiableList(expandedCode);
+ }
+
+ public void setExpandedCode(List instructions) {
+ expandedCode.clear();
+ expandedCode.addAll(instructions);
+ }
+
public abstract boolean isConstructor();
public Set getFormalParameters() {
return formalParameters;
}
+
+ public Optional getParameter(String parameterName) {
+ return formalParameters.stream().filter(p -> parameterName.equals(p.getName())).findAny();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CodeContainer that = (CodeContainer) o;
+ return formalParameters.equals(that.formalParameters);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(formalParameters);
+ }
}
diff --git a/src/main/java/nl/sander/beejava/api/CodeLine.java b/src/main/java/nl/sander/beejava/api/CodeLine.java
index d4e59c2..4d53588 100644
--- a/src/main/java/nl/sander/beejava/api/CodeLine.java
+++ b/src/main/java/nl/sander/beejava/api/CodeLine.java
@@ -1,249 +1,28 @@
package nl.sander.beejava.api;
-import nl.sander.beejava.JavaOpcode;
-import nl.sander.beejava.TypeMapper;
-import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-public final class CodeLine {
+public class CodeLine extends Instruction {
private final Opcode opcode;
- private Ref ref;
- private BeeParameter parameter;
- private Class> type;
- private String methodName;
- private List> inputSignature;
- private String outputSignature;
- private BeeField ownfield; // when you create a class with a field, you can refer to it
- private Field externalfield; // when you refer to a field from another class
- private Object constValue;
- private ConstantPoolEntry assignedEntry;
private CodeContainer owner;
- private JavaOpcode javaOpcode;
- CodeLine(Opcode opcode) {
+ public CodeLine(Opcode opcode, String operand) {
+ super(operand);
this.opcode = opcode;
}
- public static CodeLine line(Opcode opcode, Ref ref) {
- return new CodeLine(opcode).withRef(ref);
- }
-
- public static CodeLine line(Opcode opcode, String fieldClass, String fieldName) {
- return new CodeLine(opcode).withExternalFieldRef(fieldClass, fieldName);
- }
-
- public static CodeLine line(Opcode opcode, String constValue) {
- return new CodeLine(opcode).withConstValue(constValue);
- }
-
- public static CodeLine line(Opcode opcode, String className, String methodName, String inputSignature) throws ClassNotFoundException {
- return new CodeLine(opcode).withClassName(className).withMethodName(methodName).withInput(parse(inputSignature)).withVoidOutput();
- }
-
- public static CodeLine line(Opcode opcode,
- Ref ref, String methodNameRef, String inputSignature) throws ClassNotFoundException {
- return new CodeLine(opcode).withRef(ref).withMethodName(methodNameRef).withInput(parse(inputSignature)).withVoidOutput();
- }
-
- public static CodeLine line(Opcode opcode,
- Ref ref, String methodNameRef, String inputSignature, String outputSignature) throws ClassNotFoundException {
- return new CodeLine(opcode).withRef(ref).withMethodName(methodNameRef).withInput(parse(inputSignature)).withOutput(outputSignature);
- }
-
- public static CodeLine line(Opcode opcode) {
- return new CodeLine(opcode);
- }
-
- public static CodeLine line(Opcode opcode, BeeParameter parameter) {
- return new CodeLine(opcode).withParameter(parameter);
- }
-
- public static CodeLine line(Opcode opcode, BeeField intField) {
- return new CodeLine(opcode).withRef(Ref.THIS).withOwnField(intField);
- }
-
- private CodeLine withRef(Ref ref) {
- this.ref = ref;
- return this;
- }
-
- private CodeLine withClassName(String className) {
- this.type = loadClass(className);
- return this;
- }
-
- private CodeLine withMethodName(String methodName) {
- this.methodName = methodName;
- return this;
- }
-
- private CodeLine withInput(List> inputSignature) {
- this.inputSignature = inputSignature;
- return this;
- }
-
- private CodeLine withVoidOutput() {
- return withOutput("V");
- }
-
- private CodeLine withOutput(String outputSignature) {
- this.outputSignature = outputSignature;
- return this;
- }
-
- private CodeLine withParameter(BeeParameter parameter) {
- this.parameter = parameter;
- return this;
- }
-
- private CodeLine withConstValue(Object constValue) {
- this.constValue = constValue;
- return this; //TODO
- }
-
- private CodeLine withOwnField(BeeField beeField) {
- this.ownfield = beeField;
- return this;
- }
-
- private CodeLine withExternalFieldRef(String className, String field) {
- this.type = loadClass(className);
- this.externalfield = loadField(field);
- return this;
- }
-
-// TODO decide whether to work with Strings or class objects...
-
- /*
- * Look up the type of a field in a class
- *
- * Assumes field is accessible
- *
- * @param className the class containing a field
- * @param field name of the field
- * @return the field type
- */
- private Field loadField(String field) {
- try {
- return type.getField(field);
- } catch (NoSuchFieldException e) {
- throw new RuntimeException(e);
- }
- }
-
- public boolean hasClassName() {
- return type != null;
- }
-
-
- public String getClassName() {
- return type.getName();
- }
-
- public String getMethodName() {
- return methodName;
- }
-
- public boolean hasMethodCall() {
- return methodName != null;
- }
-
- public String getMethodSignature() {
- return inputSignature.stream()
- .map(TypeMapper::map)
- .collect(Collectors.joining(",", "(", ")")) + outputSignature;
- }
-
- public Ref getRef() {
- return ref;
- }
-
- public boolean hasRef() {
- return ref != null;
- }
-
- public boolean hasRefToOwnField() {
- return ownfield != null;
- }
-
-
- public Object getConstValue() {
- return constValue;
- }
-
- public boolean hasConstValue() {
- return constValue != null;
- }
-
- public BeeField getOwnfield() {
- return ownfield;
- }
-
- public BeeParameter getParameter() {
- return parameter;
- }
-
-
- public boolean hasRefToExternalField() {
- return externalfield != null;
- }
-
- public Field getExternalfield() {
- return externalfield;
- }
-
- public ConstantPoolEntry getAssignedEntry() {
- return assignedEntry;
- }
-
- public void setAssignedEntry(ConstantPoolEntry assignedEntry) {
- this.assignedEntry = assignedEntry;
+ public String getOperand() {
+ return operand;
}
public Opcode getOpcode() {
return opcode;
}
- private Class> loadClass(String className) {
- try {
- return Class.forName(className);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException(e); //TODO specific exception
- }
+ public void setOwner(CodeContainer owner) {
+ this.owner = owner;
}
public CodeContainer getOwner() {
return owner;
}
-
- public void setOwner(CodeContainer codeContainer) {
- this.owner = codeContainer;
- }
-
- public JavaOpcode getJavaOpcode() {
- return javaOpcode;
- }
-
- public void setJavaOpcode(JavaOpcode javaOpcode) {
- this.javaOpcode = javaOpcode;
- }
-
- private static List> parse(String inputSignature) throws ClassNotFoundException {
- if ("()".equals(inputSignature)) {
- return Collections.emptyList();
- } else {
- String[] params = inputSignature.split(",");
- List> paramClasses = new ArrayList<>();
- for (String param : params) {
- paramClasses.add(Class.forName(param));
- }
- return paramClasses;
- }
- }
}
diff --git a/src/main/java/nl/sander/beejava/apiv2/Instruction.java b/src/main/java/nl/sander/beejava/api/Instruction.java
similarity index 81%
rename from src/main/java/nl/sander/beejava/apiv2/Instruction.java
rename to src/main/java/nl/sander/beejava/api/Instruction.java
index cbcd007..ec3eb88 100644
--- a/src/main/java/nl/sander/beejava/apiv2/Instruction.java
+++ b/src/main/java/nl/sander/beejava/api/Instruction.java
@@ -1,4 +1,4 @@
-package nl.sander.beejava.apiv2;
+package nl.sander.beejava.api;
public class Instruction {
protected final String operand;
diff --git a/src/main/java/nl/sander/beejava/api/Opcode.java b/src/main/java/nl/sander/beejava/api/Opcode.java
index 5b3dc31..df3af2d 100644
--- a/src/main/java/nl/sander/beejava/api/Opcode.java
+++ b/src/main/java/nl/sander/beejava/api/Opcode.java
@@ -1,71 +1,65 @@
package nl.sander.beejava.api;
+import java.util.Optional;
+
public enum Opcode {
- LD_VAR("ld_var"),
- LD_CONST("ld_const"),
- LD_FIELD("ld_field"),
- STORE("store"),
- CONST("const"),
- NEWARRAY("new"),
- RETURN("return"),
- ARRAYLENGTH("length"),
- THROW("throw"),
- PUSH("push"),
- CHECKCAST("checkcast"),
- ADD("add"),
- COMPARE("cmp"),
- DIVIDE("div"),
- MULTIPLY("mul"),
- NEGATE("neg"),
- REMAINDER("rem"),
- SUBTRACT("sub"),
- DUPLICATE("dup"),
- DUPLICATE_DOWN("dup_x1"),
- DUPLICATE2("dup2"),
- DUPLICATE2_DOWN("dup2_x1"),
- GET("get"),
- GOTO("goto"),
- GOTO_W("goto_w"),
- TO_DOUBLE("2d"),
- TO_INT("2i"),
- TO_LONG("2l"),
- TO_BYTE("2b"),
- TO_CHAR("2c"),
- TO_FLOAT("2f"),
- TO_SHORT("2s"),
- AND("and"),
- IF_EQUAL("ifeq"),
- IF_NOT_EQUAL("ifneq"),
- IF_LESS_THAN("iflt"),
- IF_GREATER_OR_EQUAL("ifge"),
- IF_GREATER_THAN("ifgt"),
- IF_LESS_OR_EQUAL("ifle"),
- IF_NOT_NULL("ifnotnull"),
- IF_NULL("ifnull"),
- INCREMENT("inc"),
- INSTANCEOF("instanceof"),
- INVOKE("invoke"),
- OR("or"),
- SHIFT_LEFT("shr"),
- SHIFT_RIGHT("shl"),
- LOGICAL_SHIFT_RIGHT("ushr"),
- XOR("xor"),
- LOOKUPSWITCH("lookupswitch"),
- MONITORENTER("monitorenter"),
- MONITOREXIT("monitorexit"),
- MULTIANEWARRAY("multinewarray"),
- NEW("new"),
- NOP("nop"),
- POP("pop"),
- POP2("pop2"),
- PUT("put"),
- SWAP("swap"),
- TABLESWITCH("tableswitch"),
- WIDE("wide");
+ LOAD,
+ STORE,
+ CONST,
+ RETURN,
+ ARRAYLENGTH,
+ THROW,
+ CAST,
+ ADD,
+ COMPARE,
+ DIVIDE,
+ MULTIPLY,
+ NEGATE,
+ REMAINDER,
+ SUBTRACT,
+ GET,
+ GOTO,
+ TO_DOUBLE,
+ TO_INT,
+ TO_LONG,
+ TO_BYTE,
+ TO_CHAR,
+ TO_FLOAT,
+ TO_SHORT,
+ AND,
+ IF_EQUAL,
+ IF_NOT_EQUAL,
+ IF_LESS_THAN,
+ IF_GREATER_OR_EQUAL,
+ IF_GREATER_THAN,
+ IF_LESS_OR_EQUAL,
+ IF_NOT_NULL,
+ IF_NULL,
+ INCREMENT,
+ INSTANCEOF,
+ INVOKE,
+ OR,
+ SHIFT_LEFT,
+ SHIFT_RIGHT,
+ LOGICAL_SHIFT_RIGHT,
+ XOR,
+ LOOKUPSWITCH,
+ MONITORENTER,
+ MONITOREXIT,
+ NEW,
+ NEWARRAY,
+ MULTIANEWARRAY,
+ PUT,
+ SWAP,
+ TABLESWITCH,
+ WIDE;
- private final String name;
-
- Opcode(String name) {
- this.name=name;
+ public static Optional get(String text) {
+ for (Opcode opcode : Opcode.values()) {
+ if (opcode.toString().equals(text)) {
+ return Optional.of(opcode);
+ }
+ }
+ return Optional.empty();
}
}
diff --git a/src/main/java/nl/sander/beejava/api/Ref.java b/src/main/java/nl/sander/beejava/api/Ref.java
deleted file mode 100644
index 49ea11a..0000000
--- a/src/main/java/nl/sander/beejava/api/Ref.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package nl.sander.beejava.api;
-
-/**
- * used to indicate this, super, or none of those, in which case it's class
- */
-public enum Ref {
- THIS,
- SUPER
-}
diff --git a/src/main/java/nl/sander/beejava/api/Version.java b/src/main/java/nl/sander/beejava/api/Version.java
index 4ddea20..292f416 100644
--- a/src/main/java/nl/sander/beejava/api/Version.java
+++ b/src/main/java/nl/sander/beejava/api/Version.java
@@ -1,6 +1,6 @@
package nl.sander.beejava.api;
-import nl.sander.beejava.apiv2.Opcode;
+import nl.sander.beejava.api.Opcode;
import java.util.Optional;
diff --git a/src/main/java/nl/sander/beejava/apiv2/BeeConstructor.java b/src/main/java/nl/sander/beejava/apiv2/BeeConstructor.java
deleted file mode 100644
index a4ea53a..0000000
--- a/src/main/java/nl/sander/beejava/apiv2/BeeConstructor.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package nl.sander.beejava.apiv2;
-
-import nl.sander.beejava.flags.MethodAccessFlag;
-
-import java.util.*;
-
-/**
- * Models a constructor
- */
-public final class BeeConstructor extends CodeContainer {
-
- public BeeConstructor(Set accessFlags,
- Set formalParameters,
- List code) {
- this.formalParameters.addAll(formalParameters);
- this.accessFlags.addAll(accessFlags);
- super.code.addAll(code);
- }
-
- public String getName() {
- return "";
- }
-
- @Override
- public String toString() {
- return "BeeConstructor{" +
- "formalParameters=" + formalParameters +
- '}';
- }
-
- public Class> getReturnType() {
- return Void.class;
- }
-
- @Override
- public boolean isConstructor() {
- return true;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- BeeConstructor that = (BeeConstructor) o;
- return formalParameters.equals(that.formalParameters);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(formalParameters);
- }
-
-}
diff --git a/src/main/java/nl/sander/beejava/apiv2/BeeField.java b/src/main/java/nl/sander/beejava/apiv2/BeeField.java
deleted file mode 100644
index 81e012e..0000000
--- a/src/main/java/nl/sander/beejava/apiv2/BeeField.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package nl.sander.beejava.apiv2;
-
-import nl.sander.beejava.flags.FieldAccessFlag;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Models a field in a BeeClass
- */
-public final class BeeField {
-
- private final Set accessFlags = new HashSet<>();
- private final Class> type;
- private final String name;
-
- public BeeField(Set accessFlags, Class> type, String name) {
- this.accessFlags.addAll(accessFlags);
- this.type = type;
- this.name = name;
- }
-
- public static Builder builder(){
- return new Builder();
- }
-
- public Set getAccessFlags() {
- return accessFlags;
- }
-
- public Class> getType() {
- return type;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- BeeField beeField = (BeeField) o;
- return name.equals(beeField.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name);
- }
-
- public static class Builder {
- private final Set accessFlags = new HashSet<>();
- private Class> type;
- private String name;
-
- private Builder(){
-
- }
-
- public Builder withAccessFlags(FieldAccessFlag... accessFlags) {
- this.accessFlags.addAll(Arrays.asList(accessFlags));
- return this;
- }
-
- public Builder withType(Class> type) {
- this.type=type;
- return this;
- }
-
- public Builder withName(String name) {
- this.name=name;
- return this;
- }
-
- public BeeField build() {
- return new BeeField(accessFlags, type, name);
- }
- }
-}
diff --git a/src/main/java/nl/sander/beejava/apiv2/BeeMethod.java b/src/main/java/nl/sander/beejava/apiv2/BeeMethod.java
deleted file mode 100644
index d29d62c..0000000
--- a/src/main/java/nl/sander/beejava/apiv2/BeeMethod.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package nl.sander.beejava.apiv2;
-
-import nl.sander.beejava.flags.MethodAccessFlag;
-
-import java.util.*;
-
-/**
- * Models a method in a BeeClass
- */
-public final class BeeMethod extends CodeContainer {
- private final String name;
-
- private final Class> returnType;
-
- public BeeMethod(String name, Set accessFlags,
- Set formalParameters,
- Class> returnType, List code) {
- this.name = name;
- this.accessFlags.addAll(accessFlags);
- this.formalParameters.addAll(formalParameters);
- this.returnType = returnType;
- super.code.addAll(code);
- }
-
- public String getName() {
- return name;
- }
-
- public Class> getReturnType() {
- return returnType;
- }
-
- @Override
- public boolean isConstructor() {
- return false;
- }
-
- public void validate() {
- //TODO
- /*
- * here we could add checks like:
- * -If this method is in a class rather than an interface, and the name of the method is , then the descriptor must denote a void method.
- * -If the name of the method is , then the descriptor must denote avoid method, and, in a class file whose version number is 51.0 or above,a method that takes no arguments
- */
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- if (!super.equals(o)) return false;
- BeeMethod beeMethod = (BeeMethod) o;
- return name.equals(beeMethod.name) &&
- returnType.equals(beeMethod.returnType);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(super.hashCode(), name, returnType);
- }
-}
diff --git a/src/main/java/nl/sander/beejava/apiv2/BeeParameter.java b/src/main/java/nl/sander/beejava/apiv2/BeeParameter.java
deleted file mode 100644
index 769126d..0000000
--- a/src/main/java/nl/sander/beejava/apiv2/BeeParameter.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package nl.sander.beejava.apiv2;
-
-import java.util.Objects;
-
-/**
- * Models a formal parameter in a method declaration.
- */
-public final class BeeParameter {
- private final Class> type;
- private final String name;
-
- public BeeParameter(Class> type, String name) {
- this.type = type;
- this.name = name;
- }
-
- public Class> getType() {
- return type;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- BeeParameter that = (BeeParameter) o;
- return name.equals(that.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name);
- }
-}
diff --git a/src/main/java/nl/sander/beejava/apiv2/BeeSource.java b/src/main/java/nl/sander/beejava/apiv2/BeeSource.java
deleted file mode 100644
index 4bfabd1..0000000
--- a/src/main/java/nl/sander/beejava/apiv2/BeeSource.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package nl.sander.beejava.apiv2;
-
-import nl.sander.beejava.api.Version;
-import nl.sander.beejava.flags.ClassAccessFlags;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Contains parsed class elements like constructors and methods, but the opcode is not compiled to bytecode yet.
- */
-public final class BeeSource {
- private final Set accessFlags = new HashSet<>();
- private final Set> interfaces = new HashSet<>();
- private final Set fields = new HashSet<>();
- private final Set constructors = new HashSet<>();
- private final Set methods = new HashSet<>();
- private Version classFileVersion;
- private String name;
- private Class> superClass;
-
- /**
- * @return The classfile version
- */
- public Version getClassFileVersion() {
- return classFileVersion;
- }
-
- public void setClassFileVersion(Version classFileVersion) {
- this.classFileVersion = classFileVersion;
- }
-
- /**
- * @return all constructors that are provided with the class
- */
- public Set getConstructors() {
- return Collections.unmodifiableSet(constructors);
- }
-
- public void addConstructors(BeeConstructor... constructors) {
- this.constructors.addAll(Set.of(constructors));
- }
-
- /**
- * @return all methods that are provided with the class
- */
- public Set getMethods() {
- return methods;
- }
-
- public void addMethods(BeeMethod... methods) {
- this.methods.addAll(Set.of(methods));
- }
-
- /**
- * @return The access flags for the class
- */
- public Set getAccessFlags() {
- return Collections.unmodifiableSet(accessFlags);
- }
-
- public void addAccessFlags(ClassAccessFlags... classAccessFlags) {
- this.accessFlags.addAll(Set.of(classAccessFlags));
- }
-
- /**
- * @return The full name, like java.lang.Class
- */
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * @return The superclass
- */
- public Class> getSuperClass() {
- return superClass;
- }
-
- public void setSuperClass(Class> superClass) {
- this.superClass = superClass;
- }
-
- /**
- * @return a list of unique interfaces that the class will implements
- */
- public Set> getInterfaces() {
- return Collections.unmodifiableSet(interfaces);
- }
-
- public void addInterfaces(Class>... interfaces) {
- this.interfaces.addAll(Set.of(interfaces));
- }
-
- /**
- * @return a list of unique fields that the class will contain
- */
- public Set getFields() {
- return Collections.unmodifiableSet(fields);
- }
-
- public void addFields(BeeField... fields) {
- this.fields.addAll(Set.of(fields));
- }
-}
diff --git a/src/main/java/nl/sander/beejava/apiv2/CodeContainer.java b/src/main/java/nl/sander/beejava/apiv2/CodeContainer.java
deleted file mode 100644
index 2a3829b..0000000
--- a/src/main/java/nl/sander/beejava/apiv2/CodeContainer.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package nl.sander.beejava.apiv2;
-
-import nl.sander.beejava.TypeMapper;
-import nl.sander.beejava.flags.MethodAccessFlag;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * parent of a constructor or a method.
- */
-public abstract class CodeContainer {
-
- protected final List code = new LinkedList<>();
- protected final Set formalParameters = new HashSet<>();
- protected final Set accessFlags = new HashSet<>();
- private BeeSource owner;
-
- public List getCode() {
- return code;
- }
-
- public String getSignature() {
- return getParametersSignature() + TypeMapper.map(getReturnType());
- }
-
- public abstract String getName();
-
- public abstract Class> getReturnType();
-
- private String getParametersSignature() {
- return formalParameters.stream()
- .map(BeeParameter::getType)
- .map(TypeMapper::map)
- .collect(Collectors.joining(",", "(", ")"));
- }
-
- public Set getAccessFlags() {
- return accessFlags;
- }
-
- public BeeSource getOwner() {
- return owner;
- }
-
- public void setOwner(BeeSource beeSource) {
- if (owner != null) {
- throw new IllegalStateException("Owner set twice. Sue the developer!");
- }
- this.owner = beeSource;
- }
-
- public abstract boolean isConstructor();
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- CodeContainer that = (CodeContainer) o;
- return formalParameters.equals(that.formalParameters);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(formalParameters);
- }
-}
diff --git a/src/main/java/nl/sander/beejava/apiv2/CodeLine.java b/src/main/java/nl/sander/beejava/apiv2/CodeLine.java
deleted file mode 100644
index f7de33f..0000000
--- a/src/main/java/nl/sander/beejava/apiv2/CodeLine.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package nl.sander.beejava.apiv2;
-
-
-public class CodeLine extends Instruction {
- private final Opcode opcode;
- private CodeContainer owner;
-
- public CodeLine(Opcode opcode, String operand) {
- super(operand);
- this.opcode = opcode;
- }
-
- public String getOperand() {
- return operand;
- }
-
- public Opcode getOpcode() {
- return opcode;
- }
-
- public void setOwner(CodeContainer owner) {
- this.owner = owner;
- }
-
- public CodeContainer getOwner() {
- return owner;
- }
-}
diff --git a/src/main/java/nl/sander/beejava/apiv2/Opcode.java b/src/main/java/nl/sander/beejava/apiv2/Opcode.java
deleted file mode 100644
index d2d1d20..0000000
--- a/src/main/java/nl/sander/beejava/apiv2/Opcode.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package nl.sander.beejava.apiv2;
-
-import java.util.Optional;
-
-public enum Opcode {
- LOAD,
- STORE,
- CONST,
- RETURN,
- ARRAYLENGTH,
- THROW,
- CAST,
- ADD,
- COMPARE,
- DIVIDE,
- MULTIPLY,
- NEGATE,
- REMAINDER,
- SUBTRACT,
- GET,
- GOTO,
- TO_DOUBLE,
- TO_INT,
- TO_LONG,
- TO_BYTE,
- TO_CHAR,
- TO_FLOAT,
- TO_SHORT,
- AND,
- IF_EQUAL,
- IF_NOT_EQUAL,
- IF_LESS_THAN,
- IF_GREATER_OR_EQUAL,
- IF_GREATER_THAN,
- IF_LESS_OR_EQUAL,
- IF_NOT_NULL,
- IF_NULL,
- INCREMENT,
- INSTANCEOF,
- INVOKE,
- OR,
- SHIFT_LEFT,
- SHIFT_RIGHT,
- LOGICAL_SHIFT_RIGHT,
- XOR,
- LOOKUPSWITCH,
- MONITORENTER,
- MONITOREXIT,
- NEW,
- NEWARRAY,
- MULTIANEWARRAY,
- PUT,
- SWAP,
- TABLESWITCH,
- WIDE;
-
- static Optional get(String text) {
- for (Opcode opcode : Opcode.values()) {
- if (opcode.toString().equals(text)) {
- return Optional.of(opcode);
- }
- }
- return Optional.empty();
- }
-}
diff --git a/src/main/java/nl/sander/beejava/classinfo/Info.java b/src/main/java/nl/sander/beejava/classinfo/Info.java
index 67a6a56..e114ce2 100644
--- a/src/main/java/nl/sander/beejava/classinfo/Info.java
+++ b/src/main/java/nl/sander/beejava/classinfo/Info.java
@@ -6,7 +6,7 @@ import nl.sander.beejava.constantpool.entry.Utf8Entry;
import java.util.HashSet;
import java.util.Set;
-public abstract class Info {
+public abstract class Info> {
protected final Utf8Entry nameEntry;
protected final Utf8Entry descriptorEntry;
diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantPoolEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantPoolEntry.java
index 0cced65..c399b72 100644
--- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantPoolEntry.java
+++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantPoolEntry.java
@@ -29,10 +29,19 @@ public abstract class ConstantPoolEntry {
return getBytes()[0];
}
+ /**
+ * The output of this ends up in the class file as the constantpool index of the entry.
+ *
+ * @return the cp index of the entry.
+ */
public int getIndex() {
return index;
}
+ /**
+ * With this the ConstantPoolCreator sets the calculated index.
+ * @param index the cp index to assign to the entry
+ */
public void setIndex(int index) {
this.index = index;
}
@@ -61,8 +70,20 @@ public abstract class ConstantPoolEntry {
return (byte) (u16 >>> 8);
}
- protected byte getByte(long bits, int positions) {
- return (byte) ((bits >>> (positions * 8)) & 0xFF);
+ /**
+ * get the Nth byte in an "array" of bits encoded in a long (i64). Used to create the stream representation of 64bit numbers
+ *
+ * @param bits a long in which a long or a double is encoded.
+ * @param position the index of the byte (0..7) in the array of bits
+ * @return the Nth byte in the long
+ */
+ protected byte getByte(long bits, int position) {
+ if (position > 0 && position < 8) {
+ return (byte) ((bits >>> (position * 8)) & 0xFF);
+ } else {
+ throw new IllegalArgumentException("position must be 0..7");
+ }
+
}
}
diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/FloatEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/FloatEntry.java
index aa55016..a88e16c 100644
--- a/src/main/java/nl/sander/beejava/constantpool/entry/FloatEntry.java
+++ b/src/main/java/nl/sander/beejava/constantpool/entry/FloatEntry.java
@@ -7,13 +7,17 @@ public class FloatEntry extends LeafEntry {
private final float floatVal;
+ public FloatEntry(String floatVal) {
+ this.floatVal = Float.parseFloat(floatVal);
+ }
+
public FloatEntry(float floatVal) {
this.floatVal = floatVal;
}
@Override
public String toString() {
- return "Float\t\t" +floatVal;
+ return "Float\t\t" + floatVal;
}
@Override
diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/IntegerEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/IntegerEntry.java
index f7b21b5..af195ee 100644
--- a/src/main/java/nl/sander/beejava/constantpool/entry/IntegerEntry.java
+++ b/src/main/java/nl/sander/beejava/constantpool/entry/IntegerEntry.java
@@ -7,8 +7,12 @@ public class IntegerEntry extends LeafEntry {
private final int intVal;
- public IntegerEntry(int integer) {
- this.intVal = integer;
+ public IntegerEntry(String integerVal) {
+ this.intVal = Integer.parseInt(integerVal);
+ }
+
+ public IntegerEntry(int integerVal) {
+ this.intVal = integerVal;
}
@Override
diff --git a/src/main/java/nl/sander/beejava/operands/ConstantOperand.java b/src/main/java/nl/sander/beejava/operands/ConstantOperand.java
new file mode 100644
index 0000000..599a63b
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/operands/ConstantOperand.java
@@ -0,0 +1,22 @@
+package nl.sander.beejava.operands;
+
+import nl.sander.beejava.Primitive;
+
+public class ConstantOperand extends Operand {
+ private final Primitive type;
+ private final String value;
+
+
+ public ConstantOperand(Primitive type, String value) {
+ this.type = type;
+ this.value = value;
+ }
+
+ public Primitive getType() {
+ return type;
+ }
+
+ public String getValue() {
+ return value;
+ }
+}
diff --git a/src/main/java/nl/sander/beejava/operands/FieldOperand.java b/src/main/java/nl/sander/beejava/operands/FieldOperand.java
new file mode 100644
index 0000000..ca183e0
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/operands/FieldOperand.java
@@ -0,0 +1,11 @@
+package nl.sander.beejava.operands;
+
+public class FieldOperand extends Operand{
+ public final String className;
+ public final String fieldName;
+
+ public FieldOperand(String className, String fieldName) {
+ this.className = className;
+ this.fieldName = fieldName;
+ }
+}
diff --git a/src/main/java/nl/sander/beejava/operands/LocalVariableOperand.java b/src/main/java/nl/sander/beejava/operands/LocalVariableOperand.java
new file mode 100644
index 0000000..a82bc0d
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/operands/LocalVariableOperand.java
@@ -0,0 +1,9 @@
+package nl.sander.beejava.operands;
+
+public class LocalVariableOperand extends Operand{
+ public final String name;
+
+ public LocalVariableOperand(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/nl/sander/beejava/operands/MethodOperand.java b/src/main/java/nl/sander/beejava/operands/MethodOperand.java
new file mode 100644
index 0000000..48151df
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/operands/MethodOperand.java
@@ -0,0 +1,22 @@
+package nl.sander.beejava.operands;
+
+public class MethodOperand extends Operand{
+ public final String className;
+ public final String methodName;
+ public final String signature;
+
+ public MethodOperand(String className, String methodName, String signature) {
+ this.className = className;
+ this.methodName = methodName;
+ this.signature = signature;
+ }
+
+ @Override
+ public String toString() {
+ return "MethodOperand{" +
+ "className='" + className + '\'' +
+ ", methodName='" + methodName + '\'' +
+ ", signature='" + signature + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/nl/sander/beejava/operands/Operand.java b/src/main/java/nl/sander/beejava/operands/Operand.java
new file mode 100644
index 0000000..28fa969
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/operands/Operand.java
@@ -0,0 +1,4 @@
+package nl.sander.beejava.operands;
+
+public abstract class Operand {
+}
diff --git a/src/main/java/nl/sander/beejava/operands/VoidOperand.java b/src/main/java/nl/sander/beejava/operands/VoidOperand.java
new file mode 100644
index 0000000..d0fd866
--- /dev/null
+++ b/src/main/java/nl/sander/beejava/operands/VoidOperand.java
@@ -0,0 +1,9 @@
+package nl.sander.beejava.operands;
+
+public class VoidOperand extends Operand{
+ public final static VoidOperand INSTANCE = new VoidOperand();
+
+ private VoidOperand() {
+ //
+ }
+}
diff --git a/src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java b/src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java
index 43ca295..1745856 100644
--- a/src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java
+++ b/src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java
@@ -24,6 +24,6 @@ public class BytecodeGeneratorTests {
@Test
public void testFields() throws ClassNotFoundException {
- BytecodeGenerator.generate(Compiler.compile(TestData.createClassWithField(int.class)));
+ BytecodeGenerator.generate(Compiler.compile(TestData.createClassWithField(Integer.class)));
}
}
diff --git a/src/test/java/nl/sander/beejava/SourceCompilerTest.java b/src/test/java/nl/sander/beejava/SourceCompilerTest.java
index 0a90911..4912e42 100644
--- a/src/test/java/nl/sander/beejava/SourceCompilerTest.java
+++ b/src/test/java/nl/sander/beejava/SourceCompilerTest.java
@@ -1,6 +1,9 @@
package nl.sander.beejava;
-import nl.sander.beejava.apiv2.*;
+import nl.sander.beejava.api.BeeField;
+import nl.sander.beejava.api.BeeMethod;
+import nl.sander.beejava.api.BeeParameter;
+import nl.sander.beejava.api.BeeSource;
import nl.sander.beejava.flags.AccessFlags;
import nl.sander.beejava.flags.ClassAccessFlags;
import nl.sander.beejava.flags.FieldAccessFlag;
@@ -20,11 +23,16 @@ public class SourceCompilerTest {
BeeSource beeSource = new SourceCompiler(TestData2.simpleBean).doCompile();
assertEquals("com.acme.SimpleBean", beeSource.getName());
assertEquals(ClassAccessFlags.SUPER.getBytecode() | ClassAccessFlags.PUBLIC.getBytecode(), AccessFlags.combine(beeSource.getAccessFlags()));
- assertTrue(beeSource.getFields().contains(new BeeField(Set.of(FieldAccessFlag.PRIVATE), int.class, "value")));
+ assertTrue(beeSource.getFields().contains(new BeeField(beeSource.getName(), Set.of(FieldAccessFlag.PRIVATE), int.class, "value")));
assertEquals(1, beeSource.getConstructors().size());
Set methods = beeSource.getMethods();
assertEquals(2, methods.size());
- assertTrue(methods.contains(new BeeMethod("getValue", Set.of(MethodAccessFlag.PUBLIC), Set.of(), int.class, List.of())));
- assertTrue(methods.contains(new BeeMethod("setValue", Set.of(MethodAccessFlag.PUBLIC), Set.of(new BeeParameter(int.class, "newValue")), Void.TYPE, List.of())));
+ assertTrue(methods.contains(new BeeMethod(beeSource, "getValue", Set.of(MethodAccessFlag.PUBLIC), Set.of(), int.class, List.of())));
+ assertTrue(methods.contains(new BeeMethod(beeSource, "setValue", Set.of(MethodAccessFlag.PUBLIC), Set.of(new BeeParameter(int.class, "newValue")), Void.TYPE, List.of())));
+
+ OpcodeTranslator.translate(beeSource);
+
+ Compiler.compile(beeSource);
+
}
}
diff --git a/src/test/java/nl/sander/beejava/TestData.java b/src/test/java/nl/sander/beejava/TestData.java
index 5879bb3..ff2c7b4 100644
--- a/src/test/java/nl/sander/beejava/TestData.java
+++ b/src/test/java/nl/sander/beejava/TestData.java
@@ -1,113 +1,38 @@
package nl.sander.beejava;
-import nl.sander.beejava.api.*;
-import nl.sander.beejava.flags.FieldAccessFlag;
-import nl.sander.beejava.flags.MethodAccessFlag;
-
-import java.io.Serializable;
-
-import static nl.sander.beejava.api.CodeLine.line;
-import static nl.sander.beejava.api.Opcode.*;
-import static nl.sander.beejava.flags.ClassAccessFlags.PUBLIC;
-import static nl.sander.beejava.flags.ClassAccessFlags.SUPER;
+import nl.sander.beejava.api.BeeSource;
public class TestData {
- public static BeeSource createEmptyClass() throws ClassNotFoundException {
- return BeeSource.builder()
- .withClassFileVersion(Version.V14)
- .withPackage("nl.sander.beejava.test")
- .withAccessFlags(PUBLIC, SUPER)
- .withSimpleName("EmptyBean")
- .withSuperClass(Object.class) // Not mandatory, like in java sourcecode
- .withConstructors(createDefaultConstructor()) // There's no default constructor in beejava. The user must always add them
- .build();
+ public static BeeSource createEmptyClass() {
+ return SourceCompiler.compile("""
+ class public nl.sander.beejava.test.EmptyBean
+ constructor public()
+ INVOKE this.super()
+ RETURN
+ """);
}
- public static BeeSource emptyClassWithInterface() throws ClassNotFoundException {
- return BeeSource.builder()
- .withClassFileVersion(Version.V14)
- .withPackage("nl.sander.beejava.test")
- .withAccessFlags(PUBLIC)
- .withSimpleName("EmptyBean")
- .withSuperClass(Object.class) // Not mandatory, like in java sourcecode
- .withInterfaces(Serializable.class)
- .withConstructors(createDefaultConstructor()) // There's no default constructor in beejava. The user must always add them
- .build();
+ public static BeeSource emptyClassWithInterface() {
+ return SourceCompiler.compile("""
+ class public nl.sander.beejava.test.EmptyBean implements java.io.Serializable
+ constructor public()
+ INVOKE this.super()V
+ RETURN
+ """);
}
- public static BeeSource createClassWithTwoReferencesToSomeClass() throws ClassNotFoundException {
- BeeMethod print1 = BeeMethod.builder()
- .withName("print1")
- .withAccessFlags(MethodAccessFlag.PUBLIC)
- .withCode(
- line(GET, "java.lang.System","out"),
- line(LD_CONST, "1"),
- line(INVOKE, "java.io.PrintStream", "println", "java.lang.String"),
- line(RETURN))
- .build();
+ public static BeeSource createClassWithField(Class> fieldType) {
+ String template = """
+ class com.acme.SimpleBean(V15)
+ field private %s field
+ constructor public(%s arg)
+ INVOKE this.super()V
+ LOAD arg
+ PUT this.field
+ RETURN
+ """;
-// INVOKE System.out.println("1")
-
-
- BeeMethod print2 = BeeMethod.builder()
- .withName("print2")
- .withAccessFlags(MethodAccessFlag.PUBLIC)
- .withCode(
- line(GET, "java.lang.System","out"),
- line(LD_CONST, "2"),
- line(INVOKE, "java.io.PrintStream", "println", "java.lang.String"),
- line(RETURN))
- .build();
-
- return BeeSource.builder()
- .withClassFileVersion(Version.V14)
- .withPackage("nl.sander.beejava.test")
- .withAccessFlags(PUBLIC, SUPER)
- .withSimpleName("ClassWithReferences")
- .withConstructors(createDefaultConstructor()) // There's no default constructor in beejava. The user must always add them
- .withMethods(print1, print2)
- .build();
+ return SourceCompiler.compile(String.format(template, fieldType.getName(), fieldType.getName()));
}
- public static BeeSource createClassWithField(Class> fieldType) throws ClassNotFoundException {
- BeeField field = BeeField.builder()
- .withAccessFlags(FieldAccessFlag.PRIVATE)
- .withType(fieldType)
- .withName("field")
- .build();
-
- BeeParameter parameter = BeeParameter.create(fieldType, "value");
-
- BeeConstructor constructor = BeeConstructor.builder()
- .withAccessFlags(MethodAccessFlag.PUBLIC)
- .withFormalParameters(parameter)
- .withCode(
- line(LD_VAR, Ref.THIS),
- line(INVOKE, Ref.SUPER, "", "()"),
- line(LD_VAR, Ref.THIS),
- line(LD_VAR, parameter),
- line(PUT, field),
- line(RETURN))
- .build();
-
- return BeeSource.builder()
- .withClassFileVersion(Version.V14)
- .withPackage("nl.sander.beejava.test")
- .withAccessFlags(PUBLIC)
- .withSimpleName("Bean")
- .withSuperClass(Object.class)
- .withFields(field)
- .withConstructors(constructor)
- .build();
- }
-
- public static BeeConstructor createDefaultConstructor() throws ClassNotFoundException {
- return BeeConstructor.builder()
- .withAccessFlags(MethodAccessFlag.PUBLIC)
- .withCode(
- line(LD_VAR, Ref.THIS),
- line(INVOKE, Ref.SUPER, "", "()"),
- line(RETURN))
- .build();
- }
}
diff --git a/src/test/java/nl/sander/beejava/TestData2.java b/src/test/java/nl/sander/beejava/TestData2.java
index 2961afd..82c5dd7 100644
--- a/src/test/java/nl/sander/beejava/TestData2.java
+++ b/src/test/java/nl/sander/beejava/TestData2.java
@@ -3,10 +3,10 @@ package nl.sander.beejava;
public class TestData2 {
public final static String simpleBean= """
- class com.acme.SimpleBean(V15)
+ class public com.acme.SimpleBean(V15)
field private int value
constructor public()
- INVOKE super()
+ INVOKE this.super()
RETURN
method public getValue() -> int
RETURN this.value
@@ -40,7 +40,7 @@ public class TestData2 {
String constructor_opcope = """
constructor nl.sander.beejava.Compiler(nl.sander.beejava.CompiledClass arg_0);
- INVOKE super()
+ INVOKE this.super()
NEW nl.sander.beejava.ConstantPoolCreator()
PUT this.constantPoolCreator
diff --git a/src/test/java/nl/sander/beejava/TypeMapperTest.java b/src/test/java/nl/sander/beejava/TypeMapperTest.java
index 519bc45..c877047 100644
--- a/src/test/java/nl/sander/beejava/TypeMapperTest.java
+++ b/src/test/java/nl/sander/beejava/TypeMapperTest.java
@@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.fail;
public class TypeMapperTest {
@Test
- public void test_int() throws ClassNotFoundException {
+ public void test_int() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(int.class);
@@ -24,7 +24,7 @@ public class TypeMapperTest {
}
@Test
- public void test_double() throws ClassNotFoundException {
+ public void test_double() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(double.class);
@@ -37,7 +37,7 @@ public class TypeMapperTest {
}
@Test
- public void test_float() throws ClassNotFoundException {
+ public void test_float() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(float.class);
@@ -50,7 +50,7 @@ public class TypeMapperTest {
}
@Test
- public void test_byte() throws ClassNotFoundException {
+ public void test_byte() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(byte.class);
@@ -63,7 +63,7 @@ public class TypeMapperTest {
}
@Test
- public void test_short() throws ClassNotFoundException {
+ public void test_short() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(short.class);
@@ -76,7 +76,7 @@ public class TypeMapperTest {
}
@Test
- public void test_long() throws ClassNotFoundException {
+ public void test_long() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(long.class);
@@ -89,7 +89,7 @@ public class TypeMapperTest {
}
@Test
- public void test_char() throws ClassNotFoundException {
+ public void test_char() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(char.class);
@@ -102,7 +102,7 @@ public class TypeMapperTest {
}
@Test
- public void test_boolean() throws ClassNotFoundException {
+ public void test_boolean() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(boolean.class);
@@ -115,7 +115,7 @@ public class TypeMapperTest {
}
@Test
- public void test_Object() throws ClassNotFoundException {
+ public void test_Object() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(Object.class);
@@ -128,7 +128,7 @@ public class TypeMapperTest {
}
@Test
- public void test_int_array() throws ClassNotFoundException {
+ public void test_int_array() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(int[].class);
@@ -141,7 +141,7 @@ public class TypeMapperTest {
}
@Test
- public void test_Object_array() throws ClassNotFoundException {
+ public void test_Object_array() {
// Arrange
BeeSource beeSource = TestData.createClassWithField(String[].class);
diff --git a/src/test/java/nl/sander/beejava/constantpool/entry/TagCorrectnessTest.java b/src/test/java/nl/sander/beejava/constantpool/entry/TagCorrectnessTest.java
index 6d4e606..90f3e1d 100644
--- a/src/test/java/nl/sander/beejava/constantpool/entry/TagCorrectnessTest.java
+++ b/src/test/java/nl/sander/beejava/constantpool/entry/TagCorrectnessTest.java
@@ -12,7 +12,7 @@ public class TagCorrectnessTest {
public void testSpec() {
assertEquals(1, utf8().getTag());
assertEquals(3, new IntegerEntry(0).getTag());
- assertEquals(4, new FloatEntry(0).getTag());
+ assertEquals(4, new FloatEntry(0F).getTag());
assertEquals(5, new LongEntry(0).getTag());
assertEquals(6, new DoubleEntry(0).getTag());
assertEquals(7, classEntry().getTag());
diff --git a/src/test/java/nl/sander/beejava/e2e/BeanWithMethodsTest.java b/src/test/java/nl/sander/beejava/e2e/BeanWithMethodsTest.java
index 905303f..ba6a6a2 100644
--- a/src/test/java/nl/sander/beejava/e2e/BeanWithMethodsTest.java
+++ b/src/test/java/nl/sander/beejava/e2e/BeanWithMethodsTest.java
@@ -1,9 +1,7 @@
package nl.sander.beejava.e2e;
-import nl.sander.beejava.BytecodeGenerator;
-import nl.sander.beejava.CompiledClass;
import nl.sander.beejava.Compiler;
-import nl.sander.beejava.TestData;
+import nl.sander.beejava.*;
import nl.sander.beejava.api.BeeSource;
import org.junit.jupiter.api.Test;
@@ -13,36 +11,52 @@ import java.lang.reflect.Modifier;
import static org.junit.jupiter.api.Assertions.*;
/**
- * A rather simple case, still meaningful nonetheless.
- * Green means class can be loaded, so the class file structure is valid.
- * The EmptyBean class just contains a default constructor.
+ * Proves ability to compile opcodes for GET, LOAD, INVOKE, RETURN.
+ * Secondly the usage of method refs, constants.
*/
public class BeanWithMethodsTest {
@Test
public void testEmptyBean() throws Exception {
// Arrange
- BeeSource emptyClass = TestData.createClassWithTwoReferencesToSomeClass();
+ BeeSource printer = SourceCompiler.compile("""
+ class nl.sander.beejava.test.ClassWithReferences
+ constructor public()
+ INVOKE this.super()V
+ RETURN
+ method public print1()
+ GET java.lang.System.out
+ LOAD "1"
+ INVOKE java/io/PrintStream.println(Ljava/lang/String;)V
+ RETURN
+ method public print2()
+ GET java.lang.System.out
+ LOAD int 2
+ INVOKE java/io/PrintStream.println(I)V
+ RETURN
+ """);
// Act
- CompiledClass compiledClass = Compiler.compile(emptyClass);
+ OpcodeTranslator.translate(printer);
+ CompiledClass compiledClass = Compiler.compile(printer);
byte[] bytecode = BytecodeGenerator.generate(compiledClass);
ByteClassLoader classLoader = new ByteClassLoader();
- classLoader.setByteCode("nl.sander.beejava.test.ClassWithReferences", bytecode);
+ String className = "nl.sander.beejava.test.ClassWithReferences";
+ classLoader.setByteCode(className, bytecode);
// Assert
- Class> classWithReferences = classLoader.loadClass("nl.sander.beejava.test.ClassWithReferences");
+ Class> classWithReferences = classLoader.loadClass(className);
assertNotNull(classWithReferences);
Method[] methods = classWithReferences.getDeclaredMethods();
assertEquals(2, methods.length);
assertEquals("print1", methods[0].getName());
assertTrue(Modifier.isPublic(methods[0].getModifiers()));
- assertEquals(0,methods[0].getParameterCount());
+ assertEquals(0, methods[0].getParameterCount());
assertEquals("print2", methods[1].getName()); // ordering may cause failures
assertTrue(Modifier.isPublic(methods[1].getModifiers()));
- assertEquals(0,methods[1].getParameterCount());
+ assertEquals(0, methods[1].getParameterCount());
}
}
diff --git a/src/test/java/nl/sander/beejava/e2e/EmptyBeanTest.java b/src/test/java/nl/sander/beejava/e2e/EmptyBeanTest.java
index d9e5e41..a26658e 100644
--- a/src/test/java/nl/sander/beejava/e2e/EmptyBeanTest.java
+++ b/src/test/java/nl/sander/beejava/e2e/EmptyBeanTest.java
@@ -1,37 +1,26 @@
package nl.sander.beejava.e2e;
-import nl.sander.beejava.BytecodeGenerator;
-import nl.sander.beejava.CompiledClass;
-import nl.sander.beejava.Compiler;
-import nl.sander.beejava.api.BeeConstructor;
-import nl.sander.beejava.api.BeeSource;
-import nl.sander.beejava.api.Ref;
-import nl.sander.beejava.api.Version;
-import nl.sander.beejava.flags.MethodAccessFlag;
+import nl.sander.beejava.OverallCompiler;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
-import static nl.sander.beejava.api.CodeLine.line;
-import static nl.sander.beejava.api.Opcode.*;
-import static nl.sander.beejava.flags.ClassAccessFlags.PUBLIC;
-import static nl.sander.beejava.flags.ClassAccessFlags.SUPER;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
- * A rather simple case, still meaningful nonetheless.
- * Green means class can be loaded, so the class file structure is valid.
- * The EmptyBean class just contains a default constructor.
+ * Hello world test for bejava. Proves ability to compile bejava-lang to valid bytecode.
*/
public class EmptyBeanTest {
@Test
public void testEmptyBean() throws Exception {
- // Arrange
- BeeSource emptyClass = createEmptyClass();
-
// Act
- CompiledClass compiledClass = Compiler.compile(emptyClass);
- byte[] bytecode = BytecodeGenerator.generate(compiledClass);
+ byte[] bytecode = OverallCompiler.compile("""
+ class public nl.sander.beejava.test.EmptyBean
+ constructor public()
+ INVOKE this.super()V
+ RETURN
+ """);
+
ByteClassLoader classLoader = new ByteClassLoader();
classLoader.setByteCode("nl.sander.beejava.test.EmptyBean", bytecode);
@@ -42,27 +31,5 @@ public class EmptyBeanTest {
Object instance = constructor.newInstance();
assertNotNull(instance);
-
- }
-
- private BeeSource createEmptyClass() throws ClassNotFoundException {
- return BeeSource.builder()
- .withClassFileVersion(Version.V14)
- .withPackage("nl.sander.beejava.test")
- .withAccessFlags(PUBLIC, SUPER)
- .withSimpleName("EmptyBean")
- .withSuperClass(Object.class) // Not mandatory, like in java sourcecode
- .withConstructors(createDefaultConstructor()) // There's no default constructor in beejava. The user must always add them
- .build();
- }
-
- private BeeConstructor createDefaultConstructor() throws ClassNotFoundException {
- return BeeConstructor.builder()
- .withAccessFlags(MethodAccessFlag.PUBLIC)
- .withCode(
- line(LD_VAR, Ref.THIS),
- line(INVOKE, Ref.SUPER, "", "()"),
- line(RETURN))
- .build();
}
}