Make it possible to use an enum in an expression (i.e. selecting one of the enum values: Foo.A)

This commit is contained in:
2023-03-15 19:14:04 +01:00
parent 3b928d621b
commit 6fd3f5a2e6
14 changed files with 107 additions and 94 deletions

View File

@@ -9,8 +9,7 @@ import de.hsrm.compiler.Klang.nodes.loops.WhileLoop;
import de.hsrm.compiler.Klang.nodes.statements.*;
import de.hsrm.compiler.Klang.types.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
public class ContextAnalysis extends KlangBaseVisitor<Node> {
Map<String, VariableDeclaration> vars = new HashMap<>();
@@ -319,43 +318,68 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
}
@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];
public Node visitMemberAccessExpression(KlangParser.MemberAccessExpressionContext ctx) {
var baseName = ctx.IDENT(0).getText();
var line = ctx.start.getLine();
var col = ctx.start.getCharPositionInLine();
// Create a list of member names. This excludes
// the first entry as it is the base name.
var path = new ArrayList<String>();
for (int i = 1; i < ctx.IDENT().size(); i++) {
path[i - 1] = ctx.IDENT(i).getText();
path.add(ctx.IDENT(i).getText());
}
// Determine if the base name points to an enum or a variable
var enumDef = enumDefs.get(baseName);
if (enumDef != null) {
if (path.size() != 1) {
var error = "Illegal access to enum " + enumDef.name + ".";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
var enumValueName = path.get(0);
if (Arrays.stream(enumDef.enums).noneMatch(e -> e.equals(enumValueName))) {
var error = "Unknown enum value " + enumValueName + " of enum " + enumDef.name + ".";
throw new RuntimeException(Helper.getErrorPrefix(line, col) + error);
}
var enumAccessExpression = new EnumAccessExpression(baseName, enumValueName);
enumAccessExpression.type = enumDef.type;
enumAccessExpression.line = line;
enumAccessExpression.col = col;
return enumAccessExpression;
}
// Get the referenced variable, make sure it is defined
var variableDef = this.vars.get(varName);
var variableDef = vars.get(baseName);
if (variableDef == null) {
String error = "Variable with name " + varName + " not defined.";
var error = "Variable with name " + baseName + " 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() + ".";
var 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
String structName = variableDef.type.getName();
var structName = variableDef.type.getName();
Type resultType;
try {
resultType = Helper.drillType(this.structDefs, structName, path, 0);
resultType = Helper.drillType(structDefs, structName, path.toArray(new String[0]), 0);
} catch (Exception e) {
throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage());
}
Node result = new StructFieldAccessExpression(varName, structName, path);
result.type = resultType;
result.line = line;
result.col = col;
return result;
var memberAccessExpression = new MemberAccessExpression(baseName, structName, path.toArray(new String[0]));
memberAccessExpression.type = resultType;
memberAccessExpression.line = line;
memberAccessExpression.col = col;
return memberAccessExpression;
}
@Override
@@ -749,7 +773,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
structDef.line = line;
structDef.col = col;
return super.visitStructDef(ctx);
return structDef;
}
@Override