From 547576de00e621ca1273231bcfb3d165af83bbc6 Mon Sep 17 00:00:00 2001 From: "Johan B.W. de Vries" Date: Sat, 3 Apr 2021 12:26:06 +0200 Subject: [PATCH] New repo, containing the basic idea --- Makefile | 8 ++++ compile.py | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ func.html | 20 ++++++++ log.html | 29 ++++++++++++ log.py | 5 ++ 5 files changed, 195 insertions(+) create mode 100644 Makefile create mode 100644 compile.py create mode 100644 func.html create mode 100644 log.html create mode 100644 log.py diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..58bd1f5 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +%.wat: %.py compile.py + python3.8 compile.py $< > $@ + +%.wasm: %.wat + wat2wasm $^ -o $@ + +server: + python3.8 -m http.server diff --git a/compile.py b/compile.py new file mode 100644 index 0000000..6720a4a --- /dev/null +++ b/compile.py @@ -0,0 +1,133 @@ +import _ast +import ast +import sys + +class Import: + def __init__(self, module, name, intname): + self.module = module + self.name = name + self.intname = intname + self.params = None + + def generate(self): + return '(import "{}" "{}" (func ${}{}))'.format( + self.module, + self.name, + self.intname, + ''.join(' (param {})'.format(x) for x in self.params) + ) + +class Statement: + def __init__(self, name, *args): + self.name = name + self.args = args + + def generate(self): + return '{} {}'.format(self.name, ' '.join(self.args)) + +class Function: + def __init__(self, name, exported=True): + self.name = name + self.exported = exported # TODO: Use __all__! + self.statements = [] + + def generate(self): + return '(func {}\n {})'.format( + ('(export "{}")' if self.exported else '${}').format(self.name), + '\n '.join(x.generate() for x in self.statements), + ) + +class Visitor(ast.NodeVisitor): + def __init__(self): + self._stack = [] + self.imports = [] + self.functions = [] + + 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): + func = Function( + node.name, + ) + + self._stack.append(func) + self.generic_visit(node) + self._stack.pop() + + self.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: + err(node.op) + + 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) + + def generate(self): + return '(module\n {}\n {})'.format( + '\n '.join(x.generate() for x in self.imports), + '\n '.join(x.generate() for x in self.functions), + ) + +def err(msg: str) -> None: + sys.stderr.write('{}\n'.format(msg)) + +def main(source: str) -> int: + with open(source, 'r') as fil: + code = fil.read() + + res = ast.parse(code, source) + + visitor = Visitor() + visitor.visit(res) + + print(visitor.generate()) + + return 0 + +if __name__ == '__main__': + sys.exit(main(*sys.argv[1:])) diff --git a/func.html b/func.html new file mode 100644 index 0000000..4967ac5 --- /dev/null +++ b/func.html @@ -0,0 +1,20 @@ + + + + + + + Simple add example + + + + + + + diff --git a/log.html b/log.html new file mode 100644 index 0000000..8f97d5d --- /dev/null +++ b/log.html @@ -0,0 +1,29 @@ + + + + + + + Simple log example + + + + + + + diff --git a/log.py b/log.py new file mode 100644 index 0000000..85f29fd --- /dev/null +++ b/log.py @@ -0,0 +1,5 @@ +from console import log as log +"log(i32)" + +def logIt(): + log(13 + 13 * 123)