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()) { switch (assignmentTree.lValue()) {
case LValueIdentTree(var name) -> { case LValueIdentTree(var name) -> {
VariableStatus status = data.get(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); 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) { if (status == null) {
throw new SemanticException("Variable " + name + " must be declared before assignment"); 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 @Override
public Unit visit(DeclarationTree declarationTree, Namespace<VariableStatus> data) { public Unit visit(DeclarationTree declarationTree, Namespace<VariableStatus> data) {
VariableStatus status = declarationTree.initializer() == null VariableStatus status = declarationTree.initializer() == null
? VariableStatus.DECLARED ? VariableStatus.DECLARED
: VariableStatus.INITIALIZED; : 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()) { if (existing.ordinal() >= replacement.ordinal()) {
throw new SemanticException("variable is already " + existing + ". Cannot be " + replacement + " here."); throw new SemanticException("variable is already " + existing + ". Cannot be " + replacement + " here.");
} }
return replacement; return replacement;
}); });
return NoOpVisitor.super.visit(declarationTree, data);
} }
@Override @Override