110 lines
2.9 KiB
Python
110 lines
2.9 KiB
Python
import ast
|
|
|
|
from .wasm import Function, Import, Module, Statement
|
|
|
|
class Visitor(ast.NodeVisitor):
|
|
def __init__(self, module: Module) -> None:
|
|
self._stack = []
|
|
self.module = module
|
|
|
|
# def visit_ImportFrom(self, node):
|
|
# for alias in node.names:
|
|
# self.imports.append(Import(
|
|
# node.module,
|
|
# alias.name,
|
|
# alias.asname,
|
|
# ))
|
|
|
|
def visit_FunctionDef(self, node):
|
|
is_export = False
|
|
|
|
if node.decorator_list:
|
|
# TODO: Support normal decorators
|
|
assert 1 == len(node.decorator_list)
|
|
|
|
call = node.decorator_list[0]
|
|
if not isinstance(call, ast.Name):
|
|
assert isinstance(call, ast.Call)
|
|
|
|
assert 'external' == call.func.id
|
|
assert 1 == len(call.args)
|
|
assert isinstance(call.args[0].value, str)
|
|
|
|
import_ = Import(
|
|
call.args[0].value,
|
|
node.name,
|
|
node.name,
|
|
)
|
|
|
|
import_.params = [
|
|
arg.annotation.id
|
|
for arg in node.args.args
|
|
]
|
|
|
|
self.module.imports.append(import_)
|
|
return
|
|
|
|
assert call.id == 'export'
|
|
is_export = True
|
|
|
|
func = Function(
|
|
node.name,
|
|
is_export,
|
|
)
|
|
|
|
for arg in node.args.args:
|
|
func.params.append(
|
|
|
|
)
|
|
|
|
self._stack.append(func)
|
|
self.generic_visit(node)
|
|
self._stack.pop()
|
|
|
|
self.module.functions.append(func)
|
|
|
|
def visit_Expr(self, node):
|
|
self.generic_visit(node)
|
|
|
|
def visit_Call(self, node):
|
|
self.generic_visit(node)
|
|
|
|
func = self._stack[-1]
|
|
func.statements.append(
|
|
Statement('call', '$' + node.func.id)
|
|
)
|
|
|
|
def visit_BinOp(self, node):
|
|
self.generic_visit(node)
|
|
|
|
func = self._stack[-1]
|
|
|
|
if 'Add' == node.op.__class__.__name__:
|
|
func.statements.append(
|
|
Statement('i32.add')
|
|
)
|
|
elif 'Mult' == node.op.__class__.__name__:
|
|
func.statements.append(
|
|
Statement('i32.mul')
|
|
)
|
|
else:
|
|
raise NotImplementedError
|
|
|
|
def visit_Constant(self, node):
|
|
if not self._stack:
|
|
# Constant outside of any function
|
|
imp = self.imports[-1]
|
|
prefix = imp.name + '('
|
|
val = node.value.strip()
|
|
|
|
if val.startswith(prefix) and val.endswith(')'):
|
|
imp.params = val[len(prefix):-1].split(',')
|
|
else:
|
|
func = self._stack[-1]
|
|
if isinstance(node.value, int):
|
|
func.statements.append(
|
|
Statement('i32.const', str(node.value))
|
|
)
|
|
|
|
self.generic_visit(node)
|