pwasm 0.1a0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pwasm-0.1a0/PKG-INFO +140 -0
- pwasm-0.1a0/README.md +127 -0
- pwasm-0.1a0/pyproject.toml +27 -0
- pwasm-0.1a0/src/pwasm/__init__.py +44 -0
- pwasm-0.1a0/src/pwasm/decoder.py +533 -0
- pwasm-0.1a0/src/pwasm/errors.py +31 -0
- pwasm-0.1a0/src/pwasm/executor.py +822 -0
- pwasm-0.1a0/src/pwasm/opcodes.py +622 -0
- pwasm-0.1a0/src/pwasm/py.typed +0 -0
- pwasm-0.1a0/src/pwasm/types.py +196 -0
pwasm-0.1a0/PKG-INFO
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pwasm
|
|
3
|
+
Version: 0.1a0
|
|
4
|
+
Summary: A pure Python WebAssembly runtime
|
|
5
|
+
Author: Simon Willison
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Project-URL: CI, https://github.com/simonw/pwasm/actions
|
|
9
|
+
Project-URL: Changelog, https://github.com/simonw/pwasm/releases
|
|
10
|
+
Project-URL: Homepage, https://github.com/simonw/pwasm
|
|
11
|
+
Project-URL: Issues, https://github.com/simonw/pwasm/issues
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# pwasm
|
|
15
|
+
|
|
16
|
+
[](https://pypi.org/project/pwasm/)
|
|
17
|
+
[](https://github.com/simonw/pwasm/actions/workflows/test.yml)
|
|
18
|
+
[](https://github.com/simonw/pwasm/releases)
|
|
19
|
+
[](https://github.com/simonw/pwasm/blob/main/LICENSE)
|
|
20
|
+
|
|
21
|
+
A pure Python WebAssembly runtime.
|
|
22
|
+
|
|
23
|
+
> **Warning:** This is alpha software. It is significantly slower than WebAssembly runtimes with native extensions like [wasmtime-py](https://github.com/bytecodealliance/wasmtime-py).
|
|
24
|
+
|
|
25
|
+
## Overview
|
|
26
|
+
|
|
27
|
+
`pwasm` is a WebAssembly runtime written entirely in Python with zero external dependencies. It can load and execute `.wasm` binary modules without requiring any C extensions.
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- **Pure Python** - No external dependencies or C extensions required
|
|
32
|
+
- **WebAssembly MVP support** - Parses and executes WebAssembly 1.0 binary format
|
|
33
|
+
- **Pythonic API** - Access exported functions directly as Python methods
|
|
34
|
+
- **i32 arithmetic** - Full support for 32-bit integer operations
|
|
35
|
+
- **Control flow** - Blocks, loops, conditionals, and branching instructions
|
|
36
|
+
- **Local and global variables** - Get, set, and tee operations with mutability checking
|
|
37
|
+
- **Memory support** - Linear memory with data segment initialization
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install pwasm
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or with uv:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv add pwasm
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Requirements
|
|
52
|
+
|
|
53
|
+
- Python 3.10+
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
### Loading and Running a WebAssembly Module
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from pwasm import decode_module, instantiate
|
|
61
|
+
|
|
62
|
+
# Load a WASM module from bytes
|
|
63
|
+
with open("module.wasm", "rb") as f:
|
|
64
|
+
wasm_bytes = f.read()
|
|
65
|
+
|
|
66
|
+
module = decode_module(wasm_bytes)
|
|
67
|
+
instance = instantiate(module)
|
|
68
|
+
|
|
69
|
+
# Call exported functions directly
|
|
70
|
+
result = instance.exports.add(2, 3)
|
|
71
|
+
print(result) # 5
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Working with Multiple Functions
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from pwasm import decode_module, instantiate
|
|
78
|
+
|
|
79
|
+
module = decode_module(wasm_bytes)
|
|
80
|
+
instance = instantiate(module)
|
|
81
|
+
|
|
82
|
+
# Arithmetic operations
|
|
83
|
+
print(instance.exports.add(10, 20)) # 30
|
|
84
|
+
print(instance.exports.sub(50, 8)) # 42
|
|
85
|
+
print(instance.exports.mul(6, 7)) # 42
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Error Handling
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from pwasm import decode_module, instantiate
|
|
92
|
+
from pwasm.errors import TrapError, DecodeError
|
|
93
|
+
|
|
94
|
+
# Handle runtime traps (e.g., division by zero)
|
|
95
|
+
try:
|
|
96
|
+
instance.exports.div_s(10, 0)
|
|
97
|
+
except TrapError as e:
|
|
98
|
+
print(f"Runtime trap: {e}")
|
|
99
|
+
|
|
100
|
+
# Handle malformed WASM
|
|
101
|
+
try:
|
|
102
|
+
module = decode_module(b"invalid wasm")
|
|
103
|
+
except DecodeError as e:
|
|
104
|
+
print(f"Decode error: {e}")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Architecture
|
|
108
|
+
|
|
109
|
+
### Components
|
|
110
|
+
|
|
111
|
+
- **decoder.py** - Parses WebAssembly binary format with LEB128 decoding
|
|
112
|
+
- **types.py** - WebAssembly type system (i32, i64, f32, f64, funcref, externref)
|
|
113
|
+
- **executor.py** - Stack-based bytecode interpreter
|
|
114
|
+
- **errors.py** - Exception hierarchy (WasmError, DecodeError, ValidationError, TrapError, LinkError)
|
|
115
|
+
|
|
116
|
+
### Execution Model
|
|
117
|
+
|
|
118
|
+
pwasm uses a stack-based execution model faithful to the WebAssembly specification:
|
|
119
|
+
|
|
120
|
+
1. **Value Stack** - Operand values for instructions
|
|
121
|
+
2. **Call Stack** - Function frames with locals and return addresses
|
|
122
|
+
3. **Control Flow** - Pre-computed block/loop/if targets for branching
|
|
123
|
+
|
|
124
|
+
## Development
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Clone and setup
|
|
128
|
+
git clone https://github.com/simonw/pwasm
|
|
129
|
+
cd pwasm
|
|
130
|
+
|
|
131
|
+
# Run tests
|
|
132
|
+
uv run pytest
|
|
133
|
+
|
|
134
|
+
# Format code
|
|
135
|
+
uv run black .
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
Apache 2.0
|
pwasm-0.1a0/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# pwasm
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/pwasm/)
|
|
4
|
+
[](https://github.com/simonw/pwasm/actions/workflows/test.yml)
|
|
5
|
+
[](https://github.com/simonw/pwasm/releases)
|
|
6
|
+
[](https://github.com/simonw/pwasm/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
A pure Python WebAssembly runtime.
|
|
9
|
+
|
|
10
|
+
> **Warning:** This is alpha software. It is significantly slower than WebAssembly runtimes with native extensions like [wasmtime-py](https://github.com/bytecodealliance/wasmtime-py).
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
`pwasm` is a WebAssembly runtime written entirely in Python with zero external dependencies. It can load and execute `.wasm` binary modules without requiring any C extensions.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Pure Python** - No external dependencies or C extensions required
|
|
19
|
+
- **WebAssembly MVP support** - Parses and executes WebAssembly 1.0 binary format
|
|
20
|
+
- **Pythonic API** - Access exported functions directly as Python methods
|
|
21
|
+
- **i32 arithmetic** - Full support for 32-bit integer operations
|
|
22
|
+
- **Control flow** - Blocks, loops, conditionals, and branching instructions
|
|
23
|
+
- **Local and global variables** - Get, set, and tee operations with mutability checking
|
|
24
|
+
- **Memory support** - Linear memory with data segment initialization
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install pwasm
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or with uv:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv add pwasm
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Requirements
|
|
39
|
+
|
|
40
|
+
- Python 3.10+
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
### Loading and Running a WebAssembly Module
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from pwasm import decode_module, instantiate
|
|
48
|
+
|
|
49
|
+
# Load a WASM module from bytes
|
|
50
|
+
with open("module.wasm", "rb") as f:
|
|
51
|
+
wasm_bytes = f.read()
|
|
52
|
+
|
|
53
|
+
module = decode_module(wasm_bytes)
|
|
54
|
+
instance = instantiate(module)
|
|
55
|
+
|
|
56
|
+
# Call exported functions directly
|
|
57
|
+
result = instance.exports.add(2, 3)
|
|
58
|
+
print(result) # 5
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Working with Multiple Functions
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from pwasm import decode_module, instantiate
|
|
65
|
+
|
|
66
|
+
module = decode_module(wasm_bytes)
|
|
67
|
+
instance = instantiate(module)
|
|
68
|
+
|
|
69
|
+
# Arithmetic operations
|
|
70
|
+
print(instance.exports.add(10, 20)) # 30
|
|
71
|
+
print(instance.exports.sub(50, 8)) # 42
|
|
72
|
+
print(instance.exports.mul(6, 7)) # 42
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Error Handling
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from pwasm import decode_module, instantiate
|
|
79
|
+
from pwasm.errors import TrapError, DecodeError
|
|
80
|
+
|
|
81
|
+
# Handle runtime traps (e.g., division by zero)
|
|
82
|
+
try:
|
|
83
|
+
instance.exports.div_s(10, 0)
|
|
84
|
+
except TrapError as e:
|
|
85
|
+
print(f"Runtime trap: {e}")
|
|
86
|
+
|
|
87
|
+
# Handle malformed WASM
|
|
88
|
+
try:
|
|
89
|
+
module = decode_module(b"invalid wasm")
|
|
90
|
+
except DecodeError as e:
|
|
91
|
+
print(f"Decode error: {e}")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Architecture
|
|
95
|
+
|
|
96
|
+
### Components
|
|
97
|
+
|
|
98
|
+
- **decoder.py** - Parses WebAssembly binary format with LEB128 decoding
|
|
99
|
+
- **types.py** - WebAssembly type system (i32, i64, f32, f64, funcref, externref)
|
|
100
|
+
- **executor.py** - Stack-based bytecode interpreter
|
|
101
|
+
- **errors.py** - Exception hierarchy (WasmError, DecodeError, ValidationError, TrapError, LinkError)
|
|
102
|
+
|
|
103
|
+
### Execution Model
|
|
104
|
+
|
|
105
|
+
pwasm uses a stack-based execution model faithful to the WebAssembly specification:
|
|
106
|
+
|
|
107
|
+
1. **Value Stack** - Operand values for instructions
|
|
108
|
+
2. **Call Stack** - Function frames with locals and return addresses
|
|
109
|
+
3. **Control Flow** - Pre-computed block/loop/if targets for branching
|
|
110
|
+
|
|
111
|
+
## Development
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Clone and setup
|
|
115
|
+
git clone https://github.com/simonw/pwasm
|
|
116
|
+
cd pwasm
|
|
117
|
+
|
|
118
|
+
# Run tests
|
|
119
|
+
uv run pytest
|
|
120
|
+
|
|
121
|
+
# Format code
|
|
122
|
+
uv run black .
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
Apache 2.0
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pwasm"
|
|
3
|
+
version = "0.1a0"
|
|
4
|
+
description = "A pure Python WebAssembly runtime"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Simon Willison" }
|
|
8
|
+
]
|
|
9
|
+
license = "Apache-2.0"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = []
|
|
12
|
+
|
|
13
|
+
[project.urls]
|
|
14
|
+
Homepage = "https://github.com/simonw/pwasm"
|
|
15
|
+
Changelog = "https://github.com/simonw/pwasm/releases"
|
|
16
|
+
Issues = "https://github.com/simonw/pwasm/issues"
|
|
17
|
+
CI = "https://github.com/simonw/pwasm/actions"
|
|
18
|
+
|
|
19
|
+
[build-system]
|
|
20
|
+
requires = ["uv_build>=0.9.7,<0.10.0"]
|
|
21
|
+
build-backend = "uv_build"
|
|
22
|
+
|
|
23
|
+
[dependency-groups]
|
|
24
|
+
dev = [
|
|
25
|
+
"pytest>=9.0.2",
|
|
26
|
+
"black",
|
|
27
|
+
]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Pure Python WebAssembly Runtime.
|
|
2
|
+
|
|
3
|
+
A WebAssembly runtime implemented in pure Python with no dependencies.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .decoder import (
|
|
7
|
+
decode_module,
|
|
8
|
+
BinaryReader,
|
|
9
|
+
decode_unsigned_leb128,
|
|
10
|
+
decode_signed_leb128,
|
|
11
|
+
)
|
|
12
|
+
from .errors import WasmError, DecodeError, ValidationError, TrapError, LinkError
|
|
13
|
+
from .types import Module, FuncType, Function, Export, Import, Instruction
|
|
14
|
+
from .executor import instantiate, Instance
|
|
15
|
+
|
|
16
|
+
__version__ = "0.1.0"
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
# Main API
|
|
20
|
+
"decode_module",
|
|
21
|
+
"instantiate",
|
|
22
|
+
"Instance",
|
|
23
|
+
# Decoder internals (for testing)
|
|
24
|
+
"BinaryReader",
|
|
25
|
+
"decode_unsigned_leb128",
|
|
26
|
+
"decode_signed_leb128",
|
|
27
|
+
# Types
|
|
28
|
+
"Module",
|
|
29
|
+
"FuncType",
|
|
30
|
+
"Function",
|
|
31
|
+
"Export",
|
|
32
|
+
"Import",
|
|
33
|
+
"Instruction",
|
|
34
|
+
# Errors
|
|
35
|
+
"WasmError",
|
|
36
|
+
"DecodeError",
|
|
37
|
+
"ValidationError",
|
|
38
|
+
"TrapError",
|
|
39
|
+
"LinkError",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def hello() -> str:
|
|
44
|
+
return "Hello from pwasm!"
|