Compare commits
1 Commits
da6e306fad
...
6231c6b279
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6231c6b279 |
@ -108,12 +108,16 @@ def expression(inp: ourlang.Expression) -> str:
|
||||
if isinstance(inp.function, ourlang.StructConstructor):
|
||||
return f'{inp.function.struct_type3.name}({args})'
|
||||
|
||||
# TODO: Broken after new type system
|
||||
# if isinstance(inp.function, ourlang.TupleConstructor):
|
||||
# return f'({args}, )'
|
||||
|
||||
return f'{inp.function.name}({args})'
|
||||
|
||||
if isinstance(inp, ourlang.TupleInstantiation):
|
||||
args = ', '.join(
|
||||
expression(arg)
|
||||
for arg in inp.elements
|
||||
)
|
||||
|
||||
return f'({args}, )'
|
||||
|
||||
if isinstance(inp, ourlang.Subscript):
|
||||
varref = expression(inp.varref)
|
||||
index = expression(inp.index)
|
||||
|
||||
@ -80,6 +80,10 @@ def type3(inp: type3types.Type3OrPlaceholder) -> wasm.WasmType:
|
||||
# Static Arrays are passed as pointer, which are i32
|
||||
return wasm.WasmTypeInt32()
|
||||
|
||||
if inp.base == type3types.tuple:
|
||||
# Tuples are passed as pointer, which are i32
|
||||
return wasm.WasmTypeInt32()
|
||||
|
||||
raise NotImplementedError(type3, inp)
|
||||
|
||||
# Operators that work for i32, i64, f32, f64
|
||||
@ -150,6 +154,45 @@ F64_OPERATOR_MAP = {
|
||||
'/': 'div' # Division by zero is a trap and the program will panic
|
||||
}
|
||||
|
||||
def tuple_instantiation(wgn: WasmGenerator, inp: ourlang.TupleInstantiation) -> None:
|
||||
assert isinstance(inp.type3, type3types.AppliedType3)
|
||||
assert inp.type3.base is type3types.tuple
|
||||
assert len(inp.elements) == len(inp.type3.args)
|
||||
|
||||
comment_elements = ''
|
||||
for element in inp.elements:
|
||||
assert isinstance(element.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
||||
comment_elements += f'{element.type3.name}, '
|
||||
|
||||
tmp_var = wgn.temp_var_i32('tuple_adr')
|
||||
wgn.add_statement('nop', comment=f'tmp_var := ({comment_elements})')
|
||||
|
||||
# Allocated the required amounts of bytes in memory
|
||||
wgn.i32.const(_calculate_alloc_size(inp.type3))
|
||||
wgn.call(stdlib_alloc.__alloc__)
|
||||
wgn.local.set(tmp_var)
|
||||
|
||||
# Store each element individually
|
||||
offset = 0
|
||||
for element, exp_type3 in zip(inp.elements, inp.type3.args):
|
||||
if isinstance(exp_type3, type3types.PlaceholderForType):
|
||||
assert exp_type3.resolve_as is not None
|
||||
exp_type3 = exp_type3.resolve_as
|
||||
|
||||
assert element.type3 == exp_type3
|
||||
|
||||
assert isinstance(exp_type3, type3types.PrimitiveType3), NotImplementedError('Tuple of applied types / structs')
|
||||
mtyp = LOAD_STORE_TYPE_MAP[exp_type3.name]
|
||||
|
||||
wgn.local.get(tmp_var)
|
||||
expression(wgn, element)
|
||||
wgn.add_statement(f'{mtyp}.store', 'offset=' + str(offset))
|
||||
|
||||
offset += _calculate_alloc_size(exp_type3)
|
||||
|
||||
# Return the allocated address
|
||||
wgn.local.get(tmp_var)
|
||||
|
||||
def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
"""
|
||||
Compile: Any expression
|
||||
@ -311,6 +354,10 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
wgn.add_statement('call', '${}'.format(inp.function.name))
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.TupleInstantiation):
|
||||
tuple_instantiation(wgn, inp)
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.Subscript):
|
||||
assert isinstance(inp.varref.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR
|
||||
|
||||
@ -336,11 +383,8 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
wgn.i32.mul()
|
||||
wgn.i32.add()
|
||||
|
||||
mtyp = LOAD_STORE_TYPE_MAP.get(el_type.name)
|
||||
if mtyp is None:
|
||||
# In the future might extend this by having structs or tuples
|
||||
# as members of struct or tuples
|
||||
raise NotImplementedError(expression, inp, el_type)
|
||||
assert isinstance(el_type, type3types.PrimitiveType3), NotImplementedError('Tuple of applied types / structs')
|
||||
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
|
||||
|
||||
wgn.add_statement(f'{mtyp}.load')
|
||||
return
|
||||
@ -360,11 +404,8 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
|
||||
expression(wgn, inp.varref)
|
||||
|
||||
mtyp = LOAD_STORE_TYPE_MAP.get(el_type.name)
|
||||
if mtyp is None:
|
||||
# In the future might extend this by having structs or tuples
|
||||
# as members of struct or tuples
|
||||
raise NotImplementedError(expression, inp, el_type)
|
||||
assert isinstance(el_type, type3types.PrimitiveType3), NotImplementedError('Tuple of applied types / structs')
|
||||
mtyp = LOAD_STORE_TYPE_MAP[el_type.name]
|
||||
|
||||
wgn.add_statement(f'{mtyp}.load', f'offset={offset}')
|
||||
return
|
||||
@ -372,11 +413,8 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
raise NotImplementedError(expression, inp, inp.varref.type3)
|
||||
|
||||
if isinstance(inp, ourlang.AccessStructMember):
|
||||
mtyp = LOAD_STORE_TYPE_MAP.get(inp.struct_type3.members[inp.member].name)
|
||||
if mtyp is None:
|
||||
# In the future might extend this by having structs or tuples
|
||||
# as members of struct or tuples
|
||||
raise NotImplementedError(expression, inp, inp.struct_type3)
|
||||
assert isinstance(inp.struct_type3.members[inp.member], type3types.PrimitiveType3), NotImplementedError('Tuple of applied types / structs')
|
||||
mtyp = LOAD_STORE_TYPE_MAP[inp.struct_type3.members[inp.member].name]
|
||||
|
||||
expression(wgn, inp.varref)
|
||||
wgn.add_statement(f'{mtyp}.load', 'offset=' + str(_calculate_member_offset(
|
||||
@ -538,9 +576,7 @@ def function(inp: ourlang.Function) -> wasm.Function:
|
||||
|
||||
wgn = WasmGenerator()
|
||||
|
||||
if False: # TODO: isinstance(inp, ourlang.TupleConstructor):
|
||||
pass # _generate_tuple_constructor(wgn, inp)
|
||||
elif isinstance(inp, ourlang.StructConstructor):
|
||||
if isinstance(inp, ourlang.StructConstructor):
|
||||
_generate_struct_constructor(wgn, inp)
|
||||
else:
|
||||
for stat in inp.statements:
|
||||
@ -706,30 +742,6 @@ def module(inp: ourlang.Module) -> wasm.Module:
|
||||
|
||||
return result
|
||||
|
||||
# TODO: Broken after new type system
|
||||
# def _generate_tuple_constructor(wgn: WasmGenerator, inp: ourlang.TupleConstructor) -> None:
|
||||
# tmp_var = wgn.temp_var_i32('tuple_adr')
|
||||
#
|
||||
# # Allocated the required amounts of bytes in memory
|
||||
# wgn.i32.const(inp.tuple.alloc_size())
|
||||
# wgn.call(stdlib_alloc.__alloc__)
|
||||
# wgn.local.set(tmp_var)
|
||||
#
|
||||
# # Store each member individually
|
||||
# for member in inp.tuple.members:
|
||||
# mtyp = LOAD_STORE_TYPE_MAP.get(member.type.__class__)
|
||||
# if mtyp is None:
|
||||
# # In the future might extend this by having structs or tuples
|
||||
# # as members of struct or tuples
|
||||
# raise NotImplementedError(expression, inp, member)
|
||||
#
|
||||
# wgn.local.get(tmp_var)
|
||||
# wgn.add_statement('local.get', f'$arg{member.idx}')
|
||||
# wgn.add_statement(f'{mtyp}.store', 'offset=' + str(member.offset))
|
||||
#
|
||||
# # Return the allocated address
|
||||
# wgn.local.get(tmp_var)
|
||||
|
||||
def _generate_struct_constructor(wgn: WasmGenerator, inp: ourlang.StructConstructor) -> None:
|
||||
tmp_var = wgn.temp_var_i32('struct_adr')
|
||||
|
||||
@ -771,6 +783,17 @@ def _calculate_alloc_size(typ: Union[type3types.StructType3, type3types.Type3])
|
||||
for x in typ.members.values()
|
||||
)
|
||||
|
||||
if isinstance(typ, type3types.AppliedType3):
|
||||
if typ.base is type3types.tuple:
|
||||
size = 0
|
||||
for arg in typ.args:
|
||||
if isinstance(arg, type3types.PlaceholderForType):
|
||||
assert not arg.resolve_as is None
|
||||
arg = arg.resolve_as
|
||||
size += _calculate_alloc_size(arg)
|
||||
|
||||
return size
|
||||
|
||||
raise NotImplementedError(_calculate_alloc_size, typ)
|
||||
|
||||
def _calculate_member_offset(struct_type3: type3types.StructType3, member: str) -> int:
|
||||
|
||||
@ -142,14 +142,14 @@ class TupleInstantiation(Expression):
|
||||
"""
|
||||
Instantiation a tuple
|
||||
"""
|
||||
__slots__ = ('args', )
|
||||
__slots__ = ('elements', )
|
||||
|
||||
args: List[Expression]
|
||||
elements: List[Expression]
|
||||
|
||||
def __init__(self, args: List[Expression]) -> None:
|
||||
def __init__(self, elements: List[Expression]) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.args = args
|
||||
self.elements = elements
|
||||
|
||||
class Subscript(Expression):
|
||||
"""
|
||||
|
||||
@ -60,14 +60,10 @@ class ConstraintBase:
|
||||
def __init__(self, comment: Optional[str] = None) -> None:
|
||||
self.comment = comment
|
||||
|
||||
def check(self, smap: SubstitutionMap) -> CheckResult:
|
||||
def check(self) -> CheckResult:
|
||||
"""
|
||||
Checks if the constraint hold
|
||||
|
||||
smap will contain a mapping from placeholders to types, for
|
||||
placeholders discovered from either other constraints or from
|
||||
earlier calls to check in this constraint.
|
||||
|
||||
This function can return an error, if the constraint does not hold,
|
||||
which indicates an error in the typing of the input program.
|
||||
|
||||
@ -103,7 +99,7 @@ class SameTypeConstraint(ConstraintBase):
|
||||
assert len(type_list) > 1
|
||||
self.type_list = [*type_list]
|
||||
|
||||
def check(self, smap: SubstitutionMap) -> CheckResult:
|
||||
def check(self) -> CheckResult:
|
||||
known_types: List[types.Type3] = []
|
||||
placeholders = []
|
||||
do_applied_placeholder_check: bool = False
|
||||
@ -118,8 +114,8 @@ class SameTypeConstraint(ConstraintBase):
|
||||
continue
|
||||
|
||||
if isinstance(typ, types.PlaceholderForType):
|
||||
if typ in smap:
|
||||
known_types.append(smap[typ])
|
||||
if typ.resolve_as is not None:
|
||||
known_types.append(typ.resolve_as)
|
||||
else:
|
||||
placeholders.append(typ)
|
||||
continue
|
||||
@ -159,6 +155,9 @@ class SameTypeConstraint(ConstraintBase):
|
||||
if not placeholders:
|
||||
return None
|
||||
|
||||
for typ in placeholders:
|
||||
typ.resolve_as = first_type
|
||||
|
||||
return {
|
||||
typ: first_type
|
||||
for typ in placeholders
|
||||
@ -193,14 +192,14 @@ class CastableConstraint(ConstraintBase):
|
||||
self.from_type3 = from_type3
|
||||
self.to_type3 = to_type3
|
||||
|
||||
def check(self, smap: SubstitutionMap) -> CheckResult:
|
||||
def check(self) -> CheckResult:
|
||||
ftyp = self.from_type3
|
||||
if isinstance(ftyp, types.PlaceholderForType) and ftyp in smap:
|
||||
ftyp = smap[ftyp]
|
||||
if isinstance(ftyp, types.PlaceholderForType) and ftyp.resolve_as is not None:
|
||||
ftyp = ftyp.resolve_as
|
||||
|
||||
ttyp = self.to_type3
|
||||
if isinstance(ttyp, types.PlaceholderForType) and ttyp in smap:
|
||||
ttyp = smap[ttyp]
|
||||
if isinstance(ttyp, types.PlaceholderForType) and ttyp.resolve_as is not None:
|
||||
ttyp = ttyp.resolve_as
|
||||
|
||||
if isinstance(ftyp, types.PlaceholderForType) or isinstance(ttyp, types.PlaceholderForType):
|
||||
return RequireTypeSubstitutes()
|
||||
@ -248,10 +247,10 @@ class MustImplementTypeClassConstraint(ConstraintBase):
|
||||
self.type_class3 = type_class3
|
||||
self.type3 = type3
|
||||
|
||||
def check(self, smap: SubstitutionMap) -> CheckResult:
|
||||
def check(self) -> CheckResult:
|
||||
typ = self.type3
|
||||
if isinstance(typ, types.PlaceholderForType) and typ in smap:
|
||||
typ = smap[typ]
|
||||
if isinstance(typ, types.PlaceholderForType) and typ.resolve_as is not None:
|
||||
typ = typ.resolve_as
|
||||
|
||||
if isinstance(typ, types.PlaceholderForType):
|
||||
return RequireTypeSubstitutes()
|
||||
@ -293,7 +292,7 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
self.type3 = type3
|
||||
self.literal = literal
|
||||
|
||||
def check(self, smap: SubstitutionMap) -> CheckResult:
|
||||
def check(self) -> CheckResult:
|
||||
int_table: Dict[str, Tuple[int, bool]] = {
|
||||
'u8': (1, False),
|
||||
'u32': (4, False),
|
||||
@ -309,10 +308,10 @@ class LiteralFitsConstraint(ConstraintBase):
|
||||
}
|
||||
|
||||
if isinstance(self.type3, types.PlaceholderForType):
|
||||
if self.type3 not in smap:
|
||||
if self.type3.resolve_as is None:
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
self.type3 = smap[self.type3]
|
||||
self.type3 = self.type3.resolve_as
|
||||
|
||||
if self.type3.name in int_table:
|
||||
bts, sgn = int_table[self.type3.name]
|
||||
@ -440,12 +439,12 @@ class CanBeSubscriptedConstraint(ConstraintBase):
|
||||
self.index = index
|
||||
self.index_type3 = index.type3
|
||||
|
||||
def check(self, smap: SubstitutionMap) -> CheckResult:
|
||||
def check(self) -> CheckResult:
|
||||
if isinstance(self.type3, types.PlaceholderForType):
|
||||
if self.type3 not in smap:
|
||||
if self.type3.resolve_as is None:
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
self.type3 = smap[self.type3]
|
||||
self.type3 = self.type3.resolve_as
|
||||
|
||||
if isinstance(self.type3, types.AppliedType3):
|
||||
if self.type3.base == types.static_array:
|
||||
|
||||
@ -104,7 +104,7 @@ def expression(ctx: Context, inp: ourlang.Expression) -> Generator[ConstraintBas
|
||||
|
||||
if isinstance(inp, ourlang.TupleInstantiation):
|
||||
r_type = []
|
||||
for arg in inp.args:
|
||||
for arg in inp.elements:
|
||||
yield from expression(ctx, arg)
|
||||
r_type.append(arg.type3)
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"""
|
||||
Entry point to the type3 system
|
||||
"""
|
||||
from typing import Dict, List
|
||||
from typing import Any, Dict, List, Set
|
||||
|
||||
from .. import codestyle
|
||||
from .. import ourlang
|
||||
@ -35,7 +35,7 @@ def phasm_type3(inp: ourlang.Module, verbose: bool = False) -> None:
|
||||
|
||||
new_constraint_list = []
|
||||
for constraint in constraint_list:
|
||||
check_result = constraint.check(placeholder_substitutes)
|
||||
check_result = constraint.check()
|
||||
if check_result is None:
|
||||
if verbose:
|
||||
print_constraint(placeholder_id_map, constraint)
|
||||
|
||||
@ -4,7 +4,7 @@ Contains the final types for use in Phasm
|
||||
These are actual, instantiated types; not the abstract types that the
|
||||
constraint generator works with.
|
||||
"""
|
||||
from typing import Any, Dict, Iterable, List, Protocol, Union
|
||||
from typing import Any, Dict, Iterable, List, Optional, Protocol, Union
|
||||
|
||||
TYPE3_ASSERTION_ERROR = 'You must call phasm_type3 after calling phasm_parse before you can call any other method'
|
||||
|
||||
@ -73,12 +73,14 @@ class PlaceholderForType:
|
||||
"""
|
||||
A placeholder type, for when we don't know the final type yet
|
||||
"""
|
||||
__slots__ = ('update_on_substitution', )
|
||||
__slots__ = ('update_on_substitution', 'resolve_as', )
|
||||
|
||||
update_on_substitution: List[ExpressionProtocol]
|
||||
resolve_as: Optional[Type3]
|
||||
|
||||
def __init__(self, update_on_substitution: Iterable[ExpressionProtocol]) -> None:
|
||||
self.update_on_substitution = [*update_on_substitution]
|
||||
self.resolve_as = None
|
||||
|
||||
def __repr__(self) -> str:
|
||||
uos = ', '.join(repr(x) for x in self.update_on_substitution)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user