implement context analysis for struct field access expressions

This commit is contained in:
2020-02-04 21:30:17 +01:00
parent 6a7eb8fde2
commit 1ca3f5ca8b
2 changed files with 78 additions and 2 deletions

View File

@@ -264,6 +264,45 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
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);

View File

@@ -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<String, StructDefinition> 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]);
}
}