phasm/py2wasm/compiler.py
2022-06-19 15:10:13 +02:00

116 lines
3.3 KiB
Python

"""
This module contains the code to convert parsed Ourlang into WebAssembly code
"""
from typing import Generator, Tuple
from . import ourlang
from . import wasm
Statements = Generator[wasm.Statement, None, None]
def type_(inp: ourlang.OurType) -> wasm.OurType:
if isinstance(inp, ourlang.OurTypeInt32):
return wasm.OurTypeInt32()
if isinstance(inp, ourlang.OurTypeInt64):
return wasm.OurTypeInt64()
if isinstance(inp, ourlang.OurTypeFloat32):
return wasm.OurTypeFloat32()
if isinstance(inp, ourlang.OurTypeFloat64):
return wasm.OurTypeFloat64()
raise NotImplementedError(type_, inp)
OPERATOR_MAP = {
'+': 'add',
'-': 'sub',
}
def expression(inp: ourlang.Expression) -> Statements:
if isinstance(inp, ourlang.ConstantInt32):
yield wasm.Statement('i32.const', str(inp.value))
return
if isinstance(inp, ourlang.ConstantInt64):
yield wasm.Statement('i64.const', str(inp.value))
return
if isinstance(inp, ourlang.ConstantFloat32):
yield wasm.Statement('f32.const', str(inp.value))
return
if isinstance(inp, ourlang.ConstantFloat64):
yield wasm.Statement('f64.const', str(inp.value))
return
if isinstance(inp, ourlang.VariableReference):
yield wasm.Statement('local.get', '${}'.format(inp.name))
return
if isinstance(inp, ourlang.BinaryOp):
yield from expression(inp.left)
yield from expression(inp.right)
if isinstance(inp.type, ourlang.OurTypeInt32):
if operator := OPERATOR_MAP.get(inp.operator, None):
yield wasm.Statement(f'i32.{operator}')
return
if isinstance(inp.type, ourlang.OurTypeInt64):
if operator := OPERATOR_MAP.get(inp.operator, None):
yield wasm.Statement(f'i64.{operator}')
return
if isinstance(inp.type, ourlang.OurTypeFloat32):
if operator := OPERATOR_MAP.get(inp.operator, None):
yield wasm.Statement(f'f32.{operator}')
return
if isinstance(inp.type, ourlang.OurTypeFloat64):
if operator := OPERATOR_MAP.get(inp.operator, None):
yield wasm.Statement(f'f64.{operator}')
return
raise NotImplementedError(expression, inp.type, inp.operator)
raise NotImplementedError(expression, inp)
def statement_return(inp: ourlang.StatementReturn) -> Statements:
yield from expression(inp.value)
yield wasm.Statement('return')
def statement(inp: ourlang.Statement) -> Statements:
if isinstance(inp, ourlang.StatementReturn):
yield from statement_return(inp)
return
raise NotImplementedError(statement, inp)
def function_argument(inp: Tuple[str, ourlang.OurType]) -> wasm.Param:
return (inp[0], type_(inp[1]), )
def function(inp: ourlang.Function) -> wasm.Function:
return wasm.Function(
inp.name,
inp.exported,
[
function_argument(x)
for x in inp.posonlyargs
],
[], # TODO
type_(inp.returns),
[
x
for y in inp.statements
for x in statement(y)
]
)
def module(inp: ourlang.Module) -> wasm.Module:
result = wasm.Module()
result.functions = [*map(
function, inp.functions.values(),
)]
return result