MVP #1

Merged
jbwdevries merged 73 commits from idea_crc32 into master 2022-08-21 12:59:21 +00:00
3 changed files with 135 additions and 3 deletions
Showing only changes of commit c5d039aa1f - Show all commits

View File

@ -39,6 +39,23 @@ class Visitor:
if isinstance(name, ast.expr):
if isinstance(name, ast.Name):
name = name.id
elif isinstance(name, ast.Subscript) and isinstance(name.value, ast.Name) and name.value.id == 'Tuple':
assert isinstance(name.ctx, ast.Load)
assert isinstance(name.slice, ast.Index)
assert isinstance(name.slice.value, ast.Tuple)
args: List[wasm.TupleMember] = []
offset = 0
for name_arg in name.slice.value.elts:
arg = wasm.TupleMember(
self._get_type(name_arg),
offset
)
args.append(arg)
offset += arg.type.alloc_size()
return wasm.OurTypeTuple(args)
else:
raise NotImplementedError(f'_get_type(ast.{type(name).__name__})')
@ -332,11 +349,17 @@ class Visitor:
if isinstance(node, ast.Constant):
return self.visit_Constant(exp_type, node)
if isinstance(node, ast.Attribute):
return self.visit_Attribute(module, wlocals, exp_type, node)
if isinstance(node, ast.Subscript):
return self.visit_Subscript(module, wlocals, exp_type, node)
if isinstance(node, ast.Name):
return self.visit_Name(wlocals, exp_type, node)
if isinstance(node, ast.Attribute):
return self.visit_Attribute(module, wlocals, exp_type, node)
if isinstance(node, ast.Tuple):
return self.visit_Tuple(wlocals, exp_type, node)
raise NotImplementedError(node)
@ -470,7 +493,7 @@ class Visitor:
This instantiates the class
"""
# TODO: malloc call
# TODO: free call
yield wasm.Statement('i32.const', str(cls.alloc_size()))
yield wasm.Statement('call', '$___new_reference___')
@ -586,6 +609,77 @@ class Visitor:
yield wasm.Statement('local.get', '$' + node.value.id)
yield wasm.Statement(exp_type.to_wasm() + '.load', 'offset=' + str(member.offset))
def visit_Subscript(
self,
module: wasm.Module,
wlocals: WLocals,
exp_type: wasm.OurType,
node: ast.Subscript,
) -> StatementGenerator:
"""
Visits an Subscript node as (part of) an expression
"""
if not isinstance(node.value, ast.Name):
raise NotImplementedError
if not isinstance(node.slice, ast.Index):
raise NotImplementedError
if not isinstance(node.slice.value, ast.Constant):
raise NotImplementedError
if not isinstance(node.slice.value.value, int):
raise NotImplementedError
if not isinstance(node.ctx, ast.Load):
raise NotImplementedError
tpl_idx = node.slice.value.value
tpl = wlocals[node.value.id]
assert isinstance(tpl, wasm.OurTypeTuple), f'Cannot take index of {tpl}'
assert 0 <= tpl_idx < len(tpl.members), \
f'Tuple index out of bounds; {node.value.id} has {len(tpl.members)} members'
member = tpl.members[tpl_idx]
yield wasm.Statement('local.get', '$' + node.value.id)
yield wasm.Statement(exp_type.to_wasm() + '.load', 'offset=' + str(member.offset))
def visit_Tuple(
self,
wlocals: WLocals,
exp_type: wasm.OurType,
node: ast.Tuple,
) -> StatementGenerator:
"""
Visits an Tuple node as (part of) an expression
"""
assert isinstance(exp_type, wasm.OurTypeTuple), 'Expression is not expecting a tuple'
# TODO: free call
tpl = exp_type
yield wasm.Statement('nop', comment='Start tuple allocation')
yield wasm.Statement('i32.const', str(tpl.alloc_size()))
yield wasm.Statement('call', '$___new_reference___')
yield wasm.Statement('local.set', '$___new_reference___addr', comment='Allocate for tuple')
for member, arg in zip(tpl.members, node.elts):
if not isinstance(arg, ast.Constant):
raise NotImplementedError('TODO: Non-const tuple members')
yield wasm.Statement('local.get', '$___new_reference___addr')
yield wasm.Statement(f'{member.type.to_wasm()}.const', str(arg.value))
yield wasm.Statement(f'{member.type.to_wasm()}.store', 'offset=' + str(member.offset),
comment='Write tuple value to memory')
yield wasm.Statement('local.get', '$___new_reference___addr', comment='Store tuple address on stack')
def visit_Name(self, wlocals: WLocals, exp_type: wasm.OurType, node: ast.Name) -> StatementGenerator:
"""
Visits a Name node as (part of) an expression

View File

@ -80,6 +80,27 @@ class OurTypeClass(OurType):
def alloc_size(self) -> int:
return sum(x.type.alloc_size() for x in self.members)
class TupleMember:
"""
Represents a tuple member
"""
def __init__(self, type_: OurType, offset: int) -> None:
self.type = type_
self.offset = offset
class OurTypeTuple(OurType):
"""
Represents a tuple
"""
def __init__(self, members: List[TupleMember]) -> None:
self.members = members
def to_wasm(self) -> str:
return 'i32' # WASM uses 32 bit pointers
def alloc_size(self) -> int:
return sum(x.type.alloc_size() for x in self.members)
Param = Tuple[str, OurType]

View File

@ -317,3 +317,20 @@ def helper(shape1: Rectangle, shape2: Rectangle) -> i32:
assert 545 == result.returned_value
assert [] == result.log_int32_list
@pytest.mark.integration_test
def test_tuple_int():
code_py = """
@exported
def testEntry() -> i32:
return helper((24, 57, 80, ))
def helper(vector: Tuple[i32, i32, i32]) -> i32:
return vector[0] + vector[1] + vector[2]
"""
result = Suite(code_py, 'test_call').run_code()
assert 161 == result.returned_value
assert [] == result.log_int32_list