From f060608e73c3d1099aa8d11f6ad413ce85f8fd6c Mon Sep 17 00:00:00 2001 From: Antoine Viallon Date: Wed, 24 May 2023 00:24:44 +0200 Subject: [PATCH] semantic: add semantic checks for variables Check read before first assignment Check unused variables --- compiler/semantic.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/compiler/semantic.py b/compiler/semantic.py index a65a203..dc12c41 100644 --- a/compiler/semantic.py +++ b/compiler/semantic.py @@ -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):