semantic: separate assignments from definitions
Variables are no longer implicitly defined
This commit is contained in:
parent
c2faff23e1
commit
49bb3f6aaa
3 changed files with 39 additions and 11 deletions
|
|
@ -6,9 +6,9 @@ from pprint import pprint
|
|||
|
||||
from . import semantic
|
||||
from .errors import CompilationError
|
||||
from .lexer import Lexer, Tokens
|
||||
from .logger import rootLogger, LogLevel
|
||||
from .parser import Parser
|
||||
from .lexer import Lexer, Tokens
|
||||
|
||||
|
||||
def main():
|
||||
|
|
@ -19,14 +19,17 @@ def main():
|
|||
|
||||
data = """
|
||||
{
|
||||
byte = 42;
|
||||
let byte: uint32 = 42;
|
||||
}
|
||||
let byte: uint32;
|
||||
|
||||
2 + 8 - 1 * (byte = 3 + 5)
|
||||
/ (byte = 255) + byte;
|
||||
byte = byte + byte;
|
||||
{
|
||||
a = byte;
|
||||
let a: uint32 = byte;
|
||||
}
|
||||
{ let b: uint32; }
|
||||
"""
|
||||
if not args.mock:
|
||||
data = sys.stdin.read().strip()
|
||||
|
|
|
|||
|
|
@ -370,6 +370,13 @@ class Definition(Assignment):
|
|||
def pure(self) -> bool:
|
||||
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
|
||||
Value = BinaryOperation | Number | Variable | Expression
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import abc
|
|||
from typing import Literal
|
||||
|
||||
from . import nodes
|
||||
from .errors import SemanticAnalysisError
|
||||
from .logger import Logger
|
||||
from .typechecking import typecheck
|
||||
|
||||
|
|
@ -39,11 +40,12 @@ class Type(SymbolABC):
|
|||
|
||||
class Variable(SymbolABC):
|
||||
@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)
|
||||
self.type = typedef if typedef is not None else context.get_type("__unknown")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.__class__.__name__}({self.name})"
|
||||
return f"{self.__class__.__name__}({self.name} : {self.type.fully_qualified_name()})"
|
||||
|
||||
|
||||
class Context:
|
||||
|
|
@ -79,13 +81,29 @@ class Context:
|
|||
def get_variable(self, name: str) -> Variable | None:
|
||||
return self._resolve_symbol("variables", name)
|
||||
|
||||
def set_variable(self, name: str, value: nodes.Value) -> Variable:
|
||||
variable: Variable
|
||||
def define_variable(self, name: str, type_identifier: nodes.Identifier, value: nodes.Value) -> Variable:
|
||||
if name in self.variables:
|
||||
variable = self.variables[name]
|
||||
variable.definitions += [value]
|
||||
else:
|
||||
variable = Variable(self, name, value)
|
||||
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.definitions += [value]
|
||||
|
||||
self.variables[name] = variable
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue