Split Num into NatNum and IntNum

This is because Haskell defines negate, abs and signum
for Num, but they don't work with our unsigned number
types. (abs would be a noop.) Haskell has Word32 / Word64,
but there negate doesn't make much sense to me.

Implemented neg and abs.

Implemented a type class inheritance check.

Removed Integral from u8 and i8 since it wasn't implemented.
This commit is contained in:
Johan B.W. de Vries 2025-04-06 16:12:36 +02:00
parent 74ab3b47fd
commit 7544055a94
11 changed files with 272 additions and 68 deletions

View File

@ -97,3 +97,9 @@ References
[4] https://www.w3.org/TR/wasm-core-1/ [4] https://www.w3.org/TR/wasm-core-1/
[5] https://en.wikipedia.org/w/index.php?title=WebAssembly&oldid=1103639883 [5] https://en.wikipedia.org/w/index.php?title=WebAssembly&oldid=1103639883
[6] https://github.com/WebAssembly/wabt [6] https://github.com/WebAssembly/wabt
Links
-----
- https://pengowray.github.io/wasm-ops/
Shorthand overview for supported operations in WebAssembly.

View File

@ -30,3 +30,4 @@
- ourlang.BinaryOp should probably always be a Type3ClassMethod - ourlang.BinaryOp should probably always be a Type3ClassMethod
- Remove U32_OPERATOR_MAP / U64_OPERATOR_MAP - Remove U32_OPERATOR_MAP / U64_OPERATOR_MAP
- Make prelude more an actual thing - Make prelude more an actual thing
- Implemented Bounded: https://hackage.haskell.org/package/base-4.21.0.0/docs/Prelude.html#t:Bounded

View File

@ -53,29 +53,41 @@ INSTANCES = {
'a=i32': stdlib_types.i32_integral_div, 'a=i32': stdlib_types.i32_integral_div,
'a=i64': stdlib_types.i64_integral_div, 'a=i64': stdlib_types.i64_integral_div,
}, },
type3classes.Num.operators['+']: { type3classes.IntNum.methods['abs']: {
'a=u32': stdlib_types.u32_num_add, 'a=i32': stdlib_types.i32_intnum_abs,
'a=u64': stdlib_types.u64_num_add, 'a=i64': stdlib_types.i64_intnum_abs,
'a=i32': stdlib_types.i32_num_add, 'a=f32': stdlib_types.f32_intnum_abs,
'a=i64': stdlib_types.i64_num_add, 'a=f64': stdlib_types.f64_intnum_abs,
'a=f32': stdlib_types.f32_num_add,
'a=f64': stdlib_types.f64_num_add,
}, },
type3classes.Num.operators['-']: { type3classes.IntNum.methods['neg']: {
'a=u32': stdlib_types.u32_num_sub, 'a=i32': stdlib_types.i32_intnum_neg,
'a=u64': stdlib_types.u64_num_sub, 'a=i64': stdlib_types.i64_intnum_neg,
'a=i32': stdlib_types.i32_num_sub, 'a=f32': stdlib_types.f32_intnum_neg,
'a=i64': stdlib_types.i64_num_sub, 'a=f64': stdlib_types.f64_intnum_neg,
'a=f32': stdlib_types.f32_num_sub,
'a=f64': stdlib_types.f64_num_sub,
}, },
type3classes.Num.operators['*']: { type3classes.NatNum.operators['+']: {
'a=u32': stdlib_types.u32_num_mul, 'a=u32': stdlib_types.u32_natnum_add,
'a=u64': stdlib_types.u64_num_mul, 'a=u64': stdlib_types.u64_natnum_add,
'a=i32': stdlib_types.i32_num_mul, 'a=i32': stdlib_types.i32_natnum_add,
'a=i64': stdlib_types.i64_num_mul, 'a=i64': stdlib_types.i64_natnum_add,
'a=f32': stdlib_types.f32_num_mul, 'a=f32': stdlib_types.f32_natnum_add,
'a=f64': stdlib_types.f64_num_mul, 'a=f64': stdlib_types.f64_natnum_add,
},
type3classes.NatNum.operators['-']: {
'a=u32': stdlib_types.u32_natnum_sub,
'a=u64': stdlib_types.u64_natnum_sub,
'a=i32': stdlib_types.i32_natnum_sub,
'a=i64': stdlib_types.i64_natnum_sub,
'a=f32': stdlib_types.f32_natnum_sub,
'a=f64': stdlib_types.f64_natnum_sub,
},
type3classes.NatNum.operators['*']: {
'a=u32': stdlib_types.u32_natnum_mul,
'a=u64': stdlib_types.u64_natnum_mul,
'a=i32': stdlib_types.i32_natnum_mul,
'a=i64': stdlib_types.i64_natnum_mul,
'a=f32': stdlib_types.f32_natnum_mul,
'a=f64': stdlib_types.f64_natnum_mul,
}, },
} }
@ -894,6 +906,8 @@ 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.__i32_intnum_abs__,
stdlib_types.__i64_intnum_abs__,
] + [ ] + [
function(x) function(x)
for x in inp.functions.values() for x in inp.functions.values()

View File

@ -39,7 +39,8 @@ PRELUDE_OPERATORS = {
**type3typeclasses.Eq.operators, **type3typeclasses.Eq.operators,
**type3typeclasses.Fractional.operators, **type3typeclasses.Fractional.operators,
**type3typeclasses.Integral.operators, **type3typeclasses.Integral.operators,
**type3typeclasses.Num.operators, **type3typeclasses.IntNum.operators,
**type3typeclasses.NatNum.operators,
} }
PRELUDE_METHODS = { PRELUDE_METHODS = {
@ -47,7 +48,8 @@ PRELUDE_METHODS = {
**type3typeclasses.Floating.methods, **type3typeclasses.Floating.methods,
**type3typeclasses.Fractional.methods, **type3typeclasses.Fractional.methods,
**type3typeclasses.Integral.methods, **type3typeclasses.Integral.methods,
**type3typeclasses.Num.methods, **type3typeclasses.IntNum.methods,
**type3typeclasses.NatNum.methods,
} }
def phasm_parse(source: str) -> Module: def phasm_parse(source: str) -> Module:

View File

@ -4,6 +4,7 @@ stdlib: Standard types that are not wasm primitives
from phasm.stdlib import alloc from phasm.stdlib import alloc
from phasm.wasmgenerator import Generator, func_wrapper from phasm.wasmgenerator import Generator, func_wrapper
from phasm.wasmgenerator import VarType_i32 as i32 from phasm.wasmgenerator import VarType_i32 as i32
from phasm.wasmgenerator import VarType_i64 as i64
@func_wrapper() @func_wrapper()
@ -66,6 +67,59 @@ 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 __i32_intnum_abs__(g: Generator, x: i32) -> i32:
# https://stackoverflow.com/a/14194764
y = i32('y')
# z = i32('z')
# y = x >> 31
g.local.get(x)
g.i32.const(31)
g.i32.shr_s() # Must be arithmetic shift
g.local.set(y)
# abs(x) = (x XOR y) - y
# (x XOR y)
g.local.get(x)
g.local.get(y)
g.i32.xor()
# - y
g.local.get(y)
g.i32.sub()
g.return_()
return i32('return')
@func_wrapper()
def __i64_intnum_abs__(g: Generator, x: i64) -> i64:
# https://stackoverflow.com/a/14194764
y = i64('y')
# z = i64('z')
# y = x >> 31
g.local.get(x)
g.i64.const(31)
g.i64.shr_s() # Must be arithmetic shift
g.local.set(y)
# abs(x) = (x XOR y) - y
# (x XOR y)
g.local.get(x)
g.local.get(y)
g.i64.xor()
# - y
g.local.get(y)
g.i64.sub()
g.return_()
return i64('return')
def u8_eq_equals(g: Generator) -> None: def u8_eq_equals(g: Generator) -> None:
g.add_statement('i32.eq') g.add_statement('i32.eq')
@ -114,56 +168,82 @@ def i32_integral_div(g: Generator) -> None:
def i64_integral_div(g: Generator) -> None: def i64_integral_div(g: Generator) -> None:
g.add_statement('i64.div_s') g.add_statement('i64.div_s')
def u32_num_add(g: Generator) -> None: def u32_natnum_add(g: Generator) -> None:
g.add_statement('i32.add') g.add_statement('i32.add')
def u64_num_add(g: Generator) -> None: def u64_natnum_add(g: Generator) -> None:
g.add_statement('i64.add') g.add_statement('i64.add')
def i32_num_add(g: Generator) -> None: def i32_natnum_add(g: Generator) -> None:
g.add_statement('i32.add') g.add_statement('i32.add')
def i64_num_add(g: Generator) -> None: def i64_natnum_add(g: Generator) -> None:
g.add_statement('i64.add') g.add_statement('i64.add')
def f32_num_add(g: Generator) -> None: def f32_natnum_add(g: Generator) -> None:
g.add_statement('f32.add') g.add_statement('f32.add')
def f64_num_add(g: Generator) -> None: def f64_natnum_add(g: Generator) -> None:
g.add_statement('f64.add') g.add_statement('f64.add')
def u32_num_sub(g: Generator) -> None: def u32_natnum_sub(g: Generator) -> None:
g.add_statement('i32.sub') g.add_statement('i32.sub')
def u64_num_sub(g: Generator) -> None: def u64_natnum_sub(g: Generator) -> None:
g.add_statement('i64.sub') g.add_statement('i64.sub')
def i32_num_sub(g: Generator) -> None: def i32_natnum_sub(g: Generator) -> None:
g.add_statement('i32.sub') g.add_statement('i32.sub')
def i64_num_sub(g: Generator) -> None: def i64_natnum_sub(g: Generator) -> None:
g.add_statement('i64.sub') g.add_statement('i64.sub')
def f32_num_sub(g: Generator) -> None: def f32_natnum_sub(g: Generator) -> None:
g.add_statement('f32.sub') g.add_statement('f32.sub')
def f64_num_sub(g: Generator) -> None: def f64_natnum_sub(g: Generator) -> None:
g.add_statement('f64.sub') g.add_statement('f64.sub')
def u32_num_mul(g: Generator) -> None: def u32_natnum_mul(g: Generator) -> None:
g.add_statement('i32.mul') g.add_statement('i32.mul')
def u64_num_mul(g: Generator) -> None: def u64_natnum_mul(g: Generator) -> None:
g.add_statement('i64.mul') g.add_statement('i64.mul')
def i32_num_mul(g: Generator) -> None: def i32_natnum_mul(g: Generator) -> None:
g.add_statement('i32.mul') g.add_statement('i32.mul')
def i64_num_mul(g: Generator) -> None: def i64_natnum_mul(g: Generator) -> None:
g.add_statement('i64.mul') g.add_statement('i64.mul')
def f32_num_mul(g: Generator) -> None: def f32_natnum_mul(g: Generator) -> None:
g.add_statement('f32.mul') g.add_statement('f32.mul')
def f64_num_mul(g: Generator) -> None: def f64_natnum_mul(g: Generator) -> None:
g.add_statement('f64.mul') g.add_statement('f64.mul')
def i32_intnum_abs(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i32_intnum_abs__')
def i64_intnum_abs(g: Generator) -> None:
g.add_statement('call $stdlib.types.__i64_intnum_abs__')
def f32_intnum_abs(g: Generator) -> None:
g.f32.abs()
def f64_intnum_abs(g: Generator) -> None:
g.f64.abs()
def i32_intnum_neg(g: Generator) -> None:
g.i32.const(-1)
g.i32.mul()
def i64_intnum_neg(g: Generator) -> None:
g.i64.const(-1)
g.i64.mul()
def f32_intnum_neg(g: Generator) -> None:
g.f32.neg()
def f64_intnum_neg(g: Generator) -> None:
g.f64.neg()

View File

@ -1,4 +1,4 @@
from typing import Any, Dict, Iterable, Optional, List, Mapping, Union from typing import Any, Dict, Iterable, List, Mapping, Optional, Union
class TypeVariable: class TypeVariable:
@ -62,12 +62,13 @@ class Type3ClassMethod:
return f'Type3ClassMethod({repr(self.type3_class)}, {repr(self.name)}, {repr(self.signature)})' return f'Type3ClassMethod({repr(self.type3_class)}, {repr(self.name)}, {repr(self.signature)})'
class Type3Class: class Type3Class:
__slots__ = ('name', 'args', 'methods', 'operators', ) __slots__ = ('name', 'args', 'methods', 'operators', 'inherited_classes', )
name: str name: str
args: List[TypeVariable] args: List[TypeVariable]
methods: Dict[str, Type3ClassMethod] methods: Dict[str, Type3ClassMethod]
operators: Dict[str, Type3ClassMethod] operators: Dict[str, Type3ClassMethod]
inherited_classes: List['Type3Class']
def __init__( def __init__(
self, self,
@ -77,8 +78,6 @@ class Type3Class:
operators: Mapping[str, str], operators: Mapping[str, str],
inherited_classes: Optional[List['Type3Class']] = None, inherited_classes: Optional[List['Type3Class']] = None,
) -> None: ) -> None:
del inherited_classes # Not implemented yet
self.name = name self.name = name
self.args = [TypeVariable(x) for x in args] self.args = [TypeVariable(x) for x in args]
self.methods = { self.methods = {
@ -89,6 +88,7 @@ class Type3Class:
k: Type3ClassMethod(self, k, v) k: Type3ClassMethod(self, k, v)
for k, v in operators.items() for k, v in operators.items()
} }
self.inherited_classes = inherited_classes or []
def __repr__(self) -> str: def __repr__(self) -> str:
return self.name return self.name
@ -97,20 +97,25 @@ Eq = Type3Class('Eq', ['a'], methods={}, operators={
'==': 'a -> a -> bool', '==': 'a -> a -> bool',
}) })
Num = Type3Class('Num', ['a'], methods={}, operators={ NatNum = Type3Class('NatNum', ['a'], methods={}, operators={
'+': 'a -> a -> a', '+': 'a -> a -> a',
'-': 'a -> a -> a', '-': 'a -> a -> a',
'*': 'a -> a -> a', '*': 'a -> a -> a',
}) })
IntNum = Type3Class('IntNum', ['a'], methods={
'abs': 'a -> a',
'neg': 'a -> a',
}, operators={}, inherited_classes=[NatNum])
Integral = Type3Class('Eq', ['a'], methods={
'div': 'a -> a -> a',
}, operators={}, inherited_classes=[NatNum])
Fractional = Type3Class('Fractional', ['a'], methods={}, operators={ Fractional = Type3Class('Fractional', ['a'], methods={}, operators={
'/': 'a -> a -> a', '/': 'a -> a -> a',
}, inherited_classes=[Num]) }, inherited_classes=[NatNum])
Floating = Type3Class('Floating', ['a'], methods={ Floating = Type3Class('Floating', ['a'], methods={
'sqrt': 'a -> a', 'sqrt': 'a -> a',
}, operators={}, inherited_classes=[Fractional]) }, operators={}, inherited_classes=[Fractional])
Integral = Type3Class('Eq', ['a'], methods={
'div': 'a -> a -> a',
}, operators={})

View File

@ -4,9 +4,9 @@ Contains the final types for use in Phasm
These are actual, instantiated types; not the abstract types that the These are actual, instantiated types; not the abstract types that the
constraint generator works with. constraint generator works with.
""" """
from typing import Any, Dict, Iterable, List, Optional, Protocol, Union from typing import Any, Dict, Iterable, List, Optional, Protocol, Set, Union
from .typeclasses import Eq, Floating, Fractional, Integral, Num, Type3Class from .typeclasses import Eq, Floating, Fractional, Integral, IntNum, NatNum, 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'
@ -31,14 +31,19 @@ class Type3:
The name of the string, as parsed and outputted by codestyle. The name of the string, as parsed and outputted by codestyle.
""" """
classes: List[Type3Class] classes: Set[Type3Class]
""" """
The type classes that this type implements The type classes that this type implements
""" """
def __init__(self, name: str, classes: Iterable[Type3Class]) -> None: def __init__(self, name: str, classes: Iterable[Type3Class]) -> None:
self.name = name self.name = name
self.classes = [*classes] self.classes = set(classes)
for cls in self.classes:
for inh_cls in cls.inherited_classes:
if inh_cls not in self.classes:
raise Exception(f'No instance for ({inh_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)})'
@ -242,28 +247,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, Integral]) u8 = PrimitiveType3('u8', [Eq])
""" """
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, Num]) u32 = PrimitiveType3('u32', [Eq, Integral, NatNum])
""" """
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, Num]) u64 = PrimitiveType3('u64', [Eq, Integral, NatNum])
""" """
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, Integral]) i8 = PrimitiveType3('i8', [Eq])
""" """
The signed 8-bit integer type. The signed 8-bit integer type.
@ -271,7 +276,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, Num]) i32 = PrimitiveType3('i32', [Eq, Integral, IntNum, NatNum])
""" """
The unsigned 32-bit integer type. The unsigned 32-bit integer type.
@ -279,7 +284,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, Num]) i64 = PrimitiveType3('i64', [Eq, Integral, IntNum, NatNum])
""" """
The unsigned 64-bit integer type. The unsigned 64-bit integer type.
@ -287,12 +292,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, Num]) f32 = PrimitiveType3('f32', [Eq, Floating, Fractional, IntNum, NatNum])
""" """
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, Num]) f64 = PrimitiveType3('f64', [Eq, Floating, Fractional, IntNum, NatNum])
""" """
A 32-bits IEEE 754 float, of 64 bits width. A 32-bits IEEE 754 float, of 64 bits width.
""" """

View File

@ -21,6 +21,9 @@ class VarType_u8(VarType_Base):
class VarType_i32(VarType_Base): class VarType_i32(VarType_Base):
wasm_type = wasm.WasmTypeInt32 wasm_type = wasm.WasmTypeInt32
class VarType_i64(VarType_Base):
wasm_type = wasm.WasmTypeInt64
class Generator_i32i64: class Generator_i32i64:
def __init__(self, prefix: str, generator: 'Generator') -> None: def __init__(self, prefix: str, generator: 'Generator') -> None:
self.prefix = prefix self.prefix = prefix
@ -31,6 +34,10 @@ 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.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.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')
@ -60,8 +67,23 @@ class Generator_f32f64:
self.generator = generator self.generator = generator
# 2.4.1. Numeric Instructions # 2.4.1. Numeric Instructions
# funop
self.abs = functools.partial(self.generator.add_statement, f'{prefix}.abs')
self.neg = functools.partial(self.generator.add_statement, f'{prefix}.neg')
self.sqrt = functools.partial(self.generator.add_statement, f'{prefix}.sqrt')
self.ceil = functools.partial(self.generator.add_statement, f'{prefix}.ceil')
self.floor = functools.partial(self.generator.add_statement, f'{prefix}.floor')
self.trunc = functools.partial(self.generator.add_statement, f'{prefix}.trunc')
self.nearest = functools.partial(self.generator.add_statement, f'{prefix}.nearest')
# fbinop # fbinop
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.mul = functools.partial(self.generator.add_statement, f'{prefix}.mul')
self.div = functools.partial(self.generator.add_statement, f'{prefix}.div')
self.min = functools.partial(self.generator.add_statement, f'{prefix}.min')
self.max = functools.partial(self.generator.add_statement, f'{prefix}.max')
self.copysign = functools.partial(self.generator.add_statement, f'{prefix}.copysign')
# frelop # frelop
self.eq = functools.partial(self.generator.add_statement, f'{prefix}.eq') self.eq = functools.partial(self.generator.add_statement, f'{prefix}.eq')

View File

@ -26,10 +26,10 @@ class Foo:
@exported @exported
def testEntry(x: Foo, y: Foo) -> Foo: def testEntry(x: Foo, y: Foo) -> Foo:
return x + y return x == y
""" """
with pytest.raises(Type3Exception, match='Foo does not implement the Num type class'): with pytest.raises(Type3Exception, match='Foo does not implement the Eq type class'):
Suite(code_py).run_code() Suite(code_py).run_code()
@pytest.mark.integration_test @pytest.mark.integration_test

View File

@ -0,0 +1,69 @@
import pytest
from ..helpers import Suite
INT_TYPES = ['i32', 'i64']
FLOAT_TYPES = ['f32', 'f64']
TYPE_MAP = {
'i32': int,
'i64': int,
'f32': float,
'f64': float,
}
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', INT_TYPES)
def test_abs_int(type_):
code_py = f"""
@exported
def testEntry() -> {type_}:
return abs(-3)
"""
result = Suite(code_py).run_code()
assert 3 == result.returned_value
assert TYPE_MAP[type_] is type(result.returned_value)
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', FLOAT_TYPES)
def test_abs_float(type_):
code_py = f"""
@exported
def testEntry() -> {type_}:
return abs(-3.5)
"""
result = Suite(code_py).run_code()
assert 3.5 == result.returned_value
assert TYPE_MAP[type_] is type(result.returned_value)
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', INT_TYPES)
def test_neg_int(type_):
code_py = f"""
@exported
def testEntry() -> {type_}:
return neg(3)
"""
result = Suite(code_py).run_code()
assert -3 == result.returned_value
assert TYPE_MAP[type_] is type(result.returned_value)
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', FLOAT_TYPES)
def test_neg_float(type_):
code_py = f"""
@exported
def testEntry() -> {type_}:
return neg(3.5)
"""
result = Suite(code_py).run_code()
assert -3.5 == result.returned_value
assert TYPE_MAP[type_] is type(result.returned_value)

View File

@ -27,7 +27,7 @@ def testEntry(x: Foo, y: Foo) -> Foo:
return x + y return x + y
""" """
with pytest.raises(Type3Exception, match='Foo does not implement the Num type class'): with pytest.raises(Type3Exception, match='Foo does not implement the NatNum type class'):
Suite(code_py).run_code() Suite(code_py).run_code()
@pytest.mark.integration_test @pytest.mark.integration_test
@ -122,7 +122,7 @@ def testEntry() -> {type_}:
result = Suite(code_py).run_code() result = Suite(code_py).run_code()
assert 30 == result.returned_value assert 30 == result.returned_value
assert TYPE_MAP[type_] == type(result.returned_value) assert TYPE_MAP[type_] is type(result.returned_value)
@pytest.mark.integration_test @pytest.mark.integration_test
@pytest.mark.parametrize('type_', FLOAT_TYPES) @pytest.mark.parametrize('type_', FLOAT_TYPES)
@ -136,7 +136,7 @@ def testEntry() -> {type_}:
result = Suite(code_py).run_code() result = Suite(code_py).run_code()
assert 4.0 == result.returned_value assert 4.0 == result.returned_value
assert TYPE_MAP[type_] == type(result.returned_value) assert TYPE_MAP[type_] is type(result.returned_value)
@pytest.mark.integration_test @pytest.mark.integration_test
@pytest.mark.parametrize('type_', INT_TYPES) @pytest.mark.parametrize('type_', INT_TYPES)