Implements the Ord type class

This commit is contained in:
Johan B.W. de Vries 2025-04-09 12:40:15 +02:00
parent 46dbc90475
commit 94c8f9388c
8 changed files with 492 additions and 30 deletions

View File

@ -49,6 +49,66 @@ INSTANCES = {
'a=f32': stdlib_types.f32_eq_not_equals, 'a=f32': stdlib_types.f32_eq_not_equals,
'a=f64': stdlib_types.f64_eq_not_equals, 'a=f64': stdlib_types.f64_eq_not_equals,
}, },
type3classes.Ord.methods['min']: {
'a=u8': stdlib_types.u8_ord_min,
'a=u32': stdlib_types.u32_ord_min,
'a=u64': stdlib_types.u64_ord_min,
'a=i8': stdlib_types.i8_ord_min,
'a=i32': stdlib_types.i32_ord_min,
'a=i64': stdlib_types.i64_ord_min,
'a=f32': stdlib_types.f32_ord_min,
'a=f64': stdlib_types.f64_ord_min,
},
type3classes.Ord.methods['max']: {
'a=u8': stdlib_types.u8_ord_max,
'a=u32': stdlib_types.u32_ord_max,
'a=u64': stdlib_types.u64_ord_max,
'a=i8': stdlib_types.i8_ord_max,
'a=i32': stdlib_types.i32_ord_max,
'a=i64': stdlib_types.i64_ord_max,
'a=f32': stdlib_types.f32_ord_max,
'a=f64': stdlib_types.f64_ord_max,
},
type3classes.Ord.operators['<']: {
'a=u8': stdlib_types.u8_ord_less_than,
'a=u32': stdlib_types.u32_ord_less_than,
'a=u64': stdlib_types.u64_ord_less_than,
'a=i8': stdlib_types.i8_ord_less_than,
'a=i32': stdlib_types.i32_ord_less_than,
'a=i64': stdlib_types.i64_ord_less_than,
'a=f32': stdlib_types.f32_ord_less_than,
'a=f64': stdlib_types.f64_ord_less_than,
},
type3classes.Ord.operators['<=']: {
'a=u8': stdlib_types.u8_ord_less_than_or_equal,
'a=u32': stdlib_types.u32_ord_less_than_or_equal,
'a=u64': stdlib_types.u64_ord_less_than_or_equal,
'a=i8': stdlib_types.i8_ord_less_than_or_equal,
'a=i32': stdlib_types.i32_ord_less_than_or_equal,
'a=i64': stdlib_types.i64_ord_less_than_or_equal,
'a=f32': stdlib_types.f32_ord_less_than_or_equal,
'a=f64': stdlib_types.f64_ord_less_than_or_equal,
},
type3classes.Ord.operators['>']: {
'a=u8': stdlib_types.u8_ord_greater_than,
'a=u32': stdlib_types.u32_ord_greater_than,
'a=u64': stdlib_types.u64_ord_greater_than,
'a=i8': stdlib_types.i8_ord_greater_than,
'a=i32': stdlib_types.i32_ord_greater_than,
'a=i64': stdlib_types.i64_ord_greater_than,
'a=f32': stdlib_types.f32_ord_greater_than,
'a=f64': stdlib_types.f64_ord_greater_than,
},
type3classes.Ord.operators['>=']: {
'a=u8': stdlib_types.u8_ord_greater_than_or_equal,
'a=u32': stdlib_types.u32_ord_greater_than_or_equal,
'a=u64': stdlib_types.u64_ord_greater_than_or_equal,
'a=i8': stdlib_types.i8_ord_greater_than_or_equal,
'a=i32': stdlib_types.i32_ord_greater_than_or_equal,
'a=i64': stdlib_types.i64_ord_greater_than_or_equal,
'a=f32': stdlib_types.f32_ord_greater_than_or_equal,
'a=f64': stdlib_types.f64_ord_greater_than_or_equal,
},
type3classes.Floating.methods['sqrt']: { type3classes.Floating.methods['sqrt']: {
'a=f32': stdlib_types.f32_floating_sqrt, 'a=f32': stdlib_types.f32_floating_sqrt,
'a=f64': stdlib_types.f64_floating_sqrt, 'a=f64': stdlib_types.f64_floating_sqrt,
@ -200,10 +260,6 @@ U8_OPERATOR_MAP = {
} }
U32_OPERATOR_MAP = { U32_OPERATOR_MAP = {
'<': 'lt_u',
'>': 'gt_u',
'<=': 'le_u',
'>=': 'ge_u',
'<<': 'shl', '<<': 'shl',
'>>': 'shr_u', '>>': 'shr_u',
'^': 'xor', '^': 'xor',
@ -212,10 +268,6 @@ U32_OPERATOR_MAP = {
} }
U64_OPERATOR_MAP = { U64_OPERATOR_MAP = {
'<': 'lt_u',
'>': 'gt_u',
'<=': 'le_u',
'>=': 'ge_u',
'<<': 'shl', '<<': 'shl',
'>>': 'shr_u', '>>': 'shr_u',
'^': 'xor', '^': 'xor',
@ -223,18 +275,10 @@ U64_OPERATOR_MAP = {
'&': 'and', '&': 'and',
} }
I32_OPERATOR_MAP = { I32_OPERATOR_MAP: dict[str, str] = {
'<': 'lt_s',
'>': 'gt_s',
'<=': 'le_s',
'>=': 'ge_s',
} }
I64_OPERATOR_MAP = { I64_OPERATOR_MAP: dict[str, str] = {
'<': 'lt_s',
'>': 'gt_s',
'<=': 'le_s',
'>=': 'ge_s',
} }
def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) -> None: def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) -> None:
@ -923,6 +967,14 @@ def module(inp: ourlang.Module) -> wasm.Module:
stdlib_alloc.__alloc__, stdlib_alloc.__alloc__,
stdlib_types.__alloc_bytes__, stdlib_types.__alloc_bytes__,
stdlib_types.__subscript_bytes__, stdlib_types.__subscript_bytes__,
stdlib_types.__u32_ord_min__,
stdlib_types.__u64_ord_min__,
stdlib_types.__i32_ord_min__,
stdlib_types.__i64_ord_min__,
stdlib_types.__u32_ord_max__,
stdlib_types.__u64_ord_max__,
stdlib_types.__i32_ord_max__,
stdlib_types.__i64_ord_max__,
stdlib_types.__i32_intnum_abs__, stdlib_types.__i32_intnum_abs__,
stdlib_types.__i64_intnum_abs__, stdlib_types.__i64_intnum_abs__,
] + [ ] + [

View File

@ -36,6 +36,7 @@ from .type3 import types as type3types
PRELUDE_OPERATORS = { PRELUDE_OPERATORS = {
**type3typeclasses.Eq.operators, **type3typeclasses.Eq.operators,
**type3typeclasses.Ord.operators,
**type3typeclasses.Fractional.operators, **type3typeclasses.Fractional.operators,
**type3typeclasses.Integral.operators, **type3typeclasses.Integral.operators,
**type3typeclasses.IntNum.operators, **type3typeclasses.IntNum.operators,
@ -44,6 +45,7 @@ PRELUDE_OPERATORS = {
PRELUDE_METHODS = { PRELUDE_METHODS = {
**type3typeclasses.Eq.methods, **type3typeclasses.Eq.methods,
**type3typeclasses.Ord.methods,
**type3typeclasses.Floating.methods, **type3typeclasses.Floating.methods,
**type3typeclasses.Fractional.methods, **type3typeclasses.Fractional.methods,
**type3typeclasses.Integral.methods, **type3typeclasses.Integral.methods,
@ -405,12 +407,16 @@ class OurVisitor:
if isinstance(node.ops[0], ast.Gt): if isinstance(node.ops[0], ast.Gt):
operator = '>' operator = '>'
elif isinstance(node.ops[0], ast.GtE):
operator = '>='
elif isinstance(node.ops[0], ast.Eq): elif isinstance(node.ops[0], ast.Eq):
operator = '==' operator = '=='
elif isinstance(node.ops[0], ast.NotEq): elif isinstance(node.ops[0], ast.NotEq):
operator = '!=' operator = '!='
elif isinstance(node.ops[0], ast.Lt): elif isinstance(node.ops[0], ast.Lt):
operator = '<' operator = '<'
elif isinstance(node.ops[0], ast.LtE):
operator = '<='
else: else:
raise NotImplementedError(f'Operator {node.ops}') raise NotImplementedError(f'Operator {node.ops}')

View File

@ -67,6 +67,126 @@ def __subscript_bytes__(g: Generator, adr: i32, ofs: i32) -> i32:
return i32('return') # To satisfy mypy return i32('return') # To satisfy mypy
@func_wrapper()
def __u32_ord_min__(g: Generator, x: i32, y: i32) -> i32:
g.local.get(x)
g.local.get(y)
g.i32.lt_u()
with g.if_():
g.local.get(x)
g.return_()
g.local.get(y)
g.return_()
return i32('return') # To satisfy mypy
@func_wrapper()
def __u64_ord_min__(g: Generator, x: i64, y: i64) -> i64:
g.local.get(x)
g.local.get(y)
g.i64.lt_u()
with g.if_():
g.local.get(x)
g.return_()
g.local.get(y)
g.return_()
return i64('return') # To satisfy mypy
@func_wrapper()
def __i32_ord_min__(g: Generator, x: i32, y: i32) -> i32:
g.local.get(x)
g.local.get(y)
g.i32.lt_s()
with g.if_():
g.local.get(x)
g.return_()
g.local.get(y)
g.return_()
return i32('return') # To satisfy mypy
@func_wrapper()
def __i64_ord_min__(g: Generator, x: i64, y: i64) -> i64:
g.local.get(x)
g.local.get(y)
g.i64.lt_s()
with g.if_():
g.local.get(x)
g.return_()
g.local.get(y)
g.return_()
return i64('return') # To satisfy mypy
@func_wrapper()
def __u32_ord_max__(g: Generator, x: i32, y: i32) -> i32:
g.local.get(x)
g.local.get(y)
g.i32.gt_u()
with g.if_():
g.local.get(x)
g.return_()
g.local.get(y)
g.return_()
return i32('return') # To satisfy mypy
@func_wrapper()
def __u64_ord_max__(g: Generator, x: i64, y: i64) -> i64:
g.local.get(x)
g.local.get(y)
g.i64.gt_u()
with g.if_():
g.local.get(x)
g.return_()
g.local.get(y)
g.return_()
return i64('return') # To satisfy mypy
@func_wrapper()
def __i32_ord_max__(g: Generator, x: i32, y: i32) -> i32:
g.local.get(x)
g.local.get(y)
g.i32.gt_s()
with g.if_():
g.local.get(x)
g.return_()
g.local.get(y)
g.return_()
return i32('return') # To satisfy mypy
@func_wrapper()
def __i64_ord_max__(g: Generator, x: i64, y: i64) -> i64:
g.local.get(x)
g.local.get(y)
g.i64.gt_s()
with g.if_():
g.local.get(x)
g.return_()
g.local.get(y)
g.return_()
return i64('return') # To satisfy mypy
@func_wrapper() @func_wrapper()
def __i32_intnum_abs__(g: Generator, x: i32) -> i32: def __i32_intnum_abs__(g: Generator, x: i32) -> i32:
# https://stackoverflow.com/a/14194764 # https://stackoverflow.com/a/14194764
@ -170,6 +290,153 @@ def f32_eq_not_equals(g: Generator) -> None:
def f64_eq_not_equals(g: Generator) -> None: def f64_eq_not_equals(g: Generator) -> None:
g.f64.ne() g.f64.ne()
## ###
## class Ord
def u8_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_ord_min__')
def u32_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_ord_min__')
def u64_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u64_ord_min__')
def i8_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i32_ord_min__')
def i32_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i32_ord_min__')
def i64_ord_min(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i64_ord_min__')
def f32_ord_min(g: Generator) -> None:
g.f32.min()
def f64_ord_min(g: Generator) -> None:
g.f64.min()
def u8_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_ord_max__')
def u32_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u32_ord_max__')
def u64_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__u64_ord_max__')
def i8_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i32_ord_max__')
def i32_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i32_ord_max__')
def i64_ord_max(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i64_ord_max__')
def f32_ord_max(g: Generator) -> None:
g.f32.max()
def f64_ord_max(g: Generator) -> None:
g.f64.max()
def u8_ord_less_than(g: Generator) -> None:
g.i32.lt_u()
def u32_ord_less_than(g: Generator) -> None:
g.i32.lt_u()
def u64_ord_less_than(g: Generator) -> None:
g.i64.lt_u()
def i8_ord_less_than(g: Generator) -> None:
g.i32.lt_s()
def i32_ord_less_than(g: Generator) -> None:
g.i32.lt_s()
def i64_ord_less_than(g: Generator) -> None:
g.i64.lt_s()
def f32_ord_less_than(g: Generator) -> None:
g.f32.lt()
def f64_ord_less_than(g: Generator) -> None:
g.f64.lt()
def u8_ord_less_than_or_equal(g: Generator) -> None:
g.i32.le_u()
def u32_ord_less_than_or_equal(g: Generator) -> None:
g.i32.le_u()
def u64_ord_less_than_or_equal(g: Generator) -> None:
g.i64.le_u()
def i8_ord_less_than_or_equal(g: Generator) -> None:
g.i32.le_s()
def i32_ord_less_than_or_equal(g: Generator) -> None:
g.i32.le_s()
def i64_ord_less_than_or_equal(g: Generator) -> None:
g.i64.le_s()
def f32_ord_less_than_or_equal(g: Generator) -> None:
g.f32.le()
def f64_ord_less_than_or_equal(g: Generator) -> None:
g.f64.le()
def u8_ord_greater_than(g: Generator) -> None:
g.i32.gt_u()
def u32_ord_greater_than(g: Generator) -> None:
g.i32.gt_u()
def u64_ord_greater_than(g: Generator) -> None:
g.i64.gt_u()
def i8_ord_greater_than(g: Generator) -> None:
g.i32.gt_s()
def i32_ord_greater_than(g: Generator) -> None:
g.i32.gt_s()
def i64_ord_greater_than(g: Generator) -> None:
g.i64.gt_s()
def f32_ord_greater_than(g: Generator) -> None:
g.f32.gt()
def f64_ord_greater_than(g: Generator) -> None:
g.f64.gt()
def u8_ord_greater_than_or_equal(g: Generator) -> None:
g.i32.ge_u()
def u32_ord_greater_than_or_equal(g: Generator) -> None:
g.i32.ge_u()
def u64_ord_greater_than_or_equal(g: Generator) -> None:
g.i64.ge_u()
def i8_ord_greater_than_or_equal(g: Generator) -> None:
g.i32.ge_s()
def i32_ord_greater_than_or_equal(g: Generator) -> None:
g.i32.ge_s()
def i64_ord_greater_than_or_equal(g: Generator) -> None:
g.i64.ge_s()
def f32_ord_greater_than_or_equal(g: Generator) -> None:
g.f32.ge()
def f64_ord_greater_than_or_equal(g: Generator) -> None:
g.f64.ge()
## ### ## ###
## class Fractional ## class Fractional

View File

@ -98,6 +98,16 @@ Eq = Type3Class('Eq', ['a'], methods={}, operators={
'!=': 'a -> a -> bool', '!=': 'a -> a -> bool',
}) })
Ord = Type3Class('Ord', ['a'], methods={
'min': 'a -> a -> a',
'max': 'a -> a -> a',
}, operators={
'<': 'a -> a -> bool',
'<=': 'a -> a -> bool',
'>': 'a -> a -> bool',
'>=': 'a -> a -> bool',
}, inherited_classes=[Eq])
NatNum = Type3Class('NatNum', ['a'], methods={}, operators={ NatNum = Type3Class('NatNum', ['a'], methods={}, operators={
'+': 'a -> a -> a', '+': 'a -> a -> a',
'-': 'a -> a -> a', '-': 'a -> a -> a',

View File

@ -6,7 +6,16 @@ constraint generator works with.
""" """
from typing import Any, Dict, Iterable, List, Optional, Protocol, Set, Union from typing import Any, Dict, Iterable, List, Optional, Protocol, Set, Union
from .typeclasses import Eq, Floating, Fractional, Integral, IntNum, NatNum, Type3Class from .typeclasses import (
Eq,
Floating,
Fractional,
Integral,
IntNum,
NatNum,
Ord,
Type3Class,
)
TYPE3_ASSERTION_ERROR = 'You must call phasm_type3 after calling phasm_parse before you can call any other method' TYPE3_ASSERTION_ERROR = 'You must call phasm_type3 after calling phasm_parse before you can call any other method'
@ -43,7 +52,10 @@ class Type3:
for cls in self.classes: for cls in self.classes:
for inh_cls in cls.inherited_classes: for inh_cls in cls.inherited_classes:
if inh_cls not in self.classes: if inh_cls not in self.classes:
raise Exception(f'No instance for ({inh_cls} {self.name})') raise Exception(
f'No instance for ({inh_cls} {self.name})'
f'; required for ({cls} {self.name})'
)
def __repr__(self) -> str: def __repr__(self) -> str:
return f'Type3({repr(self.name)}, {repr(self.classes)})' return f'Type3({repr(self.name)}, {repr(self.classes)})'
@ -247,28 +259,28 @@ The bool type, either True or False
Suffixes with an underscores, as it's a Python builtin Suffixes with an underscores, as it's a Python builtin
""" """
u8 = PrimitiveType3('u8', [Eq]) u8 = PrimitiveType3('u8', [Eq, Ord])
""" """
The unsigned 8-bit integer type. The unsigned 8-bit integer type.
Operations on variables employ modular arithmetic, with modulus 2^8. Operations on variables employ modular arithmetic, with modulus 2^8.
""" """
u32 = PrimitiveType3('u32', [Eq, Integral, NatNum]) u32 = PrimitiveType3('u32', [Eq, Integral, NatNum, Ord])
""" """
The unsigned 32-bit integer type. The unsigned 32-bit integer type.
Operations on variables employ modular arithmetic, with modulus 2^32. Operations on variables employ modular arithmetic, with modulus 2^32.
""" """
u64 = PrimitiveType3('u64', [Eq, Integral, NatNum]) u64 = PrimitiveType3('u64', [Eq, Integral, NatNum, Ord])
""" """
The unsigned 64-bit integer type. The unsigned 64-bit integer type.
Operations on variables employ modular arithmetic, with modulus 2^64. Operations on variables employ modular arithmetic, with modulus 2^64.
""" """
i8 = PrimitiveType3('i8', [Eq]) i8 = PrimitiveType3('i8', [Eq, Ord])
""" """
The signed 8-bit integer type. The signed 8-bit integer type.
@ -276,7 +288,7 @@ Operations on variables employ modular arithmetic, with modulus 2^8, but
with the middel point being 0. with the middel point being 0.
""" """
i32 = PrimitiveType3('i32', [Eq, Integral, IntNum, NatNum]) i32 = PrimitiveType3('i32', [Eq, Integral, IntNum, NatNum, Ord])
""" """
The unsigned 32-bit integer type. The unsigned 32-bit integer type.
@ -284,7 +296,7 @@ Operations on variables employ modular arithmetic, with modulus 2^32, but
with the middel point being 0. with the middel point being 0.
""" """
i64 = PrimitiveType3('i64', [Eq, Integral, IntNum, NatNum]) i64 = PrimitiveType3('i64', [Eq, Integral, IntNum, NatNum, Ord])
""" """
The unsigned 64-bit integer type. The unsigned 64-bit integer type.
@ -292,12 +304,12 @@ Operations on variables employ modular arithmetic, with modulus 2^64, but
with the middel point being 0. with the middel point being 0.
""" """
f32 = PrimitiveType3('f32', [Eq, Floating, Fractional, IntNum, NatNum]) f32 = PrimitiveType3('f32', [Eq, Floating, Fractional, IntNum, NatNum, Ord])
""" """
A 32-bits IEEE 754 float, of 32 bits width. A 32-bits IEEE 754 float, of 32 bits width.
""" """
f64 = PrimitiveType3('f64', [Eq, Floating, Fractional, IntNum, NatNum]) f64 = PrimitiveType3('f64', [Eq, Floating, Fractional, IntNum, NatNum, Ord])
""" """
A 32-bits IEEE 754 float, of 64 bits width. A 32-bits IEEE 754 float, of 64 bits width.
""" """

View File

@ -34,15 +34,29 @@ class Generator_i32i64:
self.add = functools.partial(self.generator.add_statement, f'{prefix}.add') self.add = functools.partial(self.generator.add_statement, f'{prefix}.add')
self.sub = functools.partial(self.generator.add_statement, f'{prefix}.sub') self.sub = functools.partial(self.generator.add_statement, f'{prefix}.sub')
self.mul = functools.partial(self.generator.add_statement, f'{prefix}.mul') self.mul = functools.partial(self.generator.add_statement, f'{prefix}.mul')
self.div_s = functools.partial(self.generator.add_statement, f'{prefix}.div_s')
self.div_u = functools.partial(self.generator.add_statement, f'{prefix}.div_u')
self.rem_s = functools.partial(self.generator.add_statement, f'{prefix}.rem_s')
self.rem_u = functools.partial(self.generator.add_statement, f'{prefix}.rem_u')
self.and_ = functools.partial(self.generator.add_statement, f'{prefix}.and')
self.or_ = functools.partial(self.generator.add_statement, f'{prefix}.or')
self.xor = functools.partial(self.generator.add_statement, f'{prefix}.xor')
self.shl = functools.partial(self.generator.add_statement, f'{prefix}.shl')
self.shr_s = functools.partial(self.generator.add_statement, f'{prefix}.shr_s') self.shr_s = functools.partial(self.generator.add_statement, f'{prefix}.shr_s')
self.shr_u = functools.partial(self.generator.add_statement, f'{prefix}.shr_u') self.shr_u = functools.partial(self.generator.add_statement, f'{prefix}.shr_u')
self.rotl = functools.partial(self.generator.add_statement, f'{prefix}.rotl')
self.rotr = functools.partial(self.generator.add_statement, f'{prefix}.rotr') self.rotr = functools.partial(self.generator.add_statement, f'{prefix}.rotr')
self.xor = functools.partial(self.generator.add_statement, f'{prefix}.xor')
# irelop # irelop
self.eq = functools.partial(self.generator.add_statement, f'{prefix}.eq') self.eq = functools.partial(self.generator.add_statement, f'{prefix}.eq')
self.ne = functools.partial(self.generator.add_statement, f'{prefix}.ne') self.ne = functools.partial(self.generator.add_statement, f'{prefix}.ne')
self.lt_s = functools.partial(self.generator.add_statement, f'{prefix}.lt_s')
self.lt_u = functools.partial(self.generator.add_statement, f'{prefix}.lt_u') self.lt_u = functools.partial(self.generator.add_statement, f'{prefix}.lt_u')
self.gt_s = functools.partial(self.generator.add_statement, f'{prefix}.gt_s')
self.gt_u = functools.partial(self.generator.add_statement, f'{prefix}.gt_u')
self.le_s = functools.partial(self.generator.add_statement, f'{prefix}.le_s')
self.le_u = functools.partial(self.generator.add_statement, f'{prefix}.le_u')
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')
# 2.4.4. Memory Instructions # 2.4.4. Memory Instructions
@ -88,6 +102,10 @@ class Generator_f32f64:
# frelop # frelop
self.eq = functools.partial(self.generator.add_statement, f'{prefix}.eq') self.eq = functools.partial(self.generator.add_statement, f'{prefix}.eq')
self.ne = functools.partial(self.generator.add_statement, f'{prefix}.ne') self.ne = functools.partial(self.generator.add_statement, f'{prefix}.ne')
self.lt = functools.partial(self.generator.add_statement, f'{prefix}.lt')
self.gt = functools.partial(self.generator.add_statement, f'{prefix}.gt')
self.le = functools.partial(self.generator.add_statement, f'{prefix}.le')
self.ge = functools.partial(self.generator.add_statement, f'{prefix}.ge')
# 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')

View File

@ -253,7 +253,7 @@ def _load_memory_stored_returned_value(
assert isinstance(wasm_value, int), wasm_value assert isinstance(wasm_value, int), wasm_value
return 0 != wasm_value return 0 != wasm_value
if ret_type3 in (type3types.i32, type3types.i64): if ret_type3 in (type3types.i8, type3types.i32, type3types.i64):
assert isinstance(wasm_value, int), wasm_value assert isinstance(wasm_value, int), wasm_value
return wasm_value return wasm_value

View File

@ -0,0 +1,97 @@
import struct
import pytest
from ..helpers import Suite
TYPE_LIST = [
'u8', 'u32', 'u64',
'i8', 'i32', 'i64',
'f32', 'f64',
]
BOUND_MAP = {
'u8': struct.unpack('<BB', bytes.fromhex('00FF')),
'u32': struct.unpack('<II', bytes.fromhex('00000000FFFFFFFF')),
'u64': struct.unpack('<QQ', bytes.fromhex('0000000000000000FFFFFFFFFFFFFFFF')),
'i8': struct.unpack('<bb', bytes.fromhex('807F')),
'i32': struct.unpack('<ii', bytes.fromhex('00000080FFFFFF7F')),
'i64': struct.unpack('<qq', bytes.fromhex('0000000000000080FFFFFFFFFFFFFF7F')),
'f32': struct.unpack('<ff', bytes.fromhex('01000000FFFF7F7F')),
'f64': struct.unpack('<dd', bytes.fromhex('0000000000001000FFFFFFFFFFFFEF7F')),
}
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', TYPE_LIST)
@pytest.mark.parametrize('test_lft,test_opr,test_rgt,test_out', [
(1, '<', 2, True, ),
(1, '<', 0, False, ),
(1, '<=', 1, True, ),
(1, '<=', 0, False, ),
(1, '>', 0, True, ),
(1, '>', 1, False, ),
(1, '>=', 0, True, ),
(1, '>=', 2, False, ),
])
def test_ord_operators(type_, test_lft, test_opr, test_rgt, test_out):
code_py = f"""
@exported
def testEntry(lft: {type_}, rgt: {type_}) -> bool:
return lft {test_opr} rgt
"""
if type_[0] == 'f':
test_lft = float(test_lft)
test_rgt = float(test_rgt)
result = Suite(code_py).run_code(test_lft, test_rgt)
assert test_out is result.returned_value
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', TYPE_LIST)
@pytest.mark.parametrize('test_mth,test_lft,test_rgt,test_out', [
('min', 1, 2, 1),
('min', 2, 1, 1),
('min', 2, 2, 2),
('max', 1, 2, 2),
('max', 2, 1, 2),
('max', 2, 2, 2),
])
def test_ord_methods(type_, test_mth, test_lft, test_rgt, test_out):
code_py = f"""
@exported
def testEntry(lft: {type_}, rgt: {type_}) -> {type_}:
return {test_mth}(lft, rgt)
"""
if type_[0] == 'f':
test_lft = float(test_lft)
test_rgt = float(test_rgt)
result = Suite(code_py).run_code(test_lft, test_rgt)
assert test_out == result.returned_value
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', TYPE_LIST)
@pytest.mark.parametrize('test_mth', ['min', 'max'])
def test_ord_bounds_min_max(type_, test_mth):
code_py = f"""
@exported
def testEntry(lft: {type_}, rgt: {type_}) -> {type_}:
return {test_mth}(lft, rgt)
"""
test_lft, test_rgt = BOUND_MAP[type_]
result = Suite(code_py).run_code(test_lft, test_rgt)
if 'min' == test_mth:
assert test_lft == result.returned_value
else:
assert test_rgt == result.returned_value