Merge branch '24-structs' into 'master'
Resolve "Structs" Closes #24 See merge request mkais001/klang!17
This commit is contained in:
@@ -8,6 +8,8 @@ import de.hsrm.compiler.Klang.nodes.Block;
|
||||
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
|
||||
import de.hsrm.compiler.Klang.nodes.Parameter;
|
||||
import de.hsrm.compiler.Klang.nodes.Program;
|
||||
import de.hsrm.compiler.Klang.nodes.StructDefinition;
|
||||
import de.hsrm.compiler.Klang.nodes.StructField;
|
||||
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.ForLoop;
|
||||
@@ -18,7 +20,13 @@ import de.hsrm.compiler.Klang.types.Type;
|
||||
public class EvalVisitor implements Visitor<Value> {
|
||||
|
||||
Map<String, FunctionDefinition> funcs = new HashMap<>();
|
||||
Map<String, StructDefinition> structs;
|
||||
Map<String, Value> env = new HashMap<>();
|
||||
Map<String, Map<String, Value>> heap = new HashMap<>();
|
||||
|
||||
public EvalVisitor(Map<String, StructDefinition> structs) {
|
||||
this.structs = structs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(IntegerExpression e) {
|
||||
@@ -463,4 +471,70 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(StructDefinition e) {
|
||||
// We get these from a previous visitor
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(StructField e) {
|
||||
// Nothing to do here...
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(StructFieldAccessExpression e) {
|
||||
Value var = this.env.get(e.varName);
|
||||
Map<String, Value> struct = var.asStruct();
|
||||
|
||||
Value currentValue = struct.get(e.path[0]);
|
||||
for (int i = 1; i < e.path.length; i++) {
|
||||
currentValue = currentValue.asStruct().get(e.path[i]);
|
||||
}
|
||||
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(ConstructorCall e) {
|
||||
StructDefinition structDef = this.structs.get(e.structName);
|
||||
Map<String, Value> struct = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < e.args.length; i++) {
|
||||
var arg = e.args[i].welcome(this);
|
||||
struct.put(structDef.fields[i].name, arg);
|
||||
}
|
||||
|
||||
return new Value(struct);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(NullExpression e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(DestructorCall e) {
|
||||
this.env.remove(e.name);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value visit(FieldAssignment e) {
|
||||
Value val = this.env.get(e.varName);
|
||||
String fieldNameToUpdate = e.path[e.path.length - 1];
|
||||
|
||||
// Find the struct that holds the field to be updated
|
||||
Map<String, Value> struct = val.asStruct();
|
||||
for (int i = 0; i < e.path.length - 1; i++) {
|
||||
struct = struct.get(e.path[i]).asStruct();
|
||||
}
|
||||
|
||||
// if we are here, struct contains a reference to the struct that holds the field to be updated
|
||||
struct.put(fieldNameToUpdate, e.expression.welcome(this));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import de.hsrm.compiler.Klang.helper.Helper;
|
||||
import de.hsrm.compiler.Klang.nodes.*;
|
||||
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop;
|
||||
@@ -107,6 +108,7 @@ public class GenASM implements Visitor<Void> {
|
||||
private FloatWriter fw = new FloatWriter();
|
||||
private String mainName;
|
||||
Map<String, Integer> env = new HashMap<>();
|
||||
Map<String, StructDefinition> structs;
|
||||
Set<String> vars;
|
||||
String[] registers = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" };
|
||||
String[] floatRegisters = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
|
||||
@@ -147,14 +149,15 @@ public class GenASM implements Visitor<Void> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public GenASM(ExWriter ex, String mainName) {
|
||||
|
||||
public GenASM(ExWriter ex, String mainName, Map<String, StructDefinition> structs) {
|
||||
this.ex = ex;
|
||||
this.mainName = mainName;
|
||||
this.structs = structs;
|
||||
}
|
||||
|
||||
public GenASM(ExWriter ex) {
|
||||
this.ex = ex;
|
||||
this.mainName = "main";
|
||||
public GenASM(ExWriter ex, Map<String, StructDefinition> structs) {
|
||||
this(ex, "main", structs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -790,4 +793,115 @@ public class GenASM implements Visitor<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructDefinition e) {
|
||||
// We get these from a previous visitor
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructField e) {
|
||||
// Nothing to do here...
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructFieldAccessExpression e) {
|
||||
var structDef = this.structs.get(e.structName);
|
||||
int offset = this.env.get(e.varName);
|
||||
|
||||
// move struct address into rax
|
||||
this.ex.write(" movq " + offset + "(%rbp), %rax\n");
|
||||
|
||||
// "follow" the first path element by moving the referenced value into rax
|
||||
this.ex.write(" movq " + Helper.getFieldOffset(structDef, e.path[0]) + "(%rax), %rax\n");
|
||||
for (int i = 1; i < e.path.length; i++) {
|
||||
// "follow" the current path element
|
||||
structDef = this.structs.get(structDef.fields[Helper.getFieldIndex(structDef, e.path[i - 1])].type.getName());
|
||||
this.ex.write(" movq " + Helper.getFieldOffset(structDef, e.path[i]) + "(%rax), %rax\n");
|
||||
}
|
||||
|
||||
// desired value now in rax
|
||||
|
||||
// push rax to xmm0 if the result type is a float
|
||||
if (e.type.equals(Type.getFloatType())) {
|
||||
this.ex.write(" movq %rax, %xmm0\n");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ConstructorCall e) {
|
||||
// push arguments onto the stack
|
||||
for (var arg: e.args) {
|
||||
arg.welcome(this);
|
||||
|
||||
// move float values from xmm0 to rax first
|
||||
if (arg.type.equals(Type.getFloatType())) {
|
||||
this.ex.write(" movq %xmm0, %rax\n");
|
||||
}
|
||||
|
||||
this.ex.write(" pushq %rax\n");
|
||||
}
|
||||
|
||||
// allocate heap memory by calling malloc
|
||||
var structDef = this.structs.get(e.structName);
|
||||
this.ex.write(" movl $" + Helper.getFieldSizeBytes(structDef) + ", %edi\n");
|
||||
this.ex.write(" call malloc@PLT\n"); // struct address now in rax
|
||||
|
||||
// push args into struct memory, last arg is ontop of the stack
|
||||
for (int i = e.args.length - 1; i >= 0; i--) {
|
||||
this.ex.write(" popq " + Helper.getFieldOffset(structDef, i) + "(%rax)\n");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(NullExpression e) {
|
||||
this.ex.write(" movq $0, %rax\n");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(DestructorCall e) {
|
||||
this.ex.write(" movq " +this.env.get(e.name) + "(%rbp), %rdi\n");
|
||||
this.ex.write(" call free@PLT\n");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(FieldAssignment e) {
|
||||
var structDef = this.structs.get(e.structName);
|
||||
int offset = this.env.get(e.varName);
|
||||
String fieldNameToUpdate = e.path[e.path.length - 1];
|
||||
|
||||
e.expression.welcome(this);
|
||||
|
||||
// Move it from xmm0 rax if its a flaot
|
||||
if (e.expression.type.equals(Type.getFloatType())) {
|
||||
this.ex.write(" movq %xmm0, %rax\n");
|
||||
}
|
||||
|
||||
// Push the expression onto the stack
|
||||
this.ex.write(" pushq %rax\n");
|
||||
|
||||
// move struct address into rax
|
||||
this.ex.write(" movq " + offset + "(%rbp), %rax\n");
|
||||
|
||||
// If there are at least two elements in the path,
|
||||
// move the address of the next referenced struct into rax
|
||||
for (int i = 1; i < e.path.length - 1; i++) {
|
||||
structDef = this.structs.get(structDef.fields[Helper.getFieldIndex(structDef, e.path[i - 1])].type.getName());
|
||||
this.ex.write(" movq " + Helper.getFieldOffset(structDef, e.path[i]) + "(%rax), %rax\n");
|
||||
}
|
||||
|
||||
// pop the expression that is ontop of the stack into the field of the struct that has to be updated
|
||||
this.ex.write(" popq " + Helper.getFieldOffset(structDef, fieldNameToUpdate) + "(%rax)\n");
|
||||
this.ex.write(" movq $0, %rax\n"); // clear rax sind an assignment has no result
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -234,4 +234,38 @@ class GetVars implements Visitor<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructDefinition e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructField e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructFieldAccessExpression e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ConstructorCall e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(NullExpression e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(DestructorCall e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(FieldAssignment e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,13 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
ex.nl();
|
||||
ex.nl();
|
||||
}
|
||||
|
||||
for (var structDef: e.structs.values()) {
|
||||
structDef.welcome(this);
|
||||
ex.nl();
|
||||
ex.nl();
|
||||
}
|
||||
|
||||
e.expression.welcome(this);
|
||||
ex.write(";");
|
||||
return null;
|
||||
@@ -370,4 +377,76 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructDefinition e) {
|
||||
ex.write("struct " + e.name + " {");
|
||||
ex.addIndent();
|
||||
for(var field: e.fields) {
|
||||
ex.nl();
|
||||
field.welcome(this);
|
||||
}
|
||||
ex.subIndent();
|
||||
ex.nl();
|
||||
ex.write("}");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructField e) {
|
||||
ex.write(e.name +": " + e.type.getName() + ";");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(StructFieldAccessExpression e) {
|
||||
ex.write(e.varName);
|
||||
for (int i = 0; i < e.path.length; i++) {
|
||||
ex.write(".");
|
||||
ex.write(e.path[i]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ConstructorCall e) {
|
||||
ex.write("create " + e.structName + "(");
|
||||
boolean first = true;
|
||||
for (Expression arg : e.args) {
|
||||
if (!first) {
|
||||
ex.write(", ");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
arg.welcome(this);
|
||||
}
|
||||
ex.write(")");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(NullExpression e) {
|
||||
ex.write("null");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(DestructorCall e) {
|
||||
ex.write("destroy " + e.name + ";");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(FieldAssignment e) {
|
||||
ex.write(e.varName);
|
||||
for (int i = 0; i < e.path.length; i++) {
|
||||
ex.write(".");
|
||||
ex.write(e.path[i]);
|
||||
}
|
||||
ex.write(" = ");
|
||||
e.expression.welcome(this);
|
||||
ex.write(";");
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import de.hsrm.compiler.Klang.nodes.Block;
|
||||
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
|
||||
import de.hsrm.compiler.Klang.nodes.Parameter;
|
||||
import de.hsrm.compiler.Klang.nodes.Program;
|
||||
import de.hsrm.compiler.Klang.nodes.StructDefinition;
|
||||
import de.hsrm.compiler.Klang.nodes.StructField;
|
||||
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
||||
import de.hsrm.compiler.Klang.nodes.loops.*;
|
||||
import de.hsrm.compiler.Klang.nodes.statements.*;
|
||||
@@ -11,7 +13,7 @@ import de.hsrm.compiler.Klang.nodes.statements.*;
|
||||
public interface Visitor<R> {
|
||||
R visit(OrExpression e);
|
||||
R visit(AndExpression e);
|
||||
R visit (NotExpression e);
|
||||
R visit(NotExpression e);
|
||||
R visit(IntegerExpression e);
|
||||
R visit(FloatExpression e);
|
||||
R visit(BooleanExpression e);
|
||||
@@ -40,4 +42,11 @@ public interface Visitor<R> {
|
||||
R visit(FunctionCall e);
|
||||
R visit(Program e);
|
||||
R visit(Parameter e);
|
||||
R visit(StructDefinition e);
|
||||
R visit(StructField e);
|
||||
R visit(StructFieldAccessExpression e);
|
||||
R visit(ConstructorCall e);
|
||||
R visit(NullExpression e);
|
||||
R visit(DestructorCall e);
|
||||
R visit(FieldAssignment e);
|
||||
}
|
||||
Reference in New Issue
Block a user