Cleanup to module_constant_def, function calls

This commit is contained in:
Johan B.W. de Vries 2022-11-17 19:30:37 +01:00
parent 13f3f33740
commit 8cc47ae63e
4 changed files with 44 additions and 39 deletions

View File

@ -53,6 +53,9 @@ class ConstantPrimitive(Constant):
super().__init__() super().__init__()
self.value = value self.value = value
def __repr__(self) -> str:
return f'ConstantPrimitive({repr(self.value)})'
class ConstantTuple(Constant): class ConstantTuple(Constant):
""" """
A Tuple constant value expression within a statement A Tuple constant value expression within a statement

View File

@ -60,14 +60,16 @@ class SameTypeConstraint(ConstraintBase):
""" """
Verifies that an expression has an expected type Verifies that an expression has an expected type
""" """
__slots__ = ('expected', 'actual', ) __slots__ = ('expected', 'actual', 'message', )
expected: types.Type3 expected: types.Type3
actual: types.Type3OrPlaceholder actual: types.Type3OrPlaceholder
message: str
def __init__(self, expected: types.Type3, actual: types.Type3OrPlaceholder) -> None: def __init__(self, expected: types.Type3, actual: types.Type3OrPlaceholder, message: str) -> None:
self.expected = expected self.expected = expected
self.actual = actual self.actual = actual
self.message = message
def check(self) -> CheckResult: def check(self) -> CheckResult:
if isinstance(self.actual, types.PlaceholderForType): if isinstance(self.actual, types.PlaceholderForType):
@ -91,6 +93,9 @@ class SameTypeConstraint(ConstraintBase):
self.actual.get_substituted(smap[self.actual]) self.actual.get_substituted(smap[self.actual])
self.actual = smap[self.actual] self.actual = smap[self.actual]
def __repr__(self) -> str:
return f'SameTypeConstraint({repr(self.expected)}, {repr(self.actual)}, {repr(self.message)})'
class LiteralFitsConstraint(ConstraintBase): class LiteralFitsConstraint(ConstraintBase):
""" """
A literal value fits a given type A literal value fits a given type
@ -148,3 +153,11 @@ class LiteralFitsConstraint(ConstraintBase):
return Error('Must be real') # FIXME: Add line information return Error('Must be real') # FIXME: Add line information
raise NotImplementedError raise NotImplementedError
def substitute_placeholders(self, smap: SubstitutionMap) -> None: # FIXME: Duplicate code
if isinstance(self.type3, types.PlaceholderForType) and self.type3 in smap: # FIXME: Check recursive?
self.type3.get_substituted(smap[self.type3])
self.type3 = smap[self.type3]
def __repr__(self) -> str:
return f'LiteralFitsConstraint({repr(self.type3)}, {repr(self.literal)})'

View File

@ -22,13 +22,7 @@ def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase
def constant(ctx: Context, inp: ourlang.Constant) -> Generator[ConstraintBase, None, None]: def constant(ctx: Context, inp: ourlang.Constant) -> Generator[ConstraintBase, None, None]:
if isinstance(inp, ourlang.ConstantPrimitive): if isinstance(inp, ourlang.ConstantPrimitive):
# A constant by itself doesn't have any constraints yield LiteralFitsConstraint(inp.type3, inp)
yield from ()
return
if isinstance(inp, ourlang.ConstantTuple):
# A constant by itself doesn't have any constraints
yield from ()
return return
raise NotImplementedError(constant, inp) raise NotImplementedError(constant, inp)
@ -39,7 +33,19 @@ def expression(ctx: Context, inp: ourlang.Expression) -> Generator[ConstraintBas
return return
if isinstance(inp, ourlang.VariableReference): if isinstance(inp, ourlang.VariableReference):
yield SameTypeConstraint(inp.variable.type3, inp.type3) yield SameTypeConstraint(inp.variable.type3, inp.type3, f'The type of a variable reference is the same as the type of variable {inp.variable.name}')
return
if isinstance(inp, ourlang.FunctionCall):
yield SameTypeConstraint(inp.function.returns_type3, inp.type3, f'The type of a function call to {inp.function.name} is the same as the type that the function returns')
assert len(inp.arguments) == len(inp.function.posonlyargs) # FIXME: Make this a Constraint
for fun_arg, call_arg in zip(inp.function.posonlyargs, inp.arguments):
yield from expression(ctx, call_arg)
yield SameTypeConstraint(fun_arg.type3, call_arg.type3,
f'The type of the value passed to argument {fun_arg.name} of function {inp.function.name} should match the type of that argument')
return return
raise NotImplementedError(expression, inp) raise NotImplementedError(expression, inp)
@ -50,36 +56,11 @@ def function(ctx: Context, inp: ourlang.Function) -> Generator[ConstraintBase, N
yield from expression(ctx, inp.statements[0].value) yield from expression(ctx, inp.statements[0].value)
yield SameTypeConstraint(inp.returns_type3, inp.statements[0].value.type3) yield SameTypeConstraint(inp.returns_type3, inp.statements[0].value.type3, f'The type of the value returned from function {inp.name} should match its return type')
def module_constant_def(ctx: Context, inp: ourlang.ModuleConstantDef) -> Generator[ConstraintBase, None, None]: def module_constant_def(ctx: Context, inp: ourlang.ModuleConstantDef) -> Generator[ConstraintBase, None, None]:
yield from constant(ctx, inp.constant) yield from constant(ctx, inp.constant)
yield SameTypeConstraint(inp.type3, inp.constant.type3, f'The type of the value for module constant definition {inp.name} should match the type of that constant')
# FIXME: Redo this part
if (
inp.type3 is types.u8
or inp.type3 is types.u32
or inp.type3 is types.u64
or inp.type3 is types.i32
or inp.type3 is types.i64
or inp.type3 is types.f32
or inp.type3 is types.f64
) and isinstance(inp.constant, ourlang.ConstantPrimitive):
yield LiteralFitsConstraint(inp.type3, inp.constant)
inp.constant.type3 = inp.type3
return
if isinstance(inp.type3, types.AppliedType3):
if inp.type3.base is types.static_array and isinstance(inp.constant, ourlang.ConstantTuple):
for lit in inp.constant.value:
yield LiteralFitsConstraint(inp.type3.args[0], lit)
# lit.type3 = inp.type3.args[0]
raise NotImplementedError
return
raise NotImplementedError(constant, inp, inp.type3)
def module(ctx: Context, inp: ourlang.Module) -> Generator[ConstraintBase, None, None]: def module(ctx: Context, inp: ourlang.Module) -> Generator[ConstraintBase, None, None]:
for cdef in inp.constant_defs.values(): for cdef in inp.constant_defs.values():

View File

@ -9,6 +9,8 @@ from .constraints import Error, RequireTypeSubstitutes
from .constraintsgenerator import phasm_type3_generate_constraints from .constraintsgenerator import phasm_type3_generate_constraints
from .types import PlaceholderForType, Type3 from .types import PlaceholderForType, Type3
MAX_RESTACK_COUNT = 10
class Type3Exception(BaseException): class Type3Exception(BaseException):
""" """
Thrown when the Type3 system detects constraints that do not hold Thrown when the Type3 system detects constraints that do not hold
@ -20,8 +22,10 @@ def phasm_type3(inp: ourlang.Module) -> None:
placeholder_substitutes: Dict[PlaceholderForType, Type3] = {} placeholder_substitutes: Dict[PlaceholderForType, Type3] = {}
restack_counter = 0
error_list: List[Error] = [] error_list: List[Error] = []
while constraint_list: # FIXME: How to detect infinite loop? Is that necessary? while constraint_list:
constraint = constraint_list.pop(0) constraint = constraint_list.pop(0)
constraint.substitute_placeholders(placeholder_substitutes) constraint.substitute_placeholders(placeholder_substitutes)
@ -36,6 +40,11 @@ def phasm_type3(inp: ourlang.Module) -> None:
continue continue
if isinstance(check_result, RequireTypeSubstitutes): if isinstance(check_result, RequireTypeSubstitutes):
# FIXME: How to detect infinite loop? Is that necessary?
restack_counter += 1
if restack_counter > MAX_RESTACK_COUNT:
raise Exception('This looks like an infinite loop', constraint_list)
constraint_list.append(constraint) constraint_list.append(constraint)
continue continue
@ -45,4 +54,3 @@ def phasm_type3(inp: ourlang.Module) -> None:
raise Type3Exception(error_list) raise Type3Exception(error_list)
# TODO: Implement type substitution on the AST # TODO: Implement type substitution on the AST
print('placeholder_substitutes', placeholder_substitutes)