Fix declared/initialized analysis

This commit is contained in:
SirYwell 2025-05-07 14:24:27 +02:00
parent e1aefeba40
commit cd036e26b7
No known key found for this signature in database

View file

@ -23,30 +23,44 @@ class VariableStatusAnalysis implements NoOpVisitor<Namespace<VariableStatusAnal
switch (assignmentTree.lValue()) {
case LValueIdentTree(var name) -> {
VariableStatus status = data.get(name);
checkInitialized(name, status);
checkDeclared(name, status);
if (status != VariableStatus.INITIALIZED) {
// only update when needed, reassignment is totally fine
updateStatus(data, VariableStatus.INITIALIZED, name);
}
}
}
return NoOpVisitor.super.visit(assignmentTree, data);
}
private static void checkInitialized(NameTree name, @Nullable VariableStatus status) {
private static void checkDeclared(NameTree name, @Nullable VariableStatus status) {
if (status == null) {
throw new SemanticException("Variable " + name + " must be declared before assignment");
}
}
private static void checkInitialized(NameTree name, @Nullable VariableStatus status) {
if (status == null || status == VariableStatus.DECLARED) {
throw new SemanticException("Variable " + name + " must be initialized before use");
}
}
@Override
public Unit visit(DeclarationTree declarationTree, Namespace<VariableStatus> data) {
VariableStatus status = declarationTree.initializer() == null
? VariableStatus.DECLARED
: VariableStatus.INITIALIZED;
data.put(declarationTree.name(), status, (existing, replacement) -> {
updateStatus(data, status, declarationTree.name());
return NoOpVisitor.super.visit(declarationTree, data);
}
private static void updateStatus(Namespace<VariableStatus> data, VariableStatus status, NameTree name) {
data.put(name, status, (existing, replacement) -> {
if (existing.ordinal() >= replacement.ordinal()) {
throw new SemanticException("variable is already " + existing + ". Cannot be " + replacement + " here.");
}
return replacement;
});
return NoOpVisitor.super.visit(declarationTree, data);
}
@Override