Compare commits

..

4 Commits

Author SHA1 Message Date
Johan B.W. de Vries
c3124f4325 Converted fractional, fixed integral 2023-11-16 16:08:26 +01:00
Johan B.W. de Vries
e1bfcdeb8f Cleanup, got rid of OPERATOR_MAP 2023-11-16 15:48:53 +01:00
Johan B.W. de Vries
82f84fe724 Migrated Num 2023-11-16 15:18:55 +01:00
Johan B.W. de Vries
81eacbf69e Started on a type class system 2023-11-16 15:10:20 +01:00
25 changed files with 312 additions and 137 deletions

View File

@ -1,4 +1,7 @@
WAT2WASM := venv/bin/python wat2wasm.py
WABT_DIR := /home/johan/sources/github.com/WebAssembly/wabt
WAT2WASM := $(WABT_DIR)/bin/wat2wasm
WASM2C := $(WABT_DIR)/bin/wasm2c
%.wat: %.py $(shell find phasm -name '*.py') venv/.done
venv/bin/python -m phasm $< $@
@ -12,6 +15,12 @@ WAT2WASM := venv/bin/python wat2wasm.py
%.wasm: %.wat
$(WAT2WASM) $^ -o $@
%.c: %.wasm
$(WASM2C) $^ -o $@
# %.exe: %.c
# cc $^ -o $@ -I $(WABT_DIR)/wasm2c
examples: venv/.done $(subst .py,.wasm,$(wildcard examples/*.py)) $(subst .py,.wat.html,$(wildcard examples/*.py)) $(subst .py,.py.html,$(wildcard examples/*.py))
venv/bin/python3 -m http.server --directory examples
@ -22,10 +31,10 @@ lint: venv/.done
venv/bin/ruff check phasm tests
typecheck: venv/.done
venv/bin/mypy --strict phasm wat2wasm.py tests/integration/helpers.py tests/integration/runners.py
venv/bin/mypy --strict phasm tests/integration/helpers.py tests/integration/runners.py
venv/.done: requirements.txt
python3.12 -m venv venv
python3.10 -m venv venv
venv/bin/python3 -m pip install wheel pip --upgrade
venv/bin/python3 -m pip install -r $^
touch $@

View File

@ -32,7 +32,7 @@ make lint typecheck
To compile a Phasm file:
```sh
python3.12 -m phasm source.py output.wat
python3.10 -m phasm source.py output.wat
```
Additional required tools

17
TODO.md
View File

@ -10,20 +10,3 @@
- Storing u8 in memory still claims 32 bits (since that's what you need in local variables). However, using load8_u / loadu_s we can optimize this.
- Implement a FizzBuzz example
- Also, check the codes for FIXME and TODO
- Allocation is done using pointers for members, is this desired?
- Merge in type classes
- test_bitwise_or_inv_type
- test_bytes_index_out_of_bounds vs static trap(?)
- test_num.py is probably best as part of the generator?
- Find pytest.mark.skip
- There's a weird resolve_as reference in calculate_alloc_size
- Either there should be more of them or less
- At first glance, looks like failure in the typing system
- Related to the FIXME in phasm_type3?
- WEBASSEMBLY_BUILTIN_FLOAT_OPS and WEBASSEMBLY_BUILTIN_BYTES_OPS are special cased
- Should be part of a prelude
- Casting is not implemented except u32 which is special cased
- Parser is putting stuff in ModuleDataBlock
- Compiler should probably do that

View File

@ -1,5 +1,3 @@
# CRC-32/ISO-HDLC
#
# #include <inttypes.h> // uint32_t, uint8_t
#
# uint32_t CRC32(const uint8_t data[], size_t data_length) {

View File

@ -497,12 +497,10 @@ class OurVisitor:
if 1 != len(node.args):
_raise_static_error(node, f'Function {node.func.id} requires 1 arguments but {len(node.args)} are given')
unary_op = UnaryOp(
return UnaryOp(
'cast',
self.visit_Module_FunctionDef_expr(module, function, our_locals, node.args[0]),
)
unary_op.type3 = type3types.u32
return unary_op
elif node.func.id == 'len':
if 1 != len(node.args):
_raise_static_error(node, f'Function {node.func.id} requires 1 arguments but {len(node.args)} are given')
@ -705,7 +703,7 @@ def _not_implemented(check: Any, msg: str) -> None:
if not check:
raise NotImplementedError(msg)
def _raise_static_error(node: Union[ast.stmt, ast.expr], msg: str) -> NoReturn:
def _raise_static_error(node: Union[ast.mod, ast.stmt, ast.expr], msg: str) -> NoReturn:
raise StaticError(
f'Static error on line {node.lineno}: {msg}'
)

View File

@ -1,19 +1,10 @@
marko==2.1.3
mypy==1.15.0
pygments==2.19.1
pytest==8.3.5
mypy==0.991
pygments==2.12.0
pytest==7.2.0
pytest-integration==0.2.2
ruff==0.11.4
wasmtime==31.0.0
# TODO:
# extism?
# wasmedge
# Check 2025-04-05
# wasm3: minimal maintenance phase
# py-wasm: last updated 6 years ago
# wasmer-python: Not compatible with python3.12, last updated 2 years ago
# WAVM: Last updated 3 years ago
pywasm==1.0.7
pywasm3==0.5.0
ruff==0.1.5
wasmer==1.1.0
wasmer_compiler_cranelift==1.1.0
wasmtime==3.0.0

14
stubs/pywasm/__init__.pyi Normal file
View File

@ -0,0 +1,14 @@
from typing import Any, Dict, List, Optional, Union
from . import binary
from . import option
from . import execution
class Runtime:
store: execution.Store
def __init__(self, module: binary.Module, imps: Optional[Dict[str, Any]] = None, opts: Optional[option.Option] = None):
...
def exec(self, name: str, args: List[Union[int, float]]) -> Any:
...

6
stubs/pywasm/binary.pyi Normal file
View File

@ -0,0 +1,6 @@
from typing import BinaryIO
class Module:
@classmethod
def from_reader(cls, reader: BinaryIO) -> 'Module':
...

View File

@ -0,0 +1,10 @@
from typing import List
class Result:
...
class MemoryInstance:
data: bytearray
class Store:
memory_list: List[MemoryInstance]

2
stubs/pywasm/option.pyi Normal file
View File

@ -0,0 +1,2 @@
class Option:
...

23
stubs/wasm3.pyi Normal file
View File

@ -0,0 +1,23 @@
from typing import Any, Callable
class Module:
...
class Runtime:
...
def load(self, wasm_bin: Module) -> None:
...
def get_memory(self, memid: int) -> memoryview:
...
def find_function(self, name: str) -> Callable[[Any], Any]:
...
class Environment:
def new_runtime(self, mem_size: int) -> Runtime:
...
def parse_module(self, wasm_bin: bytes) -> Module:
...

39
stubs/wasmer.pyi Normal file
View File

@ -0,0 +1,39 @@
from typing import Any, Dict, Callable, Union
def wat2wasm(inp: str) -> bytes:
...
class Store:
...
class Function:
def __init__(self, store: Store, func: Callable[[Any], Any]) -> None:
...
class Module:
def __init__(self, store: Store, wasm: bytes) -> None:
...
class Uint8Array:
def __getitem__(self, index: Union[int, slice]) -> int:
...
def __setitem__(self, idx: int, value: int) -> None:
...
class Memory:
def uint8_view(self, offset: int = 0) -> Uint8Array:
...
class Exports:
...
class ImportObject:
def register(self, region: str, values: Dict[str, Function]) -> None:
...
class Instance:
exports: Exports
def __init__(self, module: Module, imports: ImportObject) -> None:
...

View File

@ -16,7 +16,10 @@ class SuiteResult:
self.returned_value = None
RUNNER_CLASS_MAP = {
'pywasm': runners.RunnerPywasm,
'pywasm3': runners.RunnerPywasm3,
'wasmtime': runners.RunnerWasmtime,
'wasmer': runners.RunnerWasmer,
}
class Suite:
@ -26,7 +29,7 @@ class Suite:
def __init__(self, code_py: str) -> None:
self.code_py = code_py
def run_code(self, *args: Any, runtime: str = 'wasmtime', func_name: str = 'testEntry', imports: runners.Imports = None, do_format_check: bool = True) -> Any:
def run_code(self, *args: Any, runtime: str = 'pywasm3', func_name: str = 'testEntry', imports: runners.Imports = None) -> Any:
"""
Compiles the given python code into wasm and
then runs it
@ -47,11 +50,11 @@ class Suite:
write_header(sys.stderr, 'Assembly')
runner.dump_wasm_wat(sys.stderr)
runner.compile_wasm()
runner.interpreter_setup()
runner.interpreter_load(imports)
# Check if code formatting works
if do_format_check:
assert self.code_py == '\n' + phasm_render(runner.phasm_ast) # \n for formatting in tests
func_args = [x.type3 for x in runner.phasm_ast.functions[func_name].posonlyargs]

View File

@ -2,8 +2,12 @@
Runners to help run WebAssembly code on various interpreters
"""
import ctypes
import io
from typing import Any, Callable, Dict, Iterable, Optional, TextIO
import pywasm.binary
import wasm3
import wasmer
import wasmtime
from phasm import ourlang, wasm
@ -61,7 +65,7 @@ class RunnerBase:
"""
Compiles the WebAssembly AST into WebAssembly Binary
"""
raise NotImplementedError
self.wasm_bin = wasmer.wat2wasm(self.wasm_asm)
def interpreter_setup(self) -> None:
"""
@ -99,6 +103,77 @@ class RunnerBase:
"""
raise NotImplementedError
class RunnerPywasm(RunnerBase):
"""
Implements a runner for pywasm
See https://pypi.org/project/pywasm/
"""
module: pywasm.binary.Module
runtime: pywasm.Runtime
def interpreter_setup(self) -> None:
# Nothing to set up
pass
def interpreter_load(self, imports: Optional[Dict[str, Callable[[Any], Any]]] = None) -> None:
if imports is not None:
raise NotImplementedError
bytesio = io.BytesIO(self.wasm_bin)
self.module = pywasm.binary.Module.from_reader(bytesio)
self.runtime = pywasm.Runtime(self.module, {}, None)
def interpreter_write_memory(self, offset: int, data: Iterable[int]) -> None:
for idx, byt in enumerate(data):
self.runtime.store.memory_list[0].data[offset + idx] = byt
def interpreter_read_memory(self, offset: int, length: int) -> bytes:
return self.runtime.store.memory_list[0].data[offset:length]
def interpreter_dump_memory(self, textio: TextIO) -> None:
_dump_memory(textio, self.runtime.store.memory_list[0].data)
def call(self, function: str, *args: Any) -> Any:
return self.runtime.exec(function, [*args])
class RunnerPywasm3(RunnerBase):
"""
Implements a runner for pywasm3
See https://pypi.org/project/pywasm3/
"""
env: wasm3.Environment
rtime: wasm3.Runtime
mod: wasm3.Module
def interpreter_setup(self) -> None:
self.env = wasm3.Environment()
self.rtime = self.env.new_runtime(1024 * 1024)
def interpreter_load(self, imports: Optional[Dict[str, Callable[[Any], Any]]] = None) -> None:
if imports is not None:
raise NotImplementedError
self.mod = self.env.parse_module(self.wasm_bin)
self.rtime.load(self.mod)
def interpreter_write_memory(self, offset: int, data: Iterable[int]) -> None:
memory = self.rtime.get_memory(0)
for idx, byt in enumerate(data):
memory[offset + idx] = byt
def interpreter_read_memory(self, offset: int, length: int) -> bytes:
memory = self.rtime.get_memory(0)
return memory[offset:offset + length].tobytes()
def interpreter_dump_memory(self, textio: TextIO) -> None:
_dump_memory(textio, self.rtime.get_memory(0))
def call(self, function: str, *args: Any) -> Any:
return self.rtime.find_function(function)(*args)
class RunnerWasmtime(RunnerBase):
"""
Implements a runner for wasmtime
@ -109,44 +184,15 @@ class RunnerWasmtime(RunnerBase):
module: wasmtime.Module
instance: wasmtime.Instance
@classmethod
def func2type(cls, func: Callable[[Any], Any]) -> wasmtime.FuncType:
params: list[wasmtime.ValType] = []
code = func.__code__
for idx in range(code.co_argcount):
varname = code.co_varnames[idx]
vartype = func.__annotations__[varname]
if vartype is int:
params.append(wasmtime.ValType.i32())
else:
raise NotImplementedError
results: list[wasmtime.ValType] = []
if func.__annotations__['return'] is None:
pass # No return value
elif func.__annotations__['return'] is int:
results.append(wasmtime.ValType.i32())
else:
raise NotImplementedError('Return type', func.__annotations__['return'])
return wasmtime.FuncType(params, results)
def interpreter_setup(self) -> None:
self.store = wasmtime.Store()
def interpreter_load(self, imports: Optional[Dict[str, Callable[[Any], Any]]] = None) -> None:
functions: list[wasmtime.Func] = []
if imports is not None:
functions = [
wasmtime.Func(self.store, self.__class__.func2type(f), f)
for f in imports.values()
]
raise NotImplementedError
self.module = wasmtime.Module(self.store.engine, self.wasm_asm)
self.instance = wasmtime.Instance(self.store, self.module, functions)
self.module = wasmtime.Module(self.store.engine, self.wasm_bin)
self.instance = wasmtime.Instance(self.store, self.module, [])
def interpreter_write_memory(self, offset: int, data: Iterable[int]) -> None:
exports = self.instance.exports(self.store)
@ -171,7 +217,8 @@ class RunnerWasmtime(RunnerBase):
data_len = memory.data_len(self.store)
raw = ctypes.string_at(data_ptr, data_len)
return raw[offset:offset + length]
return raw[offset:length]
def interpreter_dump_memory(self, textio: TextIO) -> None:
exports = self.instance.exports(self.store)
@ -190,6 +237,63 @@ class RunnerWasmtime(RunnerBase):
return func(self.store, *args)
class RunnerWasmer(RunnerBase):
"""
Implements a runner for wasmer
See https://pypi.org/project/wasmer/
"""
# pylint: disable=E1101
store: wasmer.Store
module: wasmer.Module
instance: wasmer.Instance
def interpreter_setup(self) -> None:
self.store = wasmer.Store()
def interpreter_load(self, imports: Optional[Dict[str, Callable[[Any], Any]]] = None) -> None:
import_object = wasmer.ImportObject()
if imports:
import_object.register('imports', {
k: wasmer.Function(self.store, v)
for k, v in (imports or {}).items()
})
self.module = wasmer.Module(self.store, self.wasm_bin)
self.instance = wasmer.Instance(self.module, import_object)
def interpreter_write_memory(self, offset: int, data: Iterable[int]) -> None:
exports = self.instance.exports
memory = getattr(exports, 'memory')
assert isinstance(memory, wasmer.Memory)
view = memory.uint8_view(offset)
for idx, byt in enumerate(data):
view[idx] = byt
def interpreter_read_memory(self, offset: int, length: int) -> bytes:
exports = self.instance.exports
memory = getattr(exports, 'memory')
assert isinstance(memory, wasmer.Memory)
view = memory.uint8_view(offset)
return bytes(view[offset:length])
def interpreter_dump_memory(self, textio: TextIO) -> None:
exports = self.instance.exports
memory = getattr(exports, 'memory')
assert isinstance(memory, wasmer.Memory)
view = memory.uint8_view()
_dump_memory(textio, view) # type: ignore
def call(self, function: str, *args: Any) -> Any:
exports = self.instance.exports
func = getattr(exports, function)
return func(*args)
def _dump_memory(textio: TextIO, mem: bytes) -> None:
line_width = 16

View File

@ -8,7 +8,7 @@ def test_index():
with open('examples/buffer.py', 'r', encoding='ASCII') as fil:
code_py = "\n" + fil.read()
result = Suite(code_py).run_code(b'Hello, world!', 5, func_name='index')
result = Suite(code_py).run_code(b'Hello, world!', 5, func_name='index', runtime='wasmtime')
assert 44 == result.returned_value
@pytest.mark.slow_integration_test

View File

@ -1,3 +1,5 @@
import binascii
import pytest
from ..helpers import Suite
@ -5,15 +7,28 @@ from ..helpers import Suite
@pytest.mark.slow_integration_test
def test_crc32():
with open('examples/crc32.py', 'r', encoding='ASCII') as fil:
code_py = "\n" + fil.read()
# FIXME: Stub
# crc = 0xFFFFFFFF
# byt = 0x61
# => (crc >> 8) ^ _CRC32_Table[(crc & 0xFF) ^ byt]
# (crc >> 8) = 0x00FFFFFF
# => 0x00FFFFFF ^ _CRC32_Table[(crc & 0xFF) ^ byt]
# (crc & 0xFF) = 0xFF
# => 0x00FFFFFF ^ _CRC32_Table[0xFF ^ byt]
# 0xFF ^ 0x61 = 0x9E
# => 0x00FFFFFF ^ _CRC32_Table[0x9E]
# _CRC32_Table[0x9E] = 0x17b7be43
# => 0x00FFFFFF ^ 0x17b7be43
# https://reveng.sourceforge.io/crc-catalogue/legend.htm#crc.legend.params
in_put = b'123456789'
code_py = """
def _crc32_f(crc: u32, byt: u8) -> u32:
return 16777215 ^ 397917763
# https://reveng.sourceforge.io/crc-catalogue/17plus.htm#crc.cat.crc-32-iso-hdlc
check = 0xcbf43926
def testEntry(data: bytes) -> u32:
return 4294967295 ^ _crc32_f(4294967295, data[0])
"""
exp_result = binascii.crc32(b'a')
result = Suite(code_py).run_code(in_put, func_name='crc32', do_format_check=False)
result = Suite(code_py).run_code(b'a')
assert check == result.returned_value
assert exp_result == result.returned_value

View File

@ -102,7 +102,6 @@ def generate_code(markdown, template, settings):
print()
print('from ..helpers import Suite')
print()
print()
for test in get_tests(template):
assert len(test) == 4, test
@ -122,7 +121,7 @@ def generate_code(markdown, template, settings):
print('@pytest.mark.integration_test')
print(f'def test_{type_name}_{test_id}():')
print(' """')
print(' ' + user_story.strip().replace('\n', '\n '))
print(' ' + user_story.replace('\n', '\n '))
print(' """')
print(' code_py = """')
if 'CODE_HEADER' in settings:

View File

@ -3,15 +3,16 @@ import sys
import pytest
from ..helpers import Suite, write_header
from ..runners import RunnerWasmtime
from ..runners import RunnerPywasm
def setup_interpreter(phash_code: str) -> RunnerWasmtime:
runner = RunnerWasmtime(phash_code)
def setup_interpreter(phash_code: str) -> RunnerPywasm:
runner = RunnerPywasm(phash_code)
runner.parse()
runner.compile_ast()
runner.compile_wat()
runner.compile_wasm()
runner.interpreter_setup()
runner.interpreter_load()
@ -37,16 +38,16 @@ def testEntry(b: bytes) -> u8:
result = suite.run_code(b'')
assert 128 == result.returned_value
result = suite.run_code(b'\x80')
result = suite.run_code(b'\x80', runtime='pywasm')
assert 128 == result.returned_value
result = suite.run_code(b'\x80\x40')
result = suite.run_code(b'\x80\x40', runtime='pywasm')
assert 192 == result.returned_value
result = suite.run_code(b'\x80\x40\x20\x10')
result = suite.run_code(b'\x80\x40\x20\x10', runtime='pywasm')
assert 240 == result.returned_value
result = suite.run_code(b'\x80\x40\x20\x10\x08\x04\x02\x01')
result = suite.run_code(b'\x80\x40\x20\x10\x08\x04\x02\x01', runtime='pywasm')
assert 255 == result.returned_value
@pytest.mark.integration_test

View File

@ -20,7 +20,7 @@ def testEntry() -> {type_}:
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', TYPE_LIST)
def test_division_float_follow_ieee_so_inf_pos(type_):
def test_division_zero_let_it_crash_float(type_):
code_py = f"""
@exported
def testEntry() -> {type_}:
@ -31,17 +31,3 @@ def testEntry() -> {type_}:
# https://www.w3.org/TR/wasm-core-1/#-hrefop-fdivmathrmfdiv_n-z_1-z_2
result = Suite(code_py).run_code()
assert float('+inf') == result.returned_value
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', TYPE_LIST)
def test_division_float_follow_ieee_so_inf_neg(type_):
code_py = f"""
@exported
def testEntry() -> {type_}:
return -10.0 / 0.0
"""
# WebAssembly dictates that float division follows the IEEE rules
# https://www.w3.org/TR/wasm-core-1/#-hrefop-fdivmathrmfdiv_n-z_1-z_2
result = Suite(code_py).run_code()
assert float('-inf') == result.returned_value

View File

@ -21,6 +21,7 @@ def testEntry() -> i32:
return 4238 * mul
result = Suite(code_py).run_code(
runtime='wasmer',
imports={
'helper': helper,
}
@ -46,6 +47,7 @@ def testEntry() -> None:
prop = mul
result = Suite(code_py).run_code(
runtime='wasmer',
imports={
'helper': helper,
}
@ -71,6 +73,7 @@ def testEntry(x: u32) -> u8:
with pytest.raises(Type3Exception, match=r'u32 must be u8 instead'):
Suite(code_py).run_code(
runtime='wasmer',
imports={
'helper': helper,
}

View File

@ -42,7 +42,7 @@ def testEntry() -> {type_}:
result = Suite(code_py).run_code()
assert 13 == result.returned_value
assert TYPE_MAP[type_] is type(result.returned_value)
assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', FLOAT_TYPES)
@ -56,7 +56,7 @@ def testEntry() -> {type_}:
result = Suite(code_py).run_code()
assert 32.125 == result.returned_value
assert TYPE_MAP[type_] is type(result.returned_value)
assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', INT_TYPES)
@ -70,7 +70,7 @@ def testEntry() -> {type_}:
result = Suite(code_py).run_code()
assert 7 == result.returned_value
assert TYPE_MAP[type_] is type(result.returned_value)
assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', FLOAT_TYPES)
@ -84,7 +84,7 @@ def testEntry() -> {type_}:
result = Suite(code_py).run_code()
assert 32.125 == result.returned_value
assert TYPE_MAP[type_] is type(result.returned_value)
assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test
def test_subtraction_negative_result():
@ -153,7 +153,7 @@ def helper(left: {type_}, right: {type_}) -> {type_}:
result = Suite(code_py).run_code()
assert 22 == result.returned_value
assert TYPE_MAP[type_] is type(result.returned_value)
assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', FLOAT_TYPES)
@ -170,4 +170,4 @@ def helper(left: {type_}, right: {type_}) -> {type_}:
result = Suite(code_py).run_code()
assert 32.125 == result.returned_value
assert TYPE_MAP[type_] is type(result.returned_value)
assert TYPE_MAP[type_] == type(result.returned_value)

View File

@ -1,5 +1,4 @@
import pytest
import wasmtime
from phasm.type3.entry import Type3Exception
@ -65,7 +64,7 @@ def testEntry(x: u32) -> u8:
return CONSTANT[x]
"""
with pytest.raises(wasmtime.Trap):
with pytest.raises(RuntimeError):
Suite(code_py).run_code(3)
@pytest.mark.integration_test

View File

@ -74,9 +74,11 @@ CONSTANT: (u32, u8, u8, ) = (24, 4000, 1, )
@pytest.mark.integration_test
def test_tuple_must_use_literal_for_indexing():
code_py = """
CONSTANT: u32 = 0
@exported
def testEntry(x: (u8, u32, u64), y: u8) -> u64:
return x[y]
def testEntry(x: (u8, u32, u64)) -> u64:
return x[CONSTANT]
"""
with pytest.raises(Type3Exception, match='Must index with literal'):

View File

@ -3,7 +3,7 @@ import sys
import pytest
from ..helpers import write_header
from ..runners import RunnerWasmtime as Runner
from ..runners import RunnerPywasm3 as Runner
def setup_interpreter(phash_code: str) -> Runner:
@ -12,6 +12,7 @@ def setup_interpreter(phash_code: str) -> Runner:
runner.parse()
runner.compile_ast()
runner.compile_wat()
runner.compile_wasm()
runner.interpreter_setup()
runner.interpreter_load()

View File

@ -1,11 +0,0 @@
import sys
from wasmtime import wat2wasm
def main(_prog: str, inp: str, _dash_o: str, out: str) -> None:
with open(inp, 'rb') as inp_obj:
with open(out, 'wb') as out_obj:
out_obj.write(wat2wasm(inp_obj.read()))
if __name__ == '__main__':
main(*sys.argv)