MVP #1

Merged
jbwdevries merged 73 commits from idea_crc32 into master 2022-08-21 12:59:21 +00:00
4 changed files with 120 additions and 15 deletions
Showing only changes of commit 453c2865a8 - Show all commits

View File

@ -21,6 +21,11 @@ def type_(inp: ourlang.OurType) -> wasm.OurType:
if isinstance(inp, ourlang.OurTypeFloat64):
return wasm.OurTypeFloat64()
if isinstance(inp, ourlang.Struct):
# Structs are passed as pointer
# And pointers are i32
return wasm.OurTypeInt32()
raise NotImplementedError(type_, inp)
OPERATOR_MAP = {
@ -89,6 +94,19 @@ def expression(inp: ourlang.Expression) -> Statements:
yield wasm.Statement('call', '${}'.format(inp.function.name))
return
if isinstance(inp, ourlang.AccessStructMember):
# FIXME: Properly implement this
# inp.type.render() is also a hack that doesn't really work consistently
if not isinstance(inp.type, (
ourlang.OurTypeInt32, ourlang.OurTypeFloat32,
ourlang.OurTypeInt64, ourlang.OurTypeFloat64,
)):
raise NotImplementedError(inp, inp.type)
yield from expression(inp.varref)
yield wasm.Statement(inp.type.render() + '.load', 'offset=' + str(inp.member.offset))
return
raise NotImplementedError(expression, inp)
def statement_return(inp: ourlang.StatementReturn) -> Statements:
@ -125,6 +143,21 @@ def function_argument(inp: Tuple[str, ourlang.OurType]) -> wasm.Param:
return (inp[0], type_(inp[1]), )
def function(inp: ourlang.Function) -> wasm.Function:
if isinstance(inp, ourlang.StructConstructor):
statements = [
*_generate_struct_constructor(inp)
]
locals_ = [
('___new_reference___addr', wasm.OurTypeInt32(), ),
]
else:
statements = [
x
for y in inp.statements
for x in statement(y)
]
locals_ = [] # TODO
return wasm.Function(
inp.name,
inp.exported,
@ -132,20 +165,63 @@ def function(inp: ourlang.Function) -> wasm.Function:
function_argument(x)
for x in inp.posonlyargs
],
[], # TODO
locals_,
type_(inp.returns),
[
x
for y in inp.statements
for x in statement(y)
]
statements
)
def module(inp: ourlang.Module) -> wasm.Module:
result = wasm.Module()
result.functions = [*map(
function, inp.functions.values(),
)]
result.functions = [
_generate_allocator(inp),
] + [
function(x)
for x in inp.functions.values()
]
return result
def _generate_allocator(mod: ourlang.Module) -> wasm.Function:
return wasm.Function(
'___new_reference___',
False,
[
('alloc_size', type_(mod.types['i32']), ),
],
[
('result', type_(mod.types['i32']), ),
],
type_(mod.types['i32']),
[
wasm.Statement('i32.const', '0'),
wasm.Statement('i32.const', '0'),
wasm.Statement('i32.load'),
wasm.Statement('local.tee', '$result', comment='Address for this call'),
wasm.Statement('local.get', '$alloc_size'),
wasm.Statement('i32.add'),
wasm.Statement('i32.store', comment='Address for the next call'),
wasm.Statement('local.get', '$result'),
],
)
def _generate_struct_constructor(inp: ourlang.StructConstructor) -> Statements:
yield wasm.Statement('i32.const', str(inp.struct.alloc_size()))
yield wasm.Statement('call', '$___new_reference___')
yield wasm.Statement('local.set', '$___new_reference___addr')
for member in inp.struct.members:
# FIXME: Properly implement this
# inp.type.render() is also a hack that doesn't really work consistently
if not isinstance(member.type, (
ourlang.OurTypeInt32, ourlang.OurTypeFloat32,
ourlang.OurTypeInt64, ourlang.OurTypeFloat64,
)):
raise NotImplementedError
yield wasm.Statement('local.get', '$___new_reference___addr')
yield wasm.Statement('local.get', f'${member.name}')
yield wasm.Statement(f'{member.type.render()}.store', 'offset=' + str(member.offset))
yield wasm.Statement('local.get', '$___new_reference___addr')

View File

@ -217,7 +217,9 @@ class UnaryOp(Expression):
operator: str
right: Expression
def __init__(self, operator: str, right: Expression) -> None:
def __init__(self, type_: OurType, operator: str, right: Expression) -> None:
super().__init__(type_)
self.operator = operator
self.right = right
@ -234,6 +236,8 @@ class FunctionCall(Expression):
arguments: List[Expression]
def __init__(self, function: 'Function') -> None:
super().__init__(function.returns)
self.function = function
self.arguments = []
@ -258,6 +262,8 @@ class AccessStructMember(Expression):
member: 'StructMember'
def __init__(self, varref: VariableReference, member: 'StructMember') -> None:
super().__init__(member.type)
self.varref = varref
self.member = member
@ -275,6 +281,8 @@ class AccessTupleMember(Expression):
member_type: 'OurType'
def __init__(self, varref: VariableReference, member_idx: int, member_type: 'OurType') -> None:
super().__init__(member_type)
self.varref = varref
self.member_idx = member_idx
self.member_type = member_type
@ -286,13 +294,14 @@ class TupleCreation(Expression):
"""
Create a tuple instance
"""
__slots__ = ('type', 'members', )
__slots__ = ('members', )
type: OurTypeTuple
members: List[Expression]
def __init__(self, type_: OurTypeTuple) -> None:
self.type = type_
super().__init__(type_)
self.members = []
def render(self) -> str:
@ -488,6 +497,12 @@ class Struct(OurType):
return result
def alloc_size(self) -> int:
return sum(
x.type.alloc_size()
for x in self.members
)
class Module:
"""
A module is a file and consists of functions
@ -747,6 +762,7 @@ class OurVisitor:
raise NotImplementedError(f'Operator {node.op}')
return UnaryOp(
exp_type,
operator,
self.visit_Module_FunctionDef_expr(module, function, our_locals, exp_type, node.operand),
)

View File

@ -199,7 +199,7 @@ class Visitor:
params.append((arg.arg, self._get_type(arg.annotation), ))
locals_: List[wasm.Param] = [
('___new_reference___addr', self._get_type('i32')), # For the ___new_reference__ method
('___new_reference___addr', self._get_type('i32')), # For the ___new_reference___ method
]
return wasm.Function(node.name, exported, params, locals_, result, [])

View File

@ -232,6 +232,18 @@ class Function:
'\n '.join(x.generate() for x in self.statements),
)
class ModuleMemory:
def __init__(self, data: bytes = b'') -> None:
self.data = data
def generate(self) -> str:
return '(memory 1)\n (data (memory 0) (i32.const 0) "{}")\n'.format(
''.join(
f'\\{x:02x}'
for x in self.data
)
)
class Module:
"""
Represents a Web Assembly module
@ -239,13 +251,14 @@ class Module:
def __init__(self) -> None:
self.imports: List[Import] = []
self.functions: List[Function] = []
self.memory = ModuleMemory(b'\x04') # For ___new_reference___
def generate(self) -> str:
"""
Generates the text version
"""
return '(module\n (memory 1)\n (data (memory 0) (i32.const 0) {})\n {}\n {})\n'.format(
'"\\04\\00\\00\\00"',
return '(module\n {}\n {}\n {})\n'.format(
self.memory.generate(),
'\n '.join(x.generate() for x in self.imports),
'\n '.join(x.generate() for x in self.functions),
)