diff --git a/phasm/compiler.py b/phasm/compiler.py index c38d180..d7d0cc8 100644 --- a/phasm/compiler.py +++ b/phasm/compiler.py @@ -133,12 +133,18 @@ INSTANCES = { 'a=f32': stdlib_types.f32_fractional_div, 'a=f64': stdlib_types.f64_fractional_div, }, - type3classes.Integral.methods['div']: { + type3classes.Integral.operators['//']: { 'a=u32': stdlib_types.u32_integral_div, 'a=u64': stdlib_types.u64_integral_div, 'a=i32': stdlib_types.i32_integral_div, 'a=i64': stdlib_types.i64_integral_div, }, + type3classes.Integral.operators['%']: { + 'a=u32': stdlib_types.u32_integral_rem, + 'a=u64': stdlib_types.u64_integral_rem, + 'a=i32': stdlib_types.i32_integral_rem, + 'a=i64': stdlib_types.i64_integral_rem, + }, type3classes.IntNum.methods['abs']: { 'a=i32': stdlib_types.i32_intnum_abs, 'a=i64': stdlib_types.i64_intnum_abs, diff --git a/phasm/parser.py b/phasm/parser.py index dfe0ae2..2e44f92 100644 --- a/phasm/parser.py +++ b/phasm/parser.py @@ -366,6 +366,10 @@ class OurVisitor: operator = '*' elif isinstance(node.op, ast.Div): operator = '/' + elif isinstance(node.op, ast.FloorDiv): + operator = '//' + elif isinstance(node.op, ast.Mod): + operator = '%' elif isinstance(node.op, ast.LShift): operator = '<<' elif isinstance(node.op, ast.RShift): diff --git a/phasm/stdlib/types.py b/phasm/stdlib/types.py index 186dfb7..7f85017 100644 --- a/phasm/stdlib/types.py +++ b/phasm/stdlib/types.py @@ -495,6 +495,18 @@ def i32_integral_div(g: Generator) -> None: def i64_integral_div(g: Generator) -> None: g.add_statement('i64.div_s') +def u32_integral_rem(g: Generator) -> None: + g.add_statement('i32.rem_u') + +def u64_integral_rem(g: Generator) -> None: + g.add_statement('i64.rem_u') + +def i32_integral_rem(g: Generator) -> None: + g.add_statement('i32.rem_s') + +def i64_integral_rem(g: Generator) -> None: + g.add_statement('i64.rem_s') + ## ### ## class NatNum diff --git a/phasm/type3/typeclasses.py b/phasm/type3/typeclasses.py index 638e5fb..eae6c6e 100644 --- a/phasm/type3/typeclasses.py +++ b/phasm/type3/typeclasses.py @@ -120,8 +120,10 @@ IntNum = Type3Class('IntNum', ['a'], methods={ }, operators={}, inherited_classes=[NatNum]) Integral = Type3Class('Eq', ['a'], methods={ - 'div': 'a -> a -> a', -}, operators={}, inherited_classes=[NatNum]) +}, operators={ + '//': 'a -> a -> a', + '%': 'a -> a -> a', +}, inherited_classes=[NatNum]) Fractional = Type3Class('Fractional', ['a'], methods={ 'ceil': 'a -> a', diff --git a/tests/integration/test_lang/test_integral.py b/tests/integration/test_lang/test_integral.py index 7bbb373..c51d892 100644 --- a/tests/integration/test_lang/test_integral.py +++ b/tests/integration/test_lang/test_integral.py @@ -6,11 +6,11 @@ TYPE_LIST = ['u32', 'u64', 'i32', 'i64'] @pytest.mark.integration_test @pytest.mark.parametrize('type_', TYPE_LIST) -def test_division_int(type_): +def test_integral_div_ok(type_): code_py = f""" @exported def testEntry() -> {type_}: - return div(10, 3) + return 10 // 3 """ result = Suite(code_py).run_code() @@ -20,11 +20,39 @@ def testEntry() -> {type_}: @pytest.mark.integration_test @pytest.mark.parametrize('type_', TYPE_LIST) -def test_division_zero_let_it_crash_int(type_): +def test_integral_div_zero_let_it_crash_int(type_): code_py = f""" @exported def testEntry() -> {type_}: - return div(10, 0) + return 10 // 0 +""" + + # WebAssembly dictates that integer division is a partial operator (e.g. unreachable for 0) + # https://www.w3.org/TR/wasm-core-1/#-hrefop-idiv-umathrmidiv_u_n-i_1-i_2 + with pytest.raises(Exception): + Suite(code_py).run_code() + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', TYPE_LIST) +def test_integral_rem_ok(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 10 % 3 +""" + + result = Suite(code_py).run_code() + + assert 1 == result.returned_value + assert isinstance(result.returned_value, int) + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', TYPE_LIST) +def test_integral_rem_zero_let_it_crash_int(type_): + code_py = f""" +@exported +def testEntry() -> {type_}: + return 10 % 0 """ # WebAssembly dictates that integer division is a partial operator (e.g. unreachable for 0)