Implements sum for Foldable types
Foldable take a TypeConstructor. The first argument must be a NatNum. The FunctionSignatureRouter wasn't completely on point, instead this commit adds an TypeClassArgsRouter lookup router. This makes sense since the only available arguments we have to find a router is the list of type class arguments.
This commit is contained in:
parent
6c627bca01
commit
b5f0fda133
1
TODO.md
1
TODO.md
@ -12,6 +12,7 @@
|
|||||||
- Also, check the codes for FIXME and TODO
|
- Also, check the codes for FIXME and TODO
|
||||||
- Allocation is done using pointers for members, is this desired?
|
- Allocation is done using pointers for members, is this desired?
|
||||||
- See if we want to replace Fractional with Real, and add Rational, Irrationl, Algebraic, Transendental
|
- See if we want to replace Fractional with Real, and add Rational, Irrationl, Algebraic, Transendental
|
||||||
|
- Implement q32? q64? Two i32/i64 divided?
|
||||||
- Does Subscript do what we want? It's a language feature rather a normal typed thing. How would you implement your own Subscript-able type?
|
- Does Subscript do what we want? It's a language feature rather a normal typed thing. How would you implement your own Subscript-able type?
|
||||||
- Clean up Subscript implementation - it's half implemented in the compiler. Makes more sense to move more parts to stdlib_types.
|
- Clean up Subscript implementation - it's half implemented in the compiler. Makes more sense to move more parts to stdlib_types.
|
||||||
- Have a set of rules or guidelines for the constraint comments, they're messy.
|
- Have a set of rules or guidelines for the constraint comments, they're messy.
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
This module contains the code to convert parsed Ourlang into WebAssembly code
|
This module contains the code to convert parsed Ourlang into WebAssembly code
|
||||||
"""
|
"""
|
||||||
import struct
|
import struct
|
||||||
from typing import Dict, List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from . import codestyle, ourlang, prelude, wasm
|
from . import codestyle, ourlang, prelude, wasm
|
||||||
from .runtime import calculate_alloc_size, calculate_member_offset
|
from .runtime import calculate_alloc_size, calculate_member_offset
|
||||||
@ -292,15 +292,20 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
expression(wgn, inp.left)
|
expression(wgn, inp.left)
|
||||||
expression(wgn, inp.right)
|
expression(wgn, inp.right)
|
||||||
|
|
||||||
type_var_map: Dict[type3functions.TypeVariable, type3types.Type3] = {}
|
type_var_map: dict[type3functions.TypeVariable, type3types.Type3] = {}
|
||||||
|
|
||||||
for type_var, arg_expr in zip(inp.operator.signature.args, [inp.left, inp.right, inp], strict=True):
|
for type_var, arg_expr in zip(inp.operator.signature.args, [inp.left, inp.right, inp], strict=True):
|
||||||
if not isinstance(type_var, type3functions.TypeVariable):
|
assert arg_expr.type3 is not None, TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
|
if isinstance(type_var, type3types.Type3):
|
||||||
# Fixed type, not part of the lookup requirements
|
# Fixed type, not part of the lookup requirements
|
||||||
continue
|
continue
|
||||||
|
|
||||||
assert arg_expr.type3 is not None, TYPE3_ASSERTION_ERROR
|
if isinstance(type_var, type3functions.TypeVariable):
|
||||||
type_var_map[type_var] = arg_expr.type3
|
type_var_map[type_var] = arg_expr.type3
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise NotImplementedError(type_var, arg_expr.type3)
|
||||||
|
|
||||||
router = prelude.PRELUDE_TYPE_CLASS_INSTANCE_METHODS[inp.operator]
|
router = prelude.PRELUDE_TYPE_CLASS_INSTANCE_METHODS[inp.operator]
|
||||||
router(wgn, type_var_map)
|
router(wgn, type_var_map)
|
||||||
@ -315,12 +320,17 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
type_var_map = {}
|
type_var_map = {}
|
||||||
|
|
||||||
for type_var, arg_expr in zip(inp.function.signature.args, inp.arguments + [inp], strict=True):
|
for type_var, arg_expr in zip(inp.function.signature.args, inp.arguments + [inp], strict=True):
|
||||||
if not isinstance(type_var, type3functions.TypeVariable):
|
assert arg_expr.type3 is not None, TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
|
if isinstance(type_var, type3types.Type3):
|
||||||
# Fixed type, not part of the lookup requirements
|
# Fixed type, not part of the lookup requirements
|
||||||
continue
|
continue
|
||||||
|
|
||||||
assert arg_expr.type3 is not None, TYPE3_ASSERTION_ERROR
|
if isinstance(type_var, type3functions.TypeVariable):
|
||||||
type_var_map[type_var] = arg_expr.type3
|
type_var_map[type_var] = arg_expr.type3
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise NotImplementedError(type_var, arg_expr.type3)
|
||||||
|
|
||||||
router = prelude.PRELUDE_TYPE_CLASS_INSTANCE_METHODS[inp.function]
|
router = prelude.PRELUDE_TYPE_CLASS_INSTANCE_METHODS[inp.function]
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -1,27 +1,33 @@
|
|||||||
"""
|
"""
|
||||||
The prelude are all the builtin types, type classes and methods
|
The prelude are all the builtin types, type classes and methods
|
||||||
"""
|
"""
|
||||||
from typing import Callable
|
from typing import Any, Callable
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
|
||||||
from phasm.stdlib import types as stdtypes
|
from phasm.stdlib import types as stdtypes
|
||||||
from phasm.wasmgenerator import Generator
|
from phasm.wasmgenerator import Generator
|
||||||
|
|
||||||
from ..type3.functions import TypeVariable
|
from ..type3.functions import (
|
||||||
from ..type3.routers import FunctionSignatureRouter
|
Constraint_TypeClassInstanceExists,
|
||||||
|
TypeConstructorVariable,
|
||||||
|
TypeVariable,
|
||||||
|
TypeVariableApplication_Nullary,
|
||||||
|
)
|
||||||
|
from ..type3.routers import TypeClassArgsRouter, TypeVariableLookup
|
||||||
from ..type3.typeclasses import Type3Class, Type3ClassMethod
|
from ..type3.typeclasses import Type3Class, Type3ClassMethod
|
||||||
from ..type3.types import (
|
from ..type3.types import (
|
||||||
IntType3,
|
IntType3,
|
||||||
Type3,
|
Type3,
|
||||||
TypeApplication_Nullary,
|
TypeApplication_Nullary,
|
||||||
|
TypeConstructor_Base,
|
||||||
TypeConstructor_StaticArray,
|
TypeConstructor_StaticArray,
|
||||||
TypeConstructor_Struct,
|
TypeConstructor_Struct,
|
||||||
TypeConstructor_Tuple,
|
TypeConstructor_Tuple,
|
||||||
)
|
)
|
||||||
|
|
||||||
PRELUDE_TYPE_CLASS_INSTANCES_EXISTING: set[tuple[Type3Class, tuple[Type3, ...]]] = set()
|
PRELUDE_TYPE_CLASS_INSTANCES_EXISTING: set[tuple[Type3Class, tuple[Type3 | TypeConstructor_Base[Any], ...]]] = set()
|
||||||
|
|
||||||
PRELUDE_TYPE_CLASS_INSTANCE_METHODS: dict[Type3ClassMethod, FunctionSignatureRouter[Generator, None]] = {}
|
PRELUDE_TYPE_CLASS_INSTANCE_METHODS: dict[Type3ClassMethod, TypeClassArgsRouter[Generator, None]] = {}
|
||||||
|
|
||||||
class MissingImplementationException(Exception):
|
class MissingImplementationException(Exception):
|
||||||
pass
|
pass
|
||||||
@ -31,18 +37,26 @@ class MissingImplementationWarning(Warning):
|
|||||||
|
|
||||||
def instance_type_class(
|
def instance_type_class(
|
||||||
cls: Type3Class,
|
cls: Type3Class,
|
||||||
*typ: Type3,
|
*typ: Type3 | TypeConstructor_Base[Any],
|
||||||
methods: dict[str, Callable[[Generator], None]] = {},
|
methods: dict[str, Callable[[Generator, TypeVariableLookup], None]] = {},
|
||||||
operators: dict[str, Callable[[Generator], None]] = {},
|
operators: dict[str, Callable[[Generator, TypeVariableLookup], None]] = {},
|
||||||
) -> None:
|
) -> None:
|
||||||
global PRELUDE_TYPE_CLASS_INSTANCES_EXISTING
|
global PRELUDE_TYPE_CLASS_INSTANCES_EXISTING
|
||||||
global PRELUDE_TYPE_CLASS_INSTANCE_METHODS
|
global PRELUDE_TYPE_CLASS_INSTANCE_METHODS
|
||||||
|
|
||||||
assert len(cls.args) == len(typ)
|
assert len(cls.args) == len(typ)
|
||||||
|
|
||||||
type_var_map = {}
|
tv_map: dict[TypeVariable, Type3] = {}
|
||||||
|
tc_map: dict[TypeConstructorVariable, TypeConstructor_Base[Any]] = {}
|
||||||
for arg_tv, arg_tp in zip(cls.args, typ, strict=True):
|
for arg_tv, arg_tp in zip(cls.args, typ, strict=True):
|
||||||
type_var_map[arg_tv] = arg_tp
|
if isinstance(arg_tv, TypeVariable):
|
||||||
|
assert isinstance(arg_tp, Type3)
|
||||||
|
tv_map[arg_tv] = arg_tp
|
||||||
|
elif isinstance(arg_tv, TypeConstructorVariable):
|
||||||
|
assert isinstance(arg_tp, TypeConstructor_Base)
|
||||||
|
tc_map[arg_tv] = arg_tp
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(arg_tv, arg_tp)
|
||||||
|
|
||||||
# TODO: Check for required existing instantiations
|
# TODO: Check for required existing instantiations
|
||||||
|
|
||||||
@ -51,7 +65,7 @@ def instance_type_class(
|
|||||||
for method_name, method in cls.methods.items():
|
for method_name, method in cls.methods.items():
|
||||||
router = PRELUDE_TYPE_CLASS_INSTANCE_METHODS.get(method)
|
router = PRELUDE_TYPE_CLASS_INSTANCE_METHODS.get(method)
|
||||||
if router is None:
|
if router is None:
|
||||||
router = FunctionSignatureRouter[Generator, None](method.signature)
|
router = TypeClassArgsRouter[Generator, None](cls.args)
|
||||||
PRELUDE_TYPE_CLASS_INSTANCE_METHODS[method] = router
|
PRELUDE_TYPE_CLASS_INSTANCE_METHODS[method] = router
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -60,12 +74,12 @@ def instance_type_class(
|
|||||||
warn(MissingImplementationWarning(str(method), cls.name + ' ' + ' '.join(x.name for x in typ)))
|
warn(MissingImplementationWarning(str(method), cls.name + ' ' + ' '.join(x.name for x in typ)))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
router.add(type_var_map, generator)
|
router.add(tv_map, tc_map, generator)
|
||||||
|
|
||||||
for operator_name, operator in cls.operators.items():
|
for operator_name, operator in cls.operators.items():
|
||||||
router = PRELUDE_TYPE_CLASS_INSTANCE_METHODS.get(operator)
|
router = PRELUDE_TYPE_CLASS_INSTANCE_METHODS.get(operator)
|
||||||
if router is None:
|
if router is None:
|
||||||
router = FunctionSignatureRouter[Generator, None](operator.signature)
|
router = TypeClassArgsRouter[Generator, None](cls.args)
|
||||||
PRELUDE_TYPE_CLASS_INSTANCE_METHODS[operator] = router
|
PRELUDE_TYPE_CLASS_INSTANCE_METHODS[operator] = router
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -74,7 +88,7 @@ def instance_type_class(
|
|||||||
warn(MissingImplementationWarning(str(operator), cls.name + ' ' + ' '.join(x.name for x in typ)))
|
warn(MissingImplementationWarning(str(operator), cls.name + ' ' + ' '.join(x.name for x in typ)))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
router.add(type_var_map, generator)
|
router.add(tv_map, tc_map, generator)
|
||||||
|
|
||||||
none = Type3('none', TypeApplication_Nullary(None, None))
|
none = Type3('none', TypeApplication_Nullary(None, None))
|
||||||
"""
|
"""
|
||||||
@ -195,11 +209,12 @@ PRELUDE_TYPES: dict[str, Type3] = {
|
|||||||
'bytes': bytes_,
|
'bytes': bytes_,
|
||||||
}
|
}
|
||||||
|
|
||||||
a = TypeVariable('a')
|
a = TypeVariable('a', TypeVariableApplication_Nullary(None, None))
|
||||||
b = TypeVariable('b')
|
b = TypeVariable('b', TypeVariableApplication_Nullary(None, None))
|
||||||
|
|
||||||
|
t = TypeConstructorVariable('t')
|
||||||
|
|
||||||
InternalPassAsPointer = Type3Class('InternalPassAsPointer', [a], methods={}, operators={})
|
InternalPassAsPointer = Type3Class('InternalPassAsPointer', (a, ), methods={}, operators={})
|
||||||
"""
|
"""
|
||||||
Internal type class to keep track which types we pass arounds as a pointer.
|
Internal type class to keep track which types we pass arounds as a pointer.
|
||||||
"""
|
"""
|
||||||
@ -209,7 +224,7 @@ instance_type_class(InternalPassAsPointer, bytes_)
|
|||||||
# instance_type_class(InternalPassAsPointer, tuple_)
|
# instance_type_class(InternalPassAsPointer, tuple_)
|
||||||
# instance_type_class(InternalPassAsPointer, struct)
|
# instance_type_class(InternalPassAsPointer, struct)
|
||||||
|
|
||||||
Eq = Type3Class('Eq', [a], methods={}, operators={
|
Eq = Type3Class('Eq', (a, ), methods={}, operators={
|
||||||
'==': [a, a, bool_],
|
'==': [a, a, bool_],
|
||||||
'!=': [a, a, bool_],
|
'!=': [a, a, bool_],
|
||||||
# FIXME: Do we want to expose 'eqz'? Or is that a compiler optimization?
|
# FIXME: Do we want to expose 'eqz'? Or is that a compiler optimization?
|
||||||
@ -248,7 +263,7 @@ instance_type_class(Eq, f64, operators={
|
|||||||
'!=': stdtypes.f64_eq_not_equals,
|
'!=': stdtypes.f64_eq_not_equals,
|
||||||
})
|
})
|
||||||
|
|
||||||
Ord = Type3Class('Ord', [a], methods={
|
Ord = Type3Class('Ord', (a, ), methods={
|
||||||
'min': [a, a, a],
|
'min': [a, a, a],
|
||||||
'max': [a, a, a],
|
'max': [a, a, a],
|
||||||
}, operators={
|
}, operators={
|
||||||
@ -331,7 +346,7 @@ instance_type_class(Ord, f64, methods={
|
|||||||
'>=': stdtypes.f64_ord_greater_than_or_equal,
|
'>=': stdtypes.f64_ord_greater_than_or_equal,
|
||||||
})
|
})
|
||||||
|
|
||||||
Bits = Type3Class('Bits', [a], methods={
|
Bits = Type3Class('Bits', (a, ), methods={
|
||||||
'shl': [a, u32, a], # Logical shift left
|
'shl': [a, u32, a], # Logical shift left
|
||||||
'shr': [a, u32, a], # Logical shift right
|
'shr': [a, u32, a], # Logical shift right
|
||||||
'rotl': [a, u32, a], # Rotate bits left
|
'rotl': [a, u32, a], # Rotate bits left
|
||||||
@ -374,7 +389,7 @@ instance_type_class(Bits, u64, methods={
|
|||||||
'^': stdtypes.u64_bits_bitwise_xor,
|
'^': stdtypes.u64_bits_bitwise_xor,
|
||||||
})
|
})
|
||||||
|
|
||||||
NatNum = Type3Class('NatNum', [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],
|
||||||
@ -425,7 +440,7 @@ instance_type_class(NatNum, f64, operators={
|
|||||||
'>>': stdtypes.f64_natnum_arithmic_shift_right,
|
'>>': stdtypes.f64_natnum_arithmic_shift_right,
|
||||||
})
|
})
|
||||||
|
|
||||||
IntNum = Type3Class('IntNum', [a], methods={
|
IntNum = Type3Class('IntNum', (a, ), methods={
|
||||||
'abs': [a, a],
|
'abs': [a, a],
|
||||||
'neg': [a, a],
|
'neg': [a, a],
|
||||||
}, operators={}, inherited_classes=[NatNum])
|
}, operators={}, inherited_classes=[NatNum])
|
||||||
@ -447,7 +462,7 @@ instance_type_class(IntNum, f64, methods={
|
|||||||
'neg': stdtypes.f64_intnum_neg,
|
'neg': stdtypes.f64_intnum_neg,
|
||||||
})
|
})
|
||||||
|
|
||||||
Integral = Type3Class('Eq', [a], methods={
|
Integral = Type3Class('Eq', (a, ), methods={
|
||||||
}, operators={
|
}, operators={
|
||||||
'//': [a, a, a],
|
'//': [a, a, a],
|
||||||
'%': [a, a, a],
|
'%': [a, a, a],
|
||||||
@ -470,7 +485,7 @@ instance_type_class(Integral, i64, operators={
|
|||||||
'%': stdtypes.i64_integral_rem,
|
'%': stdtypes.i64_integral_rem,
|
||||||
})
|
})
|
||||||
|
|
||||||
Fractional = Type3Class('Fractional', [a], methods={
|
Fractional = Type3Class('Fractional', (a, ), methods={
|
||||||
'ceil': [a, a],
|
'ceil': [a, a],
|
||||||
'floor': [a, a],
|
'floor': [a, a],
|
||||||
'trunc': [a, a],
|
'trunc': [a, a],
|
||||||
@ -496,7 +511,7 @@ instance_type_class(Fractional, f64, methods={
|
|||||||
'/': stdtypes.f64_fractional_div,
|
'/': stdtypes.f64_fractional_div,
|
||||||
})
|
})
|
||||||
|
|
||||||
Floating = Type3Class('Floating', [a], methods={
|
Floating = Type3Class('Floating', (a, ), methods={
|
||||||
'sqrt': [a, a],
|
'sqrt': [a, a],
|
||||||
}, operators={}, inherited_classes=[Fractional])
|
}, operators={}, inherited_classes=[Fractional])
|
||||||
|
|
||||||
@ -509,7 +524,7 @@ instance_type_class(Floating, f64, methods={
|
|||||||
'sqrt': stdtypes.f64_floating_sqrt,
|
'sqrt': stdtypes.f64_floating_sqrt,
|
||||||
})
|
})
|
||||||
|
|
||||||
Sized_ = Type3Class('Sized', [a], methods={
|
Sized_ = Type3Class('Sized', (a, ), methods={
|
||||||
'len': [a, u32],
|
'len': [a, u32],
|
||||||
}, operators={}) # FIXME: Once we get type class families, add [] here
|
}, operators={}) # FIXME: Once we get type class families, add [] here
|
||||||
|
|
||||||
@ -517,7 +532,7 @@ instance_type_class(Sized_, bytes_, methods={
|
|||||||
'len': stdtypes.bytes_sized_len,
|
'len': stdtypes.bytes_sized_len,
|
||||||
})
|
})
|
||||||
|
|
||||||
Extendable = Type3Class('Extendable', [a, b], methods={
|
Extendable = Type3Class('Extendable', (a, b, ), methods={
|
||||||
'extend': [a, b],
|
'extend': [a, b],
|
||||||
'wrap': [b, a],
|
'wrap': [b, a],
|
||||||
}, operators={})
|
}, operators={})
|
||||||
@ -547,7 +562,7 @@ instance_type_class(Extendable, i32, i64, methods={
|
|||||||
'wrap': stdtypes.i32_i64_wrap,
|
'wrap': stdtypes.i32_i64_wrap,
|
||||||
})
|
})
|
||||||
|
|
||||||
Promotable = Type3Class('Promotable', [a, b], methods={
|
Promotable = Type3Class('Promotable', (a, b, ), methods={
|
||||||
'promote': [a, b],
|
'promote': [a, b],
|
||||||
'demote': [b, a],
|
'demote': [b, a],
|
||||||
}, operators={})
|
}, operators={})
|
||||||
@ -557,6 +572,16 @@ instance_type_class(Promotable, f32, f64, methods={
|
|||||||
'demote': stdtypes.f32_f64_demote,
|
'demote': stdtypes.f32_f64_demote,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Foldable = Type3Class('Foldable', (t, ), methods={
|
||||||
|
'sum': [t(a), a],
|
||||||
|
}, operators={}, additional_context={
|
||||||
|
'sum': [Constraint_TypeClassInstanceExists(NatNum, (a, ))],
|
||||||
|
})
|
||||||
|
|
||||||
|
instance_type_class(Foldable, static_array, methods={
|
||||||
|
'sum': stdtypes.static_array_sum,
|
||||||
|
})
|
||||||
|
|
||||||
PRELUDE_TYPE_CLASSES = {
|
PRELUDE_TYPE_CLASSES = {
|
||||||
'Eq': Eq,
|
'Eq': Eq,
|
||||||
'Ord': Ord,
|
'Ord': Ord,
|
||||||
@ -592,4 +617,5 @@ PRELUDE_METHODS = {
|
|||||||
**Sized_.methods,
|
**Sized_.methods,
|
||||||
**Extendable.methods,
|
**Extendable.methods,
|
||||||
**Promotable.methods,
|
**Promotable.methods,
|
||||||
|
**Foldable.methods,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
stdlib: Standard types that are not wasm primitives
|
stdlib: Standard types that are not wasm primitives
|
||||||
"""
|
"""
|
||||||
from phasm.stdlib import alloc
|
from phasm.stdlib import alloc
|
||||||
|
from phasm.type3.routers import TypeVariableLookup
|
||||||
|
from phasm.type3.types import IntType3, Type3
|
||||||
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
|
from phasm.wasmgenerator import VarType_i64 as i64
|
||||||
@ -387,444 +389,579 @@ def __u8_rotr__(g: Generator, x: i32, r: i32) -> i32:
|
|||||||
## ###
|
## ###
|
||||||
## class Eq
|
## class Eq
|
||||||
|
|
||||||
def u8_eq_equals(g: Generator) -> None:
|
def u8_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.eq()
|
g.i32.eq()
|
||||||
|
|
||||||
def u32_eq_equals(g: Generator) -> None:
|
def u32_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.eq()
|
g.i32.eq()
|
||||||
|
|
||||||
def u64_eq_equals(g: Generator) -> None:
|
def u64_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.eq()
|
g.i64.eq()
|
||||||
|
|
||||||
def i8_eq_equals(g: Generator) -> None:
|
def i8_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.eq()
|
g.i32.eq()
|
||||||
|
|
||||||
def i32_eq_equals(g: Generator) -> None:
|
def i32_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.eq()
|
g.i32.eq()
|
||||||
|
|
||||||
def i64_eq_equals(g: Generator) -> None:
|
def i64_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.eq()
|
g.i64.eq()
|
||||||
|
|
||||||
def f32_eq_equals(g: Generator) -> None:
|
def f32_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.eq()
|
g.f32.eq()
|
||||||
|
|
||||||
def f64_eq_equals(g: Generator) -> None:
|
def f64_eq_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.eq()
|
g.f64.eq()
|
||||||
|
|
||||||
def u8_eq_not_equals(g: Generator) -> None:
|
def u8_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.ne()
|
g.i32.ne()
|
||||||
|
|
||||||
def u32_eq_not_equals(g: Generator) -> None:
|
def u32_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.ne()
|
g.i32.ne()
|
||||||
|
|
||||||
def u64_eq_not_equals(g: Generator) -> None:
|
def u64_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.ne()
|
g.i64.ne()
|
||||||
|
|
||||||
def i8_eq_not_equals(g: Generator) -> None:
|
def i8_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.ne()
|
g.i32.ne()
|
||||||
|
|
||||||
def i32_eq_not_equals(g: Generator) -> None:
|
def i32_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.ne()
|
g.i32.ne()
|
||||||
|
|
||||||
def i64_eq_not_equals(g: Generator) -> None:
|
def i64_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.ne()
|
g.i64.ne()
|
||||||
|
|
||||||
def f32_eq_not_equals(g: Generator) -> None:
|
def f32_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.ne()
|
g.f32.ne()
|
||||||
|
|
||||||
def f64_eq_not_equals(g: Generator) -> None:
|
def f64_eq_not_equals(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.ne()
|
g.f64.ne()
|
||||||
|
|
||||||
## ###
|
## ###
|
||||||
## class Ord
|
## class Ord
|
||||||
|
|
||||||
def u8_ord_min(g: Generator) -> None:
|
def u8_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u32_ord_min__')
|
g.add_statement('call $stdlib.types.__u32_ord_min__')
|
||||||
|
|
||||||
def u32_ord_min(g: Generator) -> None:
|
def u32_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u32_ord_min__')
|
g.add_statement('call $stdlib.types.__u32_ord_min__')
|
||||||
|
|
||||||
def u64_ord_min(g: Generator) -> None:
|
def u64_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u64_ord_min__')
|
g.add_statement('call $stdlib.types.__u64_ord_min__')
|
||||||
|
|
||||||
def i8_ord_min(g: Generator) -> None:
|
def i8_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__i32_ord_min__')
|
g.add_statement('call $stdlib.types.__i32_ord_min__')
|
||||||
|
|
||||||
def i32_ord_min(g: Generator) -> None:
|
def i32_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__i32_ord_min__')
|
g.add_statement('call $stdlib.types.__i32_ord_min__')
|
||||||
|
|
||||||
def i64_ord_min(g: Generator) -> None:
|
def i64_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__i64_ord_min__')
|
g.add_statement('call $stdlib.types.__i64_ord_min__')
|
||||||
|
|
||||||
def f32_ord_min(g: Generator) -> None:
|
def f32_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.min()
|
g.f32.min()
|
||||||
|
|
||||||
def f64_ord_min(g: Generator) -> None:
|
def f64_ord_min(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.min()
|
g.f64.min()
|
||||||
|
|
||||||
def u8_ord_max(g: Generator) -> None:
|
def u8_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u32_ord_max__')
|
g.add_statement('call $stdlib.types.__u32_ord_max__')
|
||||||
|
|
||||||
def u32_ord_max(g: Generator) -> None:
|
def u32_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u32_ord_max__')
|
g.add_statement('call $stdlib.types.__u32_ord_max__')
|
||||||
|
|
||||||
def u64_ord_max(g: Generator) -> None:
|
def u64_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u64_ord_max__')
|
g.add_statement('call $stdlib.types.__u64_ord_max__')
|
||||||
|
|
||||||
def i8_ord_max(g: Generator) -> None:
|
def i8_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__i32_ord_max__')
|
g.add_statement('call $stdlib.types.__i32_ord_max__')
|
||||||
|
|
||||||
def i32_ord_max(g: Generator) -> None:
|
def i32_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__i32_ord_max__')
|
g.add_statement('call $stdlib.types.__i32_ord_max__')
|
||||||
|
|
||||||
def i64_ord_max(g: Generator) -> None:
|
def i64_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__i64_ord_max__')
|
g.add_statement('call $stdlib.types.__i64_ord_max__')
|
||||||
|
|
||||||
def f32_ord_max(g: Generator) -> None:
|
def f32_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.max()
|
g.f32.max()
|
||||||
|
|
||||||
def f64_ord_max(g: Generator) -> None:
|
def f64_ord_max(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.max()
|
g.f64.max()
|
||||||
|
|
||||||
|
|
||||||
def u8_ord_less_than(g: Generator) -> None:
|
def u8_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.lt_u()
|
g.i32.lt_u()
|
||||||
|
|
||||||
def u32_ord_less_than(g: Generator) -> None:
|
def u32_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.lt_u()
|
g.i32.lt_u()
|
||||||
|
|
||||||
def u64_ord_less_than(g: Generator) -> None:
|
def u64_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.lt_u()
|
g.i64.lt_u()
|
||||||
|
|
||||||
def i8_ord_less_than(g: Generator) -> None:
|
def i8_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.lt_s()
|
g.i32.lt_s()
|
||||||
|
|
||||||
def i32_ord_less_than(g: Generator) -> None:
|
def i32_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.lt_s()
|
g.i32.lt_s()
|
||||||
|
|
||||||
def i64_ord_less_than(g: Generator) -> None:
|
def i64_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.lt_s()
|
g.i64.lt_s()
|
||||||
|
|
||||||
def f32_ord_less_than(g: Generator) -> None:
|
def f32_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.lt()
|
g.f32.lt()
|
||||||
|
|
||||||
def f64_ord_less_than(g: Generator) -> None:
|
def f64_ord_less_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.lt()
|
g.f64.lt()
|
||||||
|
|
||||||
def u8_ord_less_than_or_equal(g: Generator) -> None:
|
def u8_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.le_u()
|
g.i32.le_u()
|
||||||
|
|
||||||
def u32_ord_less_than_or_equal(g: Generator) -> None:
|
def u32_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.le_u()
|
g.i32.le_u()
|
||||||
|
|
||||||
def u64_ord_less_than_or_equal(g: Generator) -> None:
|
def u64_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.le_u()
|
g.i64.le_u()
|
||||||
|
|
||||||
def i8_ord_less_than_or_equal(g: Generator) -> None:
|
def i8_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.le_s()
|
g.i32.le_s()
|
||||||
|
|
||||||
def i32_ord_less_than_or_equal(g: Generator) -> None:
|
def i32_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.le_s()
|
g.i32.le_s()
|
||||||
|
|
||||||
def i64_ord_less_than_or_equal(g: Generator) -> None:
|
def i64_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.le_s()
|
g.i64.le_s()
|
||||||
|
|
||||||
def f32_ord_less_than_or_equal(g: Generator) -> None:
|
def f32_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.le()
|
g.f32.le()
|
||||||
|
|
||||||
def f64_ord_less_than_or_equal(g: Generator) -> None:
|
def f64_ord_less_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.le()
|
g.f64.le()
|
||||||
|
|
||||||
def u8_ord_greater_than(g: Generator) -> None:
|
def u8_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.gt_u()
|
g.i32.gt_u()
|
||||||
|
|
||||||
def u32_ord_greater_than(g: Generator) -> None:
|
def u32_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.gt_u()
|
g.i32.gt_u()
|
||||||
|
|
||||||
def u64_ord_greater_than(g: Generator) -> None:
|
def u64_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.gt_u()
|
g.i64.gt_u()
|
||||||
|
|
||||||
def i8_ord_greater_than(g: Generator) -> None:
|
def i8_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.gt_s()
|
g.i32.gt_s()
|
||||||
|
|
||||||
def i32_ord_greater_than(g: Generator) -> None:
|
def i32_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.gt_s()
|
g.i32.gt_s()
|
||||||
|
|
||||||
def i64_ord_greater_than(g: Generator) -> None:
|
def i64_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.gt_s()
|
g.i64.gt_s()
|
||||||
|
|
||||||
def f32_ord_greater_than(g: Generator) -> None:
|
def f32_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.gt()
|
g.f32.gt()
|
||||||
|
|
||||||
def f64_ord_greater_than(g: Generator) -> None:
|
def f64_ord_greater_than(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.gt()
|
g.f64.gt()
|
||||||
|
|
||||||
def u8_ord_greater_than_or_equal(g: Generator) -> None:
|
def u8_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.ge_u()
|
g.i32.ge_u()
|
||||||
|
|
||||||
def u32_ord_greater_than_or_equal(g: Generator) -> None:
|
def u32_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.ge_u()
|
g.i32.ge_u()
|
||||||
|
|
||||||
def u64_ord_greater_than_or_equal(g: Generator) -> None:
|
def u64_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.ge_u()
|
g.i64.ge_u()
|
||||||
|
|
||||||
def i8_ord_greater_than_or_equal(g: Generator) -> None:
|
def i8_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.ge_s()
|
g.i32.ge_s()
|
||||||
|
|
||||||
def i32_ord_greater_than_or_equal(g: Generator) -> None:
|
def i32_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.ge_s()
|
g.i32.ge_s()
|
||||||
|
|
||||||
def i64_ord_greater_than_or_equal(g: Generator) -> None:
|
def i64_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.ge_s()
|
g.i64.ge_s()
|
||||||
|
|
||||||
def f32_ord_greater_than_or_equal(g: Generator) -> None:
|
def f32_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.ge()
|
g.f32.ge()
|
||||||
|
|
||||||
def f64_ord_greater_than_or_equal(g: Generator) -> None:
|
def f64_ord_greater_than_or_equal(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.ge()
|
g.f64.ge()
|
||||||
|
|
||||||
## ###
|
## ###
|
||||||
## class Bits
|
## class Bits
|
||||||
|
|
||||||
def u8_bits_logical_shift_left(g: Generator) -> None:
|
def u8_bits_logical_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.shl()
|
g.i32.shl()
|
||||||
g.i32.const(255)
|
g.i32.const(255)
|
||||||
g.i32.and_()
|
g.i32.and_()
|
||||||
|
|
||||||
def u32_bits_logical_shift_left(g: Generator) -> None:
|
def u32_bits_logical_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.shl()
|
g.i32.shl()
|
||||||
|
|
||||||
def u64_bits_logical_shift_left(g: Generator) -> None:
|
def u64_bits_logical_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_u()
|
g.i64.extend_i32_u()
|
||||||
g.i64.shl()
|
g.i64.shl()
|
||||||
|
|
||||||
def u8_bits_logical_shift_right(g: Generator) -> None:
|
def u8_bits_logical_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.shr_u()
|
g.i32.shr_u()
|
||||||
|
|
||||||
def u32_bits_logical_shift_right(g: Generator) -> None:
|
def u32_bits_logical_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.shr_u()
|
g.i32.shr_u()
|
||||||
|
|
||||||
def u64_bits_logical_shift_right(g: Generator) -> None:
|
def u64_bits_logical_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_u()
|
g.i64.extend_i32_u()
|
||||||
g.i64.shr_u()
|
g.i64.shr_u()
|
||||||
|
|
||||||
def u8_bits_rotate_left(g: Generator) -> None:
|
def u8_bits_rotate_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u8_rotl__')
|
g.add_statement('call $stdlib.types.__u8_rotl__')
|
||||||
|
|
||||||
def u32_bits_rotate_left(g: Generator) -> None:
|
def u32_bits_rotate_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.rotl()
|
g.i32.rotl()
|
||||||
|
|
||||||
def u64_bits_rotate_left(g: Generator) -> None:
|
def u64_bits_rotate_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_u()
|
g.i64.extend_i32_u()
|
||||||
g.i64.rotl()
|
g.i64.rotl()
|
||||||
|
|
||||||
def u8_bits_rotate_right(g: Generator) -> None:
|
def u8_bits_rotate_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u8_rotr__')
|
g.add_statement('call $stdlib.types.__u8_rotr__')
|
||||||
|
|
||||||
def u32_bits_rotate_right(g: Generator) -> None:
|
def u32_bits_rotate_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.rotr()
|
g.i32.rotr()
|
||||||
|
|
||||||
def u64_bits_rotate_right(g: Generator) -> None:
|
def u64_bits_rotate_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_u()
|
g.i64.extend_i32_u()
|
||||||
g.i64.rotr()
|
g.i64.rotr()
|
||||||
|
|
||||||
def u8_bits_bitwise_and(g: Generator) -> None:
|
def u8_bits_bitwise_and(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.and_()
|
g.i32.and_()
|
||||||
|
|
||||||
def u32_bits_bitwise_and(g: Generator) -> None:
|
def u32_bits_bitwise_and(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.and_()
|
g.i32.and_()
|
||||||
|
|
||||||
def u64_bits_bitwise_and(g: Generator) -> None:
|
def u64_bits_bitwise_and(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.and_()
|
g.i64.and_()
|
||||||
|
|
||||||
def u8_bits_bitwise_or(g: Generator) -> None:
|
def u8_bits_bitwise_or(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.or_()
|
g.i32.or_()
|
||||||
|
|
||||||
def u32_bits_bitwise_or(g: Generator) -> None:
|
def u32_bits_bitwise_or(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.or_()
|
g.i32.or_()
|
||||||
|
|
||||||
def u64_bits_bitwise_or(g: Generator) -> None:
|
def u64_bits_bitwise_or(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.or_()
|
g.i64.or_()
|
||||||
|
|
||||||
def u8_bits_bitwise_xor(g: Generator) -> None:
|
def u8_bits_bitwise_xor(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.xor()
|
g.i32.xor()
|
||||||
|
|
||||||
def u32_bits_bitwise_xor(g: Generator) -> None:
|
def u32_bits_bitwise_xor(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.xor()
|
g.i32.xor()
|
||||||
|
|
||||||
def u64_bits_bitwise_xor(g: Generator) -> None:
|
def u64_bits_bitwise_xor(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.xor()
|
g.i64.xor()
|
||||||
|
|
||||||
## ###
|
## ###
|
||||||
## class Fractional
|
## class Fractional
|
||||||
|
|
||||||
def f32_fractional_ceil(g: Generator) -> None:
|
def f32_fractional_ceil(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.ceil()
|
g.f32.ceil()
|
||||||
|
|
||||||
def f64_fractional_ceil(g: Generator) -> None:
|
def f64_fractional_ceil(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.ceil()
|
g.f64.ceil()
|
||||||
|
|
||||||
def f32_fractional_floor(g: Generator) -> None:
|
def f32_fractional_floor(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.floor()
|
g.f32.floor()
|
||||||
|
|
||||||
def f64_fractional_floor(g: Generator) -> None:
|
def f64_fractional_floor(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.floor()
|
g.f64.floor()
|
||||||
|
|
||||||
def f32_fractional_trunc(g: Generator) -> None:
|
def f32_fractional_trunc(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.trunc()
|
g.f32.trunc()
|
||||||
|
|
||||||
def f64_fractional_trunc(g: Generator) -> None:
|
def f64_fractional_trunc(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.trunc()
|
g.f64.trunc()
|
||||||
|
|
||||||
def f32_fractional_nearest(g: Generator) -> None:
|
def f32_fractional_nearest(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.nearest()
|
g.f32.nearest()
|
||||||
|
|
||||||
def f64_fractional_nearest(g: Generator) -> None:
|
def f64_fractional_nearest(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.nearest()
|
g.f64.nearest()
|
||||||
|
|
||||||
def f32_fractional_div(g: Generator) -> None:
|
def f32_fractional_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.div()
|
g.f32.div()
|
||||||
|
|
||||||
def f64_fractional_div(g: Generator) -> None:
|
def f64_fractional_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.div()
|
g.f64.div()
|
||||||
|
|
||||||
## ###
|
## ###
|
||||||
## class Floating
|
## class Floating
|
||||||
|
|
||||||
def f32_floating_sqrt(g: Generator) -> None:
|
def f32_floating_sqrt(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('f32.sqrt')
|
g.add_statement('f32.sqrt')
|
||||||
|
|
||||||
def f64_floating_sqrt(g: Generator) -> None:
|
def f64_floating_sqrt(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('f64.sqrt')
|
g.add_statement('f64.sqrt')
|
||||||
|
|
||||||
## ###
|
## ###
|
||||||
## class Integral
|
## class Integral
|
||||||
|
|
||||||
def u32_integral_div(g: Generator) -> None:
|
def u32_integral_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i32.div_u')
|
g.add_statement('i32.div_u')
|
||||||
|
|
||||||
def u64_integral_div(g: Generator) -> None:
|
def u64_integral_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i64.div_u')
|
g.add_statement('i64.div_u')
|
||||||
|
|
||||||
def i32_integral_div(g: Generator) -> None:
|
def i32_integral_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i32.div_s')
|
g.add_statement('i32.div_s')
|
||||||
|
|
||||||
def i64_integral_div(g: Generator) -> None:
|
def i64_integral_div(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i64.div_s')
|
g.add_statement('i64.div_s')
|
||||||
|
|
||||||
def u32_integral_rem(g: Generator) -> None:
|
def u32_integral_rem(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i32.rem_u')
|
g.add_statement('i32.rem_u')
|
||||||
|
|
||||||
def u64_integral_rem(g: Generator) -> None:
|
def u64_integral_rem(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i64.rem_u')
|
g.add_statement('i64.rem_u')
|
||||||
|
|
||||||
def i32_integral_rem(g: Generator) -> None:
|
def i32_integral_rem(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i32.rem_s')
|
g.add_statement('i32.rem_s')
|
||||||
|
|
||||||
def i64_integral_rem(g: Generator) -> None:
|
def i64_integral_rem(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i64.rem_s')
|
g.add_statement('i64.rem_s')
|
||||||
|
|
||||||
## ###
|
## ###
|
||||||
## class NatNum
|
## class NatNum
|
||||||
|
|
||||||
def u32_natnum_add(g: Generator) -> None:
|
def u32_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i32.add')
|
g.add_statement('i32.add')
|
||||||
|
|
||||||
def u64_natnum_add(g: Generator) -> None:
|
def u64_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i64.add')
|
g.add_statement('i64.add')
|
||||||
|
|
||||||
def i32_natnum_add(g: Generator) -> None:
|
def i32_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i32.add')
|
g.add_statement('i32.add')
|
||||||
|
|
||||||
def i64_natnum_add(g: Generator) -> None:
|
def i64_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i64.add')
|
g.add_statement('i64.add')
|
||||||
|
|
||||||
def f32_natnum_add(g: Generator) -> None:
|
def f32_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('f32.add')
|
g.add_statement('f32.add')
|
||||||
|
|
||||||
def f64_natnum_add(g: Generator) -> None:
|
def f64_natnum_add(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('f64.add')
|
g.add_statement('f64.add')
|
||||||
|
|
||||||
def u32_natnum_sub(g: Generator) -> None:
|
def u32_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i32.sub')
|
g.add_statement('i32.sub')
|
||||||
|
|
||||||
def u64_natnum_sub(g: Generator) -> None:
|
def u64_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i64.sub')
|
g.add_statement('i64.sub')
|
||||||
|
|
||||||
def i32_natnum_sub(g: Generator) -> None:
|
def i32_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i32.sub')
|
g.add_statement('i32.sub')
|
||||||
|
|
||||||
def i64_natnum_sub(g: Generator) -> None:
|
def i64_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i64.sub')
|
g.add_statement('i64.sub')
|
||||||
|
|
||||||
def f32_natnum_sub(g: Generator) -> None:
|
def f32_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('f32.sub')
|
g.add_statement('f32.sub')
|
||||||
|
|
||||||
def f64_natnum_sub(g: Generator) -> None:
|
def f64_natnum_sub(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('f64.sub')
|
g.add_statement('f64.sub')
|
||||||
|
|
||||||
def u32_natnum_mul(g: Generator) -> None:
|
def u32_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i32.mul')
|
g.add_statement('i32.mul')
|
||||||
|
|
||||||
def u64_natnum_mul(g: Generator) -> None:
|
def u64_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i64.mul')
|
g.add_statement('i64.mul')
|
||||||
|
|
||||||
def i32_natnum_mul(g: Generator) -> None:
|
def i32_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i32.mul')
|
g.add_statement('i32.mul')
|
||||||
|
|
||||||
def i64_natnum_mul(g: Generator) -> None:
|
def i64_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('i64.mul')
|
g.add_statement('i64.mul')
|
||||||
|
|
||||||
def f32_natnum_mul(g: Generator) -> None:
|
def f32_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('f32.mul')
|
g.add_statement('f32.mul')
|
||||||
|
|
||||||
def f64_natnum_mul(g: Generator) -> None:
|
def f64_natnum_mul(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('f64.mul')
|
g.add_statement('f64.mul')
|
||||||
|
|
||||||
def u32_natnum_arithmic_shift_left(g: Generator) -> None:
|
def u32_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.shl()
|
g.i32.shl()
|
||||||
|
|
||||||
def u64_natnum_arithmic_shift_left(g: Generator) -> None:
|
def u64_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_u()
|
g.i64.extend_i32_u()
|
||||||
g.i64.shl()
|
g.i64.shl()
|
||||||
|
|
||||||
def i32_natnum_arithmic_shift_left(g: Generator) -> None:
|
def i32_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.shl()
|
g.i32.shl()
|
||||||
|
|
||||||
def i64_natnum_arithmic_shift_left(g: Generator) -> None:
|
def i64_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_u()
|
g.i64.extend_i32_u()
|
||||||
g.i64.shl()
|
g.i64.shl()
|
||||||
|
|
||||||
def f32_natnum_arithmic_shift_left(g: Generator) -> None:
|
def f32_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u32_pow2__')
|
g.add_statement('call $stdlib.types.__u32_pow2__')
|
||||||
g.f32.convert_i32_u()
|
g.f32.convert_i32_u()
|
||||||
g.f32.mul()
|
g.f32.mul()
|
||||||
|
|
||||||
def f64_natnum_arithmic_shift_left(g: Generator) -> None:
|
def f64_natnum_arithmic_shift_left(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u32_pow2__')
|
g.add_statement('call $stdlib.types.__u32_pow2__')
|
||||||
g.f64.convert_i32_u()
|
g.f64.convert_i32_u()
|
||||||
g.f64.mul()
|
g.f64.mul()
|
||||||
|
|
||||||
def u32_natnum_arithmic_shift_right(g: Generator) -> None:
|
def u32_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.shr_u()
|
g.i32.shr_u()
|
||||||
|
|
||||||
def u64_natnum_arithmic_shift_right(g: Generator) -> None:
|
def u64_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_u()
|
g.i64.extend_i32_u()
|
||||||
g.i64.shr_u()
|
g.i64.shr_u()
|
||||||
|
|
||||||
def i32_natnum_arithmic_shift_right(g: Generator) -> None:
|
def i32_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.shr_s()
|
g.i32.shr_s()
|
||||||
|
|
||||||
def i64_natnum_arithmic_shift_right(g: Generator) -> None:
|
def i64_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_u()
|
g.i64.extend_i32_u()
|
||||||
g.i64.shr_s()
|
g.i64.shr_s()
|
||||||
|
|
||||||
def f32_natnum_arithmic_shift_right(g: Generator) -> None:
|
def f32_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u32_pow2__')
|
g.add_statement('call $stdlib.types.__u32_pow2__')
|
||||||
g.f32.convert_i32_u()
|
g.f32.convert_i32_u()
|
||||||
g.f32.div()
|
g.f32.div()
|
||||||
|
|
||||||
def f64_natnum_arithmic_shift_right(g: Generator) -> None:
|
def f64_natnum_arithmic_shift_right(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__u32_pow2__')
|
g.add_statement('call $stdlib.types.__u32_pow2__')
|
||||||
g.f64.convert_i32_u()
|
g.f64.convert_i32_u()
|
||||||
g.f64.div()
|
g.f64.div()
|
||||||
@ -832,91 +969,219 @@ def f64_natnum_arithmic_shift_right(g: Generator) -> None:
|
|||||||
## ###
|
## ###
|
||||||
## class IntNum
|
## class IntNum
|
||||||
|
|
||||||
def i32_intnum_abs(g: Generator) -> None:
|
def i32_intnum_abs(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__i32_intnum_abs__')
|
g.add_statement('call $stdlib.types.__i32_intnum_abs__')
|
||||||
|
|
||||||
def i64_intnum_abs(g: Generator) -> None:
|
def i64_intnum_abs(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.add_statement('call $stdlib.types.__i64_intnum_abs__')
|
g.add_statement('call $stdlib.types.__i64_intnum_abs__')
|
||||||
|
|
||||||
def f32_intnum_abs(g: Generator) -> None:
|
def f32_intnum_abs(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.abs()
|
g.f32.abs()
|
||||||
|
|
||||||
def f64_intnum_abs(g: Generator) -> None:
|
def f64_intnum_abs(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.abs()
|
g.f64.abs()
|
||||||
|
|
||||||
def i32_intnum_neg(g: Generator) -> None:
|
def i32_intnum_neg(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.const(-1)
|
g.i32.const(-1)
|
||||||
g.i32.mul()
|
g.i32.mul()
|
||||||
|
|
||||||
def i64_intnum_neg(g: Generator) -> None:
|
def i64_intnum_neg(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.const(-1)
|
g.i64.const(-1)
|
||||||
g.i64.mul()
|
g.i64.mul()
|
||||||
|
|
||||||
def f32_intnum_neg(g: Generator) -> None:
|
def f32_intnum_neg(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.neg()
|
g.f32.neg()
|
||||||
|
|
||||||
def f64_intnum_neg(g: Generator) -> None:
|
def f64_intnum_neg(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.neg()
|
g.f64.neg()
|
||||||
|
|
||||||
## ###
|
## ###
|
||||||
## Class Sized
|
## Class Sized
|
||||||
|
|
||||||
def bytes_sized_len(g: Generator) -> None:
|
def bytes_sized_len(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
# The length is stored in the first 4 bytes
|
# The length is stored in the first 4 bytes
|
||||||
g.i32.load()
|
g.i32.load()
|
||||||
|
|
||||||
## ###
|
## ###
|
||||||
## Extendable
|
## Extendable
|
||||||
|
|
||||||
def u8_u32_extend(g: Generator) -> None:
|
def u8_u32_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
# No-op
|
# No-op
|
||||||
# u8 is already stored as u32
|
# u8 is already stored as u32
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def u8_u64_extend(g: Generator) -> None:
|
def u8_u64_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_u()
|
g.i64.extend_i32_u()
|
||||||
|
|
||||||
def u32_u64_extend(g: Generator) -> None:
|
def u32_u64_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_u()
|
g.i64.extend_i32_u()
|
||||||
|
|
||||||
def i8_i32_extend(g: Generator) -> None:
|
def i8_i32_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
# No-op
|
# No-op
|
||||||
# i8 is already stored as i32
|
# i8 is already stored as i32
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def i8_i64_extend(g: Generator) -> None:
|
def i8_i64_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_s()
|
g.i64.extend_i32_s()
|
||||||
|
|
||||||
def i32_i64_extend(g: Generator) -> None:
|
def i32_i64_extend(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i64.extend_i32_s()
|
g.i64.extend_i32_s()
|
||||||
|
|
||||||
def u8_u32_wrap(g: Generator) -> None:
|
def u8_u32_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.const(0xFF)
|
g.i32.const(0xFF)
|
||||||
g.i32.and_()
|
g.i32.and_()
|
||||||
|
|
||||||
def u8_u64_wrap(g: Generator) -> None:
|
def u8_u64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.wrap_i64()
|
g.i32.wrap_i64()
|
||||||
g.i32.const(0xFF)
|
g.i32.const(0xFF)
|
||||||
g.i32.and_()
|
g.i32.and_()
|
||||||
|
|
||||||
def u32_u64_wrap(g: Generator) -> None:
|
def u32_u64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.wrap_i64()
|
g.i32.wrap_i64()
|
||||||
|
|
||||||
def i8_i32_wrap(g: Generator) -> None:
|
def i8_i32_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.const(0xFF)
|
g.i32.const(0xFF)
|
||||||
g.i32.and_()
|
g.i32.and_()
|
||||||
|
|
||||||
def i8_i64_wrap(g: Generator) -> None:
|
def i8_i64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.wrap_i64()
|
g.i32.wrap_i64()
|
||||||
|
|
||||||
def i32_i64_wrap(g: Generator) -> None:
|
def i32_i64_wrap(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.i32.wrap_i64()
|
g.i32.wrap_i64()
|
||||||
|
|
||||||
## ###
|
## ###
|
||||||
## Promotable
|
## Promotable
|
||||||
|
|
||||||
def f32_f64_promote(g: Generator) -> None:
|
def f32_f64_promote(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f64.promote_f32()
|
g.f64.promote_f32()
|
||||||
|
|
||||||
def f32_f64_demote(g: Generator) -> None:
|
def f32_f64_demote(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
del tv_map
|
||||||
g.f32.demote_f64()
|
g.f32.demote_f64()
|
||||||
|
|
||||||
|
def static_array_sum(g: Generator, tv_map: TypeVariableLookup) -> None:
|
||||||
|
assert len(tv_map) == 1
|
||||||
|
sa_type, sa_len = next(iter(tv_map.values()))
|
||||||
|
assert isinstance(sa_type, Type3)
|
||||||
|
assert isinstance(sa_len, IntType3)
|
||||||
|
|
||||||
|
if sa_len.value < 1:
|
||||||
|
raise NotImplementedError('Default value in case sum is empty')
|
||||||
|
|
||||||
|
# FIXME: We should probably use LOAD_STORE_TYPE_MAP for this?
|
||||||
|
mtyp_map = {
|
||||||
|
'u32': 'i32',
|
||||||
|
'u64': 'i64',
|
||||||
|
'i32': 'i32',
|
||||||
|
'i64': 'i64',
|
||||||
|
'f32': 'f32',
|
||||||
|
'f64': 'f64',
|
||||||
|
}
|
||||||
|
|
||||||
|
# FIXME: We should probably use calc_alloc_size for this?
|
||||||
|
type_var_size_map = {
|
||||||
|
'u32': 4,
|
||||||
|
'u64': 8,
|
||||||
|
'i32': 4,
|
||||||
|
'i64': 8,
|
||||||
|
'f32': 4,
|
||||||
|
'f64': 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
type_var_add_generator = {
|
||||||
|
'u32': u32_natnum_add,
|
||||||
|
'u64': u64_natnum_add,
|
||||||
|
'i32': i32_natnum_add,
|
||||||
|
'i64': i64_natnum_add,
|
||||||
|
'f32': f32_natnum_add,
|
||||||
|
'f64': f64_natnum_add,
|
||||||
|
}
|
||||||
|
|
||||||
|
# By default, constructed types are passed as pointers
|
||||||
|
# FIXME: We don't know what add function to call
|
||||||
|
sa_type_mtyp = mtyp_map.get(sa_type.name, 'i32')
|
||||||
|
sa_type_alloc_size = type_var_size_map.get(sa_type.name, 4)
|
||||||
|
sa_type_add_gen = type_var_add_generator[sa_type.name]
|
||||||
|
|
||||||
|
# Definitions
|
||||||
|
sum_adr = g.temp_var(i32('sum_adr'))
|
||||||
|
sum_stop = g.temp_var(i32('sum_stop'))
|
||||||
|
|
||||||
|
# Stack before: [adr]
|
||||||
|
# Stack after: [sum]
|
||||||
|
|
||||||
|
# adr = {address of what's currently on stack}
|
||||||
|
# Stack: [adr] -> []
|
||||||
|
g.nop(comment=f'Start sum for {sa_type.name}[{sa_len.value}]')
|
||||||
|
g.local.set(sum_adr)
|
||||||
|
|
||||||
|
# stop = adr + ar_len * sa_type_alloc_size
|
||||||
|
# Stack: []
|
||||||
|
g.nop(comment='Calculate address at which to stop looping')
|
||||||
|
g.local.get(sum_adr)
|
||||||
|
g.i32.const(sa_len.value * sa_type_alloc_size)
|
||||||
|
g.i32.add()
|
||||||
|
g.local.set(sum_stop)
|
||||||
|
|
||||||
|
# sum = *adr
|
||||||
|
# Stack: [] -> [sum]
|
||||||
|
g.nop(comment='Get the first array value as starting point')
|
||||||
|
g.local.get(sum_adr)
|
||||||
|
g.add_statement(f'{sa_type_mtyp}.load')
|
||||||
|
|
||||||
|
# Since we did the first one, increase adr
|
||||||
|
# adr = adr + sa_type_alloc_size
|
||||||
|
# Stack: [sum] -> [sum]
|
||||||
|
g.local.get(sum_adr)
|
||||||
|
g.i32.const(sa_type_alloc_size)
|
||||||
|
g.i32.add()
|
||||||
|
g.local.set(sum_adr)
|
||||||
|
|
||||||
|
if sa_len.value > 1:
|
||||||
|
with g.loop(params=[sa_type_mtyp], result=sa_type_mtyp):
|
||||||
|
# sum = sum + *adr
|
||||||
|
# Stack: [sum] -> [sum + *adr]
|
||||||
|
g.nop(comment='Add array value')
|
||||||
|
g.local.get(sum_adr)
|
||||||
|
g.add_statement(f'{sa_type_mtyp}.load')
|
||||||
|
sa_type_add_gen(g, {})
|
||||||
|
|
||||||
|
# adr = adr + sa_type_alloc_size
|
||||||
|
# Stack: [sum] -> [sum]
|
||||||
|
g.nop(comment='Calculate address of the next value')
|
||||||
|
g.local.get(sum_adr)
|
||||||
|
g.i32.const(sa_type_alloc_size)
|
||||||
|
g.i32.add()
|
||||||
|
g.local.tee(sum_adr)
|
||||||
|
|
||||||
|
# loop if adr < stop
|
||||||
|
g.nop(comment='Check if address exceeds array bounds')
|
||||||
|
g.local.get(sum_stop)
|
||||||
|
g.i32.lt_u()
|
||||||
|
g.br_if(0)
|
||||||
|
# else: sum x[1] === x => so we don't need to loop
|
||||||
|
|
||||||
|
g.nop(comment=f'Completed sum for {sa_type.name}[{sa_len.value}]')
|
||||||
|
# End result: [sum]
|
||||||
|
|||||||
@ -3,7 +3,7 @@ This module contains possible constraints generated based on the AST
|
|||||||
|
|
||||||
These need to be resolved before the program can be compiled.
|
These need to be resolved before the program can be compiled.
|
||||||
"""
|
"""
|
||||||
from typing import Dict, Iterable, List, Optional, Tuple, Union
|
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from .. import ourlang, prelude
|
from .. import ourlang, prelude
|
||||||
from . import placeholders, typeclasses, types
|
from . import placeholders, typeclasses, types
|
||||||
@ -50,7 +50,7 @@ class Context:
|
|||||||
__slots__ = ('type_class_instances_existing', )
|
__slots__ = ('type_class_instances_existing', )
|
||||||
|
|
||||||
# Constraint_TypeClassInstanceExists
|
# Constraint_TypeClassInstanceExists
|
||||||
type_class_instances_existing: set[tuple[typeclasses.Type3Class, tuple[types.Type3, ...]]]
|
type_class_instances_existing: set[tuple[typeclasses.Type3Class, tuple[Union[types.Type3, types.TypeConstructor_Base[Any], types.TypeConstructor_Struct], ...]]]
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.type_class_instances_existing = set()
|
self.type_class_instances_existing = set()
|
||||||
@ -158,6 +158,46 @@ class SameTypeConstraint(ConstraintBase):
|
|||||||
|
|
||||||
return f'SameTypeConstraint({args}, comment={repr(self.comment)})'
|
return f'SameTypeConstraint({args}, comment={repr(self.comment)})'
|
||||||
|
|
||||||
|
class SameTypeArgumentConstraint(ConstraintBase):
|
||||||
|
__slots__ = ('tc_var', 'arg_var', )
|
||||||
|
|
||||||
|
tc_var: PlaceholderForType
|
||||||
|
arg_var: PlaceholderForType
|
||||||
|
|
||||||
|
def __init__(self, tc_var: PlaceholderForType, arg_var: PlaceholderForType, *, comment: str) -> None:
|
||||||
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
|
self.tc_var = tc_var
|
||||||
|
self.arg_var = arg_var
|
||||||
|
|
||||||
|
def check(self) -> CheckResult:
|
||||||
|
if self.tc_var.resolve_as is None or self.arg_var.resolve_as is None:
|
||||||
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
|
tc_typ = self.tc_var.resolve_as
|
||||||
|
arg_typ = self.arg_var.resolve_as
|
||||||
|
|
||||||
|
if isinstance(tc_typ.application, types.TypeApplication_Nullary):
|
||||||
|
return Error(f'{tc_typ:s} must be a constructed type instead')
|
||||||
|
|
||||||
|
if isinstance(tc_typ.application, types.TypeApplication_TypeStar):
|
||||||
|
# Sure, it's a constructed type. But it's like a struct,
|
||||||
|
# though without the way to implement type classes
|
||||||
|
# Presumably, doing a naked `foo :: t a -> a`
|
||||||
|
# doesn't work since you don't have any info on t
|
||||||
|
# So we can let the MustImplementTypeClassConstraint handle it.
|
||||||
|
return None
|
||||||
|
|
||||||
|
# FIXME: This feels sketchy. Shouldn't the type variable
|
||||||
|
# have the exact same number as arguments?
|
||||||
|
if isinstance(tc_typ.application, types.TypeApplication_TypeInt):
|
||||||
|
if tc_typ.application.arguments[0] == arg_typ:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return Error(f'{tc_typ.application.arguments[0]:s} must be {arg_typ:s} instead')
|
||||||
|
|
||||||
|
raise NotImplementedError(tc_typ, arg_typ)
|
||||||
|
|
||||||
class TupleMatchConstraint(ConstraintBase):
|
class TupleMatchConstraint(ConstraintBase):
|
||||||
__slots__ = ('exp_type', 'args', )
|
__slots__ = ('exp_type', 'args', )
|
||||||
|
|
||||||
@ -229,7 +269,7 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
|||||||
self.types = types
|
self.types = types
|
||||||
|
|
||||||
def check(self) -> CheckResult:
|
def check(self) -> CheckResult:
|
||||||
typ_list = []
|
typ_list: list[types.Type3 | types.TypeConstructor_Base[Any] | types.TypeConstructor_Struct] = []
|
||||||
for typ in self.types:
|
for typ in self.types:
|
||||||
if isinstance(typ, placeholders.PlaceholderForType) and typ.resolve_as is not None:
|
if isinstance(typ, placeholders.PlaceholderForType) and typ.resolve_as is not None:
|
||||||
typ = typ.resolve_as
|
typ = typ.resolve_as
|
||||||
@ -237,7 +277,15 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
|||||||
if isinstance(typ, placeholders.PlaceholderForType):
|
if isinstance(typ, placeholders.PlaceholderForType):
|
||||||
return RequireTypeSubstitutes()
|
return RequireTypeSubstitutes()
|
||||||
|
|
||||||
typ_list.append(typ)
|
if isinstance(typ.application, (types.TypeApplication_Nullary, types.TypeApplication_Struct, )):
|
||||||
|
typ_list.append(typ)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(typ.application, (types.TypeApplication_TypeInt, types.TypeApplication_TypeStar)):
|
||||||
|
typ_list.append(typ.application.constructor)
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise NotImplementedError(typ, typ.application)
|
||||||
|
|
||||||
assert len(typ_list) == len(self.types)
|
assert len(typ_list) == len(self.types)
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ from .constraints import (
|
|||||||
Context,
|
Context,
|
||||||
LiteralFitsConstraint,
|
LiteralFitsConstraint,
|
||||||
MustImplementTypeClassConstraint,
|
MustImplementTypeClassConstraint,
|
||||||
|
SameTypeArgumentConstraint,
|
||||||
SameTypeConstraint,
|
SameTypeConstraint,
|
||||||
TupleMatchConstraint,
|
TupleMatchConstraint,
|
||||||
)
|
)
|
||||||
@ -39,6 +40,116 @@ def constant(ctx: Context, inp: ourlang.Constant, phft: placeholders.Placeholder
|
|||||||
|
|
||||||
raise NotImplementedError(constant, inp)
|
raise NotImplementedError(constant, inp)
|
||||||
|
|
||||||
|
def expression_binary_op(ctx: Context, inp: ourlang.BinaryOp, phft: PlaceholderForType) -> ConstraintGenerator:
|
||||||
|
return _expression_function_call(
|
||||||
|
ctx,
|
||||||
|
f'({inp.operator.name})',
|
||||||
|
inp.operator.signature,
|
||||||
|
[inp.left, inp.right],
|
||||||
|
inp,
|
||||||
|
phft,
|
||||||
|
)
|
||||||
|
|
||||||
|
def expression_function_call(ctx: Context, inp: ourlang.FunctionCall, phft: PlaceholderForType) -> ConstraintGenerator:
|
||||||
|
return _expression_function_call(
|
||||||
|
ctx,
|
||||||
|
inp.function.name,
|
||||||
|
inp.function.signature,
|
||||||
|
inp.arguments,
|
||||||
|
inp,
|
||||||
|
phft,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _expression_function_call(
|
||||||
|
ctx: Context,
|
||||||
|
func_name: str,
|
||||||
|
signature: functions.FunctionSignature,
|
||||||
|
arguments: list[ourlang.Expression],
|
||||||
|
return_expr: ourlang.Expression,
|
||||||
|
return_phft: PlaceholderForType,
|
||||||
|
) -> ConstraintGenerator:
|
||||||
|
"""
|
||||||
|
Generates all type-level constraints for a function call.
|
||||||
|
|
||||||
|
A Binary operator functions pretty much the same as a function call
|
||||||
|
with two arguments - it's only a syntactic difference.
|
||||||
|
"""
|
||||||
|
# First create placeholders for all arguments, and generate their constraints
|
||||||
|
arg_placeholders = {
|
||||||
|
arg_expr: PlaceholderForType([arg_expr])
|
||||||
|
for arg_expr in arguments
|
||||||
|
}
|
||||||
|
arg_placeholders[return_expr] = return_phft
|
||||||
|
|
||||||
|
for call_arg in arguments:
|
||||||
|
yield from expression(ctx, call_arg, arg_placeholders[call_arg])
|
||||||
|
|
||||||
|
# Then generate placeholders the function signature
|
||||||
|
# and apply constraints that the function requires
|
||||||
|
# Skip any fully reference types
|
||||||
|
# Making this a map ensures that if a function signature has
|
||||||
|
# the same type on multiple arguments, we only get one
|
||||||
|
# placeholder here. These don't need to update anything once
|
||||||
|
# subsituted - that's done by arg_placeholders.
|
||||||
|
type_var_map = {
|
||||||
|
x: placeholders.PlaceholderForType([])
|
||||||
|
for x in signature.args
|
||||||
|
if isinstance(x, functions.TypeVariable)
|
||||||
|
}
|
||||||
|
|
||||||
|
for constraint in signature.context.constraints:
|
||||||
|
if isinstance(constraint, functions.Constraint_TypeClassInstanceExists):
|
||||||
|
yield MustImplementTypeClassConstraint(
|
||||||
|
ctx,
|
||||||
|
constraint.type_class3,
|
||||||
|
[type_var_map[x] for x in constraint.types],
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise NotImplementedError(constraint)
|
||||||
|
|
||||||
|
# If some of the function arguments are type constructors,
|
||||||
|
# we need to deal with those separately.
|
||||||
|
# That is, given `foo :: t a -> a` we need to ensure
|
||||||
|
# that both a's are the same.
|
||||||
|
for sig_arg in signature.args:
|
||||||
|
if isinstance(sig_arg, type3types.Type3):
|
||||||
|
# Not a type variable at all
|
||||||
|
continue
|
||||||
|
|
||||||
|
if sig_arg.application.constructor is None:
|
||||||
|
# Not a type variable for a type constructor
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not isinstance(sig_arg.application, functions.TypeVariableApplication_Unary):
|
||||||
|
raise NotImplementedError(sig_arg.application)
|
||||||
|
|
||||||
|
assert sig_arg.application.arguments in type_var_map # When does this happen?
|
||||||
|
|
||||||
|
yield SameTypeArgumentConstraint(
|
||||||
|
type_var_map[sig_arg],
|
||||||
|
type_var_map[sig_arg.application.arguments],
|
||||||
|
comment=f'Ensure `{sig_arg.application.arguments.name}` matches in {signature}',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Lastly, tie the signature and expression together
|
||||||
|
for arg_no, (sig_part, arg_expr) in enumerate(zip(signature.args, arguments + [return_expr], strict=True)):
|
||||||
|
if arg_no == len(arguments):
|
||||||
|
comment = f'The type of a function call to {func_name} is the same as the type that the function returns'
|
||||||
|
else:
|
||||||
|
comment = f'The type of the value passed to argument {arg_no} of function {func_name} should match the type of that argument'
|
||||||
|
|
||||||
|
if isinstance(sig_part, functions.TypeVariable):
|
||||||
|
yield SameTypeConstraint(type_var_map[sig_part], arg_placeholders[arg_expr], comment=comment)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(sig_part, type3types.Type3):
|
||||||
|
yield SameTypeConstraint(sig_part, arg_placeholders[arg_expr], comment=comment)
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise NotImplementedError(sig_part)
|
||||||
|
return
|
||||||
|
|
||||||
def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.PlaceholderForType) -> ConstraintGenerator:
|
def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.PlaceholderForType) -> ConstraintGenerator:
|
||||||
if isinstance(inp, ourlang.Constant):
|
if isinstance(inp, ourlang.Constant):
|
||||||
yield from constant(ctx, inp, phft)
|
yield from constant(ctx, inp, phft)
|
||||||
@ -49,53 +160,12 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
|||||||
comment=f'typeOf("{inp.variable.name}") == typeOf({inp.variable.name})')
|
comment=f'typeOf("{inp.variable.name}") == typeOf({inp.variable.name})')
|
||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.BinaryOp) or isinstance(inp, ourlang.FunctionCall):
|
if isinstance(inp, ourlang.BinaryOp):
|
||||||
signature = inp.operator.signature if isinstance(inp, ourlang.BinaryOp) else inp.function.signature
|
yield from expression_binary_op(ctx, inp, phft)
|
||||||
arguments = [inp.left, inp.right] if isinstance(inp, ourlang.BinaryOp) else inp.arguments
|
return
|
||||||
|
|
||||||
func_name = f'({inp.operator.name})' if isinstance(inp, ourlang.BinaryOp) else inp.function.name
|
if isinstance(inp, ourlang.FunctionCall):
|
||||||
|
yield from expression_function_call(ctx, inp, phft)
|
||||||
type_var_map = {
|
|
||||||
x: placeholders.PlaceholderForType([])
|
|
||||||
for x in signature.args
|
|
||||||
if isinstance(x, functions.TypeVariable)
|
|
||||||
}
|
|
||||||
|
|
||||||
arg_placeholders = {
|
|
||||||
arg_expr: PlaceholderForType([arg_expr])
|
|
||||||
for arg_expr in arguments
|
|
||||||
}
|
|
||||||
arg_placeholders[inp] = phft
|
|
||||||
|
|
||||||
for arg_expr in arguments:
|
|
||||||
yield from expression(ctx, arg_expr, arg_placeholders[arg_expr])
|
|
||||||
|
|
||||||
for constraint in signature.context.constraints:
|
|
||||||
if isinstance(constraint, functions.Constraint_TypeClassInstanceExists):
|
|
||||||
yield MustImplementTypeClassConstraint(
|
|
||||||
ctx,
|
|
||||||
constraint.type_class3,
|
|
||||||
[type_var_map[x] for x in constraint.types],
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
raise NotImplementedError(constraint)
|
|
||||||
|
|
||||||
for arg_no, (sig_part, arg_expr) in enumerate(zip(signature.args, arguments + [inp], strict=True)):
|
|
||||||
if arg_no == len(arguments):
|
|
||||||
comment = f'The type of a function call to {func_name} is the same as the type that the function returns'
|
|
||||||
else:
|
|
||||||
comment = f'The type of the value passed to argument {arg_no} of function {func_name} should match the type of that argument'
|
|
||||||
|
|
||||||
if isinstance(sig_part, functions.TypeVariable):
|
|
||||||
yield SameTypeConstraint(type_var_map[sig_part], arg_placeholders[arg_expr], comment=comment)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(sig_part, type3types.Type3):
|
|
||||||
yield SameTypeConstraint(sig_part, arg_placeholders[arg_expr], comment=comment)
|
|
||||||
continue
|
|
||||||
|
|
||||||
raise NotImplementedError(sig_part)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.TupleInstantiation):
|
if isinstance(inp, ourlang.TupleInstantiation):
|
||||||
|
|||||||
@ -1,10 +1,36 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Iterable, List, Union
|
from typing import TYPE_CHECKING, Any, Hashable, Iterable, List, Union
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .typeclasses import Type3Class
|
from .typeclasses import Type3Class
|
||||||
from .types import Type3
|
from .types import Type3
|
||||||
|
|
||||||
|
|
||||||
|
class TypeVariableApplication_Base[T: Hashable, S: Hashable]:
|
||||||
|
"""
|
||||||
|
Records the constructor and arguments used to create this type.
|
||||||
|
|
||||||
|
Nullary types, or types of kind *, have both arguments set to None.
|
||||||
|
"""
|
||||||
|
constructor: T
|
||||||
|
arguments: S
|
||||||
|
|
||||||
|
def __init__(self, constructor: T, arguments: S) -> None:
|
||||||
|
self.constructor = constructor
|
||||||
|
self.arguments = arguments
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return hash((self.constructor, self.arguments, ))
|
||||||
|
|
||||||
|
def __eq__(self, other: Any) -> bool:
|
||||||
|
if not isinstance(other, TypeVariableApplication_Base):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
return (self.constructor == other.constructor # type: ignore[no-any-return]
|
||||||
|
and self.arguments == other.arguments)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'{self.__class__.__name__}({self.constructor!r}, {self.arguments!r})'
|
||||||
|
|
||||||
class TypeVariable:
|
class TypeVariable:
|
||||||
"""
|
"""
|
||||||
Types variable are used in function definition.
|
Types variable are used in function definition.
|
||||||
@ -14,25 +40,77 @@ class TypeVariable:
|
|||||||
during type checking. These type variables are used solely in the
|
during type checking. These type variables are used solely in the
|
||||||
function's definition
|
function's definition
|
||||||
"""
|
"""
|
||||||
__slots__ = ('letter', )
|
__slots__ = ('name', 'application', )
|
||||||
|
|
||||||
letter: str
|
name: str
|
||||||
|
application: TypeVariableApplication_Base[Any, Any]
|
||||||
|
|
||||||
def __init__(self, letter: str) -> None:
|
def __init__(self, name: str, application: TypeVariableApplication_Base[Any, Any]) -> None:
|
||||||
assert len(letter) == 1, f'{letter} is not a valid type variable'
|
self.name = name
|
||||||
self.letter = letter
|
self.application = application
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
def __hash__(self) -> int:
|
||||||
return hash(self.letter)
|
return hash((self.name, self.application, ))
|
||||||
|
|
||||||
def __eq__(self, other: Any) -> bool:
|
def __eq__(self, other: Any) -> bool:
|
||||||
if not isinstance(other, TypeVariable):
|
if not isinstance(other, TypeVariable):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
return self.letter == other.letter
|
return (self.name == other.name
|
||||||
|
and self.application == other.application)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'TypeVariable({repr(self.letter)})'
|
return f'TypeVariable({repr(self.name)})'
|
||||||
|
|
||||||
|
class TypeVariableApplication_Nullary(TypeVariableApplication_Base[None, None]):
|
||||||
|
"""
|
||||||
|
For the type for this function argument it's not relevant if it was constructed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class TypeConstructorVariable:
|
||||||
|
"""
|
||||||
|
Types constructor variable are used in function definition.
|
||||||
|
|
||||||
|
They are a lot like TypeVariable, except that they represent a
|
||||||
|
type constructor rather than a type directly.
|
||||||
|
|
||||||
|
For now, we only have type constructor variables for kind
|
||||||
|
* -> *.
|
||||||
|
"""
|
||||||
|
__slots__ = ('name', )
|
||||||
|
|
||||||
|
name: str
|
||||||
|
|
||||||
|
def __init__(self, name: str) -> None:
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return hash((self.name, ))
|
||||||
|
|
||||||
|
def __eq__(self, other: Any) -> bool:
|
||||||
|
if other is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not isinstance(other, TypeConstructorVariable):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
return (self.name == other.name)
|
||||||
|
|
||||||
|
def __call__(self, tvar: TypeVariable) -> 'TypeVariable':
|
||||||
|
return TypeVariable(
|
||||||
|
self.name + ' ' + tvar.name,
|
||||||
|
TypeVariableApplication_Unary(self, tvar)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'TypeConstructorVariable({self.name!r})'
|
||||||
|
|
||||||
|
class TypeVariableApplication_Unary(TypeVariableApplication_Base[TypeConstructorVariable, TypeVariable]):
|
||||||
|
"""
|
||||||
|
The type for this function argument should be constructed from a type constructor.
|
||||||
|
|
||||||
|
And we need to know what construtor that was, since that's the one we support.
|
||||||
|
"""
|
||||||
|
|
||||||
class ConstraintBase:
|
class ConstraintBase:
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
@ -52,7 +130,7 @@ class Constraint_TypeClassInstanceExists(ConstraintBase):
|
|||||||
assert len(self.type_class3.args) == len(self.types)
|
assert len(self.type_class3.args) == len(self.types)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.type_class3.name + ' ' + ' '.join(x.letter for x in self.types)
|
return self.type_class3.name + ' ' + ' '.join(x.name for x in self.types)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'Constraint_TypeClassInstanceExists({self.type_class3.name}, {self.types!r})'
|
return f'Constraint_TypeClassInstanceExists({self.type_class3.name}, {self.types!r})'
|
||||||
@ -62,13 +140,11 @@ class TypeVariableContext:
|
|||||||
|
|
||||||
constraints: list[ConstraintBase]
|
constraints: list[ConstraintBase]
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self, constraints: Iterable[ConstraintBase] = ()) -> None:
|
||||||
self.constraints = []
|
self.constraints = list(constraints)
|
||||||
|
|
||||||
def __copy__(self) -> 'TypeVariableContext':
|
def __copy__(self) -> 'TypeVariableContext':
|
||||||
result = TypeVariableContext()
|
return TypeVariableContext(self.constraints)
|
||||||
result.constraints.extend(self.constraints)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
if not self.constraints:
|
if not self.constraints:
|
||||||
@ -90,7 +166,7 @@ class FunctionSignature:
|
|||||||
self.args = list(args)
|
self.args = list(args)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return str(self.context) + ' -> '.join(x.letter if isinstance(x, TypeVariable) else x.name for x in self.args)
|
return str(self.context) + ' -> '.join(x.name for x in self.args)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'FunctionSignature({self.context!r}, {self.args!r})'
|
return f'FunctionSignature({self.context!r}, {self.args!r})'
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
from typing import Any, Callable, TypeVar
|
from typing import Any, Callable
|
||||||
|
|
||||||
from .functions import FunctionSignature, TypeVariable
|
from .functions import (
|
||||||
from .types import Type3, TypeConstructor_Base
|
TypeConstructorVariable,
|
||||||
|
TypeVariable,
|
||||||
|
TypeVariableApplication_Unary,
|
||||||
|
)
|
||||||
|
from .typeclasses import Type3ClassArgs
|
||||||
|
from .types import KindArgument, Type3, TypeApplication_TypeInt, TypeConstructor_Base
|
||||||
|
|
||||||
T = TypeVar('T')
|
|
||||||
|
|
||||||
class NoRouteForTypeException(Exception):
|
class NoRouteForTypeException(Exception):
|
||||||
pass
|
pass
|
||||||
@ -36,7 +40,7 @@ class TypeApplicationRouter[S, R]:
|
|||||||
"""
|
"""
|
||||||
self.by_type[typ] = helper
|
self.by_type[typ] = helper
|
||||||
|
|
||||||
def add(self, constructor: TypeConstructor_Base[T], helper: Callable[[S, T], R]) -> None:
|
def add[T](self, constructor: TypeConstructor_Base[T], helper: Callable[[S, T], R]) -> None:
|
||||||
self.by_constructor[constructor] = helper
|
self.by_constructor[constructor] = helper
|
||||||
|
|
||||||
def __call__(self, arg0: S, typ: Type3) -> R:
|
def __call__(self, arg0: S, typ: Type3) -> R:
|
||||||
@ -50,39 +54,66 @@ class TypeApplicationRouter[S, R]:
|
|||||||
|
|
||||||
raise NoRouteForTypeException(arg0, typ)
|
raise NoRouteForTypeException(arg0, typ)
|
||||||
|
|
||||||
class FunctionSignatureRouter[S, R]:
|
TypeVariableLookup = dict[TypeVariable, tuple[KindArgument, ...]]
|
||||||
|
|
||||||
|
class TypeClassArgsRouter[S, R]:
|
||||||
"""
|
"""
|
||||||
Helper class to find a method based on a function signature
|
Helper class to find a method based on a type class argument list
|
||||||
"""
|
"""
|
||||||
__slots__ = ('signature', 'data', )
|
__slots__ = ('args', 'data', )
|
||||||
|
|
||||||
signature: FunctionSignature
|
args: Type3ClassArgs
|
||||||
|
|
||||||
data: dict[tuple[Type3, ...], Callable[[S], R]]
|
data: dict[tuple[Type3 | TypeConstructor_Base[Any], ...], Callable[[S, TypeVariableLookup], R]]
|
||||||
|
|
||||||
def __init__(self, signature: FunctionSignature) -> None:
|
def __init__(self, args: Type3ClassArgs) -> None:
|
||||||
self.signature = signature
|
self.args = args
|
||||||
self.data = {}
|
self.data = {}
|
||||||
|
|
||||||
def add(self, tv_map: dict[TypeVariable, Type3], helper: Callable[[S], R]) -> None:
|
def add(
|
||||||
key = tuple(
|
self,
|
||||||
tv_map[x]
|
tv_map: dict[TypeVariable, Type3],
|
||||||
for x in self.signature.args
|
tc_map: dict[TypeConstructorVariable, TypeConstructor_Base[Any]],
|
||||||
if isinstance(x, TypeVariable)
|
helper: Callable[[S, TypeVariableLookup], R],
|
||||||
)
|
) -> None:
|
||||||
# assert len(key) == len(tv_map), (key, tv_map)
|
|
||||||
|
|
||||||
self.data[key] = helper
|
key: list[Type3 | TypeConstructor_Base[Any]] = []
|
||||||
|
|
||||||
|
for tc_arg in self.args:
|
||||||
|
if isinstance(tc_arg, TypeVariable):
|
||||||
|
key.append(tv_map[tc_arg])
|
||||||
|
else:
|
||||||
|
key.append(tc_map[tc_arg])
|
||||||
|
|
||||||
|
self.data[tuple(key)] = helper
|
||||||
|
|
||||||
def __call__(self, arg0: S, tv_map: dict[TypeVariable, Type3]) -> R:
|
def __call__(self, arg0: S, tv_map: dict[TypeVariable, Type3]) -> R:
|
||||||
key = tuple(
|
key: list[Type3 | TypeConstructor_Base[Any]] = []
|
||||||
tv_map[x]
|
arguments: TypeVariableLookup = {}
|
||||||
for x in self.signature.args
|
|
||||||
if isinstance(x, TypeVariable)
|
|
||||||
)
|
|
||||||
|
|
||||||
t_helper = self.data.get(key)
|
for tc_arg in self.args:
|
||||||
|
if isinstance(tc_arg, TypeVariable):
|
||||||
|
key.append(tv_map[tc_arg])
|
||||||
|
continue
|
||||||
|
|
||||||
|
for tvar, typ in tv_map.items():
|
||||||
|
tvar_constructor = tvar.application.constructor
|
||||||
|
if tvar_constructor != tc_arg:
|
||||||
|
continue
|
||||||
|
|
||||||
|
key.append(typ.application.constructor)
|
||||||
|
|
||||||
|
if isinstance(tvar.application, TypeVariableApplication_Unary):
|
||||||
|
# FIXME: This feels sketchy. Shouldn't the type variable
|
||||||
|
# have the exact same number as arguments?
|
||||||
|
if isinstance(typ.application, TypeApplication_TypeInt):
|
||||||
|
arguments[tvar.application.arguments] = typ.application.arguments
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise NotImplementedError(tvar.application, typ.application)
|
||||||
|
|
||||||
|
t_helper = self.data.get(tuple(key))
|
||||||
if t_helper is not None:
|
if t_helper is not None:
|
||||||
return t_helper(arg0)
|
return t_helper(arg0, arguments)
|
||||||
|
|
||||||
raise NoRouteForTypeException(arg0, tv_map)
|
raise NoRouteForTypeException(arg0, tv_map)
|
||||||
|
|||||||
@ -2,7 +2,9 @@ from typing import Dict, Iterable, List, Mapping, Optional, Union
|
|||||||
|
|
||||||
from .functions import (
|
from .functions import (
|
||||||
Constraint_TypeClassInstanceExists,
|
Constraint_TypeClassInstanceExists,
|
||||||
|
ConstraintBase,
|
||||||
FunctionSignature,
|
FunctionSignature,
|
||||||
|
TypeConstructorVariable,
|
||||||
TypeVariable,
|
TypeVariable,
|
||||||
TypeVariableContext,
|
TypeVariableContext,
|
||||||
)
|
)
|
||||||
@ -25,11 +27,13 @@ class Type3ClassMethod:
|
|||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'Type3ClassMethod({repr(self.name)}, {repr(self.signature)})'
|
return f'Type3ClassMethod({repr(self.name)}, {repr(self.signature)})'
|
||||||
|
|
||||||
|
Type3ClassArgs = tuple[TypeVariable] | tuple[TypeVariable, TypeVariable] | tuple[TypeConstructorVariable]
|
||||||
|
|
||||||
class Type3Class:
|
class Type3Class:
|
||||||
__slots__ = ('name', 'args', 'methods', 'operators', 'inherited_classes', )
|
__slots__ = ('name', 'args', 'methods', 'operators', 'inherited_classes', )
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
args: List[TypeVariable]
|
args: Type3ClassArgs
|
||||||
methods: Dict[str, Type3ClassMethod]
|
methods: Dict[str, Type3ClassMethod]
|
||||||
operators: Dict[str, Type3ClassMethod]
|
operators: Dict[str, Type3ClassMethod]
|
||||||
inherited_classes: List['Type3Class']
|
inherited_classes: List['Type3Class']
|
||||||
@ -37,26 +41,60 @@ class Type3Class:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
args: Iterable[TypeVariable],
|
args: Type3ClassArgs,
|
||||||
methods: Mapping[str, Iterable[Union[Type3, TypeVariable]]],
|
methods: Mapping[str, Iterable[Union[Type3, TypeVariable]]],
|
||||||
operators: Mapping[str, Iterable[Union[Type3, TypeVariable]]],
|
operators: Mapping[str, Iterable[Union[Type3, TypeVariable]]],
|
||||||
inherited_classes: Optional[List['Type3Class']] = None,
|
inherited_classes: Optional[List['Type3Class']] = None,
|
||||||
|
additional_context: Optional[Mapping[str, Iterable[ConstraintBase]]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.args = list(args)
|
self.args = args
|
||||||
|
|
||||||
context = TypeVariableContext()
|
|
||||||
context.constraints.append(Constraint_TypeClassInstanceExists(self, args))
|
|
||||||
|
|
||||||
self.methods = {
|
self.methods = {
|
||||||
k: Type3ClassMethod(k, FunctionSignature(context, v))
|
k: Type3ClassMethod(k, _create_signature(v, self))
|
||||||
for k, v in methods.items()
|
for k, v in methods.items()
|
||||||
}
|
}
|
||||||
self.operators = {
|
self.operators = {
|
||||||
k: Type3ClassMethod(k, FunctionSignature(context, v))
|
k: Type3ClassMethod(k, _create_signature(v, self))
|
||||||
for k, v in operators.items()
|
for k, v in operators.items()
|
||||||
}
|
}
|
||||||
self.inherited_classes = inherited_classes or []
|
self.inherited_classes = inherited_classes or []
|
||||||
|
|
||||||
|
if additional_context:
|
||||||
|
for func_name, constraint_list in additional_context.items():
|
||||||
|
func = self.methods.get(func_name) or self.operators.get(func_name)
|
||||||
|
assert func is not None # type hint
|
||||||
|
|
||||||
|
func.signature.context.constraints.extend(constraint_list)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def _create_signature(
|
||||||
|
method_arg_list: Iterable[Type3 | TypeVariable],
|
||||||
|
type_class3: Type3Class,
|
||||||
|
) -> FunctionSignature:
|
||||||
|
context = TypeVariableContext()
|
||||||
|
if not isinstance(type_class3.args[0], TypeConstructorVariable):
|
||||||
|
context.constraints.append(Constraint_TypeClassInstanceExists(type_class3, type_class3.args))
|
||||||
|
|
||||||
|
signature_args: list[Type3 | TypeVariable] = []
|
||||||
|
for method_arg in method_arg_list:
|
||||||
|
if isinstance(method_arg, Type3):
|
||||||
|
signature_args.append(method_arg)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(method_arg, TypeVariable):
|
||||||
|
type_constructor = method_arg.application.constructor
|
||||||
|
if type_constructor is None:
|
||||||
|
signature_args.append(method_arg)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (type_constructor, ) == type_class3.args:
|
||||||
|
context.constraints.append(Constraint_TypeClassInstanceExists(type_class3, [method_arg]))
|
||||||
|
signature_args.append(method_arg)
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise NotImplementedError(method_arg)
|
||||||
|
|
||||||
|
return FunctionSignature(context, signature_args)
|
||||||
|
|||||||
@ -29,6 +29,16 @@ class TypeApplication_Base[T: Hashable, S: Hashable]:
|
|||||||
self.constructor = constructor
|
self.constructor = constructor
|
||||||
self.arguments = arguments
|
self.arguments = arguments
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return hash((self.constructor, self.arguments, ))
|
||||||
|
|
||||||
|
def __eq__(self, other: Any) -> bool:
|
||||||
|
if not isinstance(other, TypeApplication_Base):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
return (self.constructor == other.constructor # type: ignore[no-any-return]
|
||||||
|
and self.arguments == other.arguments)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'{self.__class__.__name__}({self.constructor!r}, {self.arguments!r})'
|
return f'{self.__class__.__name__}({self.constructor!r}, {self.arguments!r})'
|
||||||
|
|
||||||
@ -84,7 +94,9 @@ class Type3(KindArgument):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
class TypeApplication_Nullary(TypeApplication_Base[None, None]):
|
class TypeApplication_Nullary(TypeApplication_Base[None, None]):
|
||||||
pass
|
"""
|
||||||
|
There was no constructor used to create this type - it's a 'simple' type like u32
|
||||||
|
"""
|
||||||
|
|
||||||
class IntType3(KindArgument):
|
class IntType3(KindArgument):
|
||||||
"""
|
"""
|
||||||
@ -104,6 +116,9 @@ class IntType3(KindArgument):
|
|||||||
def __init__(self, value: int) -> None:
|
def __init__(self, value: int) -> None:
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'IntType3({self.value!r})'
|
||||||
|
|
||||||
def __format__(self, format_spec: str) -> str:
|
def __format__(self, format_spec: str) -> str:
|
||||||
if format_spec != 's':
|
if format_spec != 's':
|
||||||
raise TypeError(f'unsupported format string passed to Type3.__format__: {format_spec}')
|
raise TypeError(f'unsupported format string passed to Type3.__format__: {format_spec}')
|
||||||
@ -177,6 +192,9 @@ class TypeConstructor_Base[T]:
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f'{self.__class__.__name__}({self.name!r}, ...)'
|
||||||
|
|
||||||
class TypeConstructor_TypeInt(TypeConstructor_Base[Tuple[Type3, IntType3]]):
|
class TypeConstructor_TypeInt(TypeConstructor_Base[Tuple[Type3, IntType3]]):
|
||||||
"""
|
"""
|
||||||
Base class type constructors of kind: * -> Int -> *
|
Base class type constructors of kind: * -> Int -> *
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
Helper functions to generate WASM code by writing Python functions
|
Helper functions to generate WASM code by writing Python functions
|
||||||
"""
|
"""
|
||||||
import functools
|
import functools
|
||||||
from typing import Any, Callable, Dict, List, Optional, Type
|
from typing import Any, Callable, Dict, Iterable, List, Optional, Type
|
||||||
|
|
||||||
from . import wasm
|
from . import wasm
|
||||||
|
|
||||||
@ -24,6 +24,12 @@ class VarType_i32(VarType_Base):
|
|||||||
class VarType_i64(VarType_Base):
|
class VarType_i64(VarType_Base):
|
||||||
wasm_type = wasm.WasmTypeInt64
|
wasm_type = wasm.WasmTypeInt64
|
||||||
|
|
||||||
|
class VarType_f32(VarType_Base):
|
||||||
|
wasm_type = wasm.WasmTypeFloat32
|
||||||
|
|
||||||
|
class VarType_f64(VarType_Base):
|
||||||
|
wasm_type = wasm.WasmTypeFloat64
|
||||||
|
|
||||||
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
|
||||||
@ -164,12 +170,23 @@ class Generator_Local:
|
|||||||
self.generator.add_statement('local.tee', variable.name_ref, comment=comment)
|
self.generator.add_statement('local.tee', variable.name_ref, comment=comment)
|
||||||
|
|
||||||
class GeneratorBlock:
|
class GeneratorBlock:
|
||||||
def __init__(self, generator: 'Generator', name: str) -> None:
|
def __init__(self, generator: 'Generator', name: str, params: Iterable[str] = (), result: str | None = None) -> None:
|
||||||
self.generator = generator
|
self.generator = generator
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.params = params
|
||||||
|
self.result = result
|
||||||
|
|
||||||
def __enter__(self) -> None:
|
def __enter__(self) -> None:
|
||||||
self.generator.add_statement(self.name)
|
stmt = self.name
|
||||||
|
if self.params:
|
||||||
|
stmt = f'{stmt} ' + ' '.join(
|
||||||
|
f'(param {typ})'
|
||||||
|
for typ in self.params
|
||||||
|
)
|
||||||
|
if self.result:
|
||||||
|
stmt = f'{stmt} (result {self.result})'
|
||||||
|
|
||||||
|
self.generator.add_statement(stmt)
|
||||||
|
|
||||||
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
|
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
|
||||||
if not exc_type:
|
if not exc_type:
|
||||||
@ -210,19 +227,18 @@ class Generator:
|
|||||||
def add_statement(self, name: str, *args: str, comment: Optional[str] = None) -> None:
|
def add_statement(self, name: str, *args: str, comment: Optional[str] = None) -> None:
|
||||||
self.statements.append(wasm.Statement(name, *args, comment=comment))
|
self.statements.append(wasm.Statement(name, *args, comment=comment))
|
||||||
|
|
||||||
def temp_var_i32(self, infix: str) -> VarType_i32:
|
def temp_var[T: VarType_Base](self, var: T) -> T:
|
||||||
idx = 0
|
idx = 0
|
||||||
while (varname := f'__{infix}_tmp_var_{idx}__') in self.locals:
|
while (varname := f'__{var.name}_tmp_var_{idx}__') in self.locals:
|
||||||
idx += 1
|
idx += 1
|
||||||
|
|
||||||
return VarType_i32(varname)
|
return var.__class__(varname)
|
||||||
|
|
||||||
|
def temp_var_i32(self, infix: str) -> VarType_i32:
|
||||||
|
return self.temp_var(VarType_i32(infix))
|
||||||
|
|
||||||
def temp_var_u8(self, infix: str) -> VarType_u8:
|
def temp_var_u8(self, infix: str) -> VarType_u8:
|
||||||
idx = 0
|
return self.temp_var(VarType_u8(infix))
|
||||||
while (varname := f'__{infix}_tmp_var_{idx}__') in self.locals:
|
|
||||||
idx += 1
|
|
||||||
|
|
||||||
return VarType_u8(varname)
|
|
||||||
|
|
||||||
def func_wrapper(exported: bool = True) -> Callable[[Any], wasm.Function]:
|
def func_wrapper(exported: bool = True) -> Callable[[Any], wasm.Function]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -17,6 +17,9 @@ from . import runners
|
|||||||
|
|
||||||
DASHES = '-' * 16
|
DASHES = '-' * 16
|
||||||
|
|
||||||
|
class InvalidArgumentException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
class SuiteResult:
|
class SuiteResult:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.returned_value = None
|
self.returned_value = None
|
||||||
@ -152,18 +155,18 @@ def _allocate_memory_stored_bytes(attrs: tuple[runners.RunnerBase, bytes]) -> in
|
|||||||
def _allocate_memory_stored_static_array(attrs: tuple[runners.RunnerBase, Any], sa_args: tuple[type3types.Type3, type3types.IntType3]) -> int:
|
def _allocate_memory_stored_static_array(attrs: tuple[runners.RunnerBase, Any], sa_args: tuple[type3types.Type3, type3types.IntType3]) -> int:
|
||||||
runner, val = attrs
|
runner, val = attrs
|
||||||
|
|
||||||
assert isinstance(val, tuple)
|
|
||||||
|
|
||||||
sa_type, sa_len = sa_args
|
sa_type, sa_len = sa_args
|
||||||
|
|
||||||
|
if not isinstance(val, tuple):
|
||||||
|
raise InvalidArgumentException(f'Expected tuple of length {sa_len.value}; got {val!r} instead')
|
||||||
|
if sa_len.value != len(val):
|
||||||
|
raise InvalidArgumentException(f'Expected tuple of length {sa_len.value}; got {val!r} instead')
|
||||||
|
|
||||||
alloc_size = calculate_alloc_size_static_array(False, sa_args)
|
alloc_size = calculate_alloc_size_static_array(False, sa_args)
|
||||||
adr = runner.call('stdlib.alloc.__alloc__', alloc_size)
|
adr = runner.call('stdlib.alloc.__alloc__', alloc_size)
|
||||||
assert isinstance(adr, int)
|
assert isinstance(adr, int) # Type int
|
||||||
sys.stderr.write(f'Allocation 0x{adr:08x} {repr(val)}\n')
|
sys.stderr.write(f'Allocation 0x{adr:08x} {repr(val)}\n')
|
||||||
|
|
||||||
tuple_len = sa_len.value
|
|
||||||
assert tuple_len == len(val)
|
|
||||||
|
|
||||||
offset = adr
|
offset = adr
|
||||||
for val_el_val in val:
|
for val_el_val in val:
|
||||||
offset += _write_memory_stored_value(runner, offset, sa_type, val_el_val)
|
offset += _write_memory_stored_value(runner, offset, sa_type, val_el_val)
|
||||||
|
|||||||
71
tests/integration/test_lang/test_foldable.py
Normal file
71
tests/integration/test_lang/test_foldable.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
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
|
||||||
|
def test_foldable_invalid_return_type():
|
||||||
|
code_py = """
|
||||||
|
@exported
|
||||||
|
def testEntry(x: i32[5]) -> f64:
|
||||||
|
return sum(x)
|
||||||
|
"""
|
||||||
|
|
||||||
|
with pytest.raises(Type3Exception, match='i32 must be f64 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()
|
||||||
Loading…
x
Reference in New Issue
Block a user