Added support for methods
This commit is contained in:
parent
321182aca7
commit
10ffe459e0
7 changed files with 230 additions and 40 deletions
|
|
@ -34,6 +34,7 @@ public class Compiler {
|
|||
|
||||
CompiledClass compile() {
|
||||
compiledClass.getBeeClass().getConstructors().forEach(this::updateConstantPool);
|
||||
compiledClass.getBeeClass().getMethods().forEach(this::updateConstantPool);
|
||||
// TODO update constant pool for fields ?
|
||||
// TODO update constant pool for methods
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ public class Compiler {
|
|||
}
|
||||
|
||||
|
||||
private void updateConstantPool(ContainsCode codeContainer) {
|
||||
private void updateConstantPool(CodeContainer codeContainer) {
|
||||
codeContainer.getCode().forEach(this::updateConstantPool);
|
||||
}
|
||||
|
||||
|
|
@ -59,12 +60,16 @@ public class Compiler {
|
|||
* So Compiled class also contains a set of unique root nodes.
|
||||
*/
|
||||
private void updateConstantPool(CodeLine codeline) {
|
||||
if (codeline.hasMethod()) {
|
||||
if (codeline.hasMethodCall()) {
|
||||
compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateMethodRefEntry(codeline));
|
||||
}
|
||||
|
||||
if (codeline.hasField()) {
|
||||
if (codeline.hasRefToOwnField() || codeline.hasRefToExternalField()) {
|
||||
compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateFieldRefEntry(codeline));
|
||||
}
|
||||
|
||||
if (codeline.hasConstValue()) {
|
||||
compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreatePrimitiveEntry(codeline));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
import nl.sander.beejava.api.BeeClass;
|
||||
import nl.sander.beejava.api.CodeLine;
|
||||
import nl.sander.beejava.api.Ref;
|
||||
import nl.sander.beejava.constantpool.entry.*;
|
||||
|
|
@ -31,7 +30,16 @@ class ConstantPoolEntryCreator {
|
|||
}
|
||||
|
||||
private NameAndTypeEntry createFieldNameAndType(CodeLine codeline) {
|
||||
return cache(new NameAndTypeEntry(cache(new Utf8Entry(codeline.getField().getName())), cache(new Utf8Entry(TypeMapper.map(codeline.getField().getType())))));
|
||||
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 {
|
||||
return cache(new NameAndTypeEntry(
|
||||
cache(new Utf8Entry(codeline.getExternalfield())),
|
||||
cache(new Utf8Entry("L" + codeline.getExternalfieldClass()))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private NameAndTypeEntry getOrCreateMethodNameAndType(CodeLine codeline) {
|
||||
|
|
@ -41,6 +49,7 @@ class ConstantPoolEntryCreator {
|
|||
}
|
||||
|
||||
private ClassEntry getOrCreateClassEntry(CodeLine codeline) {
|
||||
if (codeline.hasRef()) {
|
||||
if (codeline.getRef() == Ref.SUPER) { //this and super are rather special
|
||||
ClassEntry superClass = getClassEntry(compiledClass.getBeeClass().getSuperClass().getName());
|
||||
compiledClass.setSuperClass(superClass);
|
||||
|
|
@ -50,12 +59,16 @@ class ConstantPoolEntryCreator {
|
|||
addThisClass();
|
||||
return compiledClass.getThisClass();
|
||||
}
|
||||
//TODO other cases
|
||||
} else if (codeline.hasClassName()) {
|
||||
return getClassEntry(codeline.getClassName());
|
||||
}
|
||||
|
||||
throw new RuntimeException("shouldn't be here");
|
||||
}
|
||||
|
||||
void addThisClass(){
|
||||
void addThisClass() {
|
||||
ClassEntry classEntry = getClassEntry(compiledClass.getBeeClass().getName());
|
||||
compiledClass.addConstantPoolEntry(classEntry);
|
||||
compiledClass.setThisClass(classEntry);
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +84,22 @@ class ConstantPoolEntryCreator {
|
|||
});
|
||||
}
|
||||
|
||||
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 RuntimeException(); // TODO find out why are you here
|
||||
}
|
||||
|
||||
public void addFields() {
|
||||
compiledClass.getBeeClass().getFields().forEach(field -> {
|
||||
|
|
@ -88,9 +116,11 @@ class ConstantPoolEntryCreator {
|
|||
// First create an object using the supplier, but if it's found in cache, return the cached entry and discard the first.
|
||||
// Can't check for equality unless you create a potential new entry first
|
||||
int hash = newEntry.hashCode();
|
||||
return (T) cache.computeIfAbsent(hash, k -> newEntry);
|
||||
T a = (T) cache.computeIfAbsent(hash, k -> newEntry);
|
||||
return a;
|
||||
// a hashmap with key hash of value is weird right?
|
||||
// A HashSet is a HashMap with entry: key = value, which would work, but I cannot _get_ anything from a set.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package nl.sander.beejava.api;
|
|||
|
||||
import nl.sander.beejava.flags.ClassAccessFlag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
|
@ -15,10 +16,11 @@ public class BeeClass {
|
|||
private final Set<Class<?>> interfaces = new HashSet<>();
|
||||
private final Set<BeeField> fields = new HashSet<>();
|
||||
private final Set<BeeConstructor> constructors = new HashSet<>();
|
||||
private final Set<BeeMethod> methods = new HashSet<>();
|
||||
|
||||
private BeeClass(Version classFileVersion,
|
||||
BeePackage beePackage, Set<ClassAccessFlag> accessFlags, String simpleName, Class<?> superClass,
|
||||
Set<Class<?>> interfaces, Set<BeeField> fields, Set<BeeConstructor> constructors) {
|
||||
Set<Class<?>> interfaces, Set<BeeField> fields, Set<BeeConstructor> constructors, Set<BeeMethod> methods) {
|
||||
this.classFileVersion = classFileVersion;
|
||||
this.beePackage = beePackage;
|
||||
this.accessFlags.addAll(accessFlags);
|
||||
|
|
@ -27,6 +29,7 @@ public class BeeClass {
|
|||
this.interfaces.addAll(interfaces);
|
||||
this.fields.addAll(fields);
|
||||
this.constructors.addAll(constructors);
|
||||
this.methods.addAll(methods);
|
||||
}
|
||||
|
||||
public static BeeClass.Builder builder() {
|
||||
|
|
@ -52,6 +55,10 @@ public class BeeClass {
|
|||
return constructors;
|
||||
}
|
||||
|
||||
public Set<BeeMethod> getMethods() {
|
||||
return methods;
|
||||
}
|
||||
|
||||
public Set<ClassAccessFlag> getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
|
@ -79,11 +86,12 @@ public class BeeClass {
|
|||
private final Set<ClassAccessFlag> accessFlags = new HashSet<>();
|
||||
private final Set<Class<?>> interfaces = new HashSet<>();
|
||||
private final Set<BeeField> fields = new HashSet<>();
|
||||
private final Set<BeeConstructor> constructors = new HashSet<>();
|
||||
private Version version;
|
||||
private BeePackage beePackage;
|
||||
private Class<?> superClass = Object.class;
|
||||
private String simpleName;
|
||||
private final Set<BeeConstructor> constructors = new HashSet<>();
|
||||
private final Set<BeeMethod> methods = new HashSet<>();
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
|
@ -128,10 +136,14 @@ public class BeeClass {
|
|||
return this;
|
||||
}
|
||||
|
||||
public BeeClass build() {
|
||||
return new BeeClass(version, beePackage, accessFlags, simpleName, superClass, interfaces, fields, constructors);
|
||||
public Builder withMethods(BeeMethod... methods) {
|
||||
this.methods.addAll(Arrays.asList(methods));
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeeClass build() {
|
||||
return new BeeClass(version, beePackage, accessFlags, simpleName, superClass, interfaces, fields, constructors, methods);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package nl.sander.beejava.api;
|
||||
|
||||
import nl.sander.beejava.ContainsCode;
|
||||
import nl.sander.beejava.CodeContainer;
|
||||
import nl.sander.beejava.flags.MethodAccessFlag;
|
||||
|
||||
import java.util.*;
|
||||
|
|
@ -8,17 +8,16 @@ import java.util.*;
|
|||
/**
|
||||
* Models a constructor
|
||||
*/
|
||||
public class BeeConstructor implements ContainsCode {
|
||||
public class BeeConstructor extends CodeContainer {
|
||||
private final Set<MethodAccessFlag> accessFlags = new HashSet<>();
|
||||
private final Set<BeeParameter> formalParameters = new HashSet<>();
|
||||
private final List<CodeLine> code = new LinkedList<>();
|
||||
|
||||
private BeeConstructor(Set<MethodAccessFlag> accessFlags,
|
||||
List<BeeParameter> formalParameters,
|
||||
List<CodeLine> code) {
|
||||
this.formalParameters.addAll(formalParameters);
|
||||
this.accessFlags.addAll(accessFlags);
|
||||
this.code.addAll(code);
|
||||
super.code.addAll(code);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
|
|
@ -33,11 +32,6 @@ public class BeeConstructor implements ContainsCode {
|
|||
return formalParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CodeLine> getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BeeConstructor{" +
|
||||
|
|
|
|||
59
src/main/java/nl/sander/beejava/api/BeeMethod.java
Normal file
59
src/main/java/nl/sander/beejava/api/BeeMethod.java
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package nl.sander.beejava.api;
|
||||
|
||||
import nl.sander.beejava.CodeContainer;
|
||||
import nl.sander.beejava.flags.MethodAccessFlag;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public final class BeeMethod extends CodeContainer {
|
||||
private final Set<MethodAccessFlag> accessFlags = new HashSet<>();
|
||||
private final Set<BeeParameter> formalParameters = new HashSet<>();
|
||||
private final Class<?> returnType;
|
||||
|
||||
private BeeMethod(Set<MethodAccessFlag> accessFlags,
|
||||
List<BeeParameter> formalParameters,
|
||||
Class<?> returnType, List<CodeLine> code) {
|
||||
this.accessFlags.addAll(accessFlags);
|
||||
this.formalParameters.addAll(formalParameters);
|
||||
this.returnType = returnType;
|
||||
super.code.addAll(code);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final Set<MethodAccessFlag> accessFlags = new HashSet<>();
|
||||
private final List<BeeParameter> formalParameters = new LinkedList<>();
|
||||
private final List<CodeLine> code = new LinkedList<>();
|
||||
private Class<?> returnType;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
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() {
|
||||
return new BeeMethod(accessFlags, formalParameters, returnType, code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,10 +6,15 @@ public class CodeLine {
|
|||
private final Opcode opcode;
|
||||
private Ref ref;
|
||||
private BeeParameter parameter;
|
||||
private String className;
|
||||
private String methodName;
|
||||
private String inputSignature;
|
||||
private String outputSignature;
|
||||
private BeeField field;
|
||||
private BeeField ownfield; // when you create a class with a field, you can refer to it
|
||||
private String externalfield; // when you refer to a field from another class
|
||||
|
||||
private Object constValue;
|
||||
private String externalFieldType;
|
||||
|
||||
CodeLine(int linenumber, Opcode opcode) {
|
||||
this.linenumber = linenumber;
|
||||
|
|
@ -20,6 +25,18 @@ public class CodeLine {
|
|||
return new CodeLine(nr, opcode).withRef(ref);
|
||||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode, String fieldClass, String fieldName) {
|
||||
return new CodeLine(nr, opcode).withExternalFieldRef(fieldClass, fieldName);
|
||||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode, Object constValue) {
|
||||
return new CodeLine(nr, opcode).withConstValue(constValue);
|
||||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode, String className, String methodName, String inputSignature) {
|
||||
return new CodeLine(nr, opcode).withClassName(className).withMethodName(methodName).withInput(inputSignature).withVoidOutput();
|
||||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode, Ref ref, String methodNameRef, String inputSignature) {
|
||||
return new CodeLine(nr, opcode).withRef(ref).withMethodName(methodNameRef).withInput(inputSignature).withVoidOutput();
|
||||
}
|
||||
|
|
@ -37,7 +54,7 @@ public class CodeLine {
|
|||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode, BeeField intField) {
|
||||
return new CodeLine(nr, opcode).withRef(Ref.THIS).withField(intField);
|
||||
return new CodeLine(nr, opcode).withRef(Ref.THIS).withOwnField(intField);
|
||||
}
|
||||
|
||||
private CodeLine withRef(Ref ref) {
|
||||
|
|
@ -45,6 +62,11 @@ public class CodeLine {
|
|||
return this;
|
||||
}
|
||||
|
||||
private CodeLine withClassName(String className) {
|
||||
this.className = className;
|
||||
return this;
|
||||
}
|
||||
|
||||
private CodeLine withMethodName(String methodName) {
|
||||
this.methodName = methodName;
|
||||
return this;
|
||||
|
|
@ -69,16 +91,57 @@ public class CodeLine {
|
|||
return this;
|
||||
}
|
||||
|
||||
private CodeLine withField(BeeField field) {
|
||||
this.field = field;
|
||||
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.className = className;
|
||||
this.externalFieldType = getType(className, field);
|
||||
this.externalfield = 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 String getType(String className, String field) {
|
||||
try {
|
||||
return Class.forName(className).getField(field).getType().getName();
|
||||
} catch (ClassNotFoundException | NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasClassName() {
|
||||
return className != null;
|
||||
}
|
||||
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
public boolean hasMethod() {
|
||||
public boolean hasMethodCall() {
|
||||
return methodName != null;
|
||||
}
|
||||
|
||||
|
|
@ -94,12 +157,21 @@ public class CodeLine {
|
|||
return ref != null;
|
||||
}
|
||||
|
||||
public boolean hasField() {
|
||||
return field != null;
|
||||
public boolean hasRefToOwnField() {
|
||||
return ownfield != null;
|
||||
}
|
||||
|
||||
public BeeField getField() {
|
||||
return field;
|
||||
|
||||
public Object getConstValue() {
|
||||
return constValue;
|
||||
}
|
||||
|
||||
public boolean hasConstValue() {
|
||||
return constValue != null;
|
||||
}
|
||||
|
||||
public BeeField getOwnfield() {
|
||||
return ownfield;
|
||||
}
|
||||
|
||||
public BeeParameter getParameter() {
|
||||
|
|
@ -107,4 +179,15 @@ public class CodeLine {
|
|||
}
|
||||
|
||||
|
||||
public boolean hasRefToExternalField() {
|
||||
return externalfield != null;
|
||||
}
|
||||
|
||||
public String getExternalfield() {
|
||||
return externalfield;
|
||||
}
|
||||
|
||||
public String getExternalfieldClass() {
|
||||
return externalFieldType;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
package nl.sander.beejava.testclasses;
|
||||
|
||||
// two references to System. System should not be in the constant pool twice.
|
||||
public class BeanWithClassReferences {
|
||||
|
||||
public void print1(){
|
||||
public void print1() {
|
||||
System.out.println("1");
|
||||
}
|
||||
|
||||
public void print2(){
|
||||
System.out.println("2");
|
||||
public void print2() {
|
||||
System.out.println(create2());
|
||||
}
|
||||
|
||||
public String create2() {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append("2");
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue