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