Compare commits
1 Commits
b285eb9d05
...
bfb3d2b3a0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfb3d2b3a0 |
@ -17,7 +17,6 @@ from .type3.types import (
|
||||
TypeApplication_Struct,
|
||||
TypeApplication_TypeInt,
|
||||
TypeApplication_TypeStar,
|
||||
TypeConstructor_Function,
|
||||
TypeConstructor_StaticArray,
|
||||
TypeConstructor_Tuple,
|
||||
)
|
||||
@ -356,21 +355,6 @@ def expression(wgn: WasmGenerator, mod: ourlang.Module, inp: ourlang.Expression)
|
||||
raise NotImplementedError(str(inp.function), type_var_map)
|
||||
return
|
||||
|
||||
if isinstance(inp.function, ourlang.FunctionParam):
|
||||
assert isinstance(inp.function.type3.application.constructor, TypeConstructor_Function)
|
||||
|
||||
params = [
|
||||
type3(x).to_wat()
|
||||
for x in inp.function.type3.application.arguments
|
||||
]
|
||||
|
||||
result = params.pop()
|
||||
|
||||
params_str = ' '.join(params)
|
||||
wgn.add_statement('local.get', '${}'.format(inp.function.name))
|
||||
wgn.add_statement(f'call_indirect (param {params_str}) (result {result})')
|
||||
return
|
||||
|
||||
wgn.add_statement('call', '${}'.format(inp.function.name))
|
||||
return
|
||||
|
||||
|
||||
@ -151,10 +151,10 @@ class FunctionCall(Expression):
|
||||
"""
|
||||
__slots__ = ('function', 'arguments', )
|
||||
|
||||
function: Union['Function', 'FunctionParam', Type3ClassMethod]
|
||||
function: Union['Function', Type3ClassMethod]
|
||||
arguments: List[Expression]
|
||||
|
||||
def __init__(self, function: Union['Function', 'FunctionParam', Type3ClassMethod]) -> None:
|
||||
def __init__(self, function: Union['Function', Type3ClassMethod]) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.function = function
|
||||
@ -378,15 +378,15 @@ class Module:
|
||||
"""
|
||||
A module is a file and consists of functions
|
||||
"""
|
||||
__slots__ = ('data', 'types', 'struct_definitions', 'constant_defs', 'functions', 'operators', 'functions_table', )
|
||||
__slots__ = ('data', 'types', 'struct_definitions', 'constant_defs', 'functions', 'functions_table', 'operators', )
|
||||
|
||||
data: ModuleData
|
||||
types: dict[str, Type3]
|
||||
struct_definitions: Dict[str, StructDefinition]
|
||||
constant_defs: Dict[str, ModuleConstantDef]
|
||||
functions: Dict[str, Function]
|
||||
operators: Dict[str, Type3ClassMethod]
|
||||
functions_table: dict[Function, int]
|
||||
operators: Dict[str, Type3ClassMethod]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.data = ModuleData()
|
||||
|
||||
@ -447,8 +447,7 @@ class OurVisitor:
|
||||
return VariableReference(cdef)
|
||||
|
||||
if node.id in module.functions:
|
||||
fun = module.functions[node.id]
|
||||
return FunctionReference(fun)
|
||||
return FunctionReference(module.functions[node.id])
|
||||
|
||||
_raise_static_error(node, f'Undefined variable {node.id}')
|
||||
|
||||
@ -475,18 +474,21 @@ class OurVisitor:
|
||||
if not isinstance(node.func.ctx, ast.Load):
|
||||
_raise_static_error(node, 'Must be load context')
|
||||
|
||||
func: Union[Function, FunctionParam, Type3ClassMethod]
|
||||
func: Union[Function, Type3ClassMethod]
|
||||
|
||||
if node.func.id in PRELUDE_METHODS:
|
||||
func = PRELUDE_METHODS[node.func.id]
|
||||
elif node.func.id in our_locals:
|
||||
func = our_locals[node.func.id]
|
||||
else:
|
||||
if node.func.id not in module.functions:
|
||||
_raise_static_error(node, 'Call to undefined function')
|
||||
|
||||
func = module.functions[node.func.id]
|
||||
|
||||
exp_arg_count = len(func.signature.args) - 1
|
||||
|
||||
if exp_arg_count != len(node.args):
|
||||
_raise_static_error(node, f'Function {node.func.id} requires {exp_arg_count} arguments but {len(node.args)} are given')
|
||||
|
||||
result = FunctionCall(func)
|
||||
result.arguments.extend(
|
||||
self.visit_Module_FunctionDef_expr(module, function, our_locals, arg_expr)
|
||||
@ -614,22 +616,6 @@ class OurVisitor:
|
||||
_raise_static_error(node, f'Unrecognized type {node.id}')
|
||||
|
||||
if isinstance(node, ast.Subscript):
|
||||
if isinstance(node.value, ast.Name) and node.value.id == 'Callable':
|
||||
func_arg_types: list[ast.expr]
|
||||
|
||||
if isinstance(node.slice, ast.Name):
|
||||
func_arg_types = [node.slice]
|
||||
elif isinstance(node.slice, ast.Tuple):
|
||||
func_arg_types = node.slice.elts
|
||||
else:
|
||||
_raise_static_error(node, 'Must subscript using a list of types')
|
||||
|
||||
# Function type
|
||||
return prelude.function(*[
|
||||
self.visit_type(module, e)
|
||||
for e in func_arg_types
|
||||
])
|
||||
|
||||
if isinstance(node.slice, ast.Slice):
|
||||
_raise_static_error(node, 'Must subscript using an index')
|
||||
if not isinstance(node.slice, ast.Constant):
|
||||
|
||||
@ -188,9 +188,7 @@ determined length, and each argument can be different.
|
||||
"""
|
||||
|
||||
def fn_on_create(args: tuple[Type3, ...], typ: Type3) -> None:
|
||||
# Not really a pointer; but still a i32
|
||||
# (It's actually a table lookup)
|
||||
instance_type_class(InternalPassAsPointer, typ)
|
||||
pass # ? instance_type_class(InternalPassAsPointer, typ)
|
||||
|
||||
function = TypeConstructor_Function('function', on_create=fn_on_create)
|
||||
"""
|
||||
@ -475,7 +473,7 @@ instance_type_class(IntNum, f64, methods={
|
||||
'neg': stdtypes.f64_intnum_neg,
|
||||
})
|
||||
|
||||
Integral = Type3Class('Integral', (a, ), methods={
|
||||
Integral = Type3Class('Eq', (a, ), methods={
|
||||
}, operators={
|
||||
'//': [a, a, a],
|
||||
'%': [a, a, a],
|
||||
|
||||
@ -159,7 +159,7 @@ class SameTypeConstraint(ConstraintBase):
|
||||
return (
|
||||
' == '.join('{t' + str(idx) + '}' for idx in range(len(self.type_list))),
|
||||
{
|
||||
't' + str(idx): typ
|
||||
't' + str(idx): typ.name if isinstance(typ, ourlang.Function) else typ
|
||||
for idx, typ in enumerate(self.type_list)
|
||||
},
|
||||
)
|
||||
@ -257,6 +257,9 @@ class SameFunctionArgumentConstraint(ConstraintBase):
|
||||
if isinstance(tv, Type3) or tv in type_var_map
|
||||
]
|
||||
|
||||
print('self.func_arg.args', self.func_arg.args)
|
||||
print('exp_type_arg_list', exp_type_arg_list)
|
||||
|
||||
if len(exp_type_arg_list) != len(self.func_arg.args):
|
||||
return RequireTypeSubstitutes()
|
||||
|
||||
|
||||
@ -23,10 +23,9 @@ from .functions import (
|
||||
FunctionSignature,
|
||||
TypeVariable,
|
||||
TypeVariableApplication_Unary,
|
||||
TypeVariableContext,
|
||||
)
|
||||
from .placeholders import PlaceholderForType
|
||||
from .types import Type3, TypeApplication_Struct, TypeConstructor_Function
|
||||
from .types import Type3, TypeApplication_Struct
|
||||
|
||||
ConstraintGenerator = Generator[ConstraintBase, None, None]
|
||||
|
||||
@ -57,31 +56,15 @@ def expression_binary_op(ctx: Context, inp: ourlang.BinaryOp, phft: PlaceholderF
|
||||
)
|
||||
|
||||
def expression_function_call(ctx: Context, inp: ourlang.FunctionCall, phft: PlaceholderForType) -> ConstraintGenerator:
|
||||
if isinstance(inp.function, ourlang.FunctionParam):
|
||||
assert isinstance(inp.function.type3.application.constructor, TypeConstructor_Function)
|
||||
signature = FunctionSignature(
|
||||
TypeVariableContext(),
|
||||
inp.function.type3.application.arguments,
|
||||
)
|
||||
else:
|
||||
signature = inp.function.signature
|
||||
|
||||
return _expression_function_call(
|
||||
ctx,
|
||||
inp.function.name,
|
||||
signature,
|
||||
inp.function.signature,
|
||||
inp.arguments,
|
||||
inp,
|
||||
phft,
|
||||
)
|
||||
|
||||
def expression_function_reference(ctx: Context, inp: ourlang.FunctionReference, phft: PlaceholderForType) -> ConstraintGenerator:
|
||||
yield SameTypeConstraint(
|
||||
prelude.function(*(x.type3 for x in inp.function.posonlyargs), inp.function.returns_type3),
|
||||
phft,
|
||||
comment=f'typeOf("{inp.function.name}") == typeOf({inp.function.name})',
|
||||
)
|
||||
|
||||
def _expression_function_call(
|
||||
ctx: Context,
|
||||
func_name: str,
|
||||
@ -206,6 +189,13 @@ def _expression_function_call(
|
||||
raise NotImplementedError(sig_part)
|
||||
return
|
||||
|
||||
def expression_function_reference(ctx: Context, inp: ourlang.FunctionReference, phft: PlaceholderForType) -> ConstraintGenerator:
|
||||
yield SameTypeConstraint(
|
||||
prelude.function(*(x.type3 for x in inp.function.posonlyargs), inp.function.returns_type3),
|
||||
phft,
|
||||
comment=f'typeOf("{inp.function.name}") == typeOf({inp.function.name})',
|
||||
)
|
||||
|
||||
def expression(ctx: Context, inp: ourlang.Expression, phft: PlaceholderForType) -> ConstraintGenerator:
|
||||
if isinstance(inp, ourlang.Constant):
|
||||
yield from constant(ctx, inp, phft)
|
||||
|
||||
@ -241,7 +241,7 @@ class TypeConstructor_Tuple(TypeConstructor_TypeStar):
|
||||
|
||||
class TypeConstructor_Function(TypeConstructor_TypeStar):
|
||||
def make_name(self, key: Tuple[Type3, ...]) -> str:
|
||||
return 'Callable[' + ', '.join(x.name for x in key) + ']'
|
||||
return '(' + ' -> '.join(x.name for x in key) + ')'
|
||||
|
||||
class TypeConstructor_Struct(TypeConstructor_Base[tuple[tuple[str, Type3], ...]]):
|
||||
"""
|
||||
|
||||
@ -186,8 +186,8 @@ class Module(WatSerializable):
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
self.imports: List[Import] = []
|
||||
self.table: dict[int, str] = {}
|
||||
self.functions: List[Function] = []
|
||||
self.table: dict[int, str] = {}
|
||||
self.memory = ModuleMemory()
|
||||
|
||||
def to_wat(self) -> str:
|
||||
|
||||
@ -1,182 +0,0 @@
|
||||
import pytest
|
||||
|
||||
from phasm.type3.entry import Type3Exception
|
||||
|
||||
from ..helpers import Suite
|
||||
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_sof_in_code_0_arg():
|
||||
code_py = """
|
||||
def thirteen() -> i32:
|
||||
return 13
|
||||
|
||||
def action(applicable: Callable[i32]) -> i32:
|
||||
return applicable()
|
||||
|
||||
@exported
|
||||
def testEntry() -> i32:
|
||||
return action(thirteen)
|
||||
"""
|
||||
|
||||
result = Suite(code_py).run_code()
|
||||
|
||||
assert 13 == result.returned_value
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_sof_in_code_1_arg():
|
||||
code_py = """
|
||||
def double(left: i32) -> i32:
|
||||
return left * 2
|
||||
|
||||
def action(applicable: Callable[i32, i32], left: i32) -> i32:
|
||||
return applicable(left)
|
||||
|
||||
@exported
|
||||
def testEntry() -> i32:
|
||||
return action(double, 13)
|
||||
"""
|
||||
|
||||
result = Suite(code_py).run_code()
|
||||
|
||||
assert 26 == result.returned_value
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_sof_in_code_2_arg():
|
||||
code_py = """
|
||||
def add(left: i32, right: i32) -> i32:
|
||||
return left + right
|
||||
|
||||
def action(applicable: Callable[i32, i32, i32], left: i32, right: i32) -> i32:
|
||||
return applicable(left, right)
|
||||
|
||||
@exported
|
||||
def testEntry() -> i32:
|
||||
return action(add, 13, 14)
|
||||
"""
|
||||
|
||||
result = Suite(code_py).run_code()
|
||||
|
||||
assert 27 == result.returned_value
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_sof_in_code_3_arg():
|
||||
code_py = """
|
||||
def add(left: i32, mid: i32, right: i32) -> i32:
|
||||
return left + mid + right
|
||||
|
||||
def action(applicable: Callable[i32, i32, i32, i32], left: i32, mid: i32, right: i32) -> i32:
|
||||
return applicable(left, mid, right)
|
||||
|
||||
@exported
|
||||
def testEntry() -> i32:
|
||||
return action(add, 13, 14, 15)
|
||||
"""
|
||||
|
||||
result = Suite(code_py).run_code()
|
||||
|
||||
assert 42 == result.returned_value
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_sof_wrong_argument_type():
|
||||
code_py = """
|
||||
def double(left: f32) -> f32:
|
||||
return left * 2
|
||||
|
||||
def action(applicable: Callable[i32, i32], left: i32) -> i32:
|
||||
return applicable(left)
|
||||
|
||||
@exported
|
||||
def testEntry() -> i32:
|
||||
return action(double, 13)
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match=r'Callable\[f32, f32\] must be Callable\[i32, i32\] instead'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_sof_wrong_return():
|
||||
code_py = """
|
||||
def double(left: i32) -> i32:
|
||||
return left * 2
|
||||
|
||||
def action(applicable: Callable[i32, i32], left: i32) -> f32:
|
||||
return applicable(left)
|
||||
|
||||
@exported
|
||||
def testEntry() -> i32:
|
||||
return action(double, 13)
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match=r'f32 must be i32 instead'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.skip('FIXME: Probably have the remainder be the a function type')
|
||||
def test_sof_wrong_not_enough_args_call():
|
||||
code_py = """
|
||||
def add(left: i32, right: i32) -> i32:
|
||||
return left + right
|
||||
|
||||
def action(applicable: Callable[i32, i32, i32], left: i32) -> i32:
|
||||
return applicable(left)
|
||||
|
||||
@exported
|
||||
def testEntry() -> i32:
|
||||
return action(add, 13)
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match=r'f32 must be i32 instead'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_sof_wrong_not_enough_args_refere():
|
||||
code_py = """
|
||||
def double(left: i32) -> i32:
|
||||
return left * 2
|
||||
|
||||
def action(applicable: Callable[i32, i32, i32], left: i32, right: i32) -> i32:
|
||||
return applicable(left, right)
|
||||
|
||||
@exported
|
||||
def testEntry() -> i32:
|
||||
return action(double, 13, 14)
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match=r'Callable\[i32, i32\] must be Callable\[i32, i32, i32\] instead'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.skip('FIXME: Probably have the remainder be the a function type')
|
||||
def test_sof_wrong_too_many_args_call():
|
||||
code_py = """
|
||||
def thirteen() -> i32:
|
||||
return 13
|
||||
|
||||
def action(applicable: Callable[i32], left: i32) -> i32:
|
||||
return applicable(left)
|
||||
|
||||
@exported
|
||||
def testEntry() -> i32:
|
||||
return action(thirteen, 13)
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match=r'f32 must be i32 instead'):
|
||||
Suite(code_py).run_code()
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_sof_wrong_too_many_args_refere():
|
||||
code_py = """
|
||||
def double(left: i32) -> i32:
|
||||
return left * 2
|
||||
|
||||
def action(applicable: Callable[i32]) -> i32:
|
||||
return applicable()
|
||||
|
||||
@exported
|
||||
def testEntry() -> i32:
|
||||
return action(double)
|
||||
"""
|
||||
|
||||
with pytest.raises(Type3Exception, match=r'Callable\[i32, i32\] must be Callable\[i32\] instead'):
|
||||
Suite(code_py).run_code()
|
||||
Loading…
x
Reference in New Issue
Block a user