mirror of
https://github.com/JonathanFleischmann/CompilerULTIMATE.git
synced 2024-12-28 17:28:03 +00:00
generate code for fields and constructor (without block tho)
This commit is contained in:
parent
a2fc1686b1
commit
a7eedbe98d
29
src/main/java/de/maishai/typedast/CodeGenUtils.java
Normal file
29
src/main/java/de/maishai/typedast/CodeGenUtils.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package de.maishai.typedast;
|
||||||
|
|
||||||
|
import de.maishai.typedast.typedclass.TypedParameter;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CodeGenUtils {
|
||||||
|
|
||||||
|
public static String generateDescriptor(List<TypedParameter> arguments, Type returnType) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append('(');
|
||||||
|
arguments.forEach(type -> builder.append(type.getType().getDescriptor()));
|
||||||
|
builder.append(')');
|
||||||
|
builder.append(returnType.getDescriptor());
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeClassfile(ClassWriter cw, String name) {
|
||||||
|
byte[] code = cw.toByteArray();
|
||||||
|
try {
|
||||||
|
java.io.FileOutputStream fos = new java.io.FileOutputStream("output/" + name + ".class");
|
||||||
|
fos.write(code);
|
||||||
|
fos.close();
|
||||||
|
} catch (java.io.IOException e) {
|
||||||
|
System.out.println("Error writing classfile: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,4 +25,14 @@ public class Type {
|
|||||||
return new Type(Kind.REFERENCE, reference);
|
return new Type(Kind.REFERENCE, reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDescriptor(){
|
||||||
|
return switch (kind) {
|
||||||
|
case INT -> "I";
|
||||||
|
case BOOL -> "Z";
|
||||||
|
case CHAR -> "C";
|
||||||
|
case VOID -> "V";
|
||||||
|
case REFERENCE -> "L" + reference + ";";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,19 @@ import lombok.Data;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class TypedBlock implements Node {
|
public class TypedBlock implements Node {
|
||||||
private List<TypedLocalVariable> vars;
|
private List<TypedLocalVariable> vars;
|
||||||
private List<Statement> stmts;
|
private List<Statement> stmts;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
||||||
Type typeOfLastStmt = Type.VOID;
|
Type typeOfLastStmt = Type.VOID;
|
||||||
for(TypedLocalVariable var : vars){
|
for (TypedLocalVariable var : vars) {
|
||||||
var.typeCheck(localVar, classes);
|
var.typeCheck(localVar, classes);
|
||||||
}
|
}
|
||||||
for(Statement stmt : stmts){
|
for (Statement stmt : stmts) {
|
||||||
stmt.typeCheck(localVar, classes);
|
stmt.typeCheck(localVar, classes);
|
||||||
typeOfLastStmt = stmt.typeCheck(localVar, classes);
|
typeOfLastStmt = stmt.typeCheck(localVar, classes);
|
||||||
}
|
}
|
||||||
@ -32,15 +34,15 @@ public class TypedBlock implements Node {
|
|||||||
Block untyped = (Block) unTypedAST;
|
Block untyped = (Block) unTypedAST;
|
||||||
TypedBlock typedBlock = new TypedBlock();
|
TypedBlock typedBlock = new TypedBlock();
|
||||||
|
|
||||||
for(LocalVariable var : untyped.vars()){
|
for (LocalVariable var : untyped.vars()) {
|
||||||
TypedLocalVariable typedVar = new TypedLocalVariable();
|
TypedLocalVariable typedVar = new TypedLocalVariable();
|
||||||
typedVar.convertToTypedAST(localVar, classes, var);
|
typedVar.convertToTypedAST(localVar, classes, var);
|
||||||
typedBlock.getVars().add(typedVar);
|
typedBlock.getVars().add(typedVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(de.maishai.ast.records.Statement stmt : untyped.stmts()){
|
for (de.maishai.ast.records.Statement stmt : untyped.stmts()) {
|
||||||
|
|
||||||
//TODO: Implement the conversion of the statements
|
//TODO: Implement the conversion of the statements
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package de.maishai.typedast.typedclass;
|
package de.maishai.typedast.typedclass;
|
||||||
|
|
||||||
|
import de.maishai.typedast.CodeGenUtils;
|
||||||
import de.maishai.typedast.Node;
|
import de.maishai.typedast.Node;
|
||||||
import de.maishai.typedast.Type;
|
import de.maishai.typedast.Type;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -23,14 +24,14 @@ public class TypedClass implements Node {
|
|||||||
@Override
|
@Override
|
||||||
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
||||||
|
|
||||||
if(classes.containsKey(typedId.getName())) {
|
if (classes.containsKey(typedId.getName())) {
|
||||||
throw new RuntimeException("Class " + typedId.getName() + " already exists");
|
throw new RuntimeException("Class " + typedId.getName() + " already exists");
|
||||||
}
|
}
|
||||||
classes.put(typedId.getName(), this);
|
classes.put(typedId.getName(), this);
|
||||||
for(TypedField field: typedFields) {
|
for (TypedField field : typedFields) {
|
||||||
field.typeCheck(localVar, classes);
|
field.typeCheck(localVar, classes);
|
||||||
}
|
}
|
||||||
for(TypedMethod typedMethod : typedMethods) {
|
for (TypedMethod typedMethod : typedMethods) {
|
||||||
typedMethod.typeCheck(localVar, classes);
|
typedMethod.typeCheck(localVar, classes);
|
||||||
}
|
}
|
||||||
return Type.REFERENCE(typedId.getName());
|
return Type.REFERENCE(typedId.getName());
|
||||||
@ -47,11 +48,15 @@ public class TypedClass implements Node {
|
|||||||
public Node convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) {
|
public Node convertToTypedAST(Map<String, Type> localVar, Map<String, TypedClass> classes, de.maishai.ast.records.Node unTypedAST) {
|
||||||
TypedClass typedClass = new TypedClass();
|
TypedClass typedClass = new TypedClass();
|
||||||
|
|
||||||
for (TypedField field: typedFields) {
|
for (TypedField field : typedFields) {
|
||||||
typedClass.getTypedFields().add((TypedField) field.convertToTypedAST(localVar, classes, unTypedAST));
|
typedClass.getTypedFields().add((TypedField) field.convertToTypedAST(localVar, classes, unTypedAST));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TypedMethod method: typedMethods) {
|
for (TypedConstructor constructor : typedConstructors) {
|
||||||
|
typedClass.getTypedConstructors().add((TypedConstructor) constructor.convertToTypedAST(localVar, classes, unTypedAST));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TypedMethod method : typedMethods) {
|
||||||
typedClass.getTypedMethods().add((TypedMethod) method.convertToTypedAST(localVar, classes, unTypedAST));
|
typedClass.getTypedMethods().add((TypedMethod) method.convertToTypedAST(localVar, classes, unTypedAST));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,34 +64,41 @@ public class TypedClass implements Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void codeGen() {
|
public void codeGen() {
|
||||||
ClassWriter cw = new ClassWriter( ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, typedId.getName(), null, "java/lang/Object", null);
|
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, typedId.getName(), null, "java/lang/Object", null);
|
||||||
for(TypedField field : typedFields) {
|
for (TypedField field : typedFields) {
|
||||||
//field.codeGen(cw);
|
field.codeGen(cw);
|
||||||
}
|
}
|
||||||
for(TypedMethod m: typedMethods) {
|
|
||||||
|
for (TypedConstructor constructor : typedConstructors) {
|
||||||
|
constructor.codeGen(cw);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TypedMethod m : typedMethods) {
|
||||||
//m.codeGen(cw);
|
//m.codeGen(cw);
|
||||||
}
|
}
|
||||||
writeClassfile(cw, typedId.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeClassfile(ClassWriter cw, String name) {
|
CodeGenUtils.writeClassfile(cw, typedId.getName());
|
||||||
byte[] code = cw.toByteArray();
|
|
||||||
try {
|
|
||||||
java.io.FileOutputStream fos = new java.io.FileOutputStream("output/" + name + ".class");
|
|
||||||
fos.write(code);
|
|
||||||
fos.close();
|
|
||||||
} catch (java.io.IOException e) {
|
|
||||||
System.out.println("Error writing classfile: " + e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
TypedClass c = new TypedClass();
|
TypedClass c = new TypedClass();
|
||||||
c.typedFields = new ArrayList<>();
|
c.typedId = new TypedId("SomeClass");
|
||||||
|
|
||||||
|
//Fields
|
||||||
|
TypedField f1 = new TypedField(new TypedId("someNumber"), Type.INT);
|
||||||
|
TypedField f2 = new TypedField(new TypedId("someChar"), Type.CHAR);
|
||||||
|
c.typedFields = List.of(f1, f2);
|
||||||
|
|
||||||
|
//Constructors
|
||||||
|
TypedConstructor constructor = new TypedConstructor(false, new TypedId("SomeClass"), new ArrayList<>(), new TypedBlock());
|
||||||
|
c.typedConstructors = List.of(constructor);
|
||||||
|
|
||||||
|
//Methods
|
||||||
c.typedMethods = new ArrayList<>();
|
c.typedMethods = new ArrayList<>();
|
||||||
c.typedId.setName("Test");
|
|
||||||
|
//codeGen
|
||||||
c.codeGen();
|
c.codeGen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,21 @@ package de.maishai.typedast.typedclass;
|
|||||||
import de.maishai.ast.records.Block;
|
import de.maishai.ast.records.Block;
|
||||||
import de.maishai.ast.records.Constructor;
|
import de.maishai.ast.records.Constructor;
|
||||||
import de.maishai.ast.records.Parameter;
|
import de.maishai.ast.records.Parameter;
|
||||||
|
import de.maishai.typedast.CodeGenUtils;
|
||||||
import de.maishai.typedast.Node;
|
import de.maishai.typedast.Node;
|
||||||
import de.maishai.typedast.Type;
|
import de.maishai.typedast.Type;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
public class TypedConstructor implements Node {
|
public class TypedConstructor implements Node {
|
||||||
|
|
||||||
@ -16,15 +25,16 @@ public class TypedConstructor implements Node {
|
|||||||
private TypedId typedId;
|
private TypedId typedId;
|
||||||
private List<TypedParameter> typedParameters;
|
private List<TypedParameter> typedParameters;
|
||||||
private TypedBlock typedBlock;
|
private TypedBlock typedBlock;
|
||||||
|
|
||||||
//constructor: PUBLIC? id '(' params? ')' block;
|
//constructor: PUBLIC? id '(' params? ')' block;
|
||||||
@Override
|
@Override
|
||||||
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
||||||
if(localVar.containsKey(typedId.getName())) {
|
if (localVar.containsKey(typedId.getName())) {
|
||||||
throw new RuntimeException("constructor already declared");
|
throw new RuntimeException("constructor already declared");
|
||||||
}
|
}
|
||||||
localVar.put(typedId.getName(), Type.VOID);
|
localVar.put(typedId.getName(), Type.VOID);
|
||||||
if(typedParameters != null){
|
if (typedParameters != null) {
|
||||||
for(TypedParameter param : typedParameters){
|
for (TypedParameter param : typedParameters) {
|
||||||
param.typeCheck(localVar, classes);
|
param.typeCheck(localVar, classes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,10 +48,10 @@ public class TypedConstructor implements Node {
|
|||||||
TypedConstructor typedConstructor = new TypedConstructor();
|
TypedConstructor typedConstructor = new TypedConstructor();
|
||||||
typedConstructor.setTypedId((TypedId) typedId.convertToTypedAST(localVar, classes, untyped.id()));
|
typedConstructor.setTypedId((TypedId) typedId.convertToTypedAST(localVar, classes, untyped.id()));
|
||||||
|
|
||||||
if(untyped.params().isEmpty()) {
|
if (untyped.params().isEmpty()) {
|
||||||
typedConstructor.setTypedParameters(null);
|
typedConstructor.setTypedParameters(null);
|
||||||
}else{
|
} else {
|
||||||
for(Parameter param : untyped.params()){
|
for (Parameter param : untyped.params()) {
|
||||||
TypedParameter typedParam = new TypedParameter();
|
TypedParameter typedParam = new TypedParameter();
|
||||||
typedParam.convertToTypedAST(localVar, classes, param);
|
typedParam.convertToTypedAST(localVar, classes, param);
|
||||||
typedConstructor.getTypedParameters().add(typedParam);
|
typedConstructor.getTypedParameters().add(typedParam);
|
||||||
@ -53,4 +63,22 @@ public class TypedConstructor implements Node {
|
|||||||
typedConstructor.setTypedBlock(typedBlock);
|
typedConstructor.setTypedBlock(typedBlock);
|
||||||
return typedConstructor;
|
return typedConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void codeGen(ClassWriter cw) {
|
||||||
|
int accessModifier = Opcodes.ACC_PUBLIC; // ist laut Andi ok
|
||||||
|
MethodVisitor mv = cw.visitMethod(accessModifier, "<init>", CodeGenUtils.generateDescriptor(typedParameters, Type.VOID), null, null);
|
||||||
|
mv.visitCode();
|
||||||
|
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
|
|
||||||
|
//super();
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||||
|
|
||||||
|
//TODO: deal with block
|
||||||
|
|
||||||
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
|
|
||||||
|
mv.visitMaxs(0, 0);
|
||||||
|
mv.visitEnd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,16 @@ import de.maishai.ast.records.Field;
|
|||||||
import de.maishai.typedast.Node;
|
import de.maishai.typedast.Node;
|
||||||
import de.maishai.typedast.Type;
|
import de.maishai.typedast.Type;
|
||||||
import de.maishai.typedast.TypeMapper;
|
import de.maishai.typedast.TypeMapper;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@RequiredArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
public class TypedField implements Node {
|
public class TypedField implements Node {
|
||||||
private TypedId typedId;
|
private TypedId typedId;
|
||||||
@ -15,7 +21,7 @@ public class TypedField implements Node {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
||||||
if(localVar.containsKey(typedId.getName())){
|
if (localVar.containsKey(typedId.getName())) {
|
||||||
throw new RuntimeException("Variable " + typedId.getName() + " already declared");
|
throw new RuntimeException("Variable " + typedId.getName() + " already declared");
|
||||||
}
|
}
|
||||||
localVar.put(typedId.getName(), type);
|
localVar.put(typedId.getName(), type);
|
||||||
@ -32,5 +38,8 @@ public class TypedField implements Node {
|
|||||||
return typedField;
|
return typedField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void codeGen(ClassWriter cw) {
|
||||||
|
int access = Opcodes.ACC_PUBLIC; // laut Andi ist es ok, dass alle Felder public sind
|
||||||
|
cw.visitField(access, typedId.getName(), type.getDescriptor(), null, null).visitEnd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ public class TypedId implements Expression {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
||||||
if(!localVar.containsKey(name)){
|
if (!localVar.containsKey(name)) {
|
||||||
throw new RuntimeException("Variable " + name + " not declared or not found");
|
throw new RuntimeException("Variable " + name + " not declared or not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,11 @@ package de.maishai.typedast.typedclass;
|
|||||||
import de.maishai.typedast.Node;
|
import de.maishai.typedast.Node;
|
||||||
import de.maishai.typedast.Type;
|
import de.maishai.typedast.Type;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
public class TypedParameter implements Node {
|
public class TypedParameter implements Node {
|
||||||
private TypedId typedId;
|
private TypedId typedId;
|
||||||
@ -13,7 +15,7 @@ public class TypedParameter implements Node {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
public Type typeCheck(Map<String, Type> localVar, Map<String, TypedClass> classes) {
|
||||||
if(localVar.containsKey(typedId.getName())) {
|
if (localVar.containsKey(typedId.getName())) {
|
||||||
throw new RuntimeException("Parameter " + typedId.getName() + " already exists");
|
throw new RuntimeException("Parameter " + typedId.getName() + " already exists");
|
||||||
}
|
}
|
||||||
localVar.put(typedId.getName(), type);
|
localVar.put(typedId.getName(), type);
|
||||||
|
Loading…
Reference in New Issue
Block a user