From 8fa2e4830e5da96f4ee8190f309710618fd95906 Mon Sep 17 00:00:00 2001 From: "Johan B.W. de Vries" Date: Tue, 14 Nov 2023 14:09:17 +0100 Subject: [PATCH] Support negative literals --- phasm/parser.py | 31 +++++++++++++++++++ phasm/wasmgenerator.py | 2 +- .../generator_tuple_all_primitives.json | 4 +-- .../integration/test_lang/test_primitives.py | 26 ---------------- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/phasm/parser.py b/phasm/parser.py index e3799ab..fc1d28f 100644 --- a/phasm/parser.py +++ b/phasm/parser.py @@ -39,11 +39,39 @@ def phasm_parse(source: str) -> Module: """ res = ast.parse(source, '') + res = OptimizerTransformer().visit(res) + our_visitor = OurVisitor() return our_visitor.visit_Module(res) OurLocals = Dict[str, Union[FunctionParam]] # FIXME: Does it become easier if we add ModuleConstantDef to this dict? +class OptimizerTransformer(ast.NodeTransformer): + """ + This class optimizes the Python AST, to prepare it for parsing + by the OurVisitor class below. + """ + def visit_UnaryOp(self, node: ast.UnaryOp) -> Union[ast.UnaryOp, ast.Constant]: + """ + UnaryOp optimizations + + In the given example: + ```py + x = -4 + ``` + Python will parse it as a unary minus operation on the constant four. + For Phasm purposes, this counts as a literal -4. + """ + if ( + isinstance(node.op, (ast.UAdd, ast.USub, )) + and isinstance(node.operand, ast.Constant) + and isinstance(node.operand.value, (int, float, )) + ): + if isinstance(node.op, ast.USub): + node.operand.value = -node.operand.value + return node.operand + return node + class OurVisitor: """ Class to visit a Python syntax tree and create an ourlang syntax tree @@ -52,6 +80,9 @@ class OurVisitor: At some point, we may deviate from Python syntax. If nothing else, we probably won't keep up with the Python syntax changes. + + See OptimizerTransformer for the changes we make after the Python + parsing is done but before the phasm parsing is done. """ # pylint: disable=C0103,C0116,C0301,R0201,R0912 diff --git a/phasm/wasmgenerator.py b/phasm/wasmgenerator.py index 48cca1a..379ee73 100644 --- a/phasm/wasmgenerator.py +++ b/phasm/wasmgenerator.py @@ -45,7 +45,7 @@ class Generator_i32i64: self.store = functools.partial(self.generator.add_statement, f'{prefix}.store') def const(self, value: int, comment: Optional[str] = None) -> None: - self.generator.add_statement(f'{self.prefix}.const', f'0x{value:08x}', comment=comment) + self.generator.add_statement(f'{self.prefix}.const', f'{value}', comment=comment) class Generator_i32(Generator_i32i64): def __init__(self, generator: 'Generator') -> None: diff --git a/tests/integration/test_lang/generator_tuple_all_primitives.json b/tests/integration/test_lang/generator_tuple_all_primitives.json index 94785ff..e391d9b 100644 --- a/tests/integration/test_lang/generator_tuple_all_primitives.json +++ b/tests/integration/test_lang/generator_tuple_all_primitives.json @@ -1,5 +1,5 @@ { "TYPE_NAME": "tuple_all_primitives", - "TYPE": "(u8, u32, u64, i8, i32, i64, f32, f64, bytes, )", - "VAL0": "(1, 4, 8, 1, 4, 8, 125.125, 5000.5, b'Hello, world!', )" + "TYPE": "(u8, u32, u64, i8, i8, i32, i32, i64, i64, f32, f32, f64, f64, bytes, )", + "VAL0": "(1, 4, 8, 1, -1, 4, -4, 8, -8, 125.125, -125.125, 5000.5, -5000.5, b'Hello, world!', )" } diff --git a/tests/integration/test_lang/test_primitives.py b/tests/integration/test_lang/test_primitives.py index 96b5ad2..6458d77 100644 --- a/tests/integration/test_lang/test_primitives.py +++ b/tests/integration/test_lang/test_primitives.py @@ -267,32 +267,6 @@ def testEntry() -> {type_}: assert 5 == result.returned_value assert TYPE_MAP[type_] == type(result.returned_value) -@pytest.mark.integration_test -@pytest.mark.skip('TODO') -def test_explicit_positive_number(): - code_py = """ -@exported -def testEntry() -> i32: - return +523 -""" - - result = Suite(code_py).run_code() - - assert 523 == result.returned_value - -@pytest.mark.integration_test -@pytest.mark.skip('TODO') -def test_explicit_negative_number(): - code_py = """ -@exported -def testEntry() -> i32: - return -19 -""" - - result = Suite(code_py).run_code() - - assert -19 == result.returned_value - @pytest.mark.integration_test def test_call_pre_defined(): code_py = """