From 292c9548fb6a44625d82b9a29f10751fa454fa54 Mon Sep 17 00:00:00 2001 From: "Johan B.W. de Vries" Date: Sun, 27 Apr 2025 12:10:27 +0200 Subject: [PATCH] Removes some hardcoded references to prelude --- phasm/ourlang.py | 16 ++++++---- phasm/parser.py | 34 +++++++++------------- tests/integration/test_lang/test_struct.py | 24 +++++++++++++++ 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/phasm/ourlang.py b/phasm/ourlang.py index ad34243..d92849c 100644 --- a/phasm/ourlang.py +++ b/phasm/ourlang.py @@ -7,8 +7,8 @@ from typing import Dict, Iterable, List, Optional, Union from typing_extensions import Final from . import prelude -from .type3 import typeclasses as type3typeclasses from .type3.placeholders import PlaceholderForType, Type3OrPlaceholder +from .type3.typeclasses import Type3ClassMethod from .type3.types import Type3 WEBASSEMBLY_BUILTIN_BYTES_OPS: Final = ('len', ) @@ -150,11 +150,11 @@ class BinaryOp(Expression): """ __slots__ = ('operator', 'left', 'right', ) - operator: type3typeclasses.Type3ClassMethod + operator: Type3ClassMethod left: Expression right: Expression - def __init__(self, operator: type3typeclasses.Type3ClassMethod, left: Expression, right: Expression) -> None: + def __init__(self, operator: Type3ClassMethod, left: Expression, right: Expression) -> None: super().__init__() self.operator = operator @@ -170,10 +170,10 @@ class FunctionCall(Expression): """ __slots__ = ('function', 'arguments', ) - function: Union['Function', type3typeclasses.Type3ClassMethod] + function: Union['Function', Type3ClassMethod] arguments: List[Expression] - def __init__(self, function: Union['Function', type3typeclasses.Type3ClassMethod]) -> None: + def __init__(self, function: Union['Function', Type3ClassMethod]) -> None: super().__init__() self.function = function @@ -411,15 +411,19 @@ class Module: """ A module is a file and consists of functions """ - __slots__ = ('data', 'types', 'struct_definitions', 'constant_defs', 'functions',) + __slots__ = ('data', 'types', 'struct_definitions', 'constant_defs', 'functions', 'operators', ) data: ModuleData + types: dict[str, Type3] struct_definitions: Dict[str, StructDefinition] constant_defs: Dict[str, ModuleConstantDef] functions: Dict[str, Function] + operators: Dict[str, Type3ClassMethod] def __init__(self) -> None: self.data = ModuleData() + self.types = {} self.struct_definitions = {} self.constant_defs = {} self.functions = {} + self.operators = {} diff --git a/phasm/parser.py b/phasm/parser.py index 03dead5..dc644da 100644 --- a/phasm/parser.py +++ b/phasm/parser.py @@ -97,6 +97,9 @@ class OurVisitor: def visit_Module(self, node: ast.Module) -> Module: module = Module() + module.operators.update(PRELUDE_OPERATORS) + module.types.update(PRELUDE_TYPES) + _not_implemented(not node.type_ignores, 'Module.type_ignores') # Second pass for the types @@ -113,14 +116,15 @@ class OurVisitor: module.constant_defs[res.name] = res if isinstance(res, StructDefinition): - if res.struct_type3.name in module.struct_definitions: + if res.struct_type3.name in module.types: raise StaticError( - f'{res.struct_type3.name} already defined on line {module.struct_definitions[res.struct_type3.name].lineno}' + f'{res.struct_type3.name} already defined as type' ) + module.types[res.struct_type3.name] = res.struct_type3 + module.functions[res.struct_type3.name] = StructConstructor(res.struct_type3) + # Store that the definition was done in this module for the formatter module.struct_definitions[res.struct_type3.name] = res - constructor = StructConstructor(res.struct_type3) - module.functions[constructor.name] = constructor if isinstance(res, Function): if res.name in module.functions: @@ -367,11 +371,11 @@ class OurVisitor: else: raise NotImplementedError(f'Operator {node.op}') - if operator not in PRELUDE_OPERATORS: + if operator not in module.operators: raise NotImplementedError(f'Operator {operator}') return BinaryOp( - PRELUDE_OPERATORS[operator], + module.operators[operator], self.visit_Module_FunctionDef_expr(module, function, our_locals, node.left), self.visit_Module_FunctionDef_expr(module, function, our_locals, node.right), ) @@ -408,11 +412,11 @@ class OurVisitor: else: raise NotImplementedError(f'Operator {node.ops}') - if operator not in PRELUDE_OPERATORS: + if operator not in module.operators: raise NotImplementedError(f'Operator {operator}') return BinaryOp( - PRELUDE_OPERATORS[operator], + module.operators[operator], self.visit_Module_FunctionDef_expr(module, function, our_locals, node.left), self.visit_Module_FunctionDef_expr(module, function, our_locals, node.comparators[0]), ) @@ -476,13 +480,6 @@ class OurVisitor: if node.func.id in PRELUDE_METHODS: func = PRELUDE_METHODS[node.func.id] - elif node.func.id in module.struct_definitions: - struct_definition = module.struct_definitions[node.func.id] - struct_constructor = StructConstructor(struct_definition.struct_type3) - - # FIXME: Defer struct de-allocation - - func = module.functions[struct_constructor.name] elif node.func.id == 'u32': if 1 != len(node.args): _raise_static_error(node, f'Function {node.func.id} requires 1 arguments but {len(node.args)} are given') @@ -654,11 +651,8 @@ class OurVisitor: if not isinstance(node.ctx, ast.Load): _raise_static_error(node, 'Must be load context') - if node.id in PRELUDE_TYPES: - return PRELUDE_TYPES[node.id] - - if node.id in module.struct_definitions: - return module.struct_definitions[node.id].struct_type3 + if node.id in module.types: + return module.types[node.id] _raise_static_error(node, f'Unrecognized type {node.id}') diff --git a/tests/integration/test_lang/test_struct.py b/tests/integration/test_lang/test_struct.py index 7f8f456..98020c6 100644 --- a/tests/integration/test_lang/test_struct.py +++ b/tests/integration/test_lang/test_struct.py @@ -1,5 +1,6 @@ import pytest +from phasm.exceptions import StaticError from phasm.type3.entry import Type3Exception from ..helpers import Suite @@ -76,3 +77,26 @@ def testEntry(arg: Struct) -> (i32, i32, ): with pytest.raises(Type3Exception, match=type_ + r' must be \(i32, i32, \) instead'): Suite(code_py).run_code() + +@pytest.mark.integration_test +def test_name_already_use_struct(): + code_py = """ +class Struct: + param: i32 + +class Struct: + param: i64 +""" + + with pytest.raises(StaticError, match='Struct already defined as type'): + Suite(code_py).run_code() + +@pytest.mark.integration_test +def test_name_already_use_type(): + code_py = """ +class f32: + param: i32 +""" + + with pytest.raises(StaticError, match='f32 already defined as type'): + Suite(code_py).run_code()