New repo, containing the basic idea
This commit is contained in:
commit
547576de00
8
Makefile
Normal file
8
Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
%.wat: %.py compile.py
|
||||
python3.8 compile.py $< > $@
|
||||
|
||||
%.wasm: %.wat
|
||||
wat2wasm $^ -o $@
|
||||
|
||||
server:
|
||||
python3.8 -m http.server
|
||||
133
compile.py
Normal file
133
compile.py
Normal file
@ -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:]))
|
||||
20
func.html
Normal file
20
func.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Simple add example</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
|
||||
WebAssembly.instantiateStreaming(fetch('func.wasm'))
|
||||
.then(obj => {
|
||||
console.log(obj.instance.exports.add(1, 2)); // "3"
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
29
log.html
Normal file
29
log.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Simple log example</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
|
||||
var importObject = {
|
||||
console: {
|
||||
log: function(arg) {
|
||||
console.log(arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
WebAssembly.instantiateStreaming(fetch('log.wasm'), importObject)
|
||||
.then(obj => {
|
||||
obj.instance.exports.logIt();
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user