Support negative literals

This commit is contained in:
Johan B.W. de Vries 2023-11-14 14:09:17 +01:00
parent ddc0bbdf30
commit 8fa2e4830e
4 changed files with 34 additions and 29 deletions

View File

@ -39,11 +39,39 @@ def phasm_parse(source: str) -> Module:
""" """
res = ast.parse(source, '') res = ast.parse(source, '')
res = OptimizerTransformer().visit(res)
our_visitor = OurVisitor() our_visitor = OurVisitor()
return our_visitor.visit_Module(res) return our_visitor.visit_Module(res)
OurLocals = Dict[str, Union[FunctionParam]] # FIXME: Does it become easier if we add ModuleConstantDef to this dict? 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 OurVisitor:
""" """
Class to visit a Python syntax tree and create an ourlang syntax tree 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, At some point, we may deviate from Python syntax. If nothing else,
we probably won't keep up with the Python syntax changes. 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 # pylint: disable=C0103,C0116,C0301,R0201,R0912

View File

@ -45,7 +45,7 @@ class Generator_i32i64:
self.store = functools.partial(self.generator.add_statement, f'{prefix}.store') self.store = functools.partial(self.generator.add_statement, f'{prefix}.store')
def const(self, value: int, comment: Optional[str] = None) -> None: 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): class Generator_i32(Generator_i32i64):
def __init__(self, generator: 'Generator') -> None: def __init__(self, generator: 'Generator') -> None:

View File

@ -1,5 +1,5 @@
{ {
"TYPE_NAME": "tuple_all_primitives", "TYPE_NAME": "tuple_all_primitives",
"TYPE": "(u8, u32, u64, i8, i32, i64, f32, f64, bytes, )", "TYPE": "(u8, u32, u64, i8, i8, i32, i32, i64, i64, f32, f32, f64, f64, bytes, )",
"VAL0": "(1, 4, 8, 1, 4, 8, 125.125, 5000.5, b'Hello, world!', )" "VAL0": "(1, 4, 8, 1, -1, 4, -4, 8, -8, 125.125, -125.125, 5000.5, -5000.5, b'Hello, world!', )"
} }

View File

@ -267,32 +267,6 @@ def testEntry() -> {type_}:
assert 5 == result.returned_value assert 5 == result.returned_value
assert TYPE_MAP[type_] == type(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 @pytest.mark.integration_test
def test_call_pre_defined(): def test_call_pre_defined():
code_py = """ code_py = """