Merge branch 'feature/better-errors' into 'master'

Feature/better errors

See merge request mkais001/klang!10
This commit is contained in:
Dennis Kaiser
2020-02-03 23:50:49 +01:00
6 changed files with 225 additions and 60 deletions

View File

@@ -4,6 +4,7 @@ import java.util.Map;
import java.util.HashMap;
import de.hsrm.compiler.Klang.helper.FunctionInformation;
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;
@@ -28,8 +29,10 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
funcs[i] = (FunctionDefinition) this.visit(ctx.functionDef(i));
}
Expression expression = (Expression) this.visit(ctx.expression());
Program result = new Program(funcs, expression);
Program result = new Program(funcs, expression);
result.type = expression.type;
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@@ -52,13 +55,19 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
statements[i] = (Statement) currentStatement;
actualStatementCount += 1;
// We use the existance of a type to indicate that this statement returns something
// for which the VariableDeclaration is an exception
// We use the existance of a type to indicate that this statement returns
// something for which the VariableDeclaration is an exception
if (currentStatement.type != null && !(currentStatement instanceof VariableDeclaration)) {
// check whether the type matches
this.currentDeclaredReturnType.combine(currentStatement.type);
try {
this.currentDeclaredReturnType.combine(currentStatement.type);
} catch (Exception e) {
throw new RuntimeException(
Helper.getErrorPrefix(currentStatement.line, currentStatement.col) + e.getMessage());
}
// since we have a return guaranteed, every statement after this one is unreachable code
// since we have a return guaranteed, every statement
// after this one is unreachable code
hasReturn = true;
break;
}
@@ -81,14 +90,20 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
result.type = this.currentDeclaredReturnType;
}
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@Override
public Node visitPrint(KlangParser.PrintContext ctx) {
ctx.start.getLine();
ctx.start.getCharPositionInLine();
Node expression = this.visit(ctx.expression());
PrintStatement result = new PrintStatement((Expression) expression);
PrintStatement result = new PrintStatement((Expression) expression);
result.type = null;
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@@ -112,9 +127,14 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
}
if (thenBlock.type != null && type != null) {
result.type = thenBlock.type.combine(type);
// Since a block verifies that it can combine with the return type of the
// function it is defined in, we do not have check whether the then and
// alt block return types match
result.type = thenBlock.type;
}
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@@ -122,14 +142,20 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitWhileLoop(KlangParser.WhileLoopContext ctx) {
Node condition = this.visit(ctx.cond);
Node block = this.visit(ctx.braced_block());
return new WhileLoop((Expression) condition, (Block) block);
Node result = new WhileLoop((Expression) condition, (Block) block);
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@Override
public Node visitDoWhileLoop(KlangParser.DoWhileLoopContext ctx) {
Node condition = this.visit(ctx.cond);
Node block = this.visit(ctx.braced_block());
return new DoWhileLoop((Expression) condition, (Block) block);
Node result = new DoWhileLoop((Expression) condition, (Block) block);
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@Override
@@ -138,23 +164,33 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
Node condition = this.visit(ctx.cond);
Node step = this.visit(ctx.step);
Node block = this.visit(ctx.braced_block());
return new ForLoop((Statement) init, (Expression) condition, (VariableAssignment) step, (Block) block);
Node result = new ForLoop((Statement) init, (Expression) condition, (VariableAssignment) step, (Block) block);
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@Override
public Node visitVariable_declaration(KlangParser.Variable_declarationContext ctx) {
String name = ctx.IDENT().getText();
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
Type declaredType = Type.getByName(ctx.type_annotation().type().getText());
if (this.vars.get(name) != null) {
throw new RuntimeException("Redeclaration of variable with name \"" + name + "\".");
String error = "Redeclaration of variable with name \"" + name + "\".";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
// Create the appropriate instance
VariableDeclaration result;
if (ctx.expression() != null) {
Node expression = this.visit(ctx.expression());
declaredType = declaredType.combine(expression.type);
try {
declaredType = declaredType.combine(expression.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
result = new VariableDeclaration(name, (Expression) expression);
result.type = declaredType; // add the type only if there is an expression
} else {
@@ -164,26 +200,38 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
// Add it to the global map of variable declarations
this.vars.put(name, result);
result.line = line;
result.col = col;
return result;
}
@Override
public Node visitVariable_assignment(KlangParser.Variable_assignmentContext 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) {
throw new RuntimeException("Variable with name \"" + name + "\" not defined.");
String error = "Variable with name \"" + name + "\" not defined.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
// Evaluate the expression
Expression expression = (Expression) this.visit(ctx.expression());
// Make sure expression can be assigned to the variable
expression.type.combine(var.type);
try {
expression.type.combine(var.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
// Create a new node and add the type of the expression to it
return new VariableAssignment(name, expression);
Node result = new VariableAssignment(name, expression);
result.line = line;
result.col = col;
return result;
}
@Override
@@ -191,6 +239,8 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
Expression expression = (Expression) this.visit(ctx.expression());
ReturnStatement result = new ReturnStatement(expression);
result.type = expression.type;
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@@ -199,7 +249,9 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
OrExpression result = new OrExpression((Expression) lhs, (Expression) rhs);
result.type = lhs.type.combine(rhs.type);
result.type = Type.getBooleanType();
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@@ -208,7 +260,9 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
AndExpression result = new AndExpression((Expression) lhs, (Expression) rhs);
result.type = lhs.type.combine(rhs.type);
result.type = Type.getBooleanType();
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@@ -216,8 +270,16 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitAdditionExpression(KlangParser.AdditionExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
AdditionExpression result = new AdditionExpression((Expression) lhs, (Expression) rhs);
result.type = lhs.type.combine(rhs.type);
try {
result.type = lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@@ -230,13 +292,19 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitEqualityExpression(KlangParser.EqualityExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) {
throw new RuntimeException("Both operants of this expression have to be a number");
try {
lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
EqualityExpression result = new EqualityExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
return result;
}
@@ -244,13 +312,18 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitNotEqualityExpression(KlangParser.NotEqualityExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) {
throw new RuntimeException("Both operants of this expression have to be a number");
String error = "Both operants of this expression have to be a number.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
NotEqualityExpression result = new NotEqualityExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
return result;
}
@@ -258,13 +331,18 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitLessThanExpression(KlangParser.LessThanExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) {
throw new RuntimeException("Both operants of this expression have to be a number");
String error = "Both operants of this expression have to be a number.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
LTExpression result = new LTExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
return result;
}
@@ -272,13 +350,18 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitGreaterThanExpression(KlangParser.GreaterThanExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) {
throw new RuntimeException("Both operants of this expression have to be a number");
String error = "Both operants of this expression have to be a number.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
GTExpression result = new GTExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
return result;
}
@@ -286,13 +369,18 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitLessThanOrEqualToExpression(KlangParser.LessThanOrEqualToExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) {
throw new RuntimeException("Both operants of this expression have to be a number");
String error = "Both operants of this expression have to be a number.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
LTEExpression result = new LTEExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
return result;
}
@@ -300,13 +388,18 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitGreaterThanOrEqualToExpression(KlangParser.GreaterThanOrEqualToExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) {
throw new RuntimeException("Both operants of this expression have to be a number");
String error = "Both operants of this expression have to be a number.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
GTEExpression result = new GTEExpression((Expression) lhs, (Expression) rhs);
result.type = Type.getBooleanType();
result.line = line;
result.col = col;
return result;
}
@@ -314,8 +407,16 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitSubstractionExpression(KlangParser.SubstractionExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
SubstractionExpression result = new SubstractionExpression((Expression) lhs, (Expression) rhs);
result.type = lhs.type.combine(rhs.type);
try {
result.type = lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
result.line = line;
result.col = col;
return result;
}
@@ -323,8 +424,16 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitMultiplicationExpression(KlangParser.MultiplicationExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
MultiplicationExpression result = new MultiplicationExpression((Expression) lhs, (Expression) rhs);
result.type = lhs.type.combine(rhs.type);
try {
result.type = lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
result.line = line;
result.col = col;
return result;
}
@@ -332,8 +441,16 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitDivisionExpression(KlangParser.DivisionExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
DivisionExpression result = new DivisionExpression((Expression) lhs, (Expression) rhs);
result.type = lhs.type.combine(rhs.type);
try {
result.type = lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
result.line = line;
result.col = col;
return result;
}
@@ -341,8 +458,16 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitModuloExpression(KlangParser.ModuloExpressionContext ctx) {
Node lhs = this.visit(ctx.lhs);
Node rhs = this.visit(ctx.rhs);
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
ModuloExpression result = new ModuloExpression((Expression) lhs, (Expression) rhs);
result.type = lhs.type.combine(rhs.type);
try {
result.type = lhs.type.combine(rhs.type);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
result.line = line;
result.col = col;
return result;
}
@@ -351,6 +476,8 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
Node expression = this.visit(ctx.expression());
NegateExpression result = new NegateExpression((Expression) expression);
result.type = expression.type;
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@@ -359,20 +486,27 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
Node expression = this.visit(ctx.expression());
NotExpression result = new NotExpression((Expression) expression);
result.type = expression.type;
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@Override
public Node visitVariable(KlangParser.VariableContext 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) {
throw new RuntimeException("Variable with name \"" + name + "\" not defined.");
String error = "Variable with name \"" + name + "\" not defined.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
Variable result = new Variable(ctx.IDENT().getText());
result.type = var.type;
result.line = line;
result.col = col;
return result;
}
@@ -385,6 +519,8 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitIntAtom(KlangParser.IntAtomContext ctx) {
Node n = new IntegerExpression(Integer.parseInt(ctx.getText()));
n.type = Type.getIntegerType();
n.line = ctx.start.getLine();
n.col = ctx.start.getCharPositionInLine();
return n;
}
@@ -392,12 +528,16 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
public Node visitBoolAtom(KlangParser.BoolAtomContext ctx) {
Node n = new BooleanExpression(ctx.getText().equals("true") ? true : false);
n.type = Type.getBooleanType();
n.line = ctx.start.getLine();
n.col = ctx.start.getCharPositionInLine();
return n;
}
@Override
public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) {
String name = ctx.funcName.getText();
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
Type returnType = Type.getByName(ctx.returnType.type().getText());
this.currentDeclaredReturnType = returnType;
@@ -419,13 +559,18 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
this.vars.put(param.name, var);
}
// Visit the block, make sure the types are matching
// Visit the block, make sure that a return value is guaranteed
Node block = this.visit(ctx.braced_block());
block.type.combine(returnType);
if (block.type == null) {
String error = "Function " + name + " has to return something of type " + returnType.getName() + ".";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
FunctionDefinition result = new FunctionDefinition(name, params, (Block) block);
result.type = returnType;
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@@ -435,35 +580,47 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
Type type = Type.getByName(ctx.type_annotation().type().getText());
Parameter result = new Parameter(name);
result.type = type;
result.line = ctx.start.getLine();
result.col = ctx.start.getCharPositionInLine();
return result;
}
@Override
public Node visitFunctionCallExpression(KlangParser.FunctionCallExpressionContext ctx) {
String name = ctx.functionCall().IDENT().getText();
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
FunctionInformation func = this.funcs.get(name);
if (func == null) {
throw new RuntimeException("Function with name \"" + name + "\" not defined.");
String error = "Function with name \"" + name + "\" not defined.";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
// Make sure the number of arguments matches the number of parameters
int argCount = ctx.functionCall().arguments().expression().size();
int paramCount = func.parameters.size();
if (argCount != paramCount) {
throw new RuntimeException("Function \"" + name + "\" expects " + paramCount + " parameters, but got " + argCount + ".");
String error = "Function \"" + name + "\" expects " + paramCount + " parameters, but got " + argCount + ".";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
// Evaluate every argument
Expression[] args = new Expression[argCount];
for (int i = 0; i < argCount; i++) {
Expression expression = (Expression) this.visit(ctx.functionCall().arguments().expression(i));
expression.type.combine(func.signature[i]); // Make sure the types are matching
Expression expression = (Expression) this.visit(ctx.functionCall().arguments().expression(i));
try {
expression.type.combine(func.signature[i]); // Make sure the types are matching
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + "argument " + i + " " + e.getMessage());
}
args[i] = expression;
}
FunctionCall result = new FunctionCall(name, args);
result.type = func.returnType;
result.line = line;
result.col = col;
return result;
}
}

View File

@@ -25,9 +25,12 @@ public class GetFunctions extends KlangBaseVisitor<Void> {
@Override
public Void visitFunctionDef(KlangParser.FunctionDefContext ctx) {
String name = ctx.funcName.getText();
int line = ctx.start.getLine();
int col = ctx.start.getCharPositionInLine();
if (this.funcs.containsKey(name)) {
throw new Error("Function " + name + " defined multiple times");
String error = "Function " + name + " defined multiple times.";
throw new Error(Helper.getErrorPrefix(line, col) + error);
}
Type returnType = Type.getByName(ctx.returnType.type().getText());

View File

@@ -83,29 +83,35 @@ public class Klang {
// Parse tokens to AST
ParseTree tree = parser.parse(); // begin parsing at init rule
// Extract information about all functions
var functionDefinitions = new HashMap<String, FunctionInformation>();
new GetFunctions(functionDefinitions).visit(tree);
// Context Analysis and DAST generation
ContextAnalysis ctxAnal = new ContextAnalysis(functionDefinitions);
Node node = ctxAnal.visit(tree); // this gets us the DAST
Node root;
try {
// Extract information about all functions
var functionDefinitions = new HashMap<String, FunctionInformation>();
new GetFunctions(functionDefinitions).visit(tree);
// Create the DAST
ContextAnalysis ctxAnal = new ContextAnalysis(functionDefinitions);
root = ctxAnal.visit(tree);
} catch (Exception e) {
System.err.println(e.getMessage());
return;
}
if (prettyPrint) {
// Pretty Print the sourcecode
StringWriter w = new StringWriter();
PrettyPrintVisitor.ExWriter ex = new PrettyPrintVisitor.ExWriter(w);
PrettyPrintVisitor printVisitor = new PrettyPrintVisitor(ex);
node.welcome(printVisitor);
generateOutput(out, w.toString());
return;
root.welcome(printVisitor);
System.out.println(w.toString());
}
if (evaluate) {
// Evaluate the sourcecode and print the result
System.out.println("\nEvaluating the source code:");
EvalVisitor evalVisitor = new EvalVisitor();
Value result = node.welcome(evalVisitor);
Value result = root.welcome(evalVisitor);
if (result != null) {
generateOutput(out, "Result was: TODO");
} else {
@@ -119,7 +125,7 @@ public class Klang {
StringWriter wAsm = new StringWriter();
GenASM.ExWriter exAsm = new GenASM.ExWriter(wAsm);
GenASM genasm = new GenASM(exAsm, mainName);
node.welcome(genasm);
root.welcome(genasm);
generateOutput(out, wAsm.toString());
}
}

View File

@@ -0,0 +1,7 @@
package de.hsrm.compiler.Klang.helper;
public class Helper {
public static String getErrorPrefix(int line, int col) {
return "Error in line " + line + ":" + col + " ";
}
}

View File

@@ -5,5 +5,8 @@ import de.hsrm.compiler.Klang.visitors.*;
public abstract class Node {
public Type type;
public int line;
public int col;
public abstract <R> R welcome(Visitor<R> v);
}

View File

@@ -152,13 +152,7 @@ public class EvalVisitor implements Visitor<Value> {
@Override
public Value visit(Variable e) {
Value result = this.env.get(e.name);
if (result == null) {
throw new RuntimeException("Variable with name " + e.name + " not found.");
}
return result;
return this.env.get(e.name);
}
@Override
@@ -271,11 +265,6 @@ public class EvalVisitor implements Visitor<Value> {
// Die funktionsdefinition speichern
FunctionDefinition func = this.funcs.get(e.name);
// Stelle sicher, dass die Länge der argumente und parameter übereinstimmen
if (e.arguments.length != func.parameters.length) {
throw new RuntimeException("Error with function call " + e.name + ": Number of parameters wrong");
}
// Baue ein neues environment
Map<String, Value> newEnv = new HashMap<>();
for (int i = 0; i < func.parameters.length; i++) {