This commit is contained in:
Johan B.W. de Vries 2022-06-19 16:09:06 +02:00
parent 9dbdb11732
commit 453c2865a8
4 changed files with 120 additions and 15 deletions

View File

@ -21,6 +21,11 @@ def type_(inp: ourlang.OurType) -> wasm.OurType:
if isinstance(inp, ourlang.OurTypeFloat64): if isinstance(inp, ourlang.OurTypeFloat64):
return wasm.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) raise NotImplementedError(type_, inp)
OPERATOR_MAP = { OPERATOR_MAP = {
@ -89,6 +94,19 @@ def expression(inp: ourlang.Expression) -> Statements:
yield wasm.Statement('call', '${}'.format(inp.function.name)) yield wasm.Statement('call', '${}'.format(inp.function.name))
return 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) raise NotImplementedError(expression, inp)
def statement_return(inp: ourlang.StatementReturn) -> Statements: 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]), ) return (inp[0], type_(inp[1]), )
def function(inp: ourlang.Function) -> wasm.Function: 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( return wasm.Function(
inp.name, inp.name,
inp.exported, inp.exported,
@ -132,20 +165,63 @@ def function(inp: ourlang.Function) -> wasm.Function:
function_argument(x) function_argument(x)
for x in inp.posonlyargs for x in inp.posonlyargs
], ],
[], # TODO locals_,
type_(inp.returns), type_(inp.returns),
[ statements
x
for y in inp.statements
for x in statement(y)
]
) )
def module(inp: ourlang.Module) -> wasm.Module: def module(inp: ourlang.Module) -> wasm.Module:
result = wasm.Module() result = wasm.Module()
result.functions = [*map( result.functions = [
function, inp.functions.values(), _generate_allocator(inp),
)] ] + [
function(x)
for x in inp.functions.values()
]
return result 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 operator: str
right: Expression 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.operator = operator
self.right = right self.right = right
@ -234,6 +236,8 @@ class FunctionCall(Expression):
arguments: List[Expression] arguments: List[Expression]
def __init__(self, function: 'Function') -> None: def __init__(self, function: 'Function') -> None:
super().__init__(function.returns)
self.function = function self.function = function
self.arguments = [] self.arguments = []
@ -258,6 +262,8 @@ class AccessStructMember(Expression):
member: 'StructMember' member: 'StructMember'
def __init__(self, varref: VariableReference, member: 'StructMember') -> None: def __init__(self, varref: VariableReference, member: 'StructMember') -> None:
super().__init__(member.type)
self.varref = varref self.varref = varref
self.member = member self.member = member
@ -275,6 +281,8 @@ class AccessTupleMember(Expression):
member_type: 'OurType' member_type: 'OurType'
def __init__(self, varref: VariableReference, member_idx: int, member_type: 'OurType') -> None: def __init__(self, varref: VariableReference, member_idx: int, member_type: 'OurType') -> None:
super().__init__(member_type)
self.varref = varref self.varref = varref
self.member_idx = member_idx self.member_idx = member_idx
self.member_type = member_type self.member_type = member_type
@ -286,13 +294,14 @@ class TupleCreation(Expression):
""" """
Create a tuple instance Create a tuple instance
""" """
__slots__ = ('type', 'members', ) __slots__ = ('members', )
type: OurTypeTuple type: OurTypeTuple
members: List[Expression] members: List[Expression]
def __init__(self, type_: OurTypeTuple) -> None: def __init__(self, type_: OurTypeTuple) -> None:
self.type = type_ super().__init__(type_)
self.members = [] self.members = []
def render(self) -> str: def render(self) -> str:
@ -488,6 +497,12 @@ class Struct(OurType):
return result return result
def alloc_size(self) -> int:
return sum(
x.type.alloc_size()
for x in self.members
)
class Module: class Module:
""" """
A module is a file and consists of functions A module is a file and consists of functions
@ -747,6 +762,7 @@ class OurVisitor:
raise NotImplementedError(f'Operator {node.op}') raise NotImplementedError(f'Operator {node.op}')
return UnaryOp( return UnaryOp(
exp_type,
operator, operator,
self.visit_Module_FunctionDef_expr(module, function, our_locals, exp_type, node.operand), 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), )) params.append((arg.arg, self._get_type(arg.annotation), ))
locals_: List[wasm.Param] = [ 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, []) 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), '\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: class Module:
""" """
Represents a Web Assembly module Represents a Web Assembly module
@ -239,13 +251,14 @@ class Module:
def __init__(self) -> None: def __init__(self) -> None:
self.imports: List[Import] = [] self.imports: List[Import] = []
self.functions: List[Function] = [] self.functions: List[Function] = []
self.memory = ModuleMemory(b'\x04') # For ___new_reference___
def generate(self) -> str: def generate(self) -> str:
""" """
Generates the text version Generates the text version
""" """
return '(module\n (memory 1)\n (data (memory 0) (i32.const 0) {})\n {}\n {})\n'.format( return '(module\n {}\n {}\n {})\n'.format(
'"\\04\\00\\00\\00"', self.memory.generate(),
'\n '.join(x.generate() for x in self.imports), '\n '.join(x.generate() for x in self.imports),
'\n '.join(x.generate() for x in self.functions), '\n '.join(x.generate() for x in self.functions),
) )