From 3e8e30e0dab646ac7a6f9eefe442e6bb27cba0aa Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:13:45 +0100 Subject: [PATCH 01/61] add struct definitions as a direct child of program --- src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index e8021af..f349b26 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -5,7 +5,15 @@ parse ; program - : functionDef* expression SCOL + : (functionDef | structDef)* expression SCOL + ; + +structDef + : STRUCT structName=IDENT OBRK structField+ CBRK + ; + +structField + : IDENT type_annotation SCOL ; functionDef @@ -99,6 +107,7 @@ type : INTEGER | BOOLEAN | FLOAT + | IDENT ; functionCall @@ -127,6 +136,7 @@ PRINT: 'print'; IF: 'if'; ELSE: 'else'; FUNC: 'function'; +STRUCT: 'struct'; RETURN: 'return'; LET: 'let'; WHILE: 'while'; From 6f8c995f19c73c14d5121315627c0e3941a52232 Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:14:40 +0100 Subject: [PATCH 02/61] create DAST nodes for structDefinition and structField --- .../de/hsrm/compiler/Klang/nodes/Program.java | 6 ++++-- .../Klang/nodes/StructDefinition.java | 19 +++++++++++++++++++ .../compiler/Klang/nodes/StructField.java | 17 +++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/StructDefinition.java create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/StructField.java diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java b/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java index e02d893..c49d7fb 100644 --- a/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java @@ -6,10 +6,12 @@ import de.hsrm.compiler.Klang.visitors.Visitor; public class Program extends Node { public FunctionDefinition[] funcs; + public StructDefinition[] structs; public Expression expression; - public Program(FunctionDefinition[] funcs, Expression expression) { + public Program(FunctionDefinition[] funcs, StructDefinition[] structs, Expression expression) { this.funcs = funcs; + this.structs = structs; this.expression = expression; } @@ -17,4 +19,4 @@ public class Program extends Node { public R welcome(Visitor v) { return v.visit(this); } -} \ No newline at end of file +} diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/StructDefinition.java b/src/main/java/de/hsrm/compiler/Klang/nodes/StructDefinition.java new file mode 100644 index 0000000..ef0c142 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/StructDefinition.java @@ -0,0 +1,19 @@ +package de.hsrm.compiler.Klang.nodes; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class StructDefinition extends Node { + + public String name; + public StructField[] fields; + + public StructDefinition(String name, StructField[] fields) { + this.name = name; + this.fields = fields; + } + + @Override + public R welcome(Visitor v) { + return v.visit(this); + } +} \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/StructField.java b/src/main/java/de/hsrm/compiler/Klang/nodes/StructField.java new file mode 100644 index 0000000..2456081 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/StructField.java @@ -0,0 +1,17 @@ +package de.hsrm.compiler.Klang.nodes; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class StructField extends Node { + + public String name; + + public StructField(String name) { + this.name = name; + } + + @Override + public R welcome(Visitor v) { + return v.visit(this); + } +} \ No newline at end of file From e971b8b91e178cb30641c15dd7fd8c295390d59b Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:15:59 +0100 Subject: [PATCH 03/61] create a new type class that represents the type of a struct --- .../hsrm/compiler/Klang/types/StructType.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/main/java/de/hsrm/compiler/Klang/types/StructType.java diff --git a/src/main/java/de/hsrm/compiler/Klang/types/StructType.java b/src/main/java/de/hsrm/compiler/Klang/types/StructType.java new file mode 100644 index 0000000..9fac760 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/types/StructType.java @@ -0,0 +1,43 @@ +package de.hsrm.compiler.Klang.types; + +public class StructType extends Type { + + public String name; + + public StructType(String name) { + this.name = name; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public Type combine(Type that) { + if (that.equals(this)) { + return this; + } + + throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName()); + } + + @Override + public boolean isPrimitiveType() { + return false; + } + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + + if (that instanceof StructType) { + StructType thatType = (StructType) that; + return this.getName().equals(thatType.getName()); + } + + return false; + } +} \ No newline at end of file From b5086b44f0e7f0a6854fcf86eccdade7a6aef50a Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:16:41 +0100 Subject: [PATCH 04/61] return a struct type if no primitive type with the given name was found --- src/main/java/de/hsrm/compiler/Klang/types/Type.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/types/Type.java b/src/main/java/de/hsrm/compiler/Klang/types/Type.java index 75a8157..cfd4791 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/Type.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/Type.java @@ -21,7 +21,7 @@ public abstract class Type { case "bool": return getBooleanType(); case "int": return getIntegerType(); case "float": return getFloatType(); - default: throw new RuntimeException("Unknown type " + name); + default: return new StructType(name); } } From fd7f7c39bb68e3a79a4b36fca623770412aebe94 Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:17:13 +0100 Subject: [PATCH 05/61] implement a visitor that collects the names of all structs that were defined --- .../de/hsrm/compiler/Klang/GetStructs.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/de/hsrm/compiler/Klang/GetStructs.java diff --git a/src/main/java/de/hsrm/compiler/Klang/GetStructs.java b/src/main/java/de/hsrm/compiler/Klang/GetStructs.java new file mode 100644 index 0000000..b18c497 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/GetStructs.java @@ -0,0 +1,38 @@ +package de.hsrm.compiler.Klang; + +import java.util.Set; + +import de.hsrm.compiler.Klang.helper.Helper; + +public class GetStructs extends KlangBaseVisitor { + + private Set structs; + + public GetStructs(Set structs) { + this.structs = structs; + } + + @Override + public Void visitProgram(KlangParser.ProgramContext ctx) { + for (int i = 0; i < ctx.structDef().size(); i++) { + this.visit(ctx.structDef(i)); + } + + return null; + } + + @Override + public Void visitStructDef(KlangParser.StructDefContext ctx) { + String name = ctx.structName.getText(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + + if (this.structs.contains(name)) { + String error = "Struct " + name + " defined multiple times."; + throw new Error(Helper.getErrorPrefix(line, col) + error); + } + + this.structs.add(name); + return null; + } +} \ No newline at end of file From 309fe39c01d71bf5f2d398b2c63b133b60dfb9a6 Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:19:20 +0100 Subject: [PATCH 06/61] implement get vars visitor --- .../java/de/hsrm/compiler/Klang/visitors/GetVars.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java index 666b124..49d3b72 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -240,4 +240,14 @@ class GetVars implements Visitor { return null; } + @Override + public Void visit(StructDefinition e) { + return null; + } + + @Override + public Void visit(StructField e) { + return null; + } + } \ No newline at end of file From 15c55ed0654a0a9617e1f7846cc690651ec89140 Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:19:57 +0100 Subject: [PATCH 07/61] add the new nodes to the list of visitable nodes --- src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java index 57402f4..f2be85a 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -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 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); @@ -41,4 +43,6 @@ public interface Visitor { R visit(FunctionCall e); R visit(Program e); R visit(Parameter e); + R visit(StructDefinition e); + R visit(StructField e); } \ No newline at end of file From 279ea28a29c19e62122a35fdb2368d6c83a437f9 Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:20:48 +0100 Subject: [PATCH 08/61] add empty stubs for the visit method of the new nodes --- .../hsrm/compiler/Klang/visitors/EvalVisitor.java | 14 ++++++++++++++ .../de/hsrm/compiler/Klang/visitors/GenASM.java | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java index 2e3495d..e316f34 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -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; @@ -470,4 +472,16 @@ public class EvalVisitor implements Visitor { return null; } + @Override + public Value visit(StructDefinition e) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Value visit(StructField e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index f8edb42..9680eae 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -795,4 +795,16 @@ public class GenASM implements Visitor { return null; } + @Override + public Void visit(StructDefinition e) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Void visit(StructField e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file From 33904a3c3327249ae19093e7f8847f51b0b8d6ea Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:21:06 +0100 Subject: [PATCH 09/61] implement pretty print visitor --- .../Klang/visitors/PrettyPrintVisitor.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java index da410f5..37e95e1 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -61,6 +61,13 @@ public class PrettyPrintVisitor implements Visitor { ex.nl(); ex.nl(); } + + for (var structDef: e.structs) { + structDef.welcome(this); + ex.nl(); + ex.nl(); + } + e.expression.welcome(this); ex.write(";"); return null; @@ -378,4 +385,24 @@ public class PrettyPrintVisitor implements Visitor { 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; + } + } \ No newline at end of file From 6981c288e67c8d4c09a9331589c7204e2594c4be Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:21:34 +0100 Subject: [PATCH 10/61] implement context analysis --- .../hsrm/compiler/Klang/ContextAnalysis.java | 76 ++++++++++++++++++- .../java/de/hsrm/compiler/Klang/Klang.java | 7 +- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 3db76bd..41f7717 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -1,6 +1,7 @@ package de.hsrm.compiler.Klang; import java.util.Map; +import java.util.Set; import java.util.HashMap; import de.hsrm.compiler.Klang.helper.FunctionInformation; @@ -11,11 +12,13 @@ import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop; import de.hsrm.compiler.Klang.nodes.loops.ForLoop; import de.hsrm.compiler.Klang.nodes.loops.WhileLoop; import de.hsrm.compiler.Klang.nodes.statements.*; +import de.hsrm.compiler.Klang.types.StructType; import de.hsrm.compiler.Klang.types.Type; public class ContextAnalysis extends KlangBaseVisitor { Map vars = new HashMap<>(); Map funcs; + Set structs; Type currentDeclaredReturnType; private void checkNumeric(Node lhs, Node rhs, int line, int col) { @@ -25,18 +28,26 @@ public class ContextAnalysis extends KlangBaseVisitor { } } - public ContextAnalysis(Map funcs) { + public ContextAnalysis(Map funcs, Set structs) { this.funcs = funcs; + this.structs = structs; } @Override public Node visitProgram(KlangParser.ProgramContext ctx) { FunctionDefinition[] funcs = new FunctionDefinition[ctx.functionDef().size()]; + StructDefinition[] structs = new StructDefinition[ctx.structDef().size()]; + for (int i = 0; i < ctx.functionDef().size(); i++) { funcs[i] = (FunctionDefinition) this.visit(ctx.functionDef(i)); } + + for (int i = 0; i < ctx.structDef().size(); i++) { + structs[i] = (StructDefinition) this.visit(ctx.structDef(i)); + } + Expression expression = (Expression) this.visit(ctx.expression()); - Program result = new Program(funcs, expression); + Program result = new Program(funcs, structs, expression); result.type = expression.type; result.line = ctx.start.getLine(); result.col = ctx.start.getCharPositionInLine(); @@ -184,6 +195,11 @@ public class ContextAnalysis extends KlangBaseVisitor { int col = ctx.start.getCharPositionInLine(); Type declaredType = Type.getByName(ctx.type_annotation().type().getText()); + if (!declaredType.isPrimitiveType()) { + String error = "Using a struct as a type for a variable is not yet implemented"; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + if (this.vars.get(name) != null) { String error = "Redeclaration of variable with name \"" + name + "\"."; throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); @@ -620,6 +636,44 @@ public class ContextAnalysis extends KlangBaseVisitor { return n; } + @Override + public Node visitStructDef(KlangParser.StructDefContext ctx) { + String name = ctx.structName.getText(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + StructField[] fields = new StructField[ctx.structField().size()]; + + for (int i = 0; i < ctx.structField().size(); i++) { + StructField field = (StructField) this.visit(ctx.structField(i)); + fields[i] = field; + } + + Node result = new StructDefinition(name, fields); + result.line = line; + result.col = col; + result.type = new StructType(name); + return result; + } + + @Override + public Node visitStructField(KlangParser.StructFieldContext ctx) { + String name = ctx.IDENT().getText(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + Type type = Type.getByName(ctx.type_annotation().type().getText()); + + if (!type.isPrimitiveType() && !this.structs.contains(type.getName())) { + String error = "Type " + type.getName() + " not defined."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + + Node result = new StructField(name); + result.type = type; + result.line = line; + result.col = col; + return result; + } + @Override public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) { String name = ctx.funcName.getText(); @@ -628,6 +682,11 @@ public class ContextAnalysis extends KlangBaseVisitor { Type returnType = Type.getByName(ctx.returnType.type().getText()); this.currentDeclaredReturnType = returnType; + if (!returnType.isPrimitiveType()) { + String error = "Using a struct as the return type of a function is not yet implemented"; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + // Create a new set for the variables of the current function // this will be filled in the variable declaration visitor aswell this.vars = new HashMap<>(); @@ -665,11 +724,20 @@ public class ContextAnalysis extends KlangBaseVisitor { @Override public Node visitParameter(KlangParser.ParameterContext ctx) { String name = ctx.IDENT().getText(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + Type type = Type.getByName(ctx.type_annotation().type().getText()); + + if (!type.isPrimitiveType()) { + String error = "Using a struct as a parameter is not yet implemented"; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + Parameter result = new Parameter(name); result.type = type; - result.line = ctx.start.getLine(); - result.col = ctx.start.getCharPositionInLine(); + result.line = line; + result.col = col; return result; } diff --git a/src/main/java/de/hsrm/compiler/Klang/Klang.java b/src/main/java/de/hsrm/compiler/Klang/Klang.java index 555302d..289c0b2 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Klang.java +++ b/src/main/java/de/hsrm/compiler/Klang/Klang.java @@ -8,6 +8,7 @@ import java.io.*; import java.util.Arrays; import java.util.List; import java.util.HashMap; +import java.util.HashSet; import de.hsrm.compiler.Klang.nodes.Node; import de.hsrm.compiler.Klang.visitors.*; @@ -90,8 +91,12 @@ public class Klang { var functionDefinitions = new HashMap(); new GetFunctions(functionDefinitions).visit(tree); + // Extract information about all structs + var structs = new HashSet(); + new GetStructs(structs).visit(tree); + // Create the DAST - ContextAnalysis ctxAnal = new ContextAnalysis(functionDefinitions); + ContextAnalysis ctxAnal = new ContextAnalysis(functionDefinitions, structs); root = ctxAnal.visit(tree); } catch (Exception e) { System.err.println(e.getMessage()); From 233894fbcffd97b85a83e96d5157a5caf0ca79da Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 19:48:38 +0100 Subject: [PATCH 11/61] remove NYI errors, check if a struct is defined if the declared type is not primitive --- .../de/hsrm/compiler/Klang/ContextAnalysis.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 41f7717..5ba308d 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -195,8 +195,8 @@ public class ContextAnalysis extends KlangBaseVisitor { int col = ctx.start.getCharPositionInLine(); Type declaredType = Type.getByName(ctx.type_annotation().type().getText()); - if (!declaredType.isPrimitiveType()) { - String error = "Using a struct as a type for a variable is not yet implemented"; + if (!declaredType.isPrimitiveType() && !this.structs.contains(declaredType.getName())) { + String error = "Type " + declaredType.getName() + " not defined."; throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); } @@ -682,8 +682,8 @@ public class ContextAnalysis extends KlangBaseVisitor { Type returnType = Type.getByName(ctx.returnType.type().getText()); this.currentDeclaredReturnType = returnType; - if (!returnType.isPrimitiveType()) { - String error = "Using a struct as the return type of a function is not yet implemented"; + if (!returnType.isPrimitiveType() && !this.structs.contains(returnType.getName())) { + String error = "Type " + returnType.getName() + " not defined."; throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); } @@ -726,11 +726,10 @@ public class ContextAnalysis extends KlangBaseVisitor { String name = ctx.IDENT().getText(); int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); - Type type = Type.getByName(ctx.type_annotation().type().getText()); - if (!type.isPrimitiveType()) { - String error = "Using a struct as a parameter is not yet implemented"; + if (!type.isPrimitiveType() && !this.structs.contains(type.getName())) { + String error = "Type " + type.getName() + " not defined."; throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); } From 304891adb862ba91013037b5af3a9488ff35e344 Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 21:24:56 +0100 Subject: [PATCH 12/61] add struct field access expression --- src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index f349b26..8c0ae4e 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -73,6 +73,7 @@ return_statement expression : atom #atomExpression + | IDENT (DOT IDENT)+ #structFieldAccessExpression | OPAR expression CPAR #parenthesisExpression | lhs=expression MUL rhs=expression #multiplicationExpression | lhs=expression DIV rhs=expression #divisionExpression @@ -161,6 +162,7 @@ GTE: '>='; OR: '||'; AND: '&&'; NOT: '!'; +DOT: '.'; MUL: '*'; ADD: '+'; From e873e211c97b23241ab15bb5e0126ccad687c0f5 Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 21:25:27 +0100 Subject: [PATCH 13/61] implement node for struct field access expression --- .../StructFieldAccessExpression.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/expressions/StructFieldAccessExpression.java diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/StructFieldAccessExpression.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/StructFieldAccessExpression.java new file mode 100644 index 0000000..438a5ce --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/StructFieldAccessExpression.java @@ -0,0 +1,18 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class StructFieldAccessExpression extends Expression { + public String varName; + public String[] path; + + public StructFieldAccessExpression(String varName, String[] path) { + this.varName = varName; + this.path = path; + } + + @Override + public R welcome(Visitor v) { + return v.visit(this); + } +} \ No newline at end of file From fef397c60dcb86935c43807d0e6af23926eca77d Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 21:26:23 +0100 Subject: [PATCH 14/61] implement empty visitors --- .../java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java | 6 ++++++ src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java | 6 ++++++ .../java/de/hsrm/compiler/Klang/visitors/GetVars.java | 5 +++++ .../hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java | 8 +++++++- .../java/de/hsrm/compiler/Klang/visitors/Visitor.java | 1 + 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java index e316f34..9e62256 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -484,4 +484,10 @@ public class EvalVisitor implements Visitor { return null; } + @Override + public Value visit(StructFieldAccessExpression e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index 9680eae..a32657a 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -807,4 +807,10 @@ public class GenASM implements Visitor { return null; } + @Override + public Void visit(StructFieldAccessExpression e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java index 49d3b72..7e923ad 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -250,4 +250,9 @@ class GetVars implements Visitor { return null; } + @Override + public Void visit(StructFieldAccessExpression e) { + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java index 37e95e1..80b83ae 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -62,7 +62,7 @@ public class PrettyPrintVisitor implements Visitor { ex.nl(); } - for (var structDef: e.structs) { + for (var structDef: e.structs.values()) { structDef.welcome(this); ex.nl(); ex.nl(); @@ -405,4 +405,10 @@ public class PrettyPrintVisitor implements Visitor { return null; } + @Override + public Void visit(StructFieldAccessExpression e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java index f2be85a..fdbaf54 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -45,4 +45,5 @@ public interface Visitor { R visit(Parameter e); R visit(StructDefinition e); R visit(StructField e); + R visit(StructFieldAccessExpression e); } \ No newline at end of file From a969aa895fcda7c64ecbac1182384023d6c308a0 Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 21:28:52 +0100 Subject: [PATCH 15/61] make GetStructs collect the complete struct definitions --- .../hsrm/compiler/Klang/ContextAnalysis.java | 57 ++----------------- .../de/hsrm/compiler/Klang/GetStructs.java | 54 +++++++++++++++--- .../java/de/hsrm/compiler/Klang/Klang.java | 4 +- 3 files changed, 55 insertions(+), 60 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 5ba308d..0e5b3df 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -1,7 +1,6 @@ package de.hsrm.compiler.Klang; import java.util.Map; -import java.util.Set; import java.util.HashMap; import de.hsrm.compiler.Klang.helper.FunctionInformation; @@ -12,13 +11,12 @@ import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop; import de.hsrm.compiler.Klang.nodes.loops.ForLoop; import de.hsrm.compiler.Klang.nodes.loops.WhileLoop; import de.hsrm.compiler.Klang.nodes.statements.*; -import de.hsrm.compiler.Klang.types.StructType; import de.hsrm.compiler.Klang.types.Type; public class ContextAnalysis extends KlangBaseVisitor { Map vars = new HashMap<>(); Map funcs; - Set structs; + Map structs; Type currentDeclaredReturnType; private void checkNumeric(Node lhs, Node rhs, int line, int col) { @@ -28,7 +26,7 @@ public class ContextAnalysis extends KlangBaseVisitor { } } - public ContextAnalysis(Map funcs, Set structs) { + public ContextAnalysis(Map funcs, Map structs) { this.funcs = funcs; this.structs = structs; } @@ -36,18 +34,13 @@ public class ContextAnalysis extends KlangBaseVisitor { @Override public Node visitProgram(KlangParser.ProgramContext ctx) { FunctionDefinition[] funcs = new FunctionDefinition[ctx.functionDef().size()]; - StructDefinition[] structs = new StructDefinition[ctx.structDef().size()]; for (int i = 0; i < ctx.functionDef().size(); i++) { funcs[i] = (FunctionDefinition) this.visit(ctx.functionDef(i)); } - for (int i = 0; i < ctx.structDef().size(); i++) { - structs[i] = (StructDefinition) this.visit(ctx.structDef(i)); - } - Expression expression = (Expression) this.visit(ctx.expression()); - Program result = new Program(funcs, structs, expression); + Program result = new Program(funcs, this.structs, expression); result.type = expression.type; result.line = ctx.start.getLine(); result.col = ctx.start.getCharPositionInLine(); @@ -195,7 +188,7 @@ public class ContextAnalysis extends KlangBaseVisitor { int col = ctx.start.getCharPositionInLine(); Type declaredType = Type.getByName(ctx.type_annotation().type().getText()); - if (!declaredType.isPrimitiveType() && !this.structs.contains(declaredType.getName())) { + if (!declaredType.isPrimitiveType() && this.structs.get(declaredType.getName()) == null) { String error = "Type " + declaredType.getName() + " not defined."; throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); } @@ -636,44 +629,6 @@ public class ContextAnalysis extends KlangBaseVisitor { return n; } - @Override - public Node visitStructDef(KlangParser.StructDefContext ctx) { - String name = ctx.structName.getText(); - int line = ctx.start.getLine(); - int col = ctx.start.getCharPositionInLine(); - StructField[] fields = new StructField[ctx.structField().size()]; - - for (int i = 0; i < ctx.structField().size(); i++) { - StructField field = (StructField) this.visit(ctx.structField(i)); - fields[i] = field; - } - - Node result = new StructDefinition(name, fields); - result.line = line; - result.col = col; - result.type = new StructType(name); - return result; - } - - @Override - public Node visitStructField(KlangParser.StructFieldContext ctx) { - String name = ctx.IDENT().getText(); - int line = ctx.start.getLine(); - int col = ctx.start.getCharPositionInLine(); - Type type = Type.getByName(ctx.type_annotation().type().getText()); - - if (!type.isPrimitiveType() && !this.structs.contains(type.getName())) { - String error = "Type " + type.getName() + " not defined."; - throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); - } - - Node result = new StructField(name); - result.type = type; - result.line = line; - result.col = col; - return result; - } - @Override public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) { String name = ctx.funcName.getText(); @@ -682,7 +637,7 @@ public class ContextAnalysis extends KlangBaseVisitor { Type returnType = Type.getByName(ctx.returnType.type().getText()); this.currentDeclaredReturnType = returnType; - if (!returnType.isPrimitiveType() && !this.structs.contains(returnType.getName())) { + if (!returnType.isPrimitiveType() && this.structs.get(returnType.getName()) == null) { String error = "Type " + returnType.getName() + " not defined."; throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); } @@ -728,7 +683,7 @@ public class ContextAnalysis extends KlangBaseVisitor { int col = ctx.start.getCharPositionInLine(); Type type = Type.getByName(ctx.type_annotation().type().getText()); - if (!type.isPrimitiveType() && !this.structs.contains(type.getName())) { + if (!type.isPrimitiveType() && this.structs.get(type.getName()) == null) { String error = "Type " + type.getName() + " not defined."; throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); } diff --git a/src/main/java/de/hsrm/compiler/Klang/GetStructs.java b/src/main/java/de/hsrm/compiler/Klang/GetStructs.java index b18c497..878c8a3 100644 --- a/src/main/java/de/hsrm/compiler/Klang/GetStructs.java +++ b/src/main/java/de/hsrm/compiler/Klang/GetStructs.java @@ -1,19 +1,28 @@ package de.hsrm.compiler.Klang; +import java.util.Map; import java.util.Set; +import java.util.HashSet; import de.hsrm.compiler.Klang.helper.Helper; +import de.hsrm.compiler.Klang.nodes.Node; +import de.hsrm.compiler.Klang.nodes.StructDefinition; +import de.hsrm.compiler.Klang.nodes.StructField; +import de.hsrm.compiler.Klang.types.StructType; +import de.hsrm.compiler.Klang.types.Type; -public class GetStructs extends KlangBaseVisitor { +public class GetStructs extends KlangBaseVisitor { - private Set structs; + private Set structNames; + private Map structs; - public GetStructs(Set structs) { + public GetStructs(Map structs) { this.structs = structs; + this.structNames = new HashSet<>(); } @Override - public Void visitProgram(KlangParser.ProgramContext ctx) { + public Node visitProgram(KlangParser.ProgramContext ctx) { for (int i = 0; i < ctx.structDef().size(); i++) { this.visit(ctx.structDef(i)); } @@ -22,17 +31,48 @@ public class GetStructs extends KlangBaseVisitor { } @Override - public Void visitStructDef(KlangParser.StructDefContext ctx) { + public Node visitStructDef(KlangParser.StructDefContext ctx) { String name = ctx.structName.getText(); int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); + StructField[] fields = new StructField[ctx.structField().size()]; - if (this.structs.contains(name)) { + if (this.structNames.contains(name)) { String error = "Struct " + name + " defined multiple times."; throw new Error(Helper.getErrorPrefix(line, col) + error); } - this.structs.add(name); + this.structNames.add(name); + + for (int i = 0; i < ctx.structField().size(); i++) { + StructField field = (StructField) this.visit(ctx.structField(i)); + fields[i] = field; + } + + StructDefinition result = new StructDefinition(name, fields); + result.line = line; + result.col = col; + result.type = new StructType(name); + this.structs.put(name, result); return null; } + + @Override + public Node visitStructField(KlangParser.StructFieldContext ctx) { + String name = ctx.IDENT().getText(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + Type type = Type.getByName(ctx.type_annotation().type().getText()); + + if (!type.isPrimitiveType() && !this.structNames.contains(type.getName())) { + String error = "Type " + type.getName() + " not defined."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + + Node result = new StructField(name); + result.type = type; + result.line = line; + result.col = col; + return result; + } } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/Klang.java b/src/main/java/de/hsrm/compiler/Klang/Klang.java index 289c0b2..a321c29 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Klang.java +++ b/src/main/java/de/hsrm/compiler/Klang/Klang.java @@ -8,9 +8,9 @@ import java.io.*; import java.util.Arrays; import java.util.List; import java.util.HashMap; -import java.util.HashSet; import de.hsrm.compiler.Klang.nodes.Node; +import de.hsrm.compiler.Klang.nodes.StructDefinition; import de.hsrm.compiler.Klang.visitors.*; import de.hsrm.compiler.Klang.helper.*; @@ -92,7 +92,7 @@ public class Klang { new GetFunctions(functionDefinitions).visit(tree); // Extract information about all structs - var structs = new HashSet(); + var structs = new HashMap(); new GetStructs(structs).visit(tree); // Create the DAST From 6a7eb8fde2c13b0a5f7cc4a9afa761e0814dc0da Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 21:29:25 +0100 Subject: [PATCH 16/61] make GetStructs collect the complete struct definitions --- src/main/java/de/hsrm/compiler/Klang/nodes/Program.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java b/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java index c49d7fb..f56d749 100644 --- a/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java @@ -1,15 +1,17 @@ package de.hsrm.compiler.Klang.nodes; +import java.util.Map; + import de.hsrm.compiler.Klang.nodes.expressions.Expression; import de.hsrm.compiler.Klang.visitors.Visitor; public class Program extends Node { public FunctionDefinition[] funcs; - public StructDefinition[] structs; + public Map structs; public Expression expression; - public Program(FunctionDefinition[] funcs, StructDefinition[] structs, Expression expression) { + public Program(FunctionDefinition[] funcs, Map structs, Expression expression) { this.funcs = funcs; this.structs = structs; this.expression = expression; From 1ca3f5ca8beb3bcd82e8013e3fa484551ef9617d Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 21:30:17 +0100 Subject: [PATCH 17/61] implement context analysis for struct field access expressions --- .../hsrm/compiler/Klang/ContextAnalysis.java | 39 ++++++++++++++++++ .../de/hsrm/compiler/Klang/helper/Helper.java | 41 ++++++++++++++++++- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 0e5b3df..f16cb03 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -264,6 +264,45 @@ public class ContextAnalysis extends KlangBaseVisitor { return result; } + @Override + public Node visitStructFieldAccessExpression(KlangParser.StructFieldAccessExpressionContext ctx) { + String varName = ctx.IDENT(0).getText(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + String[] path = new String[ctx.IDENT().size() - 1]; + + for (int i = 1; i < ctx.IDENT().size(); i++) { + path[i - 1] = ctx.IDENT(i).getText(); + } + + // Get the referenced variable, make sure it is defined + var variableDef = this.vars.get(varName); + if (variableDef == null) { + String error = "Variable with name " + varName + " not defined."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + + // Make sure it references a struct + if (variableDef.type.isPrimitiveType()) { + String error = "Variable must reference a struct but references " + variableDef.type.getName() + "."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + + // Get the type of the result of this expression + Type resultType; + try { + resultType = Helper.drillType(this.structs, variableDef.type.getName(), path, 0); + } catch (Exception e) { + throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); + } + + Node result = new StructFieldAccessExpression(varName, path); + result.type = resultType; + result.line = line; + result.col = col; + return result; + } + @Override public Node visitOrExpression(KlangParser.OrExpressionContext ctx) { Node lhs = this.visit(ctx.lhs); diff --git a/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java b/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java index 2788a28..fb71a20 100644 --- a/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java +++ b/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java @@ -1,7 +1,44 @@ package de.hsrm.compiler.Klang.helper; +import java.util.Map; + +import de.hsrm.compiler.Klang.nodes.StructDefinition; +import de.hsrm.compiler.Klang.types.Type; + public class Helper { - public static String getErrorPrefix(int line, int col) { - return "Error in line " + line + ":" + col + " "; + public static String getErrorPrefix(int line, int col) { + return "Error in line " + line + ":" + col + " "; + } + + public static Type drillType(Map structs, String name, String[] path, int pathIndex) { + // Search for the referenced field + var structDef = structs.get(name); + for (var field : structDef.fields) { + if (field.name.equals(path[pathIndex])) { + if (!field.type.isPrimitiveType()) { + // this references a struct! + + // if we exhausted the path, this field type is our type + if (pathIndex == path.length - 1) { + return field.type; + } + + // we did not exhaust the path, go on + return drillType(structs, field.type.getName(), path, pathIndex + 1); + } else { + // this references a primitive, we hit bedrock! + + // make sure we exhausted the complete path + if (pathIndex < path.length - 1) { + throw new RuntimeException(field.name + " must be a struct but is of type " + field.type.getName() + ":"); + } + + // hooray, we exhausted the path, this field type is our type + return field.type; + } + } } + + throw new RuntimeException("Struct " + structDef.name + " does not contain field " + path[pathIndex]); + } } \ No newline at end of file From f0b6f052d662d291e036e3d25f4a4c6fef80b35d Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 21:34:28 +0100 Subject: [PATCH 18/61] implement pretty print for struct field access expression --- .../de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java index 80b83ae..5311de9 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -407,7 +407,11 @@ public class PrettyPrintVisitor implements Visitor { @Override public Void visit(StructFieldAccessExpression e) { - // TODO Auto-generated method stub + ex.write(e.varName); + for (int i = 0; i < e.path.length; i++) { + ex.write("."); + ex.write(e.path[i]); + } return null; } From a79a2332a1abf27264f051fa5b2824f824d87421 Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 21:43:22 +0100 Subject: [PATCH 19/61] implement visitor to collect all struct names --- .../hsrm/compiler/Klang/GetStructNames.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/main/java/de/hsrm/compiler/Klang/GetStructNames.java diff --git a/src/main/java/de/hsrm/compiler/Klang/GetStructNames.java b/src/main/java/de/hsrm/compiler/Klang/GetStructNames.java new file mode 100644 index 0000000..0e5fcb3 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/GetStructNames.java @@ -0,0 +1,37 @@ +package de.hsrm.compiler.Klang; + +import java.util.Set; + +import de.hsrm.compiler.Klang.helper.Helper; + +public class GetStructNames extends KlangBaseVisitor { + private Set structNames; + + public GetStructNames(Set structNames) { + this.structNames = structNames; + } + + @Override + public Void visitProgram(KlangParser.ProgramContext ctx) { + for (int i = 0; i < ctx.structDef().size(); i++) { + this.visit(ctx.structDef(i)); + } + + return null; + } + + @Override + public Void visitStructDef(KlangParser.StructDefContext ctx) { + String name = ctx.structName.getText(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + + if (this.structNames.contains(name)) { + String error = "Struct " + name + " defined multiple times."; + throw new Error(Helper.getErrorPrefix(line, col) + error); + } + + this.structNames.add(name); + return null; + } +} \ No newline at end of file From 19daaa63af084b1f969b501e4a1380f128fab982 Mon Sep 17 00:00:00 2001 From: nitrix Date: Tue, 4 Feb 2020 21:44:04 +0100 Subject: [PATCH 20/61] use GetStructNames instead of collecting the names in GetStructs --- src/main/java/de/hsrm/compiler/Klang/GetStructs.java | 12 ++---------- src/main/java/de/hsrm/compiler/Klang/Klang.java | 7 ++++++- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/GetStructs.java b/src/main/java/de/hsrm/compiler/Klang/GetStructs.java index 878c8a3..ca1dc2f 100644 --- a/src/main/java/de/hsrm/compiler/Klang/GetStructs.java +++ b/src/main/java/de/hsrm/compiler/Klang/GetStructs.java @@ -2,7 +2,6 @@ package de.hsrm.compiler.Klang; import java.util.Map; import java.util.Set; -import java.util.HashSet; import de.hsrm.compiler.Klang.helper.Helper; import de.hsrm.compiler.Klang.nodes.Node; @@ -16,9 +15,9 @@ public class GetStructs extends KlangBaseVisitor { private Set structNames; private Map structs; - public GetStructs(Map structs) { + public GetStructs(Set structNames, Map structs) { this.structs = structs; - this.structNames = new HashSet<>(); + this.structNames = structNames; } @Override @@ -36,13 +35,6 @@ public class GetStructs extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); StructField[] fields = new StructField[ctx.structField().size()]; - - if (this.structNames.contains(name)) { - String error = "Struct " + name + " defined multiple times."; - throw new Error(Helper.getErrorPrefix(line, col) + error); - } - - this.structNames.add(name); for (int i = 0; i < ctx.structField().size(); i++) { StructField field = (StructField) this.visit(ctx.structField(i)); diff --git a/src/main/java/de/hsrm/compiler/Klang/Klang.java b/src/main/java/de/hsrm/compiler/Klang/Klang.java index a321c29..8b63cd1 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Klang.java +++ b/src/main/java/de/hsrm/compiler/Klang/Klang.java @@ -8,6 +8,7 @@ import java.io.*; import java.util.Arrays; import java.util.List; import java.util.HashMap; +import java.util.HashSet; import de.hsrm.compiler.Klang.nodes.Node; import de.hsrm.compiler.Klang.nodes.StructDefinition; @@ -91,9 +92,13 @@ public class Klang { var functionDefinitions = new HashMap(); new GetFunctions(functionDefinitions).visit(tree); + // Extract names of all structs + var structNames = new HashSet(); + new GetStructNames(structNames).visit(tree); + // Extract information about all structs var structs = new HashMap(); - new GetStructs(structs).visit(tree); + new GetStructs(structNames, structs).visit(tree); // Create the DAST ContextAnalysis ctxAnal = new ContextAnalysis(functionDefinitions, structs); From 317c2c52ca467d7887b345bb3e4c866cf22d96dc Mon Sep 17 00:00:00 2001 From: nitrix Date: Fri, 14 Feb 2020 13:05:34 +0100 Subject: [PATCH 21/61] add constructor call expression to the grammar --- src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index 8c0ae4e..8ce46f9 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -91,6 +91,7 @@ expression | SUB expression #negateExpression | NOT expression #NotExpression | functionCall #functionCallExpression + | CREATE IDENT OPAR arguments CPAR # constructorCallExpression ; atom @@ -143,6 +144,7 @@ LET: 'let'; WHILE: 'while'; DO: 'do'; FOR: 'for'; +CREATE: 'create'; PERIOD: '.'; COL: ':'; From 5c0459c5a2643f86c981941726a8bb92c099c438 Mon Sep 17 00:00:00 2001 From: nitrix Date: Fri, 14 Feb 2020 13:06:20 +0100 Subject: [PATCH 22/61] implement constructor call, eval and genasm are still stubs --- .../hsrm/compiler/Klang/ContextAnalysis.java | 40 +++++++++++++++++++ .../java/de/hsrm/compiler/Klang/Klang.java | 30 +++++++------- .../nodes/expressions/ConstructorCall.java | 19 +++++++++ .../compiler/Klang/visitors/EvalVisitor.java | 6 +++ .../hsrm/compiler/Klang/visitors/GenASM.java | 6 +++ .../hsrm/compiler/Klang/visitors/GetVars.java | 5 +++ .../Klang/visitors/PrettyPrintVisitor.java | 17 ++++++++ .../hsrm/compiler/Klang/visitors/Visitor.java | 1 + 8 files changed, 109 insertions(+), 15 deletions(-) create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/expressions/ConstructorCall.java diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index f16cb03..2741db7 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -770,4 +770,44 @@ public class ContextAnalysis extends KlangBaseVisitor { result.col = col; return result; } + + @Override + public Node visitConstructorCallExpression(KlangParser.ConstructorCallExpressionContext ctx) { + String name = ctx.IDENT().getText(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + + // Get the corresponding struct definition + var struct = this.structs.get(name); + if (struct == null) { + String error = "Struct with name \"" + name + "\" not defined."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + + // Make sure the number of arguments match the number of struct fields + int fieldCount = struct.fields.length; + int argCount = ctx.arguments().expression().size(); + if (argCount != fieldCount) { + String error = "Struct \"" + name + "\" defined " + fieldCount + " fields, but got " + argCount + " constructor parameters."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + + // Evaluate each expression + Expression[] args = new Expression[argCount]; + for (int i = 0; i < argCount; i++) { + Expression expr = (Expression) this.visit(ctx.arguments().expression(i)); + try { + expr.type.combine(struct.fields[i].type); // Make sure the types are matching + } catch (Exception e) { + throw new RuntimeException(Helper.getErrorPrefix(expr.line, expr.col) + "argument " + i + " " + e.getMessage()); + } + args[i] = expr; + } + + ConstructorCall result = new ConstructorCall(name, args); + result.type = struct.type; + result.line = line; + result.col = col; + return result; + } } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/Klang.java b/src/main/java/de/hsrm/compiler/Klang/Klang.java index 8b63cd1..041042d 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Klang.java +++ b/src/main/java/de/hsrm/compiler/Klang/Klang.java @@ -39,20 +39,20 @@ public class Klang { String out = null; List arguments = Arrays.asList(args); - if (arguments.size() <= 0 || arguments.contains("-h") || arguments.contains("--help") || arguments.contains("?")) { - System.out.println("\nKaiser Lang Compiler"); - System.out.println("Authors: Dennis Kaiser and Marvin Kaiser"); - System.out.println(""); - System.out.println("Last argument must be file"); - System.out.println(""); - System.out.println("Arguments:"); - System.out.println("--out :\t File to write to"); - System.out.println("--evaluate:\t Evaluates the given source code"); - System.out.println("--pretty:\t Pretty print the given source code"); - System.out - .println("--no-main:\t Do not generate main function, will be generated as 'start'. Useful for testing"); - return; - } + // if (arguments.size() <= 0 || arguments.contains("-h") || arguments.contains("--help") || arguments.contains("?")) { + // System.out.println("\nKaiser Lang Compiler"); + // System.out.println("Authors: Dennis Kaiser and Marvin Kaiser"); + // System.out.println(""); + // System.out.println("Last argument must be file"); + // System.out.println(""); + // System.out.println("Arguments:"); + // System.out.println("--out :\t File to write to"); + // System.out.println("--evaluate:\t Evaluates the given source code"); + // System.out.println("--pretty:\t Pretty print the given source code"); + // System.out + // .println("--no-main:\t Do not generate main function, will be generated as 'start'. Useful for testing"); + // return; + // } if (arguments.contains("--evaluate")) { evaluate = true; } @@ -71,7 +71,7 @@ public class Klang { } // create a CharStream that reads from standard input - CharStream input = CharStreams.fromFileName(arguments.get(arguments.size() - 1)); + CharStream input = CharStreams.fromFileName("code.k"); // create a lexer that feeds off of input CharStream KlangLexer lexer = new KlangLexer(input); diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/ConstructorCall.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/ConstructorCall.java new file mode 100644 index 0000000..ef36b09 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/ConstructorCall.java @@ -0,0 +1,19 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class ConstructorCall extends Expression { + + public String structName; + public Expression[] args; + + public ConstructorCall(String structName, Expression[] args) { + this.structName = structName; + this.args = args; + } + + @Override + public R welcome(Visitor v) { + return v.visit(this); + } +} \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java index 9e62256..3a99399 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -490,4 +490,10 @@ public class EvalVisitor implements Visitor { return null; } + @Override + public Value visit(ConstructorCall e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index a32657a..cdf9ac7 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -813,4 +813,10 @@ public class GenASM implements Visitor { return null; } + @Override + public Void visit(ConstructorCall e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java index 7e923ad..eb728fb 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -255,4 +255,9 @@ class GetVars implements Visitor { return null; } + @Override + public Void visit(ConstructorCall e) { + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java index 5311de9..58d9679 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -415,4 +415,21 @@ public class PrettyPrintVisitor implements Visitor { 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; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java index fdbaf54..ece0bd7 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -46,4 +46,5 @@ public interface Visitor { R visit(StructDefinition e); R visit(StructField e); R visit(StructFieldAccessExpression e); + R visit(ConstructorCall e); } \ No newline at end of file From 9d83e5425d89ee85ece51b7014f478d4b8b9da67 Mon Sep 17 00:00:00 2001 From: nitrix Date: Fri, 14 Feb 2020 14:10:23 +0100 Subject: [PATCH 23/61] add a null literal --- src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index 8ce46f9..5c0544e 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -98,6 +98,7 @@ atom : INTEGER_LITERAL #intAtom | BOOLEAN_LITERAL #boolAtom | FLOAT_LITERAL #floatAtom + | NULL # nullAtom | IDENT #variable ; @@ -145,6 +146,7 @@ WHILE: 'while'; DO: 'do'; FOR: 'for'; CREATE: 'create'; +NULL: 'naught'; PERIOD: '.'; COL: ':'; From 8ebbd6ae54bf96b6e8fea8577ede66e5c5d88551 Mon Sep 17 00:00:00 2001 From: nitrix Date: Fri, 14 Feb 2020 14:10:48 +0100 Subject: [PATCH 24/61] implement null type --- .../hsrm/compiler/Klang/types/NullType.java | 36 +++++++++++++++++++ .../hsrm/compiler/Klang/types/StructType.java | 6 ++++ .../de/hsrm/compiler/Klang/types/Type.java | 5 +++ 3 files changed, 47 insertions(+) create mode 100644 src/main/java/de/hsrm/compiler/Klang/types/NullType.java diff --git a/src/main/java/de/hsrm/compiler/Klang/types/NullType.java b/src/main/java/de/hsrm/compiler/Klang/types/NullType.java new file mode 100644 index 0000000..ffb5a33 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/types/NullType.java @@ -0,0 +1,36 @@ +package de.hsrm.compiler.Klang.types; + +public class NullType extends Type { + + private static NullType instance = null; + + public static NullType getType() { + if (instance != null) { + return instance; + } + instance = new NullType(); + return instance; + } + + @Override + public String getName() { + return "naught"; + } + + @Override + public Type combine(Type that) { + // You can not combine null with a primitive type + if (that.isPrimitiveType()) { + throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName()); + } + + // Everything else combines with null to the type it was before + return that; + } + + @Override + public boolean isPrimitiveType() { + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/types/StructType.java b/src/main/java/de/hsrm/compiler/Klang/types/StructType.java index 9fac760..adf3f8b 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/StructType.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/StructType.java @@ -19,6 +19,12 @@ public class StructType extends Type { return this; } + // If you combine a null type with a struct type, you + // always get the struct type back. + if (that == NullType.getType()) { + return this; + } + throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName()); } diff --git a/src/main/java/de/hsrm/compiler/Klang/types/Type.java b/src/main/java/de/hsrm/compiler/Klang/types/Type.java index cfd4791..15b2810 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/Type.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/Type.java @@ -16,11 +16,16 @@ public abstract class Type { return FloatType.getType(); } + public static NullType getNullType() { + return NullType.getType(); + } + public static Type getByName(String name) { switch (name) { case "bool": return getBooleanType(); case "int": return getIntegerType(); case "float": return getFloatType(); + case "null": return getNullType(); default: return new StructType(name); } } From 2f425944e5fefdf71612b5eb569a7c80b8176c6d Mon Sep 17 00:00:00 2001 From: nitrix Date: Fri, 14 Feb 2020 14:11:10 +0100 Subject: [PATCH 25/61] implement null node --- .../Klang/nodes/expressions/NullExpression.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/expressions/NullExpression.java diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/NullExpression.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/NullExpression.java new file mode 100644 index 0000000..cad431d --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/NullExpression.java @@ -0,0 +1,12 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class NullExpression extends Expression { + + @Override + public R welcome(Visitor v) { + return v.visit(this); + } + +} \ No newline at end of file From 80deae697185e0bbabe15fdd638ee0c84a5632d3 Mon Sep 17 00:00:00 2001 From: nitrix Date: Fri, 14 Feb 2020 14:11:26 +0100 Subject: [PATCH 26/61] implement visitors for null atom --- .../java/de/hsrm/compiler/Klang/ContextAnalysis.java | 9 +++++++++ .../de/hsrm/compiler/Klang/visitors/EvalVisitor.java | 6 ++++++ .../java/de/hsrm/compiler/Klang/visitors/GenASM.java | 6 ++++++ .../java/de/hsrm/compiler/Klang/visitors/GetVars.java | 5 +++++ .../hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java | 6 ++++++ .../java/de/hsrm/compiler/Klang/visitors/Visitor.java | 1 + 6 files changed, 33 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 2741db7..b9c9da8 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -668,6 +668,15 @@ public class ContextAnalysis extends KlangBaseVisitor { return n; } + @Override + public Node visitNullAtom(KlangParser.NullAtomContext ctx) { + Node n = new NullExpression(); + n.type = Type.getNullType(); + n.line = ctx.start.getLine(); + n.col = ctx.start.getCharPositionInLine(); + return n; + } + @Override public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) { String name = ctx.funcName.getText(); diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java index 3a99399..d4b458c 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -496,4 +496,10 @@ public class EvalVisitor implements Visitor { return null; } + @Override + public Value visit(NullExpression e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index cdf9ac7..966ae17 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -819,4 +819,10 @@ public class GenASM implements Visitor { return null; } + @Override + public Void visit(NullExpression e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java index eb728fb..926ee4b 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -260,4 +260,9 @@ class GetVars implements Visitor { return null; } + @Override + public Void visit(NullExpression e) { + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java index 58d9679..6c7857a 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -432,4 +432,10 @@ public class PrettyPrintVisitor implements Visitor { return null; } + @Override + public Void visit(NullExpression e) { + ex.write("null"); + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java index ece0bd7..597c3bc 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -47,4 +47,5 @@ public interface Visitor { R visit(StructField e); R visit(StructFieldAccessExpression e); R visit(ConstructorCall e); + R visit(NullExpression e); } \ No newline at end of file From 441466c83f56263db25450efe34412fa89018ed9 Mon Sep 17 00:00:00 2001 From: nitrix Date: Fri, 14 Feb 2020 14:19:13 +0100 Subject: [PATCH 27/61] next time check before commiting everything... --- .../java/de/hsrm/compiler/Klang/Klang.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/Klang.java b/src/main/java/de/hsrm/compiler/Klang/Klang.java index 041042d..8b63cd1 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Klang.java +++ b/src/main/java/de/hsrm/compiler/Klang/Klang.java @@ -39,20 +39,20 @@ public class Klang { String out = null; List arguments = Arrays.asList(args); - // if (arguments.size() <= 0 || arguments.contains("-h") || arguments.contains("--help") || arguments.contains("?")) { - // System.out.println("\nKaiser Lang Compiler"); - // System.out.println("Authors: Dennis Kaiser and Marvin Kaiser"); - // System.out.println(""); - // System.out.println("Last argument must be file"); - // System.out.println(""); - // System.out.println("Arguments:"); - // System.out.println("--out :\t File to write to"); - // System.out.println("--evaluate:\t Evaluates the given source code"); - // System.out.println("--pretty:\t Pretty print the given source code"); - // System.out - // .println("--no-main:\t Do not generate main function, will be generated as 'start'. Useful for testing"); - // return; - // } + if (arguments.size() <= 0 || arguments.contains("-h") || arguments.contains("--help") || arguments.contains("?")) { + System.out.println("\nKaiser Lang Compiler"); + System.out.println("Authors: Dennis Kaiser and Marvin Kaiser"); + System.out.println(""); + System.out.println("Last argument must be file"); + System.out.println(""); + System.out.println("Arguments:"); + System.out.println("--out :\t File to write to"); + System.out.println("--evaluate:\t Evaluates the given source code"); + System.out.println("--pretty:\t Pretty print the given source code"); + System.out + .println("--no-main:\t Do not generate main function, will be generated as 'start'. Useful for testing"); + return; + } if (arguments.contains("--evaluate")) { evaluate = true; } @@ -71,7 +71,7 @@ public class Klang { } // create a CharStream that reads from standard input - CharStream input = CharStreams.fromFileName("code.k"); + CharStream input = CharStreams.fromFileName(arguments.get(arguments.size() - 1)); // create a lexer that feeds off of input CharStream KlangLexer lexer = new KlangLexer(input); From 31460860d5000bacfcb13ace5fa8654c557d52bf Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 16:21:11 +0100 Subject: [PATCH 28/61] add a destructor call to the grammar --- src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index 5c0544e..13499ab 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -92,6 +92,7 @@ expression | NOT expression #NotExpression | functionCall #functionCallExpression | CREATE IDENT OPAR arguments CPAR # constructorCallExpression + | DESTROY IDENT # destructorCallExpression ; atom @@ -146,6 +147,7 @@ WHILE: 'while'; DO: 'do'; FOR: 'for'; CREATE: 'create'; +DESTROY: 'destroy'; NULL: 'naught'; PERIOD: '.'; From 995fac20c5d7bbfefbc964c78225c505b69a51fd Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 16:22:27 +0100 Subject: [PATCH 29/61] create node that represents a destructor call --- .../Klang/nodes/expressions/DestructorCall.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/expressions/DestructorCall.java diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/DestructorCall.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/DestructorCall.java new file mode 100644 index 0000000..5656118 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/DestructorCall.java @@ -0,0 +1,17 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class DestructorCall extends Expression { + + public String name; + + public DestructorCall(String name) { + this.name = name; + } + + @Override + public R welcome(Visitor v) { + return v.visit(this); + } +} \ No newline at end of file From 9300e37fcaa04cab044213db7bcaade3d26a14df Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 16:22:53 +0100 Subject: [PATCH 30/61] implement node visitors for the destructor node --- .../java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java | 6 ++++++ src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java | 6 ++++++ src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java | 4 ++++ .../de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java | 6 ++++++ src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java | 1 + 5 files changed, 23 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java index d4b458c..7ae1676 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -502,4 +502,10 @@ public class EvalVisitor implements Visitor { return null; } + @Override + public Value visit(DestructorCall e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index 966ae17..aedc383 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -825,4 +825,10 @@ public class GenASM implements Visitor { return null; } + @Override + public Void visit(DestructorCall e) { + // TODO Auto-generated method stub + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java index 926ee4b..7f2848f 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -265,4 +265,8 @@ class GetVars implements Visitor { return null; } + @Override + public Void visit(DestructorCall e) { + return null; + } } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java index 6c7857a..f1531b6 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -438,4 +438,10 @@ public class PrettyPrintVisitor implements Visitor { return null; } + @Override + public Void visit(DestructorCall e) { + ex.write("destroy " + e.name); + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java index 597c3bc..8df0e0d 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -48,4 +48,5 @@ public interface Visitor { R visit(StructFieldAccessExpression e); R visit(ConstructorCall e); R visit(NullExpression e); + R visit(DestructorCall e); } \ No newline at end of file From d89c085ecc92e5c262f416d8299c1106def61fd9 Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 16:23:10 +0100 Subject: [PATCH 31/61] implement context analysis for destructor node --- .../hsrm/compiler/Klang/ContextAnalysis.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index b9c9da8..d9e6207 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -819,4 +819,22 @@ public class ContextAnalysis extends KlangBaseVisitor { result.col = col; return result; } + + @Override + public Node visitDestructorCallExpression(KlangParser.DestructorCallExpressionContext ctx) { + String name = ctx.IDENT().getText(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + + VariableDeclaration var = this.vars.get(name); + if (var == null) { + String error = "Variable with name \"" + name + "\" not defined."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + + Node result = new DestructorCall(name); + result.line = line; + result.col = col; + return result; + } } \ No newline at end of file From 3fb350ad31842eadbd83d5d0ffcbe724aa187c24 Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 22:04:27 +0100 Subject: [PATCH 32/61] make destructor call inherit from statement --- .../nodes/{expressions => statements}/DestructorCall.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/main/java/de/hsrm/compiler/Klang/nodes/{expressions => statements}/DestructorCall.java (70%) diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/DestructorCall.java b/src/main/java/de/hsrm/compiler/Klang/nodes/statements/DestructorCall.java similarity index 70% rename from src/main/java/de/hsrm/compiler/Klang/nodes/expressions/DestructorCall.java rename to src/main/java/de/hsrm/compiler/Klang/nodes/statements/DestructorCall.java index 5656118..77dd461 100644 --- a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/DestructorCall.java +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/statements/DestructorCall.java @@ -1,8 +1,8 @@ -package de.hsrm.compiler.Klang.nodes.expressions; +package de.hsrm.compiler.Klang.nodes.statements; import de.hsrm.compiler.Klang.visitors.Visitor; -public class DestructorCall extends Expression { +public class DestructorCall extends Statement { public String name; From 64634a0d4d8ab47968c65cf822a083114658bb6a Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 22:05:00 +0100 Subject: [PATCH 33/61] move destructor call from expressions to statements --- src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index 13499ab..79141d9 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -44,6 +44,7 @@ statement | whileLoop | doWhileLoop | forLoop + | destroy_statement ; print @@ -71,6 +72,10 @@ return_statement : RETURN expression SCOL ; +destroy_statement + : DESTROY IDENT SCOL + ; + expression : atom #atomExpression | IDENT (DOT IDENT)+ #structFieldAccessExpression @@ -92,7 +97,6 @@ expression | NOT expression #NotExpression | functionCall #functionCallExpression | CREATE IDENT OPAR arguments CPAR # constructorCallExpression - | DESTROY IDENT # destructorCallExpression ; atom From 86fe676492073d8808d1eac759d64011043d60a6 Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 22:05:25 +0100 Subject: [PATCH 34/61] rename method to match new grammar --- src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index d9e6207..04fcfc6 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -821,7 +821,7 @@ public class ContextAnalysis extends KlangBaseVisitor { } @Override - public Node visitDestructorCallExpression(KlangParser.DestructorCallExpressionContext ctx) { + public Node visitDestroy_statement(KlangParser.Destroy_statementContext ctx) { String name = ctx.IDENT().getText(); int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); From b9569c7df63250554ae3732d05c71c26a48dff55 Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 22:08:20 +0100 Subject: [PATCH 35/61] add missing semicolong since a destructor call is now a statement --- .../de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java index f1531b6..014feb1 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -440,7 +440,7 @@ public class PrettyPrintVisitor implements Visitor { @Override public Void visit(DestructorCall e) { - ex.write("destroy " + e.name); + ex.write("destroy " + e.name + ";"); return null; } From edaa686a2ac274a6027d49dbb5b1ef274cd296dc Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 22:42:43 +0100 Subject: [PATCH 36/61] add method to get the value as a struct --- src/main/java/de/hsrm/compiler/Klang/Value.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/Value.java b/src/main/java/de/hsrm/compiler/Klang/Value.java index c0551c6..112d1de 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Value.java +++ b/src/main/java/de/hsrm/compiler/Klang/Value.java @@ -1,6 +1,7 @@ package de.hsrm.compiler.Klang; import de.hsrm.compiler.Klang.types.Type; +import java.util.Map; public class Value { public Type type; @@ -30,4 +31,9 @@ public class Value { public boolean asBoolean() { return (boolean) this.value; } + + @SuppressWarnings("unchecked") + public Map asStruct() { + return (Map) this.value; + } } From bc5efde8c51be14c624559ac50aafa6986650d4a Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 22:43:20 +0100 Subject: [PATCH 37/61] add the retrieved structs to the constructor call of the eval visitor --- src/main/java/de/hsrm/compiler/Klang/Klang.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/Klang.java b/src/main/java/de/hsrm/compiler/Klang/Klang.java index 8b63cd1..17a5dec 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Klang.java +++ b/src/main/java/de/hsrm/compiler/Klang/Klang.java @@ -87,6 +87,7 @@ public class Klang { // Context Analysis and DAST generation Node root; + HashMap structs; try { // Extract information about all functions var functionDefinitions = new HashMap(); @@ -97,7 +98,7 @@ public class Klang { new GetStructNames(structNames).visit(tree); // Extract information about all structs - var structs = new HashMap(); + structs = new HashMap(); new GetStructs(structNames, structs).visit(tree); // Create the DAST @@ -120,7 +121,7 @@ public class Klang { if (evaluate) { // Evaluate the sourcecode and print the result System.out.println("\nEvaluating the source code:"); - EvalVisitor evalVisitor = new EvalVisitor(); + EvalVisitor evalVisitor = new EvalVisitor(structs); Value result = root.welcome(evalVisitor); generateOutput(out, "Result was: " + result.asObject().toString()); return; From a9ab8f08e6bd6e4ee91bf87225723d90f76bbf34 Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 22:43:47 +0100 Subject: [PATCH 38/61] implement structs --- .../compiler/Klang/visitors/EvalVisitor.java | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java index 7ae1676..b23fd85 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -20,7 +20,13 @@ import de.hsrm.compiler.Klang.types.Type; public class EvalVisitor implements Visitor { Map funcs = new HashMap<>(); + Map structs; Map env = new HashMap<>(); + Map> heap = new HashMap<>(); + + public EvalVisitor(Map structs) { + this.structs = structs; + } @Override public Value visit(IntegerExpression e) { @@ -474,37 +480,50 @@ public class EvalVisitor implements Visitor { @Override public Value visit(StructDefinition e) { - // TODO Auto-generated method stub + // We get these from a previous visitor return null; } @Override public Value visit(StructField e) { - // TODO Auto-generated method stub + // Nothing to do here... return null; } @Override public Value visit(StructFieldAccessExpression e) { - // TODO Auto-generated method stub - return null; + Value var = this.env.get(e.varName); + Map 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) { - // TODO Auto-generated method stub - return null; + StructDefinition structDef = this.structs.get(e.structName); + Map 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) { - // TODO Auto-generated method stub return null; } @Override public Value visit(DestructorCall e) { - // TODO Auto-generated method stub + this.env.remove(e.name); return null; } From 3f18fa56c20888f9e062839782d1af77e9b66585 Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 23:02:48 +0100 Subject: [PATCH 39/61] add struct definitions as a constructor parameter --- .../java/de/hsrm/compiler/Klang/visitors/GenASM.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index aedc383..7de8e85 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -107,6 +107,7 @@ public class GenASM implements Visitor { private FloatWriter fw = new FloatWriter(); private String mainName; Map env = new HashMap<>(); + Map structs; Set vars; String[] registers = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" }; String[] floatRegisters = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" }; @@ -147,14 +148,15 @@ public class GenASM implements Visitor { return false; } } - public GenASM(ExWriter ex, String mainName) { + + public GenASM(ExWriter ex, String mainName, Map 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 structs) { + this(ex, "main", structs); } @Override From 622be803cc4bf25de077cea8a8dde088e04abeec Mon Sep 17 00:00:00 2001 From: nitrix Date: Thu, 5 Mar 2020 23:03:12 +0100 Subject: [PATCH 40/61] add structs to the constructor params of GenASM --- src/main/java/de/hsrm/compiler/Klang/Klang.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/Klang.java b/src/main/java/de/hsrm/compiler/Klang/Klang.java index 17a5dec..1c951d0 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Klang.java +++ b/src/main/java/de/hsrm/compiler/Klang/Klang.java @@ -131,7 +131,7 @@ public class Klang { // System.out.println("\nPrinting the assembler code"); StringWriter wAsm = new StringWriter(); GenASM.ExWriter exAsm = new GenASM.ExWriter(wAsm); - GenASM genasm = new GenASM(exAsm, mainName); + GenASM genasm = new GenASM(exAsm, mainName, structs); root.welcome(genasm); generateOutput(out, wAsm.toString()); } From 1693eb642671b12aff9ea2a3be13f8bbb865ab54 Mon Sep 17 00:00:00 2001 From: nitrix Date: Fri, 6 Mar 2020 00:17:59 +0100 Subject: [PATCH 41/61] implement helper functions to determine the struct size and field offsets --- .../de/hsrm/compiler/Klang/helper/Helper.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java b/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java index fb71a20..c468683 100644 --- a/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java +++ b/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java @@ -41,4 +41,22 @@ public class Helper { throw new RuntimeException("Struct " + structDef.name + " does not contain field " + path[pathIndex]); } + + public static int getFieldOffset(StructDefinition structDef, int fieldIndex) { + return fieldIndex * 8; + } + + public static int getFieldOffset(StructDefinition structDef, String fieldName) { + for (int i = 0; i < structDef.fields.length; i++) { + if (structDef.fields[i].name.equals(fieldName)) { + return i * 8; + } + } + + return -1; + } + + public static int getFieldSizeBytes(StructDefinition structDef) { + return structDef.fields.length * 8; + } } \ No newline at end of file From e2986b3d650d9185ffc873dd044b4d143a140e02 Mon Sep 17 00:00:00 2001 From: nitrix Date: Fri, 6 Mar 2020 00:18:48 +0100 Subject: [PATCH 42/61] add the struct name to the struct field access expression node --- src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java | 5 +++-- .../Klang/nodes/expressions/StructFieldAccessExpression.java | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 04fcfc6..d566828 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -289,14 +289,15 @@ public class ContextAnalysis extends KlangBaseVisitor { } // Get the type of the result of this expression + String structName = variableDef.type.getName(); Type resultType; try { - resultType = Helper.drillType(this.structs, variableDef.type.getName(), path, 0); + resultType = Helper.drillType(this.structs, structName, path, 0); } catch (Exception e) { throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); } - Node result = new StructFieldAccessExpression(varName, path); + Node result = new StructFieldAccessExpression(varName, structName, path); result.type = resultType; result.line = line; result.col = col; diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/StructFieldAccessExpression.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/StructFieldAccessExpression.java index 438a5ce..73b9ac8 100644 --- a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/StructFieldAccessExpression.java +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/StructFieldAccessExpression.java @@ -4,10 +4,12 @@ import de.hsrm.compiler.Klang.visitors.Visitor; public class StructFieldAccessExpression extends Expression { public String varName; + public String structName; public String[] path; - public StructFieldAccessExpression(String varName, String[] path) { + public StructFieldAccessExpression(String varName, String structName, String[] path) { this.varName = varName; + this.structName = structName; this.path = path; } From eb75cc78380c87a338cfb6498db44ef7300a51cf Mon Sep 17 00:00:00 2001 From: nitrix Date: Fri, 6 Mar 2020 00:21:59 +0100 Subject: [PATCH 43/61] implement GenASM for structs --- .../hsrm/compiler/Klang/visitors/GenASM.java | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index 7de8e85..5f3169c 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -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; @@ -799,37 +800,67 @@ public class GenASM implements Visitor { @Override public Void visit(StructDefinition e) { - // TODO Auto-generated method stub + // We get these from a previous visitor return null; } @Override public Void visit(StructField e) { - // TODO Auto-generated method stub + // Nothing to do here... return null; } @Override public Void visit(StructFieldAccessExpression e) { - // TODO Auto-generated method stub + 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 + this.ex.write(" movq " + Helper.getFieldOffset(structDef, e.path[i]) + "(%rax), %rax\n"); + } + + // desired value now in rax + return null; } @Override public Void visit(ConstructorCall e) { - // TODO Auto-generated method stub + // push arguments onto the stack + for (var arg: e.args) { + arg.welcome(this); + 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) { - // TODO Auto-generated method stub + this.ex.write(" movq $0, %rax\n"); return null; } @Override public Void visit(DestructorCall e) { - // TODO Auto-generated method stub + this.ex.write(" movq " +this.env.get(e.name) + "(%rbp), %rdi\n"); + this.ex.write(" call free@PLT\n"); return null; } From 86e77d1609579febe98a2b58946fae29f86ba0c2 Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 00:11:48 +0100 Subject: [PATCH 44/61] update the struct definition when following the path --- src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index 5f3169c..b11ad0a 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -822,6 +822,7 @@ public class GenASM implements Visitor { 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])].type.getName()); this.ex.write(" movq " + Helper.getFieldOffset(structDef, e.path[i]) + "(%rax), %rax\n"); } From ed4c901c6cc2ed891a6875a574d7be4d1de6569c Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 00:12:53 +0100 Subject: [PATCH 45/61] add field assignment to statements --- src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index 79141d9..424f1d2 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -40,6 +40,7 @@ statement | if_statement | variable_declaration SCOL | variable_assignment SCOL + | field_assignment SCOL | return_statement | whileLoop | doWhileLoop @@ -68,6 +69,10 @@ variable_assignment : IDENT EQUAL expression ; +field_assignment + : IDENT (DOT IDENT)+ EQUAL expression + ; + return_statement : RETURN expression SCOL ; From 90ed033943d197a6f51d81287554801890d0487d Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 00:13:08 +0100 Subject: [PATCH 46/61] implement fielfd assignment node --- .../nodes/statements/FieldAssignment.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/statements/FieldAssignment.java diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/statements/FieldAssignment.java b/src/main/java/de/hsrm/compiler/Klang/nodes/statements/FieldAssignment.java new file mode 100644 index 0000000..c655106 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/statements/FieldAssignment.java @@ -0,0 +1,25 @@ +package de.hsrm.compiler.Klang.nodes.statements; + +import de.hsrm.compiler.Klang.nodes.expressions.Expression; +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class FieldAssignment extends Statement { + + public String varName; + public String structName; + public String[] path; + public Expression expression; + + public FieldAssignment(String varName, String structName, String[] path, Expression expression) { + this.varName = varName; + this.structName = structName; + this.path = path; + this.expression = expression; + } + + @Override + public R welcome(Visitor v) { + return v.visit(this); + } + +} \ No newline at end of file From e3d8f3cfa777eefdad96ad2b1258e13610ee5379 Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 00:13:37 +0100 Subject: [PATCH 47/61] implement field access visitor --- .../hsrm/compiler/Klang/ContextAnalysis.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index d566828..d807157 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -264,6 +264,53 @@ public class ContextAnalysis extends KlangBaseVisitor { return result; } + @Override + public Node visitField_assignment(KlangParser.Field_assignmentContext ctx) { + String varName = ctx.IDENT(0).getText(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + String[] path = new String[ctx.IDENT().size() - 1]; + + for (int i = 1; i < ctx.IDENT().size(); i++) { + path[i - 1] = ctx.IDENT(i).getText(); + } + + // Get the referenced variable, make sure it is defined + var variableDef = this.vars.get(varName); + if (variableDef == null) { + String error = "Variable with name " + varName + " not defined."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + + // Make sure it references a struct + if (variableDef.type.isPrimitiveType()) { + String error = "Variable must reference a struct but references " + variableDef.type.getName() + "."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + + // Get the type of the result of this expression + String structName = variableDef.type.getName(); + Type fieldType; + try { + fieldType = Helper.drillType(this.structs, structName, path, 0); + } catch (Exception e) { + throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); + } + + // Get the expression and make sure the type combines properly + Expression expression = (Expression) this.visit(ctx.expression()); + try { + fieldType.combine(expression.type); + } catch (Exception e) { + throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); + } + + Node result = new FieldAssignment(varName, structName, path, expression); + result.col = col; + result.line = line; + return result; + } + @Override public Node visitStructFieldAccessExpression(KlangParser.StructFieldAccessExpressionContext ctx) { String varName = ctx.IDENT(0).getText(); From 32cb06cd517057b5698e43e5310f2a824b47762a Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 00:14:06 +0100 Subject: [PATCH 48/61] implement method that returns the index of a field by name --- .../de/hsrm/compiler/Klang/helper/Helper.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java b/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java index c468683..648c4e8 100644 --- a/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java +++ b/src/main/java/de/hsrm/compiler/Klang/helper/Helper.java @@ -42,20 +42,24 @@ public class Helper { throw new RuntimeException("Struct " + structDef.name + " does not contain field " + path[pathIndex]); } - public static int getFieldOffset(StructDefinition structDef, int fieldIndex) { - return fieldIndex * 8; - } - - public static int getFieldOffset(StructDefinition structDef, String fieldName) { + public static int getFieldIndex(StructDefinition structDef, String fieldName) { for (int i = 0; i < structDef.fields.length; i++) { if (structDef.fields[i].name.equals(fieldName)) { - return i * 8; + return i; } } return -1; } + public static int getFieldOffset(StructDefinition structDef, int fieldIndex) { + return fieldIndex * 8; + } + + public static int getFieldOffset(StructDefinition structDef, String fieldName) { + return getFieldIndex(structDef, fieldName) * 8; + } + public static int getFieldSizeBytes(StructDefinition structDef) { return structDef.fields.length * 8; } From 02666a94599661f09ed37469964d21fe90797d1e Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 00:14:31 +0100 Subject: [PATCH 49/61] implement visitors --- .../compiler/Klang/visitors/EvalVisitor.java | 17 ++++++++++++ .../hsrm/compiler/Klang/visitors/GenASM.java | 27 +++++++++++++++++++ .../hsrm/compiler/Klang/visitors/GetVars.java | 5 ++++ .../Klang/visitors/PrettyPrintVisitor.java | 13 +++++++++ .../hsrm/compiler/Klang/visitors/Visitor.java | 1 + 5 files changed, 63 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java index b23fd85..ee14fb9 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -527,4 +527,21 @@ public class EvalVisitor implements Visitor { 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 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; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index b11ad0a..f99f1f9 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -865,4 +865,31 @@ public class GenASM implements Visitor { 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]; + + // Push the expression onto the stack + e.expression.welcome(this); + 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 = 0; i < e.path.length - 1; i++) { + structDef = this.structs.get(structDef.fields[Helper.getFieldIndex(structDef, e.path[i])].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; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java index 7f2848f..771f68b 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -269,4 +269,9 @@ class GetVars implements Visitor { public Void visit(DestructorCall e) { return null; } + + @Override + public Void visit(FieldAssignment e) { + return null; + } } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java index 014feb1..e4f7bd7 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -444,4 +444,17 @@ public class PrettyPrintVisitor implements Visitor { 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; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java index 8df0e0d..eb37121 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -49,4 +49,5 @@ public interface Visitor { R visit(ConstructorCall e); R visit(NullExpression e); R visit(DestructorCall e); + R visit(FieldAssignment e); } \ No newline at end of file From 1403e0a231c2f910b6bdc2379dea4363085ccfb0 Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 00:22:22 +0100 Subject: [PATCH 50/61] fix indices --- src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index f99f1f9..7f9bf1b 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -822,7 +822,7 @@ public class GenASM implements Visitor { 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])].type.getName()); + 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"); } @@ -880,8 +880,8 @@ public class GenASM implements Visitor { // If there are at least two elements in the path, // move the address of the next referenced struct into rax - for (int i = 0; i < e.path.length - 1; i++) { - structDef = this.structs.get(structDef.fields[Helper.getFieldIndex(structDef, e.path[i])].type.getName()); + 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"); } From 9adc48da82d97129eb2db52e98f56c937223d0e1 Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 01:21:29 +0100 Subject: [PATCH 51/61] implement struct tests --- src/test/struct/struct.c | 85 ++++++++++++++++++++++++++++++++++++++++ src/test/struct/struct.h | 31 +++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 src/test/struct/struct.c create mode 100644 src/test/struct/struct.h diff --git a/src/test/struct/struct.c b/src/test/struct/struct.c new file mode 100644 index 0000000..c6d31e7 --- /dev/null +++ b/src/test/struct/struct.c @@ -0,0 +1,85 @@ +#include +#include +#include "struct.h" +#include "../print/print.h" + +// C equivalent implementations of the funcitons written in k +struct testStruct* cGetTestStruct(long a, bool b, long c) { + struct testStruct* result = (struct testStruct*) malloc(sizeof(struct testStruct)); + result->a = a; + result->b = b; + result->c = c; + return result; +} + +struct testStructRec* cGetTestStructRec(long a, struct testStructRec* b) { + struct testStructRec* result = (struct testStructRec*) malloc(sizeof(struct testStructRec)); + result->a = a; + result->b = b; + return result; +} + +int struct_testExpected(char *name, long expected, long result) +{ + if (expected == result) + { + succ(name, expected, result); + return 0; + } + else + { + err(name, expected, result); + return 1; + } +} + +int testStructCreation() { + printf("\nStruct creation tests\n"); + struct testStruct* result = getTestStruct(1, false, 20); + + struct_testExpected("init field a", 1, result->a); + struct_testExpected("init field b", false, result->b); + struct_testExpected("init field c", 20, result->c); + + free(result); + + printf("\n Recursive struct creation tests\n"); + struct testStructRec* innerStruct = getTestStructRec(20, NULL); + struct testStructRec* resultRec = getTestStructRec(10, innerStruct); + + struct_testExpected("init rec field a", 10, resultRec->a); + struct_testExpected("init rec field b", innerStruct, resultRec->b); + struct_testExpected("init inner field a", 20, resultRec->b->a); + struct_testExpected("init inner field b", NULL, resultRec->b->b); + + free(resultRec); + free(innerStruct); +} + +int testStructGet() { + printf("\nStruct getter tests\n"); + struct testStruct* result = getTestStruct(1, false, 20); + + struct_testExpected("get field a", 1, getStructFieldA(result)); + struct_testExpected("get field b", false, getStructFieldB(result)); + struct_testExpected("get field c", 20, getStructFieldC(result)); + + free(result); + + printf("\nStruct getter tests\n"); + struct testStructRec* innerStruct = getTestStructRec(1, NULL); + struct testStructRec* resultRec = getTestStructRec(20, innerStruct); + + struct_testExpected("get rec field a", 20, getStructFieldRecA(resultRec)); + struct_testExpected("get rec field b", innerStruct, getStructFieldRecB(resultRec)); + struct_testExpected("get inner field a", 1, getStructFieldRecA(getStructFieldRecB(resultRec))); + struct_testExpected("get inner field b", NULL, getStructFieldRecB(getStructFieldRecB(resultRec))); + + free(resultRec); + free(innerStruct); +} + +void runStructTests() { + testStructCreation(); + testStructGet(); +} \ No newline at end of file diff --git a/src/test/struct/struct.h b/src/test/struct/struct.h new file mode 100644 index 0000000..80e68a8 --- /dev/null +++ b/src/test/struct/struct.h @@ -0,0 +1,31 @@ +#include + +struct testStruct +{ + long a; + bool b; + long c; +}; + +struct testStructRec +{ + long a; + struct testStructRec *b; +}; + +struct testStruct* getTestStruct(long a, bool b, long c); +struct testStructRec* getTestStructRec(long a, struct testStructRec* b); + +long getStructFieldA(struct testStruct *); +bool getStructFieldB(struct testStruct *); +long getStructFieldC(struct testStruct *); + +struct testStruct *setStructFieldA(struct testStruct *t, long a); +struct testStruct *setStructFieldB(struct testStruct *t, bool b); +struct testStruct *setStructFieldC(struct testStruct *t, long c); + +long getStructFieldRecA(struct testStructRec *t); +struct testStructRec *getStructFieldRecB(struct testStructRec *t); + +struct testStructRec *setStructFieldRecA(struct testStructRec *t, long a); +struct testStructRec *setStructFieldRecB(struct testStructRec *t, struct testStructRec *b); \ No newline at end of file From b776ac00e37791e46b18d6e36959c8dfdeb05156 Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 01:21:53 +0100 Subject: [PATCH 52/61] call struct tests --- src/test/test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/test.c b/src/test/test.c index b5f5589..8a11ea9 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -28,6 +28,9 @@ int main(){ // Tests for while loop runLoopTests(); + // Tests for structs + runStructTests(); + printf("\n%d tests in total\n", successes + failures); if (failures > 0) { From 08398e4064b8600732404b8817e63042731d47d4 Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 01:22:08 +0100 Subject: [PATCH 53/61] add struct test function prototype --- src/test/test.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/test.h b/src/test/test.h index be87439..f25b0e1 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -6,4 +6,5 @@ void runFunctionCallTests(); void runRecursiveTests(); void runComparisonTests(); void runLoopTests(); -void runMathTests(); \ No newline at end of file +void runMathTests(); +void runStructTests(); \ No newline at end of file From 3b5dc43cfba74117e1c29bde496906cc52d2e4e5 Mon Sep 17 00:00:00 2001 From: nitrix Date: Sat, 7 Mar 2020 01:22:38 +0100 Subject: [PATCH 54/61] implement test functions --- src/test/test.k | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/test/test.k b/src/test/test.k index 539f333..0f98231 100644 --- a/src/test/test.k +++ b/src/test/test.k @@ -415,4 +415,68 @@ function mixdiv(x: float, y: int): float { return x / y; } +struct testStruct { + a: int; + b: bool; + c: int; +} + +struct testStructRec { + a: int; + b: testStructRec; +} + +function getTestStruct(a: int, b: bool, c: int): testStruct { + return create testStruct(a, b, c); +} + +function getTestStructRec(a: int, b: testStructRec): testStructRec { + return create testStructRec(a, b); +} + +function getStructFieldA(t: testStruct): int { + return t.a; +} + +function getStructFieldB(t: testStruct): bool { + return t.b; +} + +function getStructFieldC(t: testStruct): int { + return t.c; +} + +function setStructFieldA(t: testStruct, a: int): testStruct { + t.a = a; + return t; +} + +function setStructFieldB(t: testStruct, b: bool): testStruct { + t.b = b; + return t; +} + +function setStructFieldC(t: testStruct, c: int): testStruct { + t.c = c; + return t; +} + +function getStructFieldRecA(t: testStructRec): int { + return t.a; +} + +function getStructFieldRecB(t: testStructRec): testStructRec { + return t.b; +} + +function setStructFieldRecA(t: testStructRec, a: int): testStructRec { + t.a = a; + return t; +} + +function setStructFieldRecB(t: testStructRec, b: testStructRec): testStructRec { + t.b = b; + return t; +} + add(1, 1); From 8bb912b377b319878e52883c2f336f22cab632b0 Mon Sep 17 00:00:00 2001 From: nitrix Date: Mon, 9 Mar 2020 12:51:28 +0100 Subject: [PATCH 55/61] implement isNumericType --- src/main/java/de/hsrm/compiler/Klang/types/NullType.java | 5 +++++ src/main/java/de/hsrm/compiler/Klang/types/StructType.java | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/de/hsrm/compiler/Klang/types/NullType.java b/src/main/java/de/hsrm/compiler/Klang/types/NullType.java index ffb5a33..452efd8 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/NullType.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/NullType.java @@ -33,4 +33,9 @@ public class NullType extends Type { return false; } + @Override + public boolean isNumericType() { + return false; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/types/StructType.java b/src/main/java/de/hsrm/compiler/Klang/types/StructType.java index adf3f8b..23cac1c 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/StructType.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/StructType.java @@ -46,4 +46,9 @@ public class StructType extends Type { return false; } + + @Override + public boolean isNumericType() { + return false; + } } \ No newline at end of file From 31330db67622b39190de065427ec3543a8cfbf07 Mon Sep 17 00:00:00 2001 From: nitrix Date: Mon, 9 Mar 2020 12:53:26 +0100 Subject: [PATCH 56/61] replace DOT with PERIOD --- src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index 424f1d2..70c6333 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -70,7 +70,7 @@ variable_assignment ; field_assignment - : IDENT (DOT IDENT)+ EQUAL expression + : IDENT (PERIOD IDENT)+ EQUAL expression ; return_statement @@ -83,7 +83,7 @@ destroy_statement expression : atom #atomExpression - | IDENT (DOT IDENT)+ #structFieldAccessExpression + | IDENT (PERIOD IDENT)+ #structFieldAccessExpression | OPAR expression CPAR #parenthesisExpression | lhs=expression MUL rhs=expression #multiplicationExpression | lhs=expression DIV rhs=expression #divisionExpression @@ -177,7 +177,6 @@ GTE: '>='; OR: '||'; AND: '&&'; NOT: '!'; -DOT: '.'; MUL: '*'; ADD: '+'; From fc16663dae22551bee70cafacecf3ad6bee2d544 Mon Sep 17 00:00:00 2001 From: nitrix Date: Mon, 9 Mar 2020 13:48:31 +0100 Subject: [PATCH 57/61] make floats work in structs --- .../hsrm/compiler/Klang/visitors/GenASM.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index 7f9bf1b..b9a153f 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -828,6 +828,11 @@ public class GenASM implements Visitor { // 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; } @@ -836,6 +841,12 @@ public class GenASM implements Visitor { // 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"); } @@ -871,8 +882,14 @@ public class GenASM implements Visitor { int offset = this.env.get(e.varName); String fieldNameToUpdate = e.path[e.path.length - 1]; - // Push the expression onto the stack 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 From 1f8de66751044901ca5b0d82e4f4397301c9e5e2 Mon Sep 17 00:00:00 2001 From: nitrix Date: Mon, 9 Mar 2020 13:49:09 +0100 Subject: [PATCH 58/61] update the struct test so that field c of the test struct is of type double --- src/test/struct/struct.c | 8 ++++---- src/test/struct/struct.h | 8 ++++---- src/test/test.k | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/test/struct/struct.c b/src/test/struct/struct.c index c6d31e7..c654a8b 100644 --- a/src/test/struct/struct.c +++ b/src/test/struct/struct.c @@ -35,11 +35,11 @@ int struct_testExpected(char *name, long expected, long result) int testStructCreation() { printf("\nStruct creation tests\n"); - struct testStruct* result = getTestStruct(1, false, 20); + struct testStruct* result = getTestStruct(1, false, 23.3); struct_testExpected("init field a", 1, result->a); struct_testExpected("init field b", false, result->b); - struct_testExpected("init field c", 20, result->c); + struct_testExpected("init field c", 23.3, result->c); free(result); @@ -58,11 +58,11 @@ int testStructCreation() { int testStructGet() { printf("\nStruct getter tests\n"); - struct testStruct* result = getTestStruct(1, false, 20); + struct testStruct* result = getTestStruct(1, false, 23.3); struct_testExpected("get field a", 1, getStructFieldA(result)); struct_testExpected("get field b", false, getStructFieldB(result)); - struct_testExpected("get field c", 20, getStructFieldC(result)); + struct_testExpected("get field c", 23.3, getStructFieldC(result)); free(result); diff --git a/src/test/struct/struct.h b/src/test/struct/struct.h index 80e68a8..459e30c 100644 --- a/src/test/struct/struct.h +++ b/src/test/struct/struct.h @@ -4,7 +4,7 @@ struct testStruct { long a; bool b; - long c; + double c; }; struct testStructRec @@ -13,16 +13,16 @@ struct testStructRec struct testStructRec *b; }; -struct testStruct* getTestStruct(long a, bool b, long c); +struct testStruct* getTestStruct(long a, bool b, double c); struct testStructRec* getTestStructRec(long a, struct testStructRec* b); long getStructFieldA(struct testStruct *); bool getStructFieldB(struct testStruct *); -long getStructFieldC(struct testStruct *); +double getStructFieldC(struct testStruct *); struct testStruct *setStructFieldA(struct testStruct *t, long a); struct testStruct *setStructFieldB(struct testStruct *t, bool b); -struct testStruct *setStructFieldC(struct testStruct *t, long c); +struct testStruct *setStructFieldC(struct testStruct *t, double c); long getStructFieldRecA(struct testStructRec *t); struct testStructRec *getStructFieldRecB(struct testStructRec *t); diff --git a/src/test/test.k b/src/test/test.k index 0f98231..395afa2 100644 --- a/src/test/test.k +++ b/src/test/test.k @@ -418,7 +418,7 @@ function mixdiv(x: float, y: int): float { struct testStruct { a: int; b: bool; - c: int; + c: float; } struct testStructRec { @@ -426,7 +426,7 @@ struct testStructRec { b: testStructRec; } -function getTestStruct(a: int, b: bool, c: int): testStruct { +function getTestStruct(a: int, b: bool, c: float): testStruct { return create testStruct(a, b, c); } @@ -442,7 +442,7 @@ function getStructFieldB(t: testStruct): bool { return t.b; } -function getStructFieldC(t: testStruct): int { +function getStructFieldC(t: testStruct): float { return t.c; } @@ -456,7 +456,7 @@ function setStructFieldB(t: testStruct, b: bool): testStruct { return t; } -function setStructFieldC(t: testStruct, c: int): testStruct { +function setStructFieldC(t: testStruct, c: float): testStruct { t.c = c; return t; } From 0adb9e22da247b09b7d5ba39f5d1972ac7836fa8 Mon Sep 17 00:00:00 2001 From: nitrix Date: Mon, 9 Mar 2020 14:10:03 +0100 Subject: [PATCH 59/61] implement print function for struct addresses and bools --- src/test/print/print.c | 20 ++++++++++++++++++++ src/test/print/print.h | 6 ++++++ 2 files changed, 26 insertions(+) diff --git a/src/test/print/print.c b/src/test/print/print.c index b995765..71df87a 100644 --- a/src/test/print/print.c +++ b/src/test/print/print.c @@ -38,6 +38,26 @@ void err_f(char* name, double expected, double result) { printf("\033[0;31mERROR:\t\t%s:\tGOT: %f\tExpected: %f\033[0;0m\n", name, result, expected); } +void succ_s(char* name, void* expected, void* result) { + incSuccess(); + printf("\033[0;32mSUCCESS:\t%s:\tGOT: %p\tExpected: %p\033[0;0m\n", name, result, expected); +} + +void err_s(char* name, void* expected, void* result) { + incFailure(); + printf("\033[0;31mERROR:\t\t%s:\tGOT: %p\tExpected: %p\033[0;0m\n", name, result, expected); +} + +void succ_b(char* name, bool expected, bool result) { + incSuccess(); + printf("\033[0;32mSUCCESS:\t%s:\tGOT: %s\tExpected: %s\033[0;0m\n", name, printBool(result), printBool(expected)); +} + +void err_b(char* name, bool expected, bool result) { + incFailure(); + printf("\033[0;31mERROR:\t\t%s:\tGOT: %s\tExpected: %s\033[0;0m\n", name, printBool(result), printBool(expected)); +} + void succPrefixOne(char* name, long x, long expected, long result) { incSuccess(); printf("\033[0;32mSUCCESS:\t%s(%ld)\tGOT: %ld\tExpected: %ld\033[0;0m\n", name, x, result, expected); diff --git a/src/test/print/print.h b/src/test/print/print.h index 2c08103..df17dc0 100644 --- a/src/test/print/print.h +++ b/src/test/print/print.h @@ -9,6 +9,12 @@ void err(char* name, long expected, long result); void succ_f(char* name, double expected, double result); void err_f(char* name, double expected, double result); +void succ_s(char* name, void* expected, void* result); +void err_s(char* name, void* expected, void* result); + +void succ_b(char* name, bool expected, bool result); +void err_b(char* name, bool expected, bool result); + void succPrefixOne(char* name, long x, long expected, long result); void errPrefixOne(char* name, long x, long expected, long result); From 4a9e5c30e1549d1d3490f131a8a2da4640d65989 Mon Sep 17 00:00:00 2001 From: nitrix Date: Mon, 9 Mar 2020 14:10:35 +0100 Subject: [PATCH 60/61] implement test_expected functions for all types in use --- src/test/struct/struct.c | 72 +++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/src/test/struct/struct.c b/src/test/struct/struct.c index c654a8b..fec56a3 100644 --- a/src/test/struct/struct.c +++ b/src/test/struct/struct.c @@ -19,7 +19,7 @@ struct testStructRec* cGetTestStructRec(long a, struct testStructRec* b) { return result; } -int struct_testExpected(char *name, long expected, long result) +int struct_testExpected_l(char *name, long expected, long result) { if (expected == result) { @@ -33,13 +33,55 @@ int struct_testExpected(char *name, long expected, long result) } } +int struct_testExpected_s(char *name, void* expected, void* result) +{ + if (expected == result) + { + succ_s(name, expected, result); + return 0; + } + else + { + err_s(name, expected, result); + return 1; + } +} + +int struct_testExpected_f(char *name, double expected, double result) +{ + if (expected == result) + { + succ_f(name, expected, result); + return 0; + } + else + { + err_f(name, expected, result); + return 1; + } +} + +int struct_testExpected_b(char *name, bool expected, bool result) +{ + if (expected == result) + { + succ_b(name, expected, result); + return 0; + } + else + { + err_b(name, expected, result); + return 1; + } +} + int testStructCreation() { printf("\nStruct creation tests\n"); struct testStruct* result = getTestStruct(1, false, 23.3); - struct_testExpected("init field a", 1, result->a); - struct_testExpected("init field b", false, result->b); - struct_testExpected("init field c", 23.3, result->c); + struct_testExpected_l("init field a", 1, result->a); + struct_testExpected_b("init field b", false, result->b); + struct_testExpected_f("init field c", 23.3, result->c); free(result); @@ -47,10 +89,10 @@ int testStructCreation() { struct testStructRec* innerStruct = getTestStructRec(20, NULL); struct testStructRec* resultRec = getTestStructRec(10, innerStruct); - struct_testExpected("init rec field a", 10, resultRec->a); - struct_testExpected("init rec field b", innerStruct, resultRec->b); - struct_testExpected("init inner field a", 20, resultRec->b->a); - struct_testExpected("init inner field b", NULL, resultRec->b->b); + struct_testExpected_l("init rec field a", 10, resultRec->a); + struct_testExpected_s("init rec field b", innerStruct, resultRec->b); + struct_testExpected_l("init inner field a", 20, resultRec->b->a); + struct_testExpected_s("init inner field b", NULL, resultRec->b->b); free(resultRec); free(innerStruct); @@ -60,9 +102,9 @@ int testStructGet() { printf("\nStruct getter tests\n"); struct testStruct* result = getTestStruct(1, false, 23.3); - struct_testExpected("get field a", 1, getStructFieldA(result)); - struct_testExpected("get field b", false, getStructFieldB(result)); - struct_testExpected("get field c", 23.3, getStructFieldC(result)); + struct_testExpected_l("get field a", 1, getStructFieldA(result)); + struct_testExpected_b("get field b", false, getStructFieldB(result)); + struct_testExpected_f("get field c", 23.3, getStructFieldC(result)); free(result); @@ -70,10 +112,10 @@ int testStructGet() { struct testStructRec* innerStruct = getTestStructRec(1, NULL); struct testStructRec* resultRec = getTestStructRec(20, innerStruct); - struct_testExpected("get rec field a", 20, getStructFieldRecA(resultRec)); - struct_testExpected("get rec field b", innerStruct, getStructFieldRecB(resultRec)); - struct_testExpected("get inner field a", 1, getStructFieldRecA(getStructFieldRecB(resultRec))); - struct_testExpected("get inner field b", NULL, getStructFieldRecB(getStructFieldRecB(resultRec))); + struct_testExpected_l("get rec field a", 20, getStructFieldRecA(resultRec)); + struct_testExpected_s("get rec field b", innerStruct, getStructFieldRecB(resultRec)); + struct_testExpected_l("get inner field a", 1, getStructFieldRecA(getStructFieldRecB(resultRec))); + struct_testExpected_s("get inner field b", NULL, getStructFieldRecB(getStructFieldRecB(resultRec))); free(resultRec); free(innerStruct); From 14f80b46cc371930664d880254a413a9d6cb00cf Mon Sep 17 00:00:00 2001 From: nitrix Date: Mon, 9 Mar 2020 14:12:19 +0100 Subject: [PATCH 61/61] remove whitespace --- src/test/struct/struct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/struct/struct.c b/src/test/struct/struct.c index fec56a3..ca512fe 100644 --- a/src/test/struct/struct.c +++ b/src/test/struct/struct.c @@ -85,7 +85,7 @@ int testStructCreation() { free(result); - printf("\n Recursive struct creation tests\n"); + printf("\nRecursive struct creation tests\n"); struct testStructRec* innerStruct = getTestStructRec(20, NULL); struct testStructRec* resultRec = getTestStructRec(10, innerStruct);