Made Integral use Python's operators

Rather than Haskell's div and rem methods, we use the
Python operators since these are often used. And we have
as goal to make it 'look like Python'
This commit is contained in:
Johan B.W. de Vries 2025-04-09 13:16:50 +02:00
parent 94c8f9388c
commit da381e4a48
5 changed files with 59 additions and 7 deletions

View File

@ -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,

View File

@ -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):

View File

@ -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

View File

@ -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',

View File

@ -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)