Compare commits
No commits in common. "6b66935c67b09b6d5e807109ad1d9dd497a9a66a" and "f6cb1a8c1dbf0541df6bc23f94b261ef95cb3c97" have entirely different histories.
6b66935c67
...
f6cb1a8c1d
@ -6,6 +6,7 @@ It's intented to be a "any color, as long as it's black" kind of renderer
|
|||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
|
||||||
from . import ourlang, prelude
|
from . import ourlang, prelude
|
||||||
|
from .type3.placeholders import TYPE3_ASSERTION_ERROR, Type3OrPlaceholder
|
||||||
from .type3.types import Type3
|
from .type3.types import Type3
|
||||||
|
|
||||||
|
|
||||||
@ -17,10 +18,12 @@ def phasm_render(inp: ourlang.Module) -> str:
|
|||||||
|
|
||||||
Statements = Generator[str, None, None]
|
Statements = Generator[str, None, None]
|
||||||
|
|
||||||
def type3(inp: Type3) -> str:
|
def type3(inp: Type3OrPlaceholder) -> str:
|
||||||
"""
|
"""
|
||||||
Render: type's name
|
Render: type's name
|
||||||
"""
|
"""
|
||||||
|
assert isinstance(inp, Type3), TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if inp is prelude.none:
|
if inp is prelude.none:
|
||||||
return 'None'
|
return 'None'
|
||||||
|
|
||||||
|
|||||||
@ -9,12 +9,11 @@ from .runtime import calculate_alloc_size, calculate_member_offset
|
|||||||
from .stdlib import alloc as stdlib_alloc
|
from .stdlib import alloc as stdlib_alloc
|
||||||
from .stdlib import types as stdlib_types
|
from .stdlib import types as stdlib_types
|
||||||
from .type3 import functions as type3functions
|
from .type3 import functions as type3functions
|
||||||
|
from .type3 import placeholders as type3placeholders
|
||||||
from .type3 import typeclasses as type3classes
|
from .type3 import typeclasses as type3classes
|
||||||
from .type3 import types as type3types
|
from .type3 import types as type3types
|
||||||
from .wasmgenerator import Generator as WasmGenerator
|
from .wasmgenerator import Generator as WasmGenerator
|
||||||
|
|
||||||
TYPE3_ASSERTION_ERROR = 'You must call phasm_type3 after calling phasm_parse before your program can be compiled'
|
|
||||||
|
|
||||||
LOAD_STORE_TYPE_MAP = {
|
LOAD_STORE_TYPE_MAP = {
|
||||||
'i8': 'i32', # Have to use an u32, since there is no native i8 type
|
'i8': 'i32', # Have to use an u32, since there is no native i8 type
|
||||||
'u8': 'i32', # Have to use an u32, since there is no native u8 type
|
'u8': 'i32', # Have to use an u32, since there is no native u8 type
|
||||||
@ -269,14 +268,14 @@ def phasm_compile(inp: ourlang.Module) -> wasm.Module:
|
|||||||
"""
|
"""
|
||||||
return module(inp)
|
return module(inp)
|
||||||
|
|
||||||
def type3(inp: type3types.Type3) -> wasm.WasmType:
|
def type3(inp: type3placeholders.Type3OrPlaceholder) -> wasm.WasmType:
|
||||||
"""
|
"""
|
||||||
Compile: type
|
Compile: type
|
||||||
|
|
||||||
Types are used for example in WebAssembly function parameters
|
Types are used for example in WebAssembly function parameters
|
||||||
and return types.
|
and return types.
|
||||||
"""
|
"""
|
||||||
assert inp is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(inp, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if inp == prelude.none:
|
if inp == prelude.none:
|
||||||
return wasm.WasmTypeNone()
|
return wasm.WasmTypeNone()
|
||||||
@ -328,7 +327,7 @@ def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) ->
|
|||||||
"""
|
"""
|
||||||
Compile: Instantiation (allocation) of a tuple
|
Compile: Instantiation (allocation) of a tuple
|
||||||
"""
|
"""
|
||||||
assert inp.type3 is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.type3, type3types.Type3)
|
||||||
|
|
||||||
args: list[type3types.Type3] = []
|
args: list[type3types.Type3] = []
|
||||||
|
|
||||||
@ -346,7 +345,7 @@ def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) ->
|
|||||||
|
|
||||||
comment_elements = ''
|
comment_elements = ''
|
||||||
for element in inp.elements:
|
for element in inp.elements:
|
||||||
assert element.type3 is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(element.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
comment_elements += f'{element.type3.name}, '
|
comment_elements += f'{element.type3.name}, '
|
||||||
|
|
||||||
tmp_var = wgn.temp_var_i32('tuple_adr')
|
tmp_var = wgn.temp_var_i32('tuple_adr')
|
||||||
@ -360,11 +359,17 @@ def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) ->
|
|||||||
# Store each element individually
|
# Store each element individually
|
||||||
offset = 0
|
offset = 0
|
||||||
for element, exp_type3 in zip(inp.elements, args, strict=True):
|
for element, exp_type3 in zip(inp.elements, args, strict=True):
|
||||||
|
if isinstance(exp_type3, type3placeholders.PlaceholderForType):
|
||||||
|
assert exp_type3.resolve_as is not None
|
||||||
|
assert isinstance(exp_type3.resolve_as, type3types.Type3)
|
||||||
|
exp_type3 = exp_type3.resolve_as
|
||||||
|
|
||||||
assert element.type3 == exp_type3
|
assert element.type3 == exp_type3
|
||||||
|
|
||||||
if (prelude.InternalPassAsPointer, (exp_type3, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
if (prelude.InternalPassAsPointer, (exp_type3, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
||||||
mtyp = 'i32'
|
mtyp = 'i32'
|
||||||
else:
|
else:
|
||||||
|
assert isinstance(exp_type3, type3types.Type3), NotImplementedError('Tuple of applied types / structs')
|
||||||
mtyp = LOAD_STORE_TYPE_MAP[exp_type3.name]
|
mtyp = LOAD_STORE_TYPE_MAP[exp_type3.name]
|
||||||
|
|
||||||
wgn.add_statement('nop', comment='PRE')
|
wgn.add_statement('nop', comment='PRE')
|
||||||
@ -387,7 +392,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
raise Exception
|
raise Exception
|
||||||
|
|
||||||
if isinstance(inp, ourlang.ConstantPrimitive):
|
if isinstance(inp, ourlang.ConstantPrimitive):
|
||||||
assert inp.type3 is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if inp.type3 in (prelude.i8, prelude.u8, ):
|
if inp.type3 in (prelude.i8, prelude.u8, ):
|
||||||
# No native u8 type - treat as i32, with caution
|
# No native u8 type - treat as i32, with caution
|
||||||
@ -428,7 +433,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp.variable, ourlang.ModuleConstantDef):
|
if isinstance(inp.variable, ourlang.ModuleConstantDef):
|
||||||
assert inp.type3 is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if (prelude.InternalPassAsPointer, (inp.type3, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
if (prelude.InternalPassAsPointer, (inp.type3, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
||||||
assert isinstance(inp.variable.constant, (ourlang.ConstantBytes, ourlang.ConstantStruct, ourlang.ConstantTuple, ))
|
assert isinstance(inp.variable.constant, (ourlang.ConstantBytes, ourlang.ConstantStruct, ourlang.ConstantTuple, ))
|
||||||
@ -438,16 +443,19 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
wgn.i32.const(address)
|
wgn.i32.const(address)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if isinstance(inp.type3, type3types.Type3):
|
||||||
expression(wgn, inp.variable.constant)
|
expression(wgn, inp.variable.constant)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
raise NotImplementedError(expression, inp)
|
||||||
|
|
||||||
raise NotImplementedError(expression, inp.variable)
|
raise NotImplementedError(expression, inp.variable)
|
||||||
|
|
||||||
if isinstance(inp, ourlang.BinaryOp):
|
if isinstance(inp, ourlang.BinaryOp):
|
||||||
expression(wgn, inp.left)
|
expression(wgn, inp.left)
|
||||||
expression(wgn, inp.right)
|
expression(wgn, inp.right)
|
||||||
|
|
||||||
assert inp.type3 is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
type_var_map: Dict[type3functions.TypeVariable, type3types.Type3] = {}
|
type_var_map: Dict[type3functions.TypeVariable, type3types.Type3] = {}
|
||||||
|
|
||||||
@ -456,7 +464,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
# 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
|
assert isinstance(arg_expr.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
type_var_map[type_var] = arg_expr.type3
|
type_var_map[type_var] = arg_expr.type3
|
||||||
|
|
||||||
instance_key = ','.join(
|
instance_key = ','.join(
|
||||||
@ -484,7 +492,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
# 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
|
assert isinstance(arg_expr.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
type_var_map[type_var] = arg_expr.type3
|
type_var_map[type_var] = arg_expr.type3
|
||||||
|
|
||||||
instance_key = ','.join(
|
instance_key = ','.join(
|
||||||
@ -507,7 +515,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.Subscript):
|
if isinstance(inp, ourlang.Subscript):
|
||||||
assert inp.varref.type3 is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.varref.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if inp.varref.type3 is prelude.bytes_:
|
if inp.varref.type3 is prelude.bytes_:
|
||||||
expression(wgn, inp.varref)
|
expression(wgn, inp.varref)
|
||||||
@ -515,7 +523,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
wgn.call(stdlib_types.__subscript_bytes__)
|
wgn.call(stdlib_types.__subscript_bytes__)
|
||||||
return
|
return
|
||||||
|
|
||||||
assert inp.varref.type3 is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.varref.type3, type3types.Type3)
|
||||||
|
|
||||||
sa_args = prelude.static_array.did_construct(inp.varref.type3)
|
sa_args = prelude.static_array.did_construct(inp.varref.type3)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
@ -541,6 +549,7 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
wgn.i32.mul()
|
wgn.i32.mul()
|
||||||
wgn.i32.add()
|
wgn.i32.add()
|
||||||
|
|
||||||
|
assert isinstance(el_type, type3types.Type3), NotImplementedError('Tuple of applied types / structs')
|
||||||
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
|
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
|
||||||
|
|
||||||
wgn.add_statement(f'{mtyp}.load')
|
wgn.add_statement(f'{mtyp}.load')
|
||||||
@ -553,17 +562,18 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
|
|
||||||
offset = 0
|
offset = 0
|
||||||
for el_type in tp_args[0:inp.index.value]:
|
for el_type in tp_args[0:inp.index.value]:
|
||||||
assert el_type is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(el_type, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
offset += calculate_alloc_size(el_type)
|
offset += calculate_alloc_size(el_type)
|
||||||
|
|
||||||
el_type = tp_args[inp.index.value]
|
el_type = tp_args[inp.index.value]
|
||||||
assert el_type is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(el_type, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
expression(wgn, inp.varref)
|
expression(wgn, inp.varref)
|
||||||
|
|
||||||
if (prelude.InternalPassAsPointer, (el_type, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
if (prelude.InternalPassAsPointer, (el_type, )) in prelude.PRELUDE_TYPE_CLASS_INSTANCES_EXISTING:
|
||||||
mtyp = 'i32'
|
mtyp = 'i32'
|
||||||
else:
|
else:
|
||||||
|
assert isinstance(el_type, type3types.Type3), NotImplementedError('Tuple of applied types / structs')
|
||||||
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
|
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
|
||||||
|
|
||||||
wgn.add_statement(f'{mtyp}.load', f'offset={offset}')
|
wgn.add_statement(f'{mtyp}.load', f'offset={offset}')
|
||||||
@ -572,13 +582,14 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
|||||||
raise NotImplementedError(expression, inp, inp.varref.type3)
|
raise NotImplementedError(expression, inp, inp.varref.type3)
|
||||||
|
|
||||||
if isinstance(inp, ourlang.AccessStructMember):
|
if isinstance(inp, ourlang.AccessStructMember):
|
||||||
assert inp.struct_type3 is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.struct_type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
st_args = prelude.struct.did_construct(inp.struct_type3)
|
st_args = prelude.struct.did_construct(inp.struct_type3)
|
||||||
assert st_args is not None
|
assert st_args is not None
|
||||||
|
|
||||||
member_type = st_args[inp.member]
|
member_type = st_args[inp.member]
|
||||||
|
|
||||||
|
assert isinstance(member_type, type3types.Type3), NotImplementedError('Tuple of applied types / structs')
|
||||||
mtyp = LOAD_STORE_TYPE_MAP[member_type.name]
|
mtyp = LOAD_STORE_TYPE_MAP[member_type.name]
|
||||||
|
|
||||||
expression(wgn, inp.varref)
|
expression(wgn, inp.varref)
|
||||||
@ -597,7 +608,7 @@ def expression_fold(wgn: WasmGenerator, inp: ourlang.Fold) -> None:
|
|||||||
"""
|
"""
|
||||||
Compile: Fold expression
|
Compile: Fold expression
|
||||||
"""
|
"""
|
||||||
assert inp.type3 is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(inp.type3, type3types.Type3), type3placeholders.TYPE3_ASSERTION_ERROR
|
||||||
|
|
||||||
if inp.iter.type3 is not prelude.bytes_:
|
if inp.iter.type3 is not prelude.bytes_:
|
||||||
raise NotImplementedError(expression_fold, inp, inp.iter.type3)
|
raise NotImplementedError(expression_fold, inp, inp.iter.type3)
|
||||||
@ -828,7 +839,7 @@ def module_data(inp: ourlang.ModuleData) -> bytes:
|
|||||||
data_list: List[bytes] = []
|
data_list: List[bytes] = []
|
||||||
|
|
||||||
for constant in block.data:
|
for constant in block.data:
|
||||||
assert constant.type3 is not None, TYPE3_ASSERTION_ERROR
|
assert isinstance(constant.type3, type3types.Type3), (id(constant), type3placeholders.TYPE3_ASSERTION_ERROR)
|
||||||
|
|
||||||
if isinstance(constant, ourlang.ConstantMemoryStored) and block is not constant.data_block:
|
if isinstance(constant, ourlang.ConstantMemoryStored) and block is not constant.data_block:
|
||||||
# It's stored in a different block
|
# It's stored in a different block
|
||||||
|
|||||||
@ -6,6 +6,7 @@ from typing import Dict, Iterable, List, Optional, Union
|
|||||||
|
|
||||||
from . import prelude
|
from . import prelude
|
||||||
from .type3.functions import FunctionSignature, TypeVariableContext
|
from .type3.functions import FunctionSignature, TypeVariableContext
|
||||||
|
from .type3.placeholders import PlaceholderForType, Type3OrPlaceholder
|
||||||
from .type3.typeclasses import Type3ClassMethod
|
from .type3.typeclasses import Type3ClassMethod
|
||||||
from .type3.types import Type3
|
from .type3.types import Type3
|
||||||
|
|
||||||
@ -16,10 +17,10 @@ class Expression:
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('type3', )
|
__slots__ = ('type3', )
|
||||||
|
|
||||||
type3: Type3 | None
|
type3: Type3OrPlaceholder
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.type3 = None
|
self.type3 = PlaceholderForType([self])
|
||||||
|
|
||||||
class Constant(Expression):
|
class Constant(Expression):
|
||||||
"""
|
"""
|
||||||
@ -197,10 +198,10 @@ class AccessStructMember(Expression):
|
|||||||
__slots__ = ('varref', 'struct_type3', 'member', )
|
__slots__ = ('varref', 'struct_type3', 'member', )
|
||||||
|
|
||||||
varref: VariableReference
|
varref: VariableReference
|
||||||
struct_type3: Type3
|
struct_type3: Type3OrPlaceholder
|
||||||
member: str
|
member: str
|
||||||
|
|
||||||
def __init__(self, varref: VariableReference, struct_type3: Type3, member: str) -> None:
|
def __init__(self, varref: VariableReference, struct_type3: Type3OrPlaceholder, member: str) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.varref = varref
|
self.varref = varref
|
||||||
@ -283,7 +284,7 @@ class FunctionParam:
|
|||||||
__slots__ = ('name', 'type3', )
|
__slots__ = ('name', 'type3', )
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
type3: Type3
|
type3: Type3OrPlaceholder
|
||||||
|
|
||||||
def __init__(self, name: str, type3: Type3) -> None:
|
def __init__(self, name: str, type3: Type3) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|||||||
@ -163,8 +163,8 @@ class OurVisitor:
|
|||||||
|
|
||||||
arg_type = self.visit_type(module, arg.annotation)
|
arg_type = self.visit_type(module, arg.annotation)
|
||||||
|
|
||||||
# FIXME: Allow TypeVariable in the function signature
|
# if isisntance(arg_type, TypeVariable):
|
||||||
# This would also require FunctionParam to accept a placeholder
|
# arg_type = PlaceHolderForType()
|
||||||
|
|
||||||
function.signature.args.append(arg_type)
|
function.signature.args.append(arg_type)
|
||||||
function.posonlyargs.append(FunctionParam(
|
function.posonlyargs.append(FunctionParam(
|
||||||
|
|||||||
@ -3,11 +3,10 @@ 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 Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
from .. import ourlang, prelude
|
from .. import ourlang, prelude
|
||||||
from . import placeholders, typeclasses, types
|
from . import placeholders, typeclasses, types
|
||||||
from .placeholders import PlaceholderForType
|
|
||||||
|
|
||||||
|
|
||||||
class Error:
|
class Error:
|
||||||
@ -158,7 +157,7 @@ class SameTypeConstraint(ConstraintBase):
|
|||||||
return f'SameTypeConstraint({args}, comment={repr(self.comment)})'
|
return f'SameTypeConstraint({args}, comment={repr(self.comment)})'
|
||||||
|
|
||||||
class TupleMatchConstraint(ConstraintBase):
|
class TupleMatchConstraint(ConstraintBase):
|
||||||
def __init__(self, exp_type: placeholders.Type3OrPlaceholder, args: Iterable[placeholders.Type3OrPlaceholder], comment: str):
|
def __init__(self, exp_type: placeholders.Type3OrPlaceholder, args: List[placeholders.Type3OrPlaceholder], comment: str):
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
self.exp_type = exp_type
|
self.exp_type = exp_type
|
||||||
@ -349,12 +348,8 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
LiteralFitsConstraint(x, y)
|
LiteralFitsConstraint(x, y)
|
||||||
for x, y in zip(tp_args, self.literal.value, strict=True)
|
for x, y in zip(tp_args, self.literal.value, strict=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate placeholders so each Literal expression
|
|
||||||
# gets updated when we figure out the type of the
|
|
||||||
# expression the literal is used in
|
|
||||||
res.extend(
|
res.extend(
|
||||||
SameTypeConstraint(x, PlaceholderForType([y]))
|
SameTypeConstraint(x, y.type3)
|
||||||
for x, y in zip(tp_args, self.literal.value, strict=True)
|
for x, y in zip(tp_args, self.literal.value, strict=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -376,12 +371,8 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
LiteralFitsConstraint(sa_type, y)
|
LiteralFitsConstraint(sa_type, y)
|
||||||
for y in self.literal.value
|
for y in self.literal.value
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate placeholders so each Literal expression
|
|
||||||
# gets updated when we figure out the type of the
|
|
||||||
# expression the literal is used in
|
|
||||||
res.extend(
|
res.extend(
|
||||||
SameTypeConstraint(sa_type, PlaceholderForType([y]))
|
SameTypeConstraint(sa_type, y.type3)
|
||||||
for y in self.literal.value
|
for y in self.literal.value
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -405,12 +396,8 @@ class LiteralFitsConstraint(ConstraintBase):
|
|||||||
LiteralFitsConstraint(x, y)
|
LiteralFitsConstraint(x, y)
|
||||||
for x, y in zip(st_args.values(), self.literal.value, strict=True)
|
for x, y in zip(st_args.values(), self.literal.value, strict=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate placeholders so each Literal expression
|
|
||||||
# gets updated when we figure out the type of the
|
|
||||||
# expression the literal is used in
|
|
||||||
res.extend(
|
res.extend(
|
||||||
SameTypeConstraint(x_t, PlaceholderForType([y]), comment=f'{self.literal.struct_name}.{x_n}')
|
SameTypeConstraint(x_t, y.type3, comment=f'{self.literal.struct_name}.{x_n}')
|
||||||
for (x_n, x_t, ), y in zip(st_args.items(), self.literal.value, strict=True)
|
for (x_n, x_t, ), y in zip(st_args.items(), self.literal.value, strict=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -434,27 +421,20 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
|||||||
"""
|
"""
|
||||||
A value that is subscipted, i.e. a[0] (tuple) or a[b] (static array)
|
A value that is subscipted, i.e. a[0] (tuple) or a[b] (static array)
|
||||||
"""
|
"""
|
||||||
__slots__ = ('ret_type3', 'type3', 'index', 'index_phft', )
|
__slots__ = ('ret_type3', 'type3', 'index', 'index_type3', )
|
||||||
|
|
||||||
ret_type3: placeholders.Type3OrPlaceholder
|
ret_type3: placeholders.Type3OrPlaceholder
|
||||||
type3: placeholders.Type3OrPlaceholder
|
type3: placeholders.Type3OrPlaceholder
|
||||||
index: ourlang.Expression
|
index: ourlang.Expression
|
||||||
index_phft: placeholders.Type3OrPlaceholder
|
index_type3: placeholders.Type3OrPlaceholder
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, ret_type3: placeholders.Type3OrPlaceholder, type3: placeholders.Type3OrPlaceholder, index: ourlang.Expression, comment: Optional[str] = None) -> None:
|
||||||
self,
|
|
||||||
ret_type3: placeholders.PlaceholderForType,
|
|
||||||
type3: placeholders.PlaceholderForType,
|
|
||||||
index: ourlang.Expression,
|
|
||||||
index_phft: placeholders.PlaceholderForType,
|
|
||||||
comment: Optional[str] = None,
|
|
||||||
) -> None:
|
|
||||||
super().__init__(comment=comment)
|
super().__init__(comment=comment)
|
||||||
|
|
||||||
self.ret_type3 = ret_type3
|
self.ret_type3 = ret_type3
|
||||||
self.type3 = type3
|
self.type3 = type3
|
||||||
self.index = index
|
self.index = index
|
||||||
self.index_phft = index_phft
|
self.index_type3 = index.type3
|
||||||
|
|
||||||
def check(self) -> CheckResult:
|
def check(self) -> CheckResult:
|
||||||
exp_type = self.type3
|
exp_type = self.type3
|
||||||
@ -471,7 +451,7 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
|||||||
sa_type, sa_len = sa_args
|
sa_type, sa_len = sa_args
|
||||||
|
|
||||||
result: List[ConstraintBase] = [
|
result: List[ConstraintBase] = [
|
||||||
SameTypeConstraint(prelude.u32, self.index_phft, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
||||||
SameTypeConstraint(sa_type, self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
SameTypeConstraint(sa_type, self.ret_type3, comment='([]) :: Subscriptable a => a b -> u32 -> b'),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -498,13 +478,13 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
|||||||
return Error('Tuple index out of range')
|
return Error('Tuple index out of range')
|
||||||
|
|
||||||
return [
|
return [
|
||||||
SameTypeConstraint(prelude.u32, self.index_phft, comment=f'Tuple subscript index {self.index.value}'),
|
SameTypeConstraint(prelude.u32, self.index_type3, comment=f'Tuple subscript index {self.index.value}'),
|
||||||
SameTypeConstraint(tp_args[self.index.value], self.ret_type3, comment=f'Tuple subscript index {self.index.value}'),
|
SameTypeConstraint(tp_args[self.index.value], self.ret_type3, comment=f'Tuple subscript index {self.index.value}'),
|
||||||
]
|
]
|
||||||
|
|
||||||
if exp_type is prelude.bytes_:
|
if exp_type is prelude.bytes_:
|
||||||
return [
|
return [
|
||||||
SameTypeConstraint(prelude.u32, self.index_phft, comment='([]) :: bytes -> u32 -> u8'),
|
SameTypeConstraint(prelude.u32, self.index_type3, comment='([]) :: bytes -> u32 -> u8'),
|
||||||
SameTypeConstraint(prelude.u8, self.ret_type3, comment='([]) :: bytes -> u32 -> u8'),
|
SameTypeConstraint(prelude.u8, self.ret_type3, comment='([]) :: bytes -> u32 -> u8'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,6 @@ from .constraints import (
|
|||||||
SameTypeConstraint,
|
SameTypeConstraint,
|
||||||
TupleMatchConstraint,
|
TupleMatchConstraint,
|
||||||
)
|
)
|
||||||
from .placeholders import PlaceholderForType
|
|
||||||
|
|
||||||
ConstraintGenerator = Generator[ConstraintBase, None, None]
|
ConstraintGenerator = Generator[ConstraintBase, None, None]
|
||||||
|
|
||||||
@ -29,23 +28,23 @@ def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase
|
|||||||
|
|
||||||
return [*module(ctx, inp)]
|
return [*module(ctx, inp)]
|
||||||
|
|
||||||
def constant(ctx: Context, inp: ourlang.Constant, phft: placeholders.PlaceholderForType) -> ConstraintGenerator:
|
def constant(ctx: Context, inp: ourlang.Constant) -> ConstraintGenerator:
|
||||||
if isinstance(inp, (ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct)):
|
if isinstance(inp, (ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct)):
|
||||||
yield LiteralFitsConstraint(
|
yield LiteralFitsConstraint(
|
||||||
phft, inp,
|
inp.type3, inp,
|
||||||
comment='The given literal must fit the expected type'
|
comment='The given literal must fit the expected type'
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
raise NotImplementedError(constant, inp)
|
raise NotImplementedError(constant, inp)
|
||||||
|
|
||||||
def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.PlaceholderForType) -> ConstraintGenerator:
|
def expression(ctx: Context, inp: ourlang.Expression) -> ConstraintGenerator:
|
||||||
if isinstance(inp, ourlang.Constant):
|
if isinstance(inp, ourlang.Constant):
|
||||||
yield from constant(ctx, inp, phft)
|
yield from constant(ctx, inp)
|
||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.VariableReference):
|
if isinstance(inp, ourlang.VariableReference):
|
||||||
yield SameTypeConstraint(inp.variable.type3, phft,
|
yield SameTypeConstraint(inp.variable.type3, inp.type3,
|
||||||
comment=f'typeOf("{inp.variable.name}") == typeOf({inp.variable.name})')
|
comment=f'typeOf("{inp.variable.name}") == typeOf({inp.variable.name})')
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -61,14 +60,8 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
|||||||
if isinstance(x, functions.TypeVariable)
|
if isinstance(x, functions.TypeVariable)
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_placeholders = {
|
for call_arg in arguments:
|
||||||
arg_expr: PlaceholderForType([arg_expr])
|
yield from expression(ctx, call_arg)
|
||||||
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:
|
for constraint in signature.context.constraints:
|
||||||
if isinstance(constraint, functions.Constraint_TypeClassInstanceExists):
|
if isinstance(constraint, functions.Constraint_TypeClassInstanceExists):
|
||||||
@ -88,11 +81,11 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
|||||||
comment = f'The type of the value passed to argument {arg_no} of function {func_name} should match the type of that argument'
|
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):
|
if isinstance(sig_part, functions.TypeVariable):
|
||||||
yield SameTypeConstraint(type_var_map[sig_part], arg_placeholders[arg_expr], comment=comment)
|
yield SameTypeConstraint(type_var_map[sig_part], arg_expr.type3, comment=comment)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(sig_part, type3types.Type3):
|
if isinstance(sig_part, type3types.Type3):
|
||||||
yield SameTypeConstraint(sig_part, arg_placeholders[arg_expr], comment=comment)
|
yield SameTypeConstraint(sig_part, arg_expr.type3, comment=comment)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
raise NotImplementedError(sig_part)
|
raise NotImplementedError(sig_part)
|
||||||
@ -101,12 +94,11 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
|||||||
if isinstance(inp, ourlang.TupleInstantiation):
|
if isinstance(inp, ourlang.TupleInstantiation):
|
||||||
r_type = []
|
r_type = []
|
||||||
for arg in inp.elements:
|
for arg in inp.elements:
|
||||||
arg_phft = PlaceholderForType([arg])
|
yield from expression(ctx, arg)
|
||||||
yield from expression(ctx, arg, arg_phft)
|
r_type.append(arg.type3)
|
||||||
r_type.append(arg_phft)
|
|
||||||
|
|
||||||
yield TupleMatchConstraint(
|
yield TupleMatchConstraint(
|
||||||
phft,
|
inp.type3,
|
||||||
r_type,
|
r_type,
|
||||||
comment='The type of a tuple is a combination of its members'
|
comment='The type of a tuple is a combination of its members'
|
||||||
)
|
)
|
||||||
@ -114,13 +106,10 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
|||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.Subscript):
|
if isinstance(inp, ourlang.Subscript):
|
||||||
varref_phft = PlaceholderForType([inp.varref])
|
yield from expression(ctx, inp.varref)
|
||||||
index_phft = PlaceholderForType([inp.index])
|
yield from expression(ctx, inp.index)
|
||||||
|
|
||||||
yield from expression(ctx, inp.varref, varref_phft)
|
yield CanBeSubscriptedConstraint(inp.type3, inp.varref.type3, inp.index)
|
||||||
yield from expression(ctx, inp.index, index_phft)
|
|
||||||
|
|
||||||
yield CanBeSubscriptedConstraint(phft, varref_phft, inp.index, index_phft)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.AccessStructMember):
|
if isinstance(inp, ourlang.AccessStructMember):
|
||||||
@ -128,40 +117,33 @@ def expression(ctx: Context, inp: ourlang.Expression, phft: placeholders.Placeho
|
|||||||
st_args = prelude.struct.did_construct(inp.struct_type3)
|
st_args = prelude.struct.did_construct(inp.struct_type3)
|
||||||
assert st_args is not None # FIXME: See test_struct.py::test_struct_not_accessible
|
assert st_args is not None # FIXME: See test_struct.py::test_struct_not_accessible
|
||||||
|
|
||||||
yield from expression(ctx, inp.varref, PlaceholderForType([inp.varref])) # TODO
|
yield from expression(ctx, inp.varref)
|
||||||
yield SameTypeConstraint(st_args[inp.member], phft,
|
yield SameTypeConstraint(st_args[inp.member], inp.type3,
|
||||||
comment=f'The type of a struct member reference is the same as the type of struct member {inp.struct_type3.name}.{inp.member}')
|
comment=f'The type of a struct member reference is the same as the type of struct member {inp.struct_type3.name}.{inp.member}')
|
||||||
return
|
return
|
||||||
|
|
||||||
if isinstance(inp, ourlang.Fold):
|
if isinstance(inp, ourlang.Fold):
|
||||||
base_phft = PlaceholderForType([inp.base])
|
yield from expression(ctx, inp.base)
|
||||||
iter_phft = PlaceholderForType([inp.iter])
|
yield from expression(ctx, inp.iter)
|
||||||
|
|
||||||
yield from expression(ctx, inp.base, base_phft)
|
yield SameTypeConstraint(inp.func.posonlyargs[0].type3, inp.func.returns_type3, inp.base.type3, inp.type3,
|
||||||
yield from expression(ctx, inp.iter, iter_phft)
|
|
||||||
|
|
||||||
yield SameTypeConstraint(inp.func.posonlyargs[0].type3, inp.func.returns_type3, base_phft, phft,
|
|
||||||
comment='foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b')
|
comment='foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b')
|
||||||
yield MustImplementTypeClassConstraint(ctx, 'Foldable', [iter_phft])
|
yield MustImplementTypeClassConstraint(ctx, 'Foldable', [inp.iter.type3])
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
raise NotImplementedError(expression, inp)
|
raise NotImplementedError(expression, inp)
|
||||||
|
|
||||||
def statement_return(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementReturn) -> ConstraintGenerator:
|
def statement_return(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementReturn) -> ConstraintGenerator:
|
||||||
phft = PlaceholderForType([inp.value])
|
yield from expression(ctx, inp.value)
|
||||||
|
|
||||||
yield from expression(ctx, inp.value, phft)
|
yield SameTypeConstraint(fun.returns_type3, inp.value.type3,
|
||||||
|
|
||||||
yield SameTypeConstraint(fun.returns_type3, phft,
|
|
||||||
comment=f'The type of the value returned from function {fun.name} should match its return type')
|
comment=f'The type of the value returned from function {fun.name} should match its return type')
|
||||||
|
|
||||||
def statement_if(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementIf) -> ConstraintGenerator:
|
def statement_if(ctx: Context, fun: ourlang.Function, inp: ourlang.StatementIf) -> ConstraintGenerator:
|
||||||
test_phft = PlaceholderForType([inp.test])
|
yield from expression(ctx, inp.test)
|
||||||
|
|
||||||
yield from expression(ctx, inp.test, test_phft)
|
yield SameTypeConstraint(inp.test.type3, prelude.bool_,
|
||||||
|
|
||||||
yield SameTypeConstraint(test_phft, prelude.bool_,
|
|
||||||
comment='Must pass a boolean expression to if')
|
comment='Must pass a boolean expression to if')
|
||||||
|
|
||||||
for stmt in inp.statements:
|
for stmt in inp.statements:
|
||||||
@ -191,10 +173,8 @@ def function(ctx: Context, inp: ourlang.Function) -> ConstraintGenerator:
|
|||||||
yield from statement(ctx, inp, stmt)
|
yield from statement(ctx, inp, stmt)
|
||||||
|
|
||||||
def module_constant_def(ctx: Context, inp: ourlang.ModuleConstantDef) -> ConstraintGenerator:
|
def module_constant_def(ctx: Context, inp: ourlang.ModuleConstantDef) -> ConstraintGenerator:
|
||||||
phft = PlaceholderForType([inp.constant])
|
yield from constant(ctx, inp.constant)
|
||||||
|
yield SameTypeConstraint(inp.type3, inp.constant.type3,
|
||||||
yield from constant(ctx, inp.constant, phft)
|
|
||||||
yield SameTypeConstraint(inp.type3, phft,
|
|
||||||
comment=f'The type of the value for module constant definition {inp.name} should match the type of that constant')
|
comment=f'The type of the value for module constant definition {inp.name} should match the type of that constant')
|
||||||
|
|
||||||
def module(ctx: Context, inp: ourlang.Module) -> ConstraintGenerator:
|
def module(ctx: Context, inp: ourlang.Module) -> ConstraintGenerator:
|
||||||
|
|||||||
@ -115,6 +115,8 @@ def phasm_type3(inp: ourlang.Module, verbose: bool = False) -> None:
|
|||||||
# FIXME: This doesn't work with e.g. `:: [a] -> a`, as the placeholder is inside a type
|
# FIXME: This doesn't work with e.g. `:: [a] -> a`, as the placeholder is inside a type
|
||||||
for plh, typ in placeholder_substitutes.items():
|
for plh, typ in placeholder_substitutes.items():
|
||||||
for expr in plh.update_on_substitution:
|
for expr in plh.update_on_substitution:
|
||||||
|
assert expr.type3 is plh
|
||||||
|
|
||||||
expr.type3 = typ
|
expr.type3 = typ
|
||||||
|
|
||||||
def print_constraint(placeholder_id_map: Dict[int, str], constraint: ConstraintBase) -> None:
|
def print_constraint(placeholder_id_map: Dict[int, str], constraint: ConstraintBase) -> None:
|
||||||
|
|||||||
@ -7,13 +7,14 @@ from typing import Any, Iterable, List, Optional, Protocol, Union
|
|||||||
|
|
||||||
from .types import Type3
|
from .types import Type3
|
||||||
|
|
||||||
|
TYPE3_ASSERTION_ERROR = 'You must call phasm_type3 after calling phasm_parse before you can call any other method'
|
||||||
|
|
||||||
class ExpressionProtocol(Protocol):
|
class ExpressionProtocol(Protocol):
|
||||||
"""
|
"""
|
||||||
A protocol for classes that should be updated on substitution
|
A protocol for classes that should be updated on substitution
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type3: Type3 | None
|
type3: 'Type3OrPlaceholder'
|
||||||
"""
|
"""
|
||||||
The type to update
|
The type to update
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -5,6 +5,7 @@ from typing import Any, Generator, Iterable, List, TextIO, Union
|
|||||||
from phasm import compiler, prelude
|
from phasm import compiler, prelude
|
||||||
from phasm.codestyle import phasm_render
|
from phasm.codestyle import phasm_render
|
||||||
from phasm.runtime import calculate_alloc_size
|
from phasm.runtime import calculate_alloc_size
|
||||||
|
from phasm.type3 import placeholders as type3placeholders
|
||||||
from phasm.type3 import types as type3types
|
from phasm.type3 import types as type3types
|
||||||
|
|
||||||
from . import runners
|
from . import runners
|
||||||
@ -64,6 +65,9 @@ class Suite:
|
|||||||
runner.interpreter_dump_memory(sys.stderr)
|
runner.interpreter_dump_memory(sys.stderr)
|
||||||
|
|
||||||
for arg, arg_typ in zip(args, func_args, strict=True):
|
for arg, arg_typ in zip(args, func_args, strict=True):
|
||||||
|
assert not isinstance(arg_typ, type3placeholders.PlaceholderForType), \
|
||||||
|
'Cannot call polymorphic function from outside'
|
||||||
|
|
||||||
if arg_typ in (prelude.u8, prelude.u32, prelude.u64, ):
|
if arg_typ in (prelude.u8, prelude.u32, prelude.u64, ):
|
||||||
assert isinstance(arg, int)
|
assert isinstance(arg, int)
|
||||||
wasm_args.append(arg)
|
wasm_args.append(arg)
|
||||||
@ -84,6 +88,7 @@ class Suite:
|
|||||||
wasm_args.append(adr)
|
wasm_args.append(adr)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
assert isinstance(arg_typ, type3types.Type3)
|
||||||
sa_args = prelude.static_array.did_construct(arg_typ)
|
sa_args = prelude.static_array.did_construct(arg_typ)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
adr = _allocate_memory_stored_value(runner, arg_typ, arg)
|
adr = _allocate_memory_stored_value(runner, arg_typ, arg)
|
||||||
@ -217,6 +222,8 @@ def _allocate_memory_stored_value(
|
|||||||
|
|
||||||
offset = adr
|
offset = adr
|
||||||
for val_el_val, val_el_typ in zip(val, tp_args, strict=True):
|
for val_el_val, val_el_typ in zip(val, tp_args, strict=True):
|
||||||
|
assert not isinstance(val_el_typ, type3placeholders.PlaceholderForType)
|
||||||
|
|
||||||
offset += _write_memory_stored_value(runner, offset, val_el_typ, val_el_val)
|
offset += _write_memory_stored_value(runner, offset, val_el_typ, val_el_val)
|
||||||
return adr
|
return adr
|
||||||
|
|
||||||
@ -233,6 +240,8 @@ def _allocate_memory_stored_value(
|
|||||||
|
|
||||||
offset = adr
|
offset = adr
|
||||||
for val_el_name, val_el_typ in st_args.items():
|
for val_el_name, val_el_typ in st_args.items():
|
||||||
|
assert not isinstance(val_el_typ, type3placeholders.PlaceholderForType)
|
||||||
|
|
||||||
val_el_val = val[val_el_name]
|
val_el_val = val[val_el_name]
|
||||||
offset += _write_memory_stored_value(runner, offset, val_el_typ, val_el_val)
|
offset += _write_memory_stored_value(runner, offset, val_el_typ, val_el_val)
|
||||||
return adr
|
return adr
|
||||||
@ -290,6 +299,8 @@ def _load_memory_stored_returned_value(
|
|||||||
|
|
||||||
return _load_bytes_from_address(runner, ret_type3, wasm_value)
|
return _load_bytes_from_address(runner, ret_type3, wasm_value)
|
||||||
|
|
||||||
|
assert isinstance(ret_type3, type3types.Type3) # Type hint
|
||||||
|
|
||||||
sa_args = prelude.static_array.did_construct(ret_type3)
|
sa_args = prelude.static_array.did_construct(ret_type3)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
assert isinstance(wasm_value, int), wasm_value
|
assert isinstance(wasm_value, int), wasm_value
|
||||||
@ -355,6 +366,8 @@ def _unpack(runner: runners.RunnerBase, typ: type3types.Type3, inp: bytes) -> An
|
|||||||
assert len(inp) == 4
|
assert len(inp) == 4
|
||||||
adr = struct.unpack('<I', inp)[0]
|
adr = struct.unpack('<I', inp)[0]
|
||||||
|
|
||||||
|
assert isinstance(typ, type3types.Type3)
|
||||||
|
|
||||||
sa_args = prelude.static_array.did_construct(typ)
|
sa_args = prelude.static_array.did_construct(typ)
|
||||||
if sa_args is not None:
|
if sa_args is not None:
|
||||||
sa_type, sa_len = sa_args
|
sa_type, sa_len = sa_args
|
||||||
@ -391,6 +404,9 @@ def _split_read_bytes(all_bytes: bytes, split_sizes: Iterable[int]) -> Generator
|
|||||||
def _load_static_array_from_address(runner: runners.RunnerBase, sub_typ: type3types.Type3, len_typ: type3types.IntType3, adr: int) -> Any:
|
def _load_static_array_from_address(runner: runners.RunnerBase, sub_typ: type3types.Type3, len_typ: type3types.IntType3, adr: int) -> Any:
|
||||||
sys.stderr.write(f'Reading 0x{adr:08x} {sub_typ:s} {len_typ:s}\n')
|
sys.stderr.write(f'Reading 0x{adr:08x} {sub_typ:s} {len_typ:s}\n')
|
||||||
|
|
||||||
|
assert not isinstance(sub_typ, type3placeholders.PlaceholderForType)
|
||||||
|
assert isinstance(len_typ, type3types.IntType3)
|
||||||
|
|
||||||
sa_len = len_typ.value
|
sa_len = len_typ.value
|
||||||
|
|
||||||
arg_size_1 = calculate_alloc_size(sub_typ, is_member=True)
|
arg_size_1 = calculate_alloc_size(sub_typ, is_member=True)
|
||||||
|
|||||||
@ -6,20 +6,7 @@ from ..helpers import Suite
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_expr_constant_literal_does_not_fit_module_constant():
|
def test_expr_constant_literal_does_not_fit():
|
||||||
code_py = """
|
|
||||||
CONSTANT: u8 = 1000
|
|
||||||
|
|
||||||
@exported
|
|
||||||
def testEntry() -> u8:
|
|
||||||
return CONSTANT
|
|
||||||
"""
|
|
||||||
|
|
||||||
with pytest.raises(Type3Exception, match=r'Must fit in 1 byte\(s\)'):
|
|
||||||
Suite(code_py).run_code()
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
|
||||||
def test_expr_constant_literal_does_not_fit_return():
|
|
||||||
code_py = """
|
code_py = """
|
||||||
@exported
|
@exported
|
||||||
def testEntry() -> u8:
|
def testEntry() -> u8:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user