Exposes Wasm's convert and trunc(ate) function
Also adds a missing type case for promotable
This commit is contained in:
parent
56ab88db2c
commit
b670bb02ad
@ -580,6 +580,45 @@ instance_type_class(Reinterpretable, f64, i64, methods={
|
||||
'reinterpret': stdtypes.f64_i64_reinterpret,
|
||||
})
|
||||
|
||||
Convertable = Type3Class('Convertable', (a, b, ), methods={
|
||||
'convert': [a, b],
|
||||
'truncate': [b, a], # To prevent name clas with Fractional
|
||||
}, operators={})
|
||||
|
||||
instance_type_class(Convertable, u32, f32, methods={
|
||||
'convert': stdtypes.u32_f32_convert,
|
||||
'truncate': stdtypes.u32_f32_truncate,
|
||||
})
|
||||
instance_type_class(Convertable, u32, f64, methods={
|
||||
'convert': stdtypes.u32_f64_convert,
|
||||
'truncate': stdtypes.u32_f64_truncate,
|
||||
})
|
||||
instance_type_class(Convertable, u64, f32, methods={
|
||||
'convert': stdtypes.u64_f32_convert,
|
||||
'truncate': stdtypes.u64_f32_truncate,
|
||||
})
|
||||
instance_type_class(Convertable, u64, f64, methods={
|
||||
'convert': stdtypes.u64_f64_convert,
|
||||
'truncate': stdtypes.u64_f64_truncate,
|
||||
})
|
||||
instance_type_class(Convertable, i32, f32, methods={
|
||||
'convert': stdtypes.i32_f32_convert,
|
||||
'truncate': stdtypes.i32_f32_truncate,
|
||||
})
|
||||
instance_type_class(Convertable, i32, f64, methods={
|
||||
'convert': stdtypes.i32_f64_convert,
|
||||
'truncate': stdtypes.i32_f64_truncate,
|
||||
})
|
||||
instance_type_class(Convertable, i64, f32, methods={
|
||||
'convert': stdtypes.i64_f32_convert,
|
||||
'truncate': stdtypes.i64_f32_truncate,
|
||||
})
|
||||
instance_type_class(Convertable, i64, f64, methods={
|
||||
'convert': stdtypes.i64_f64_convert,
|
||||
'truncate': stdtypes.i64_f64_truncate,
|
||||
})
|
||||
|
||||
|
||||
Foldable = Type3Class('Foldable', (t, ), methods={
|
||||
'sum': [t(a), a],
|
||||
'foldl': [[b, a, b], b, t(a), b],
|
||||
@ -651,5 +690,6 @@ PRELUDE_METHODS = {
|
||||
**Extendable.methods,
|
||||
**Promotable.methods,
|
||||
**Reinterpretable.methods,
|
||||
**Convertable.methods,
|
||||
**Foldable.methods,
|
||||
}
|
||||
|
||||
@ -1176,6 +1176,73 @@ def f64_u64_reinterpret(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.i64.reinterpret_f64()
|
||||
|
||||
## ###
|
||||
## Convertable
|
||||
|
||||
def u32_f32_convert(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.f32.convert_i32_u()
|
||||
|
||||
def u32_f64_convert(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.f64.convert_i32_u()
|
||||
|
||||
def u64_f32_convert(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.f32.convert_i64_u()
|
||||
|
||||
def u64_f64_convert(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.f64.convert_i64_u()
|
||||
|
||||
def i32_f32_convert(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.f32.convert_i32_s()
|
||||
|
||||
def i32_f64_convert(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.f64.convert_i32_s()
|
||||
|
||||
def i64_f32_convert(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.f32.convert_i64_s()
|
||||
|
||||
def i64_f64_convert(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.f64.convert_i64_s()
|
||||
|
||||
def u32_f32_truncate(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.i32.trunc_f32_u()
|
||||
|
||||
def u32_f64_truncate(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.i32.trunc_f64_u()
|
||||
|
||||
def u64_f32_truncate(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.i64.trunc_f32_u()
|
||||
|
||||
def u64_f64_truncate(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.i64.trunc_f64_u()
|
||||
|
||||
def i32_f32_truncate(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.i32.trunc_f32_s()
|
||||
|
||||
def i32_f64_truncate(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.i32.trunc_f64_s()
|
||||
|
||||
def i64_f32_truncate(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.i64.trunc_f32_s()
|
||||
|
||||
def i64_f64_truncate(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||
del tv_map
|
||||
g.i64.trunc_f64_s()
|
||||
|
||||
## ###
|
||||
## Foldable
|
||||
|
||||
|
||||
@ -68,6 +68,11 @@ class Generator_i32i64:
|
||||
self.ge_s = functools.partial(self.generator.add_statement, f'{prefix}.ge_s')
|
||||
self.ge_u = functools.partial(self.generator.add_statement, f'{prefix}.ge_u')
|
||||
|
||||
self.trunc_f32_s = functools.partial(self.generator.add_statement, f'{prefix}.trunc_f32_s')
|
||||
self.trunc_f32_u = functools.partial(self.generator.add_statement, f'{prefix}.trunc_f32_u')
|
||||
self.trunc_f64_s = functools.partial(self.generator.add_statement, f'{prefix}.trunc_f64_s')
|
||||
self.trunc_f64_u = functools.partial(self.generator.add_statement, f'{prefix}.trunc_f64_u')
|
||||
|
||||
# 2.4.4. Memory Instructions
|
||||
self.load = functools.partial(self.generator.add_statement, f'{prefix}.load')
|
||||
self.load8_u = functools.partial(self.generator.add_statement, f'{prefix}.load8_u')
|
||||
|
||||
101
tests/integration/test_typeclasses/test_convertable.py
Normal file
101
tests/integration/test_typeclasses/test_convertable.py
Normal file
@ -0,0 +1,101 @@
|
||||
import pytest
|
||||
import wasmtime
|
||||
|
||||
from phasm.type3.entry import Type3Exception
|
||||
|
||||
from ..helpers import Suite
|
||||
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_convert_not_implemented():
|
||||
code_py = """
|
||||
class Foo:
|
||||
val: i32
|
||||
|
||||
class Baz:
|
||||
val: i32
|
||||
|
||||
@exported
|
||||
def testEntry(x: Foo) -> Baz:
|
||||
return convert(x)
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match='Missing type class instantation: Convertable Foo Baz'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('in_typ, in_val, out_typ, exp_val', [
|
||||
('u32', 1000, 'f32', 1000.0, ),
|
||||
('u32', 1000, 'f64', 1000.0, ),
|
||||
('u64', 1000, 'f32', 1000.0, ),
|
||||
('u64', 1000, 'f64', 1000.0, ),
|
||||
('i32', 1000, 'f32', 1000.0, ),
|
||||
('i32', 1000, 'f64', 1000.0, ),
|
||||
('i64', 1000, 'f32', 1000.0, ),
|
||||
('i64', 1000, 'f64', 1000.0, ),
|
||||
])
|
||||
def test_convert_ok(in_typ, in_val, out_typ, exp_val):
|
||||
code_py = f"""
|
||||
@exported
|
||||
def testEntry(x: {in_typ}) -> {out_typ}:
|
||||
return convert(x)
|
||||
"""
|
||||
|
||||
result = Suite(code_py).run_code(in_val)
|
||||
assert exp_val == result.returned_value
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_truncate_not_implemented():
|
||||
code_py = """
|
||||
class Foo:
|
||||
val: i32
|
||||
|
||||
class Baz:
|
||||
val: i32
|
||||
|
||||
@exported
|
||||
def testEntry(x: Foo) -> Baz:
|
||||
return truncate(x)
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match='Missing type class instantation: Convertable Baz Foo'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('in_typ, in_val, out_typ, exp_val', [
|
||||
('f32', 1000.0, 'u32', 1000, ),
|
||||
('f64', 1000.0, 'u32', 1000, ),
|
||||
('f32', 1000.0, 'u64', 1000, ),
|
||||
('f64', 1000.0, 'u64', 1000, ),
|
||||
('f32', 1000.0, 'i32', 1000, ),
|
||||
('f64', 1000.0, 'i32', 1000, ),
|
||||
('f32', 1000.0, 'i64', 1000, ),
|
||||
('f64', 1000.0, 'i64', 1000, ),
|
||||
|
||||
('f32', 3e9, 'u32', 3e9, ),
|
||||
('f32', 1e19, 'u64', 9999999980506447872, ),
|
||||
])
|
||||
def test_truncate_ok(in_typ, in_val, out_typ, exp_val):
|
||||
code_py = f"""
|
||||
@exported
|
||||
def testEntry(x: {in_typ}) -> {out_typ}:
|
||||
return truncate(x)
|
||||
"""
|
||||
|
||||
result = Suite(code_py).run_code(in_val)
|
||||
assert exp_val == result.returned_value
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('in_typ, in_val, out_typ', [
|
||||
('f32', 3e9, 'i32', ),
|
||||
('f64', 1e19, 'i64', ),
|
||||
])
|
||||
def test_truncate_not_representible(in_typ, in_val, out_typ):
|
||||
code_py = f"""
|
||||
@exported
|
||||
def testEntry(x: {in_typ}) -> {out_typ}:
|
||||
return truncate(x)
|
||||
"""
|
||||
|
||||
with pytest.raises(wasmtime.Trap, match='integer overflow'):
|
||||
Suite(code_py).run_code(in_val)
|
||||
@ -36,6 +36,23 @@ def testEntry() -> f64:
|
||||
|
||||
assert 10.5 == result.returned_value
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_demote_not_implemented():
|
||||
code_py = """
|
||||
class Foo:
|
||||
val: i32
|
||||
|
||||
class Baz:
|
||||
val: i32
|
||||
|
||||
@exported
|
||||
def testEntry(x: Foo) -> Baz:
|
||||
return demote(x)
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match='Missing type class instantation: Promotable Baz Foo'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_demote_ok():
|
||||
code_py = """
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user