From af1021ed66cfc72ca22b710a5fed037419ab2d83 Mon Sep 17 00:00:00 2001 From: Marvin Kaiser Date: Mon, 9 Mar 2020 21:08:04 +0100 Subject: [PATCH] 31: Add void type --- .../antlr4/de/hsrm/compiler/Klang/Klang.g4 | 6 ++- .../hsrm/compiler/Klang/ContextAnalysis.java | 25 +++++++++++- .../java/de/hsrm/compiler/Klang/Klang.java | 10 ++++- .../nodes/statements/ReturnStatement.java | 4 ++ .../de/hsrm/compiler/Klang/types/Type.java | 5 +++ .../hsrm/compiler/Klang/types/VoidType.java | 38 +++++++++++++++++++ .../compiler/Klang/visitors/EvalVisitor.java | 3 ++ .../hsrm/compiler/Klang/visitors/GenASM.java | 4 +- .../hsrm/compiler/Klang/visitors/GetVars.java | 4 +- .../Klang/visitors/PrettyPrintVisitor.java | 7 +++- 10 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 src/main/java/de/hsrm/compiler/Klang/types/VoidType.java diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index a1a176a..cc5bc0e 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -29,7 +29,7 @@ parameter ; braced_block - : OBRK statement+ CBRK + : OBRK (statement | functionCall SCOL)+ CBRK ; @@ -69,7 +69,7 @@ field_assignment ; return_statement - : RETURN expression SCOL + : RETURN expression? SCOL ; destroy_statement @@ -116,6 +116,7 @@ type | BOOLEAN | FLOAT | IDENT + | VOID ; functionCall @@ -181,6 +182,7 @@ DIV: '/'; BOOLEAN: 'bool'; INTEGER: 'int'; FLOAT: 'float'; +VOID: 'void'; INTEGER_LITERAL : [0-9]+ diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 61275a6..01683f9 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -176,6 +176,11 @@ public class ContextAnalysis extends KlangBaseVisitor { int col = ctx.start.getCharPositionInLine(); Type declaredType = Type.getByName(ctx.type_annotation().type().getText()); + if (declaredType.equals(Type.getVoidType())) { + String error = "Type " + declaredType.getName() + " can not be used to declare variables."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + if (!declaredType.isPrimitiveType() && this.structs.get(declaredType.getName()) == null) { String error = "Type " + declaredType.getName() + " not defined."; throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); @@ -244,10 +249,21 @@ public class ContextAnalysis extends KlangBaseVisitor { @Override public Node visitReturn_statement(KlangParser.Return_statementContext ctx) { + if (currentDeclaredReturnType.equals(Type.getVoidType())) { + ReturnStatement result = new ReturnStatement(); + result.line = ctx.start.getLine(); + result.type = Type.getVoidType(); + result.col = ctx.start.getCharPositionInLine(); + if (ctx.expression() != null) { + String error = "Cannot return an expression from a void function."; + throw new RuntimeException(Helper.getErrorPrefix(result.line, result.col) + error); + } + return result; + } Expression expression = (Expression) this.visit(ctx.expression()); ReturnStatement result = new ReturnStatement(expression); - result.type = expression.type; result.line = ctx.start.getLine(); + result.type = expression.type; result.col = ctx.start.getCharPositionInLine(); return result; } @@ -721,7 +737,7 @@ public class ContextAnalysis extends KlangBaseVisitor { Type returnType = Type.getByName(ctx.returnType.type().getText()); this.currentDeclaredReturnType = returnType; - if (!returnType.isPrimitiveType() && this.structs.get(returnType.getName()) == null) { + if (!returnType.isPrimitiveType() && this.structs.get(returnType.getName()) == null && !returnType.equals(Type.getVoidType())) { String error = "Type " + returnType.getName() + " not defined."; throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); } @@ -767,6 +783,11 @@ public class ContextAnalysis extends KlangBaseVisitor { int col = ctx.start.getCharPositionInLine(); Type type = Type.getByName(ctx.type_annotation().type().getText()); + if (type.equals(Type.getVoidType())) { + String error = "Type " + type.getName() + " cannot be used to declare a parameter."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + 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/Klang.java b/src/main/java/de/hsrm/compiler/Klang/Klang.java index 1c951d0..d99f9f8 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Klang.java +++ b/src/main/java/de/hsrm/compiler/Klang/Klang.java @@ -12,6 +12,7 @@ import java.util.HashSet; import de.hsrm.compiler.Klang.nodes.Node; import de.hsrm.compiler.Klang.nodes.StructDefinition; +import de.hsrm.compiler.Klang.types.Type; import de.hsrm.compiler.Klang.visitors.*; import de.hsrm.compiler.Klang.helper.*; @@ -115,7 +116,8 @@ public class Klang { PrettyPrintVisitor.ExWriter ex = new PrettyPrintVisitor.ExWriter(w); PrettyPrintVisitor printVisitor = new PrettyPrintVisitor(ex); root.welcome(printVisitor); - System.out.println(w.toString()); + generateOutput(out, w.toString()); + return; } if (evaluate) { @@ -123,7 +125,11 @@ public class Klang { System.out.println("\nEvaluating the source code:"); EvalVisitor evalVisitor = new EvalVisitor(structs); Value result = root.welcome(evalVisitor); - generateOutput(out, "Result was: " + result.asObject().toString()); + if (result.type.equals(Type.getVoidType())) { + generateOutput(out, "Result was void"); + } else { + generateOutput(out, "Result was: " + result.asObject().toString()); + } return; } diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/statements/ReturnStatement.java b/src/main/java/de/hsrm/compiler/Klang/nodes/statements/ReturnStatement.java index ef37a52..e98ddf7 100644 --- a/src/main/java/de/hsrm/compiler/Klang/nodes/statements/ReturnStatement.java +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/statements/ReturnStatement.java @@ -11,6 +11,10 @@ public class ReturnStatement extends Statement { this.expression = expression; } + public ReturnStatement() { + this.expression = null; + } + @Override public R welcome(Visitor v) { return v.visit(this); 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 15b2810..f924e0b 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/Type.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/Type.java @@ -20,12 +20,17 @@ public abstract class Type { return NullType.getType(); } + public static VoidType getVoidType() { + return VoidType.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(); + case "void": return getVoidType(); default: return new StructType(name); } } diff --git a/src/main/java/de/hsrm/compiler/Klang/types/VoidType.java b/src/main/java/de/hsrm/compiler/Klang/types/VoidType.java new file mode 100644 index 0000000..f407327 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/types/VoidType.java @@ -0,0 +1,38 @@ +package de.hsrm.compiler.Klang.types; + +public class VoidType extends Type { + + private static VoidType instance; + + public static VoidType getType() { + if (instance != null) { + return instance; + } + instance = new VoidType(); + return instance; +} + + @Override + public String getName() { + return "void"; + } + + @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 isNumericType() { + return false; + } + +} \ 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 dad982e..58ecabb 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -413,6 +413,9 @@ public class EvalVisitor implements Visitor { @Override public Value visit(ReturnStatement e) { + if (e.expression == null) { + return new Value(null, Type.getVoidType()); + } return e.expression.welcome(this); } 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 1bc49dc..0574a8c 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -589,7 +589,9 @@ public class GenASM implements Visitor { @Override public Void visit(ReturnStatement e) { - e.expression.welcome(this); + if (e.expression != null) { + e.expression.welcome(this); + } this.ex.write(" movq %rbp, %rsp\n"); this.ex.write(" popq %rbp\n"); this.ex.write(" ret\n"); 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 50d807d..b7a039f 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -194,7 +194,9 @@ class GetVars implements Visitor { @Override public Void visit(ReturnStatement e) { - e.expression.welcome(this); + if (e.expression != null) { + e.expression.welcome(this); + } return null; } 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 563779b..db31a23 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -304,8 +304,11 @@ public class PrettyPrintVisitor implements Visitor { @Override public Void visit(ReturnStatement e) { - ex.write("return "); - e.expression.welcome(this); + ex.write("return"); + if (e.expression != null) { + ex.write(" "); + e.expression.welcome(this); + } ex.write(";"); return null; }