semantic+nodes: record variable reads
This commit is contained in:
parent
f08d697699
commit
88526aa5e6
2 changed files with 35 additions and 20 deletions
|
|
@ -316,7 +316,7 @@ class Variable(Node):
|
|||
|
||||
def semantic_analysis(self, context: semantic.Context):
|
||||
super(Variable, self).semantic_analysis(context)
|
||||
variable = context.get_variable(self.identifier.value)
|
||||
variable = context.get_variable(self.identifier.value, reader=self)
|
||||
if variable is None:
|
||||
raise SemanticAnalysisError(location=self.location(), message=f"Unknown variable '{self.identifier.value}'")
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,11 @@ class SymbolABC(abc.ABC):
|
|||
def __init__(self, context: Context, name: str, value: nodes.Value | None | Literal["builtin"] = None):
|
||||
self.context = context
|
||||
self.name = name
|
||||
self.definitions = [value]
|
||||
self.writes: list[nodes.Node] = []
|
||||
if isinstance(value, nodes.Node):
|
||||
self.writes += [value]
|
||||
|
||||
self.reads: list[nodes.Node] = []
|
||||
self._repr_guard: bool = False
|
||||
|
||||
def fully_qualified_name(self) -> str:
|
||||
|
|
@ -28,14 +32,15 @@ class SymbolABC(abc.ABC):
|
|||
if self._repr_guard:
|
||||
return str(self)
|
||||
self._repr_guard = True
|
||||
definitions = [str(d.location().begin) for d in self.writes if isinstance(d, nodes.Node)]
|
||||
writes = [str(d.location().begin) for d in self.writes]
|
||||
reads = [str(d.location().begin) for d in self.reads]
|
||||
self._repr_guard = False
|
||||
return f"{str(self)} [definitions: {', '.join(definitions)}]"
|
||||
return f"{str(self)} [writes: {', '.join(writes)}; reads: {', '.join(reads)}]"
|
||||
|
||||
|
||||
class Type(SymbolABC):
|
||||
def __init__(self, context: Context, name: str, value: nodes.Value | None | Literal["builtin"] = None):
|
||||
super().__init__(context, name, value)
|
||||
super().__init__(context, name, value=value)
|
||||
|
||||
|
||||
class Function(Type):
|
||||
|
|
@ -44,8 +49,10 @@ class Function(Type):
|
|||
|
||||
class Variable(SymbolABC):
|
||||
@typecheck
|
||||
def __init__(self, context: Context, name: str, value: nodes.Value | None = None, typedef: Type | None = None):
|
||||
super().__init__(context, name, value)
|
||||
def __init__(self, context: Context, name: str,
|
||||
value: nodes.Value | None = None,
|
||||
typedef: Type | None = None):
|
||||
super().__init__(context, name, value=value)
|
||||
self.type = typedef if typedef is not None else context.get_type("__unknown")
|
||||
|
||||
def __str__(self):
|
||||
|
|
@ -82,10 +89,18 @@ class Context:
|
|||
|
||||
return None
|
||||
|
||||
def get_variable(self, name: str) -> Variable | None:
|
||||
return self._resolve_symbol("variables", name)
|
||||
@typecheck
|
||||
def _get_symbol(self, attribute_name: str, name: str, reader: nodes.Node | None = None) -> SymbolABC | None:
|
||||
node = self._resolve_symbol(attribute_name, name)
|
||||
if node is not None and reader is not None:
|
||||
node.reads += [reader]
|
||||
return node
|
||||
|
||||
def define_variable(self, name: str, type_identifier: nodes.Identifier, value: nodes.Value) -> Variable:
|
||||
def get_variable(self, name: str, reader: nodes.Node | None = None) -> Variable | None:
|
||||
return self._get_symbol("variables", name, reader)
|
||||
|
||||
def define_variable(self, name: str,
|
||||
type_identifier: nodes.Identifier, value: nodes.Value) -> Variable:
|
||||
if name in self.variables:
|
||||
raise SemanticAnalysisError(value.location())
|
||||
|
||||
|
|
@ -94,7 +109,7 @@ class Context:
|
|||
raise SemanticAnalysisError(location=type_identifier.location(),
|
||||
message=f"Unknown type '{type_identifier.value}'")
|
||||
|
||||
variable = Variable(self, name, value, typedef)
|
||||
variable = Variable(self, name, value=value, typedef=typedef)
|
||||
|
||||
self.variables[name] = variable
|
||||
|
||||
|
|
@ -107,7 +122,7 @@ class Context:
|
|||
raise SemanticAnalysisError(value.location(),
|
||||
message=f"Can't assign a value to undeclared variable '{name}'")
|
||||
variable = self.variables[name]
|
||||
variable.definitions += [value]
|
||||
variable.writes += [value]
|
||||
|
||||
self.variables[name] = variable
|
||||
|
||||
|
|
@ -118,17 +133,17 @@ class Context:
|
|||
typedef: Type
|
||||
if name in self.types:
|
||||
typedef = self.types[name]
|
||||
typedef.definitions += [value]
|
||||
typedef.writes += [value]
|
||||
else:
|
||||
typedef = Type(self, name, value)
|
||||
typedef = Type(self, name, value=value)
|
||||
|
||||
self.types[name] = typedef
|
||||
|
||||
return typedef
|
||||
|
||||
@typecheck
|
||||
def get_type(self, name: str) -> Type | None:
|
||||
return self._resolve_symbol("types", name)
|
||||
def get_type(self, name: str, reader: nodes.Node | None = None) -> Type | None:
|
||||
return self._get_symbol("types", name, reader)
|
||||
|
||||
def add_context(self, context: Context) -> None:
|
||||
self.child_contexts[context.name] = context
|
||||
|
|
@ -163,10 +178,10 @@ class BuiltinContext(Context):
|
|||
def __init__(self):
|
||||
super().__init__(name="builtins", parent=None)
|
||||
self.types = {
|
||||
"__unknown": Type(self, "__unknown", "builtin"),
|
||||
"__function": Function(self, "__function", "builtin"),
|
||||
"uint32": Type(self, "uint32", "builtin")
|
||||
"__unknown": Type(self, "__unknown", value="builtin"),
|
||||
"__function": Function(self, "__function", value="builtin"),
|
||||
"uint32": Type(self, "uint32", value="builtin")
|
||||
}
|
||||
self.variables = {
|
||||
"display": Variable(self, "display", None, self.types["__function"])
|
||||
"display": Variable(self, "display", typedef=self.types["__function"])
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue