generate code for fields and constructor (without block tho)

This commit is contained in:
404Simon 2024-05-07 21:44:13 +02:00
parent a2fc1686b1
commit a7eedbe98d
8 changed files with 129 additions and 37 deletions

View 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);
}
}
}

View File

@ -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 + ";";
};
}
} }

View File

@ -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;
} }

View File

@ -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();
} }
} }

View File

@ -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();
}
} }

View File

@ -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();
}
} }

View File

@ -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");
} }

View File

@ -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);