Support negative literals
This commit is contained in:
parent
ddc0bbdf30
commit
8fa2e4830e
@ -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
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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!', )"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 = """
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user