31: Add void type
This commit is contained in:
@@ -33,7 +33,7 @@ parameter
|
||||
;
|
||||
|
||||
braced_block
|
||||
: OBRK statement+ CBRK
|
||||
: OBRK (statement | functionCall SCOL)+ CBRK
|
||||
;
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ field_assignment
|
||||
;
|
||||
|
||||
return_statement
|
||||
: RETURN expression SCOL
|
||||
: RETURN expression? SCOL
|
||||
;
|
||||
|
||||
destroy_statement
|
||||
@@ -120,6 +120,7 @@ type
|
||||
| BOOLEAN
|
||||
| FLOAT
|
||||
| IDENT
|
||||
| VOID
|
||||
;
|
||||
|
||||
functionCall
|
||||
@@ -186,6 +187,7 @@ DIV: '/';
|
||||
BOOLEAN: 'bool';
|
||||
INTEGER: 'int';
|
||||
FLOAT: 'float';
|
||||
VOID: 'void';
|
||||
|
||||
INTEGER_LITERAL
|
||||
: [0-9]+
|
||||
|
||||
@@ -186,6 +186,11 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||
var line = ctx.start.getLine();
|
||||
var col = ctx.start.getCharPositionInLine();
|
||||
|
||||
if (declaredType.equals(Type.getVoidType())) {
|
||||
var error = "Type " + declaredType.getName() + " can not be used to declare variables.";
|
||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||
}
|
||||
|
||||
if (!declaredType.isPrimitiveType() && !structDefs.containsKey(declaredType.getName()) && !enumDefs.containsKey(declaredType.getName())) {
|
||||
var error = "Type " + declaredType.getName() + " not defined.";
|
||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||
@@ -266,6 +271,18 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||
|
||||
@Override
|
||||
public Node visitReturn_statement(KlangParser.Return_statementContext ctx) {
|
||||
if (currentDeclaredReturnType.equals(Type.getVoidType())) {
|
||||
ReturnStatement result = new ReturnStatement();
|
||||
result.type = Type.getVoidType();
|
||||
result.line = ctx.start.getLine();
|
||||
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);
|
||||
|
||||
@@ -277,8 +294,8 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||
}
|
||||
}
|
||||
|
||||
result.type = expression.type;
|
||||
result.line = ctx.start.getLine();
|
||||
result.type = expression.type;
|
||||
result.col = ctx.start.getCharPositionInLine();
|
||||
return result;
|
||||
}
|
||||
@@ -826,26 +843,29 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||
public Node visitParameter(KlangParser.ParameterContext ctx) {
|
||||
var parameterName = ctx.IDENT().getText();
|
||||
var parameterType = Type.getByName(ctx.type_annotation().type().getText());
|
||||
|
||||
if (structDefs.containsKey(parameterName)) {
|
||||
var line = ctx.start.getLine();
|
||||
var col = ctx.start.getCharPositionInLine();
|
||||
|
||||
if (parameterType.equals(Type.getVoidType())) {
|
||||
var error = "Type " + parameterType.getName() + " cannot be used to declare a parameter.";
|
||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||
}
|
||||
|
||||
if (structDefs.containsKey(parameterName)) {
|
||||
var error = "Parameter name " + parameterName + " duplicates a struct of the same name.";
|
||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||
}
|
||||
|
||||
if (enumDefs.containsKey(parameterName)) {
|
||||
var line = ctx.start.getLine();
|
||||
var col = ctx.start.getCharPositionInLine();
|
||||
var error = "Parameter name " + parameterName + " duplicates an enum of the same name.";
|
||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||
}
|
||||
|
||||
if (!parameterType.isPrimitiveType() && !structDefs.containsKey(parameterType.getName()) && !enumDefs.containsKey(parameterType.getName())) {
|
||||
var line = ctx.type_annotation().start.getLine();
|
||||
var col = ctx.type_annotation().start.getCharPositionInLine();
|
||||
var typeLine = ctx.type_annotation().start.getLine();
|
||||
var typeCol = ctx.type_annotation().start.getCharPositionInLine();
|
||||
var error = "Type " + parameterType.getName() + " not defined.";
|
||||
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
|
||||
throw new RuntimeException(Helper.getErrorPrefix(typeLine, typeCol) + error);
|
||||
}
|
||||
|
||||
var parameter = new Parameter(parameterName);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package de.hsrm.compiler.Klang;
|
||||
|
||||
import de.hsrm.compiler.Klang.helper.*;
|
||||
import de.hsrm.compiler.Klang.nodes.EnumDefinition;
|
||||
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
|
||||
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.EvalVisitor;
|
||||
import de.hsrm.compiler.Klang.visitors.GenASM;
|
||||
import de.hsrm.compiler.Klang.visitors.PrettyPrintVisitor;
|
||||
@@ -120,7 +122,11 @@ public class Klang {
|
||||
System.out.println("\nEvaluating the source code:");
|
||||
EvalVisitor evalVisitor = new EvalVisitor(structDefs);
|
||||
Value result = root.welcome(evalVisitor);
|
||||
if (result.type.equals(Type.getVoidType())) {
|
||||
generateOutput(out, "Result was void");
|
||||
} else {
|
||||
generateOutput(out, "Result was: " + result.asObject().toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ public class ReturnStatement extends Statement {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public ReturnStatement() {
|
||||
this.expression = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R welcome(Visitor<R> v) {
|
||||
return v.visit(this);
|
||||
|
||||
@@ -27,12 +27,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 NamedType(name);
|
||||
}
|
||||
}
|
||||
|
||||
45
src/main/java/de/hsrm/compiler/Klang/types/VoidType.java
Normal file
45
src/main/java/de/hsrm/compiler/Klang/types/VoidType.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package de.hsrm.compiler.Klang.types;
|
||||
|
||||
import de.hsrm.compiler.Klang.Value;
|
||||
|
||||
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 mismatch: cannot combine " + this.getName() + " and " + that.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valuesEqual(Value a, Value b) {
|
||||
throw new RuntimeException("Can not compare void types.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrimitiveType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNumericType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -396,6 +396,9 @@ public class EvalVisitor implements Visitor<Value> {
|
||||
|
||||
@Override
|
||||
public Value visit(ReturnStatement e) {
|
||||
if (e.expression == null) {
|
||||
return new Value(null, Type.getVoidType());
|
||||
}
|
||||
return e.expression.welcome(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -525,7 +525,9 @@ public class GenASM implements Visitor<Void> {
|
||||
|
||||
@Override
|
||||
public Void visit(ReturnStatement e) {
|
||||
if (e.expression != null) {
|
||||
e.expression.welcome(this);
|
||||
}
|
||||
|
||||
// The ReturnStatement visitor is kindly removing the
|
||||
// stack space that was allocated by the FunctionDefinition
|
||||
|
||||
@@ -194,7 +194,9 @@ class GetVars implements Visitor<Void> {
|
||||
|
||||
@Override
|
||||
public Void visit(ReturnStatement e) {
|
||||
if (e.expression != null) {
|
||||
e.expression.welcome(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -310,8 +310,11 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
||||
|
||||
@Override
|
||||
public Void visit(ReturnStatement e) {
|
||||
ex.write("return ");
|
||||
ex.write("return");
|
||||
if (e.expression != null) {
|
||||
ex.write(" ");
|
||||
e.expression.welcome(this);
|
||||
}
|
||||
ex.write(";");
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user