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,
|
'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={
|
Foldable = Type3Class('Foldable', (t, ), methods={
|
||||||
'sum': [t(a), a],
|
'sum': [t(a), a],
|
||||||
'foldl': [[b, a, b], b, t(a), b],
|
'foldl': [[b, a, b], b, t(a), b],
|
||||||
@ -651,5 +690,6 @@ PRELUDE_METHODS = {
|
|||||||
**Extendable.methods,
|
**Extendable.methods,
|
||||||
**Promotable.methods,
|
**Promotable.methods,
|
||||||
**Reinterpretable.methods,
|
**Reinterpretable.methods,
|
||||||
|
**Convertable.methods,
|
||||||
**Foldable.methods,
|
**Foldable.methods,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1176,6 +1176,73 @@ def f64_u64_reinterpret(g: Generator, tv_map: TypeVariableLookup) -> None:
|
|||||||
del tv_map
|
del tv_map
|
||||||
g.i64.reinterpret_f64()
|
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
|
## Foldable
|
||||||
|
|
||||||
|
|||||||
@ -68,6 +68,11 @@ class Generator_i32i64:
|
|||||||
self.ge_s = functools.partial(self.generator.add_statement, f'{prefix}.ge_s')
|
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.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
|
# 2.4.4. Memory Instructions
|
||||||
self.load = functools.partial(self.generator.add_statement, f'{prefix}.load')
|
self.load = functools.partial(self.generator.add_statement, f'{prefix}.load')
|
||||||
self.load8_u = functools.partial(self.generator.add_statement, f'{prefix}.load8_u')
|
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
|
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
|
@pytest.mark.integration_test
|
||||||
def test_demote_ok():
|
def test_demote_ok():
|
||||||
code_py = """
|
code_py = """
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user