From 49bb3f6aaa031b87fbe669a80f2fede4095166ab Mon Sep 17 00:00:00 2001 From: Antoine Viallon Date: Tue, 23 May 2023 00:57:31 +0200 Subject: [PATCH] semantic: separate assignments from definitions Variables are no longer implicitly defined --- compiler/__main__.py | 9 ++++++--- compiler/nodes.py | 7 +++++++ compiler/semantic.py | 34 ++++++++++++++++++++++++++-------- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/compiler/__main__.py b/compiler/__main__.py index 52ced6c..8607a2c 100644 --- a/compiler/__main__.py +++ b/compiler/__main__.py @@ -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() diff --git a/compiler/nodes.py b/compiler/nodes.py index 5f24e40..b34e0c1 100644 --- a/compiler/nodes.py +++ b/compiler/nodes.py @@ -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 diff --git a/compiler/semantic.py b/compiler/semantic.py index 2c43be2..b419dc9 100644 --- a/compiler/semantic.py +++ b/compiler/semantic.py @@ -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