semantic: separate assignments from definitions

Variables are no longer implicitly defined
This commit is contained in:
Antoine Viallon 2023-05-23 00:57:31 +02:00
parent c2faff23e1
commit 49bb3f6aaa
Signed by: aviallon
GPG key ID: D126B13AB555E16F
3 changed files with 39 additions and 11 deletions

View file

@ -6,9 +6,9 @@ from pprint import pprint
from . import semantic from . import semantic
from .errors import CompilationError from .errors import CompilationError
from .lexer import Lexer, Tokens
from .logger import rootLogger, LogLevel from .logger import rootLogger, LogLevel
from .parser import Parser from .parser import Parser
from .lexer import Lexer, Tokens
def main(): def main():
@ -19,14 +19,17 @@ def main():
data = """ data = """
{ {
byte = 42; let byte: uint32 = 42;
} }
let byte: uint32;
2 + 8 - 1 * (byte = 3 + 5) 2 + 8 - 1 * (byte = 3 + 5)
/ (byte = 255) + byte; / (byte = 255) + byte;
byte = byte + byte; byte = byte + byte;
{ {
a = byte; let a: uint32 = byte;
} }
{ let b: uint32; }
""" """
if not args.mock: if not args.mock:
data = sys.stdin.read().strip() data = sys.stdin.read().strip()

View file

@ -370,6 +370,13 @@ class Definition(Assignment):
def pure(self) -> bool: def pure(self) -> bool:
return self.value is None return self.value is None
def semantic_analysis(self, context: semantic.Context):
super(Assignment, self).semantic_analysis(context)
name = self.identifier.value
variable = context.define_variable(name, type_identifier=self.type_identifier, value=self.value)
self.variable = variable
logger.debug(f"Added variable {variable} to context {context.fully_qualified_name()}")
Number = Float | Integer Number = Float | Integer
Value = BinaryOperation | Number | Variable | Expression Value = BinaryOperation | Number | Variable | Expression

View file

@ -4,6 +4,7 @@ import abc
from typing import Literal from typing import Literal
from . import nodes from . import nodes
from .errors import SemanticAnalysisError
from .logger import Logger from .logger import Logger
from .typechecking import typecheck from .typechecking import typecheck
@ -39,11 +40,12 @@ class Type(SymbolABC):
class Variable(SymbolABC): class Variable(SymbolABC):
@typecheck @typecheck
def __init__(self, context: Context, name: str, value: nodes.Value | None = None): def __init__(self, context: Context, name: str, value: nodes.Value | None = None, typedef: Type | None = None):
super().__init__(context, name, value) super().__init__(context, name, value)
self.type = typedef if typedef is not None else context.get_type("__unknown")
def __str__(self): def __str__(self):
return f"{self.__class__.__name__}({self.name})" return f"{self.__class__.__name__}({self.name} : {self.type.fully_qualified_name()})"
class Context: class Context:
@ -79,13 +81,29 @@ class Context:
def get_variable(self, name: str) -> Variable | None: def get_variable(self, name: str) -> Variable | None:
return self._resolve_symbol("variables", name) return self._resolve_symbol("variables", name)
def set_variable(self, name: str, value: nodes.Value) -> Variable: def define_variable(self, name: str, type_identifier: nodes.Identifier, value: nodes.Value) -> Variable:
variable: Variable
if name in self.variables: if name in self.variables:
raise SemanticAnalysisError(value.location())
typedef = self.get_type(type_identifier.value)
if typedef is None:
raise SemanticAnalysisError(location=type_identifier.location(),
message=f"Unknown type '{type_identifier.value}'")
variable = Variable(self, name, value, typedef)
self.variables[name] = variable
return variable
def set_variable(self, name: str, value: nodes.Value) -> Variable:
assert value is not None
if name not in self.variables:
raise SemanticAnalysisError(value.location(),
message=f"Can't assign a value to undeclared variable '{name}'")
variable = self.variables[name] variable = self.variables[name]
variable.definitions += [value] variable.definitions += [value]
else:
variable = Variable(self, name, value)
self.variables[name] = variable self.variables[name] = variable