diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index fe160b8..73acc9d 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -3,6 +3,7 @@ package de.hsrm.compiler.Klang; import java.util.Map; import java.util.HashMap; +import de.hsrm.compiler.Klang.helper.FunctionInformation; import de.hsrm.compiler.Klang.nodes.*; import de.hsrm.compiler.Klang.nodes.expressions.*; import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop; @@ -13,9 +14,13 @@ import de.hsrm.compiler.Klang.types.Type; public class ContextAnalysis extends KlangBaseVisitor { Map vars = new HashMap<>(); - Map funcs = new HashMap<>(); + Map funcs; Type currentDeclaredReturnType; + public ContextAnalysis(Map funcs) { + this.funcs = funcs; + } + @Override public Node visitProgram(KlangParser.ProgramContext ctx) { FunctionDefinition[] funcs = new FunctionDefinition[ctx.functionDef().size()]; @@ -383,14 +388,6 @@ public class ContextAnalysis extends KlangBaseVisitor { FunctionDefinition result = new FunctionDefinition(name, params, (Block) block); result.type = returnType; - // Add this function to our environment - - // TODO - // Geht nicht weil das bei ner Rekursion um die ohren fliegt, - // der funktionsprototyp muss in die funcs geschrieben werden, - // bevor der block gevisited wird - this.funcs.put(name, result); - return result; } @@ -407,15 +404,14 @@ public class ContextAnalysis extends KlangBaseVisitor { public Node visitFunctionCallExpression(KlangParser.FunctionCallExpressionContext ctx) { String name = ctx.functionCall().IDENT().getText(); - // Make sure the function that is called is defined - FunctionDefinition func = this.funcs.get(name); + FunctionInformation func = this.funcs.get(name); if (func == null) { throw new RuntimeException("Function with name \"" + name + "\" not defined."); } // Make sure the number of arguments matches the number of parameters int argCount = ctx.functionCall().arguments().expression().size(); - int paramCount = func.parameters.length; + int paramCount = func.parameters.size(); if (argCount != paramCount) { throw new RuntimeException("Function \"" + name + "\" expects " + paramCount + " parameters, but got " + argCount + "."); } @@ -424,12 +420,12 @@ public class ContextAnalysis extends KlangBaseVisitor { 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.parameters[i].type); // Make sure the types are matching + expression.type.combine(func.signature[i]); // Make sure the types are matching args[i] = expression; } FunctionCall result = new FunctionCall(name, args); - result.type = func.type; + result.type = func.returnType; return result; } } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/GetFunctions.java b/src/main/java/de/hsrm/compiler/Klang/GetFunctions.java new file mode 100644 index 0000000..8d157a5 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/GetFunctions.java @@ -0,0 +1,51 @@ +package de.hsrm.compiler.Klang; + +import java.util.Map; +import java.util.TreeMap; + +import de.hsrm.compiler.Klang.types.*; +import de.hsrm.compiler.Klang.helper.*; + +public class GetFunctions extends KlangBaseVisitor { + + private Map funcs; + + public GetFunctions(Map funcs) { + this.funcs = funcs; + } + + @Override + public Void visitProgram(KlangParser.ProgramContext ctx) { + for (int i = 0; i < ctx.functionDef().size(); i++) { + this.visit(ctx.functionDef(i)); + } + return null; + } + + @Override + public Void visitFunctionDef(KlangParser.FunctionDefContext ctx) { + String name = ctx.funcName.getText(); + + if (this.funcs.containsKey(name)) { + throw new Error("Function " + name + " defined multiple times"); + } + + Type returnType = Type.getByName(ctx.returnType.type().getText()); + + TreeMap parameters = new TreeMap(); + + // Process the paremter list by visiting every paremter in it + int paramCount = ctx.params.parameter().size(); + Type[] signature = new Type[paramCount]; + for (int i = 0; i < paramCount; i++) { + Type paramType = Type.getByName(ctx.params.parameter(i).type_annotation().getText()); + String paramName = ctx.params.parameter(i).IDENT().getText(); + parameters.put(paramName, paramType); + signature[i] = paramType; + } + + FunctionInformation information = new FunctionInformation(name, returnType, parameters, signature); + this.funcs.put(name, information); + return null; + } +} \ 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 5696616..44a12fc 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Klang.java +++ b/src/main/java/de/hsrm/compiler/Klang/Klang.java @@ -7,9 +7,11 @@ import org.antlr.v4.runtime.tree.*; import java.io.*; import java.util.Arrays; import java.util.List; +import java.util.HashMap; import de.hsrm.compiler.Klang.nodes.Node; import de.hsrm.compiler.Klang.visitors.*; +import de.hsrm.compiler.Klang.helper.*; public class Klang { @@ -58,8 +60,15 @@ public class Klang { // create a parser that feeds off the tokens buffer KlangParser parser = new KlangParser(tokens); + // Parse tokens to AST ParseTree tree = parser.parse(); // begin parsing at init rule - ContextAnalysis ctxAnal = new ContextAnalysis(); + + // Extract information about all functions + var functionDefinitions = new HashMap(); + 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 if (prettyPrint) { diff --git a/src/main/java/de/hsrm/compiler/Klang/helper/FunctionInformation.java b/src/main/java/de/hsrm/compiler/Klang/helper/FunctionInformation.java new file mode 100644 index 0000000..97508f0 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/helper/FunctionInformation.java @@ -0,0 +1,19 @@ +package de.hsrm.compiler.Klang.helper; + +import java.util.Map; + +import de.hsrm.compiler.Klang.types.Type; + +public class FunctionInformation { + public String name; + public Type returnType; + public Map parameters; + public Type[] signature; + + public FunctionInformation(String name, Type returnType, Map parameters, Type[] signature) { + this.name = name; + this.returnType = returnType; + this.parameters = parameters; + this.signature = signature; + } +} \ No newline at end of file