Had to implement both functions as arguments and type place holders (variables) for type constructors. Had to implement functions as a type as well. Still have to figure out how to pass functions around.
184 lines
4.7 KiB
Python
184 lines
4.7 KiB
Python
import pytest
|
|
|
|
from phasm.type3.entry import Type3Exception
|
|
|
|
from ..helpers import Suite
|
|
from .test_natnum import FLOAT_TYPES, INT_TYPES
|
|
|
|
|
|
@pytest.mark.integration_test
|
|
@pytest.mark.parametrize('length', [1, 5, 13])
|
|
@pytest.mark.parametrize('a_type', INT_TYPES + FLOAT_TYPES)
|
|
def test_foldable_sum(length, a_type):
|
|
code_py = f"""
|
|
@exported
|
|
def testEntry(x: {a_type}[{length}]) -> {a_type}:
|
|
return sum(x)
|
|
"""
|
|
|
|
in_put = tuple(range(length))
|
|
|
|
result = Suite(code_py).run_code(in_put)
|
|
|
|
assert sum(in_put) == result.returned_value
|
|
|
|
@pytest.mark.integration_test
|
|
def test_foldable_sum_not_natnum():
|
|
code_py = """
|
|
class Foo:
|
|
bar: i32
|
|
|
|
@exported
|
|
def testEntry(x: Foo[4]) -> Foo:
|
|
return sum(x)
|
|
"""
|
|
|
|
with pytest.raises(Type3Exception, match='Missing type class instantation: NatNum Foo'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
@pytest.mark.parametrize('length', [1, 5, 13])
|
|
@pytest.mark.parametrize('direction', ['foldl', 'foldr'])
|
|
def test_foldable_foldl_foldr_size(direction, length):
|
|
code_py = f"""
|
|
def u64_add(l: u64, r: u64) -> u64:
|
|
return l + r
|
|
|
|
@exported
|
|
def testEntry(b: u64[{length}]) -> u64:
|
|
return {direction}(u64_add, 100, b)
|
|
"""
|
|
suite = Suite(code_py)
|
|
|
|
in_put = tuple(range(1, length + 1))
|
|
|
|
result = suite.run_code(in_put)
|
|
assert (100 + sum(in_put)) == result.returned_value
|
|
|
|
@pytest.mark.integration_test
|
|
@pytest.mark.parametrize('direction', ['foldr'])
|
|
def test_foldable_foldl_foldr_compounded_type(direction):
|
|
code_py = f"""
|
|
def combine_foldl(b: u64, a: (u32, u32, )) -> u64:
|
|
return extend(a[0] * a[1]) + b
|
|
|
|
def combine_foldr(a: (u32, u32, ), b: u64) -> u64:
|
|
return extend(a[0] * a[1]) + b
|
|
|
|
@exported
|
|
def testEntry(b: (u32, u32)[3]) -> u64:
|
|
return {direction}(combine_{direction}, 10000, b)
|
|
"""
|
|
suite = Suite(code_py)
|
|
|
|
result = suite.run_code(((2, 5), (25, 4), (125, 8)))
|
|
assert 11110 == result.returned_value
|
|
|
|
@pytest.mark.integration_test
|
|
@pytest.mark.parametrize('direction, exp_result', [
|
|
('foldl', -55, ),
|
|
('foldr', -5, ),
|
|
])
|
|
def test_foldable_foldl_foldr_result(direction, exp_result):
|
|
# See https://stackoverflow.com/a/13280185
|
|
code_py = f"""
|
|
def i32_sub(l: i32, r: i32) -> i32:
|
|
return l - r
|
|
|
|
@exported
|
|
def testEntry(b: i32[10]) -> i32:
|
|
return {direction}(i32_sub, 0, b)
|
|
"""
|
|
suite = Suite(code_py)
|
|
|
|
result = suite.run_code(tuple(range(1, 11)))
|
|
assert exp_result == result.returned_value
|
|
|
|
@pytest.mark.integration_test
|
|
def test_foldable_foldl_bytes():
|
|
code_py = """
|
|
def u8_or(l: u8, r: u8) -> u8:
|
|
return l | r
|
|
|
|
@exported
|
|
def testEntry(b: bytes) -> u8:
|
|
return foldl(u8_or, 128, b)
|
|
"""
|
|
suite = Suite(code_py)
|
|
|
|
result = suite.run_code(b'')
|
|
assert 128 == result.returned_value
|
|
|
|
result = suite.run_code(b'\x80')
|
|
assert 128 == result.returned_value
|
|
|
|
result = suite.run_code(b'\x80\x40')
|
|
assert 192 == result.returned_value
|
|
|
|
result = suite.run_code(b'\x80\x40\x20\x10')
|
|
assert 240 == result.returned_value
|
|
|
|
result = suite.run_code(b'\x80\x40\x20\x10\x08\x04\x02\x01')
|
|
assert 255 == result.returned_value
|
|
|
|
@pytest.mark.integration_test
|
|
@pytest.mark.parametrize('in_typ', ['i8', 'i8[3]'])
|
|
def test_foldable_argument_must_be_a_function(in_typ):
|
|
code_py = f"""
|
|
@exported
|
|
def testEntry(x: {in_typ}, y: i32, z: i64[3]) -> i32:
|
|
return foldl(x, y, z)
|
|
"""
|
|
|
|
r_in_typ = in_typ.replace('[', '\\[').replace(']', '\\]')
|
|
|
|
with pytest.raises(Type3Exception, match=f'{r_in_typ} must be a function instead'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_foldable_argument_must_be_right_function():
|
|
code_py = """
|
|
def foo(l: i32, r: i64) -> i64:
|
|
return extend(l) + r
|
|
|
|
@exported
|
|
def testEntry(i: i64, l: i64[3]) -> i64:
|
|
return foldr(foo, i, l)
|
|
"""
|
|
|
|
with pytest.raises(Type3Exception, match=r'\(i64 -> i64 -> i64\) must be \(i32 -> i64 -> i64\) instead'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_foldable_invalid_return_type():
|
|
code_py = """
|
|
@exported
|
|
def testEntry(x: i32[5]) -> f64:
|
|
return sum(x)
|
|
"""
|
|
|
|
with pytest.raises(Type3Exception, match='f64 must be i32 instead'):
|
|
Suite(code_py).run_code((4, 5, 6, 7, 8, ))
|
|
|
|
@pytest.mark.integration_test
|
|
def test_foldable_not_constructed():
|
|
code_py = """
|
|
@exported
|
|
def testEntry(x: i32) -> i32:
|
|
return sum(x)
|
|
"""
|
|
|
|
with pytest.raises(Type3Exception, match='Missing type class instantation: Foldable i32.*i32 must be a constructed type instead'):
|
|
Suite(code_py).run_code()
|
|
|
|
@pytest.mark.integration_test
|
|
def test_foldable_not_foldable():
|
|
code_py = """
|
|
@exported
|
|
def testEntry(x: (i32, u32, )) -> i32:
|
|
return sum(x)
|
|
"""
|
|
|
|
with pytest.raises(Type3Exception, match='Missing type class instantation: Foldable tuple'):
|
|
Suite(code_py).run_code()
|