Fix declared/initialized analysis
This commit is contained in:
parent
e1aefeba40
commit
cd036e26b7
1 changed files with 18 additions and 4 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue