You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/content/getting-started/what-it-is.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -36,7 +36,7 @@ These parse for syntactic compatibility. They raise at runtime, or don't exist:
36
36
-**Async surface**: `async def` creates real coroutines, and the VM runs a cooperative scheduler. No `asyncio` module; the primitives are top-level builtins ([Async](/language/async)).
37
37
-**Metaclasses, descriptor protocol, `__slots__`**: not modeled.
38
38
-**Dynamic code**: no `exec`, no `eval`, no `compile`, no `__import__` (use the `import_module(name)` builtin to look up an already-imported module by alias).
39
-
-**Reflection**: nothing beyond `type`, `id`, `hash`, `repr`, `callable`, `getattr`, `hasattr`, `vars`, `globals`, `locals`, `isinstance`, and `issubclass`. `dir` is absent.
The release build is around 200 KB on `wasm32-unknown-unknown` (`panic=abort`, `opt-level=z`, `lto=true`, `codegen-units=1`). The pipeline: LUT-driven lexer -> single-pass Pratt parser emitting SSA-versioned bytecode directly -> peephole constant-folding optimiser -> token-threaded interpreter with two layers of adaptive specialisation.
9
9
10
-
No AST, no IR. Bytecode is the only intermediate representation. Around 17,000 lines of Rust. Production deps are `hashbrown`and `itoa` (SHA-256 in-tree). The WASM build adds `lol_alloc` for a single-threaded free-list allocator.
10
+
No AST, no IR. Bytecode is the only intermediate representation. Around 17,000 lines of Rust. Production deps are `hashbrown`, `itoa`, and `libm` (SHA-256 in-tree). The WASM build adds `lol_alloc` for a single-threaded free-list allocator.
11
11
12
12
Classes support single and multiple inheritance (C3 MRO), `super()`, full dunder dispatch, `@property` / `@x.setter`. Multi-paradigm: composition preferred, monomorphic dispatch optimised via instance-dunder IC.
13
13
@@ -23,7 +23,7 @@ Classes support single and multiple inheritance (C3 MRO), `super()`, full dunder
23
23
24
24
## Bytecode shape
25
25
26
-
Each `Instruction` is 4 bytes: 1-byte `OpCode` (`#[repr(u8)]` planned), 2-byte operand, 1 byte padding. Opcodes span 17 categories: load, store, arith, bitwise, compare, logic, identity, control flow, iter, build, container, comprehension, function, ssa (Phi), yield, side effects, unsupported (raises at runtime). Around 40 specialised `Call*` variants cover hot builtins. `LoadAttr + Call(0)` pairs fuse into `CallMethod + CallMethodArgs` after first dispatch.
26
+
Each `Instruction` is 4 bytes: 1-byte `OpCode` (`#[repr(u8)]`), 2-byte operand, 1 byte padding. Opcodes span 17 categories: load, store, arith, bitwise, compare, logic, identity, control flow, iter, build, container, comprehension, function, ssa (Phi), yield, side effects, unsupported (raises at runtime). Around 40 specialised `Call*` variants cover hot builtins. `LoadAttr + Call(0)` pairs fuse into `CallMethod + CallMethodArgs` after first dispatch.
Copy file name to clipboardExpand all lines: docs/content/implementation/fuzzing.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,9 +7,9 @@ description: "Coverage-guided fuzzing of the lex, parse, and VM pipeline with ca
7
7
8
8
The fuzzer drives the full `lex -> parse -> VM` pipeline against mutated input. It looks for panics and memory faults. It lives in [`compiler/fuzz-afl/`](https://github.com/dylan-sutton-chavez/edge-python/tree/main/compiler/fuzz-afl) and is built on [cargo-afl](https://github.com/rust-fuzz/afl.rs) (AFL++). On stable it instruments through rustc's own LLVM SanitizerCoverage (`-sanitizer-coverage-trace-pc-guard`) and links the AFL++ runtime. So it runs on **stable Rust**, no nightly toolchain required. (AFL++'s own LLVM passes, CMPLOG and IJON, are an optional, nightly-only path the project does not use.)
9
9
10
-
The target runs the VM under the sandbox profile. Runaway loops and allocations become a `VmErr` instead of a hang. Any crash the harness aborts on is a genuine bug, not resource exhaustion. Its panic hook filters one class out: arithmetic-overflow panics are a debug-only artifact of `overflow-checks`, so it ignores them and aborts on everything else. The harness tightens one field: `Limits { ops: 100_000, ..Limits::sandbox() }`. The default 100M-op budget is bounded, but takes long enough that AFL would flag a legitimately-terminating loop (or wide recursion) as a hang. The smaller budget keeps each execution inside AFL's hang timeout while still reaching deep into the language. It also sets `strict_input = true`, so `input()` raises instead of blocking on real stdin, which AFL feeds through shared memory. See [Limits and errors](/reference/limits-and-errors).
10
+
The target runs the VM under the sandbox profile. Runaway loops and allocations become a `VmErr` instead of a hang. Most crashes are genuine bugs, not resource exhaustion; the exception is arithmetic-overflow panics — a debug-only artifact of `overflow-checks` (off in the release VM) — which are triaged out by hand, not filtered automatically. The harness tightens one field: `Limits { ops: 100_000, ..Limits::sandbox() }`. The default 100M-op budget is bounded, but takes long enough that AFL would flag a legitimately-terminating loop (or wide recursion) as a hang. The smaller budget keeps each execution inside AFL's hang timeout while still reaching deep into the language. It also sets `strict_input = true`, so `input()` raises instead of blocking on real stdin, which AFL feeds through shared memory. See [Limits and errors](/reference/limits-and-errors).
11
11
12
-
The build runs `--release`. `[profile.release]` sets `debug = "line-tables-only"` for `file:line` backtraces without the `dev` profile's heavier debuginfo. (cargo-afl forces `opt-level=3`, `debug-assertions`, and `overflow-checks` into `RUSTFLAGS` regardless of profile. `debug-assertions` are what surface real bugs; `overflow-checks` only add the arithmetic-overflow panicsthe hook filters out.)
12
+
The build runs `--release`. `[profile.release]` sets `debug = "line-tables-only"` for `file:line` backtraces without the `dev` profile's heavier debuginfo. (cargo-afl forces `opt-level=3`, `debug-assertions`, and `overflow-checks` into `RUSTFLAGS` regardless of profile. `debug-assertions` are what surface real bugs; `overflow-checks` only add arithmetic-overflow panics, triaged out by hand since the release VM runs without them.)
Copy file name to clipboardExpand all lines: docs/content/implementation/lexical.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,7 @@ The token set tracks Python 3.13.12 closely. Categories implemented:
20
20
-**Wildcard**: Underscore (`_`) gets its own `Underscore` token. The parser distinguishes wildcard from name use.
21
21
-**Operators**: 1-, 2-, and 3-character operator forms (`+`, `==`, `**=`, `//=`, etc.).
22
22
-**Delimiters**: `( ) [ ] { } : , ; .`.
23
-
-**Literals**: `Name`, `Int`, `Float`, `String`, `Bytes`. There is no `Complex` token. A trailing `j` / `J` is **not** lexed as a complex suffix. `1j` tokenises as `Int(1)` followed by `Name("j")`.
23
+
-**Literals**: `Name`, `Int`, `Float`, `String`, `Bytes`. There is no `Complex` token; a trailing `j` / `J` is **not** lexed as a complex suffix (see Numeric literals).
After an atom, `postfix_tail()` handles trailers (subscript, attribute, call), iterating until none apply. So `fns[0](-3)`, `obj.method()`, `(lambda x: x)(3)`, and `compose(f, g)(x)` all parse uniformly.
67
67
68
-
`*args` / `**kwargs` are accepted in **call** position only. Starred unpacking inside literals (`[*a, *b]`, `{**d1, **d2}`, `(1, *xs, 2)`) is not supported.
68
+
`*args` / `**kwargs` are accepted in **call** position. Starred unpacking also works in list (`[*a, *b]`), set (`{*s}`), and dict (`{**d1, **d2}`) literals, lowering via `ListExtend` / `SetUpdate` / `DictUpdate`; tuple-literal unpacking (`(1, *xs, 2)`) is not.
69
69
70
70
## Operator precedence
71
71
@@ -88,7 +88,7 @@ Each binary operator declares `(l_bp, r_bp, OpCode)` in `binding_power`. Higher
88
88
89
89
`infix_bp` handles comparison chaining (`a < b < c`). When a comparison opcode is followed by another comparison token, the parser:
90
90
91
-
- stores the middle value in a synthetic `__cmp__N` slot
91
+
- stores the middle value in a synthetic `#cmp_N` slot
92
92
- emits the first comparison
93
93
- short-circuits on false
94
94
- reuses the stored value for the next comparison
@@ -219,7 +219,7 @@ Free variables (non-parameters with no local binding) are looked up in the outer
219
219
220
220
Parameter slots: `Normal`, `Star` (`*args`), `DoubleStar` (`**kwargs`). Lone `*` separator marks following params as keyword-only. Defaults live in `HeapObj::Func.defaults` and bind to the `=`-marked params in source order, so a default before `*args` and keyword-only defaults both apply correctly. Annotations (`x: T`, `-> T`) parse and drain to `chunk.annotations` (tooling-only).
221
221
222
-
`compile_body` checks impurity opcodes (`StoreItem`, `StoreAttr`, `CallPrint`, `CallInput`, `Global`, `Nonlocal`, `Import`, `Raise`, `Yield`, `LoadAttr`) to set `body.is_pure`, the flag that gates template memoisation ([Design](/implementation/design#concepts)). This static gate is complemented at runtime by an observed-impurity check that propagates through calls, so a side-effecting builtin reached as a first-class value (e.g. `print` passed to a wrapper) disqualifies the caller too.
222
+
`compile_body` checks impurity opcodes (`StoreItem`, `DelItem`, `StoreAttr`, `DelAttr`, `CallPrint`, `CallInput`, `Global`, `Nonlocal`, `Raise`, `RaiseFrom`, `Yield`, `LoadAttr`) to set `body.is_pure`, the flag that gates template memoisation ([Design](/implementation/design#concepts)). This static gate is complemented at runtime by an observed-impurity check that propagates through calls, so a side-effecting builtin reached as a first-class value (e.g. `print` passed to a wrapper) disqualifies the caller too.
223
223
224
224
## Type annotations
225
225
@@ -257,7 +257,7 @@ FormatValue 0
257
257
LoadConst ", age "
258
258
LoadName age_v
259
259
FormatValue 0
260
-
BuildString 5
260
+
BuildString 4
261
261
```
262
262
263
263
`FormatValue`'s 16-bit operand is a small flags field:
Copy file name to clipboardExpand all lines: docs/content/language/async.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -101,7 +101,7 @@ b step 2
101
101
102
102
## gather
103
103
104
-
`gather(*coros)` runs each concurrently and returns a list of results in argument order. If any raises, the first error (in argument order) propagates after all peers terminate. Survivors are not auto-cancelled.
104
+
`gather(*coros)` runs each concurrently and returns a list of results in argument order. If any raises, an error propagates after all peers terminate — currently the last one raised, not necessarily the first in argument order. Survivors are not auto-cancelled.
Copy file name to clipboardExpand all lines: docs/content/language/control-flow.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -322,7 +322,7 @@ Pre-bound exception classes (with their parent links so `except <Parent>:` match
322
322
2. Call `__enter__`.
323
323
3. Bind the result to `as`.
324
324
325
-
On exit, `__exit__(exc_type, exc_value, traceback)` runs: `(None, None, None)` on normal completion, live exception info on raise. A truthy return suppresses the exception; a falsy one propagates it. See [`/language/dunders`](/language/dunders).
325
+
On exit, `__exit__` runs; a truthy return suppresses the exception, a falsy one propagates it. See [Dunders](/language/dunders#context-managers) for the `__exit__` signature and exception info.
Copy file name to clipboardExpand all lines: docs/content/language/dunders.md
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,7 +23,7 @@ print(V(3) == V(3))
23
23
True
24
24
```
25
25
26
-
Dunders are looked up on the class chain. The instance dict is skipped. Subclasses inherit and may override. Operator overloading composes with [inheritance](/language/classes#inheritance-and-super). Monomorphic sites (same class for both operands) promote through the IC after 4 hits, then bypass lookup entirely.
26
+
Dunders are looked up on the class chain. The instance dict is skipped. Subclasses inherit and may override. Operator overloading composes with [inheritance](/language/classes#inheritance-and-super). Monomorphic sites (keyed on the receiver's class) promote through the IC after 4 hits, then bypass lookup entirely.
27
27
28
28
## Arithmetic
29
29
@@ -88,7 +88,7 @@ The bitwise and shift operators follow the same forward/reflected protocol.
88
88
89
89
`bool(x)` (and any boolean context) consults:
90
90
91
-
1.`__bool__` if defined -> cast to bool.
91
+
1.`__bool__` if defined (must return `bool`, else `TypeError`).
92
92
2.`__len__` if defined -> `False` when length is 0, else `True`.
93
93
3. Default `True`.
94
94
@@ -237,7 +237,7 @@ Existing attributes bypass `__getattr__`. Only misses trigger it.
237
237
238
238
## Context managers
239
239
240
-
`with cm() as x:` invokes `__enter__`. Its return binds to `as`. On exit, `__exit__(exc_type, exc_value, traceback)` runs: `(None, None, None)` for normal exit, live exception info on raise. A truthy return suppresses the exception; a falsy one propagates it.
240
+
`with cm() as x:` invokes `__enter__`. Its return binds to `as`. On exit, `__exit__(exc_type, exc_value, traceback)` runs: `(None, None, None)` for normal exit; on a raise, the exception type and value with `traceback` always `None`. A truthy return suppresses the exception; a falsy one propagates it.
241
241
242
242
```python
243
243
classSuppress:
@@ -265,7 +265,7 @@ Parsed for compatibility but never invoked on user classes:
-`__new__`, VM constructs the instance; `__init__` runs user logic
268
-
- Augmented-assignment dunders (`__iadd__`, ...), `a += b` desugars to `a = a + b`, so `__add__` covers it. Exception: when `a` is a name bound to a `list`,`+=` extends it in place (alias-visible), matching CPython's `list.__iadd__`
268
+
- Augmented-assignment dunders (`__iadd__`, ...), `a += b` desugars to `a = a + b`, so `__add__` covers it. Exception: list `+=` extends in place (alias-visible); see [Data types](/language/data-types#list)
269
269
- Async dunders (`__aenter__` / `__aexit__` / `__aiter__` / `__anext__`), `async with` / `async for` use the sync paths
270
270
271
271
For class basics (constructors, inheritance, properties), see [Classes](/language/classes).
0 commit comments