semantic: add semantic checks for variables

Check read before first assignment
Check unused variables
This commit is contained in:
Antoine Viallon 2023-05-24 00:24:44 +02:00
parent bcca6d4a6e
commit f060608e73
Signed by: aviallon
GPG key ID: D126B13AB555E16F

View file

@ -5,10 +5,11 @@ from typing import Literal
from . import nodes
from .errors import SemanticAnalysisError
from .logger import Logger
from .logger import Logger, Tracer, LogLevel
from .typechecking import typecheck
logger = Logger(__name__)
tracer = Tracer(logger=logger, level=LogLevel.Debug)
class SymbolABC(abc.ABC):
@ -181,6 +182,33 @@ class Context:
def __repr__(self) -> str:
return self._pprint()
@tracer.trace_method
def check(self) -> None:
for variable in self.variables.values():
# Check for reads before assignments
for read in variable.reads:
previous_write = None
for write in variable.writes:
if write.location() < read.location():
previous_write = write
break
if previous_write is None:
message = f"Reading undefined variable {variable.name}"
if len(variable.writes) > 0:
first_write = min(variable.writes, key=lambda w: w.location())
message += f" (first assignment is at {first_write.location().begin})"
raise SemanticAnalysisError(location=read.location(),
message=message)
# Check for unused variables
if len(variable.reads) == 0 and variable.definition is not None:
raise SemanticAnalysisError(variable.definition.location(),
message=f"Variable '{variable.name}' is unused")
for context in self.child_contexts.values():
context.check()
class BuiltinContext(Context):
def __init__(self):