Compare commits

..

No commits in common. "f281b78c78f12ad7afbfeefdfe2ac9f1caa94575" and "e936d6e88545b2e61eaa8c2ec904cd7a4c05b2fd" have entirely different histories.

4 changed files with 30 additions and 90 deletions

View File

@ -104,58 +104,27 @@ class SameTypeConstraint(ConstraintBase):
self.type_list = [*type_list] self.type_list = [*type_list]
def check(self, smap: SubstitutionMap) -> CheckResult: def check(self, smap: SubstitutionMap) -> CheckResult:
known_types: List[types.Type3] = [] known_types = []
placeholders = [] placeholders = []
do_applied_placeholder_check: bool = False
for typ in self.type_list: for typ in self.type_list:
if isinstance(typ, (types.PrimitiveType3, types.StructType3, )): if isinstance(typ, types.Type3):
known_types.append(typ) known_types.append(typ)
continue continue
if isinstance(typ, types.AppliedType3):
known_types.append(typ)
do_applied_placeholder_check = True
continue
if isinstance(typ, types.PlaceholderForType):
if typ in smap: if typ in smap:
known_types.append(smap[typ]) known_types.append(smap[typ])
else:
placeholders.append(typ)
continue continue
raise NotImplementedError(typ) placeholders.append(typ)
if not known_types: if not known_types:
return RequireTypeSubstitutes() return RequireTypeSubstitutes()
new_constraint_list: List[ConstraintBase] = []
first_type = known_types[0] first_type = known_types[0]
for typ in known_types[1:]: for typ in known_types[1:]:
if isinstance(first_type, types.AppliedType3) and isinstance(typ, types.AppliedType3):
if len(first_type.args) != len(typ.args):
return Error('Mismatch between applied types argument count')
if first_type.base != typ.base:
return Error('Mismatch between applied types base')
for first_type_arg, typ_arg in zip(first_type.args, typ.args):
new_constraint_list.append(SameTypeConstraint(
first_type_arg, typ_arg
))
continue
if typ != first_type: if typ != first_type:
return Error(f'{typ:s} must be {first_type:s} instead') return Error(f'{typ:s} must be {first_type:s} instead')
if new_constraint_list:
# If this happens, make CheckResult a class that can have both
assert not placeholders, 'Cannot (yet) return both new placeholders and new constraints'
return new_constraint_list
if not placeholders: if not placeholders:
return None return None

View File

@ -8,7 +8,7 @@ from .. import ourlang
from .constraints import ConstraintBase, Error, RequireTypeSubstitutes, SameTypeConstraint, SubstitutionMap from .constraints import ConstraintBase, Error, RequireTypeSubstitutes, SameTypeConstraint, SubstitutionMap
from .constraintsgenerator import phasm_type3_generate_constraints from .constraintsgenerator import phasm_type3_generate_constraints
from .types import AppliedType3, PlaceholderForType, PrimitiveType3, StructType3, Type3, Type3OrPlaceholder from .types import PlaceholderForType, Type3
MAX_RESTACK_COUNT = 100 MAX_RESTACK_COUNT = 100
@ -111,8 +111,14 @@ def print_constraint(placeholder_id_map: Dict[int, str], constraint: ConstraintB
if isinstance(fmt_val, ourlang.Expression): if isinstance(fmt_val, ourlang.Expression):
fmt_val = codestyle.expression(fmt_val) fmt_val = codestyle.expression(fmt_val)
if isinstance(fmt_val, Type3) or isinstance(fmt_val, PlaceholderForType): if isinstance(fmt_val, Type3):
fmt_val = get_printable_type_name(fmt_val, placeholder_id_map) fmt_val = fmt_val.name
if isinstance(fmt_val, PlaceholderForType):
placeholder_id = id(fmt_val)
if placeholder_id not in placeholder_id_map:
placeholder_id_map[placeholder_id] = 'T' + str(len(placeholder_id_map) + 1)
fmt_val = placeholder_id_map[placeholder_id]
if not isinstance(fmt_val, str): if not isinstance(fmt_val, str):
fmt_val = repr(fmt_val) fmt_val = repr(fmt_val)
@ -124,26 +130,6 @@ def print_constraint(placeholder_id_map: Dict[int, str], constraint: ConstraintB
else: else:
print('- ' + txt.format(**act_fmt)) print('- ' + txt.format(**act_fmt))
def get_printable_type_name(inp: Type3OrPlaceholder, placeholder_id_map: Dict[int, str]) -> str:
if isinstance(inp, (PrimitiveType3, StructType3, )):
return inp.name
if isinstance(inp, PlaceholderForType):
placeholder_id = id(inp)
if placeholder_id not in placeholder_id_map:
placeholder_id_map[placeholder_id] = 'T' + str(len(placeholder_id_map) + 1)
return placeholder_id_map[placeholder_id]
if isinstance(inp, AppliedType3):
return (
get_printable_type_name(inp.base, placeholder_id_map)
+ ' ('
+ ') ('.join(get_printable_type_name(x, placeholder_id_map) for x in inp.args)
+ ')'
)
raise NotImplementedError(inp)
def print_constraint_list(placeholder_id_map: Dict[int, str], constraint_list: List[ConstraintBase], placeholder_substitutes: SubstitutionMap) -> None: def print_constraint_list(placeholder_id_map: Dict[int, str], constraint_list: List[ConstraintBase], placeholder_substitutes: SubstitutionMap) -> None:
print('=== v type3 constraint_list v === ') print('=== v type3 constraint_list v === ')
for psk, psv in placeholder_substitutes.items(): for psk, psv in placeholder_substitutes.items():

View File

@ -62,13 +62,6 @@ class Type3:
def __bool__(self) -> bool: def __bool__(self) -> bool:
raise NotImplementedError raise NotImplementedError
class PrimitiveType3(Type3):
"""
Intermediate class to tell primitive types from others
"""
__slots__ = ()
class PlaceholderForType: class PlaceholderForType:
""" """
A placeholder type, for when we don't know the final type yet A placeholder type, for when we don't know the final type yet
@ -120,7 +113,7 @@ class AppliedType3(Type3):
""" """
__slots__ = ('base', 'args', ) __slots__ = ('base', 'args', )
base: PrimitiveType3 base: Type3
""" """
The base type The base type
""" """
@ -130,9 +123,8 @@ class AppliedType3(Type3):
The applied types (or placeholders there for) The applied types (or placeholders there for)
""" """
def __init__(self, base: PrimitiveType3, args: Iterable[Type3OrPlaceholder]) -> None: def __init__(self, base: Type3, args: Iterable[Type3OrPlaceholder]) -> None:
args = [*args] args = [*args]
assert args, 'Must at least one argument'
super().__init__( super().__init__(
base.name base.name
@ -144,13 +136,6 @@ class AppliedType3(Type3):
self.base = base self.base = base
self.args = args self.args = args
@property
def has_placeholders(self) -> bool:
return any(
isinstance(x, PlaceholderForType)
for x in self.args
)
def __eq__(self, other: Any) -> bool: def __eq__(self, other: Any) -> bool:
if not isinstance(other, Type3): if not isinstance(other, Type3):
raise NotImplementedError raise NotImplementedError
@ -195,33 +180,33 @@ class StructType3(Type3):
def __repr__(self) -> str: def __repr__(self) -> str:
return f'StructType3(repr({self.name}), repr({self.members}))' return f'StructType3(repr({self.name}), repr({self.members}))'
none = PrimitiveType3('none') none = Type3('none')
""" """
The none type, for when functions simply don't return anything. e.g., IO(). The none type, for when functions simply don't return anything. e.g., IO().
""" """
u8 = PrimitiveType3('u8') u8 = Type3('u8')
""" """
The unsigned 8-bit integer type. The unsigned 8-bit integer type.
Operations on variables employ modular arithmetic, with modulus 2^8. Operations on variables employ modular arithmetic, with modulus 2^8.
""" """
u32 = PrimitiveType3('u32') u32 = Type3('u32')
""" """
The unsigned 32-bit integer type. The unsigned 32-bit integer type.
Operations on variables employ modular arithmetic, with modulus 2^32. Operations on variables employ modular arithmetic, with modulus 2^32.
""" """
u64 = PrimitiveType3('u64') u64 = Type3('u64')
""" """
The unsigned 64-bit integer type. The unsigned 64-bit integer type.
Operations on variables employ modular arithmetic, with modulus 2^64. Operations on variables employ modular arithmetic, with modulus 2^64.
""" """
i8 = PrimitiveType3('i8') i8 = Type3('i8')
""" """
The signed 8-bit integer type. The signed 8-bit integer type.
@ -229,7 +214,7 @@ Operations on variables employ modular arithmetic, with modulus 2^8, but
with the middel point being 0. with the middel point being 0.
""" """
i32 = PrimitiveType3('i32') i32 = Type3('i32')
""" """
The unsigned 32-bit integer type. The unsigned 32-bit integer type.
@ -237,7 +222,7 @@ Operations on variables employ modular arithmetic, with modulus 2^32, but
with the middel point being 0. with the middel point being 0.
""" """
i64 = PrimitiveType3('i64') i64 = Type3('i64')
""" """
The unsigned 64-bit integer type. The unsigned 64-bit integer type.
@ -245,22 +230,22 @@ Operations on variables employ modular arithmetic, with modulus 2^64, but
with the middel point being 0. with the middel point being 0.
""" """
f32 = PrimitiveType3('f32') f32 = Type3('f32')
""" """
A 32-bits IEEE 754 float, of 32 bits width. A 32-bits IEEE 754 float, of 32 bits width.
""" """
f64 = PrimitiveType3('f64') f64 = Type3('f64')
""" """
A 32-bits IEEE 754 float, of 64 bits width. A 32-bits IEEE 754 float, of 64 bits width.
""" """
bytes = PrimitiveType3('bytes') bytes = Type3('bytes')
""" """
This is a runtime-determined length piece of memory that can be indexed at runtime. This is a runtime-determined length piece of memory that can be indexed at runtime.
""" """
static_array = PrimitiveType3('static_array') static_array = Type3('static_array')
""" """
This is a fixed length piece of memory that can be indexed at runtime. This is a fixed length piece of memory that can be indexed at runtime.
@ -268,7 +253,7 @@ It should be applied with one argument. It has a runtime-dynamic length
of the same type repeated. of the same type repeated.
""" """
tuple = PrimitiveType3('tuple') # pylint: disable=W0622 tuple = Type3('tuple') # pylint: disable=W0622
""" """
This is a fixed length piece of memory. This is a fixed length piece of memory.

View File

@ -2,7 +2,7 @@ import pytest
from phasm.type3.entry import Type3Exception from phasm.type3.entry import Type3Exception
from ..constants import ALL_FLOAT_TYPES, COMPLETE_INT_TYPES, TYPE_MAP from ..constants import ALL_FLOAT_TYPES, COMPLETE_NUMERIC_TYPES, TYPE_MAP
from ..helpers import Suite from ..helpers import Suite
@pytest.mark.integration_test @pytest.mark.integration_test
@ -82,7 +82,7 @@ def helper(x: u8) -> u8:
Suite(code_py).run_code() Suite(code_py).run_code()
@pytest.mark.integration_test @pytest.mark.integration_test
@pytest.mark.parametrize('type_', COMPLETE_INT_TYPES) @pytest.mark.parametrize('type_', COMPLETE_NUMERIC_TYPES)
def test_tuple_simple_constructor_int(type_): def test_tuple_simple_constructor_int(type_):
code_py = f""" code_py = f"""
@exported @exported