commits
Add async/await support to the JavaScript engine:
- Add `Await` opcode (0x82) to bytecode format
- Add `is_async` flag to bytecode Function struct
- Compile async function declarations, expressions, arrows, and methods
- Compile `await expr` to emit Await opcode
- Parse `for await...of` syntax
- VM creates internal generator for async functions, driven by promises
- Await suspends generator and sets up promise reactions for resume
- Rejected await throws into generator (preserving try/catch)
- Save/restore exception handlers across yield/await suspension points
- Async generators return async iterator wrappers
- 16 unit tests covering all async patterns
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Yield and Spread bytecode opcodes, is_generator flag on Function
- Implement generator functions: function*, yield, yield*, next/return/throw
- Generator objects with suspend/resume via saved registers and IP
- Compile for...of loops using the iterator protocol (@@iterator, .next())
- Add @@iterator to built-in types: Array, String, Map, Set
- Array.prototype.keys/values/entries returning proper iterators
- String.prototype[@@iterator] iterating over characters
- Fix array/object destructuring register allocation (LIFO compliance)
- Add rest element support for array destructuring ([a, ...rest])
- Add rest property support for object destructuring ({a, ...rest})
- Implement spread operator in array literals ([...arr])
- Spread opcode iterates via @@iterator protocol
- Custom iterables work with for...of
- Generator-based iterables work with for...of
- Remove 'generators' from test262 unsupported features list
- 25 new tests covering all features
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Make PROMISE_FULFILLED, PROMISE_REJECTED, PROMISE_RESULT_KEY pub
so drain_microtasks can use named constants instead of magic values
- Remove redundant add_reaction call in promise_native_resolve
(chain_promise already handles pending thenable propagation)
- Add test_promise_all_settled integration test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Promise constructor, prototype methods, and static methods to the
JavaScript engine, with a microtask queue for asynchronous execution:
- Promise constructor (via JS preamble so executor runs as bytecode)
- Promise.prototype.then/catch/finally with chaining
- Promise.resolve/reject static methods
- Promise.all/allSettled/race/any static methods
- Microtask queue: thread-local queue drained after each vm.execute()
- VM.call_function: invoke GC-managed functions (native or bytecode)
from outside the execution loop, used by microtask drain
- SameValueZero key equality preserved, insertion order maintained
Internal storage uses hidden properties (__promise_state__,
__promise_result__, __promise_reactions__) on GC-heap objects.
Promise.prototype stored as a GC root on the VM to survive collection.
29 new integration tests covering resolve/reject, constructor,
executor synchronous execution, then chaining, catch/finally,
error propagation, Promise.all/race/any/allSettled, identity
passthrough, and double-resolve prevention.
Removes Promise from test262 unsupported features list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Map, Set, WeakMap, and WeakSet constructors with prototype
methods to the JavaScript engine:
- Map: constructor (from iterable), set/get/has/delete/clear,
size property, forEach, keys/values/entries iterators.
SameValueZero key equality, insertion order preserved.
- Set: constructor (from iterable), add/has/delete/clear,
size property, forEach, keys/values/entries iterators.
SameValueZero value equality, insertion order preserved.
- WeakMap: constructor, set/get/has/delete. Keys must be objects.
- WeakSet: constructor, add/has/delete. Values must be objects.
Internal storage uses indexed entry objects on the GC heap with
deleted-slot markers for stable insertion-order iteration.
30 new integration tests covering all methods and edge cases
(NaN keys, object keys, chaining, uniqueness, constructor from
arrays, insertion order preservation).
Also removes Map/Set from test262 unsupported features list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Dot (.) without the s flag should not match U+2028 (LINE SEPARATOR)
and U+2029 (PARAGRAPH SEPARATOR) per the ECMAScript spec, not just \n
and \r. Use the existing is_line_terminator helper for consistency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- search() now saves/restores lastIndex so global/sticky regexps
always search from position 0 per the ES spec
- Remove 'v' (UnicodeSets) and 'd' (HasIndices) from lexer's accepted
regex flags since they're not implemented in the regex engine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a from-scratch regex engine and wire it into the JS runtime:
- regex.rs: Pattern parser (character classes, quantifiers, anchors,
groups, alternation, backreferences, lookahead, escape sequences)
and backtracking matcher with proper continuation-based sequence
matching for greedy/lazy quantifiers.
- RegExp constructor and prototype methods (test, exec, toString)
with support for g/i/m/s/u/y flags, lastIndex tracking, and
named capture groups.
- Compiler emits RegExp(pattern, flags) calls for regex literals.
- String.prototype gains match, matchAll, search methods; replace,
replaceAll, split updated to handle RegExp arguments with capture
group substitution ($1, $&, etc.).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Math
- Not a constructor (static methods only)
- Constants: E, LN2, LN10, LOG2E, LOG10E, PI, SQRT1_2, SQRT2
- Methods: abs, ceil, floor, round, trunc, max, min, pow, sqrt, cbrt,
hypot, sin, cos, tan, asin, acos, atan, atan2, exp, log, log2, log10,
expm1, log1p, sign, clz32, fround, random, imul
## Date
- Constructor: Date(), Date(ms), Date(string), Date(y, m, d, h, min, s, ms)
- Static: Date.now(), Date.parse(string), Date.UTC(...)
- Getters: getFullYear, getMonth, getDate, getDay, getHours, getMinutes,
getSeconds, getMilliseconds, getTime, getTimezoneOffset + UTC variants
- Setters: setFullYear, setMonth, setDate, setHours, setMinutes,
setSeconds, setMilliseconds, setTime
- Formatting: toString, toISOString, toUTCString, toLocaleDateString, toJSON
- valueOf returns milliseconds since epoch
## JSON
- JSON.parse(text): full JSON tokenizer and recursive descent parser
supporting objects, arrays, strings, numbers, booleans, null, and
escape sequences including \uXXXX unicode escapes
- JSON.stringify(value, replacer?, space?): recursive serialization with
pretty-print support, circular reference detection (throws TypeError),
handles NaN/Infinity as null, Date toJSON support
## VM Changes
- Added date_prototype field to Vm
- Added RuntimeError::syntax_error constructor
- Made js_number_to_string pub(crate) for JSON.stringify
41 new tests (369 total JS tests, all passing)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## String
- Constructor: String(), String.fromCharCode(), String.fromCodePoint()
- Prototype: charAt, charCodeAt, codePointAt, concat, slice, substring,
substr, indexOf, lastIndexOf, includes, startsWith, endsWith, trim,
trimStart, trimEnd, padStart, padEnd, repeat, split, replace,
replaceAll, toLowerCase, toUpperCase, at, toString, valueOf
## Number
- Constructor: Number()
- Static: isNaN, isFinite, isInteger, isSafeInteger, parseInt, parseFloat
- Constants: EPSILON, MAX_SAFE_INTEGER, MIN_SAFE_INTEGER, MAX_VALUE,
MIN_VALUE, NaN, POSITIVE_INFINITY, NEGATIVE_INFINITY
- Prototype: toString(radix), valueOf, toFixed, toPrecision, toExponential
## Boolean
- Constructor: Boolean() with truthiness coercion
- Prototype: toString, valueOf
## Symbol
- Factory: Symbol(description) producing unique string-based identifiers
- Well-known: Symbol.iterator, toPrimitive, toStringTag, hasInstance
- Registry: Symbol.for(key), Symbol.keyFor(sym)
## VM Changes
- Added string_prototype, number_prototype, boolean_prototype to Vm
- Primitive auto-boxing: GetProperty/GetPropertyByName now look up
prototype methods for String, Number, and Boolean values
- Global constants: NaN, Infinity, undefined
37 new tests (328 total JS tests, all passing)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- parseInt: default radix 0 (auto-detect) instead of 10, so "0xFF" works
- array_concat: use array_length_exists() to correctly spread empty arrays
- Remove unused obj_proto parameter from error constructor helpers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add comprehensive built-in object support for the JavaScript engine:
## Infrastructure
- NativeContext passed to native callbacks (GC access + this binding)
- Object.prototype and Array.prototype stored in VM
- CreateObject/CreateArray set prototype chains
- Array literals now set length property
## Object built-ins
- Constructor, Object.keys/values/entries/assign/create/is
- Object.getPrototypeOf/getOwnPropertyNames/getOwnPropertyDescriptor
- Object.defineProperty/freeze/seal/isFrozen/isSealed
- Object.fromEntries/hasOwn
- Object.prototype: hasOwnProperty/toString/valueOf
## Array built-ins
- Native: push/pop/shift/unshift, indexOf/lastIndexOf/includes
- Native: join/slice/concat/reverse/splice/fill/at/toString
- Static: Array.isArray/from/of
- JS preamble: map/filter/reduce/reduceRight/forEach
- JS preamble: find/findIndex/some/every/sort/flat/flatMap
## Error built-ins
- Error/TypeError/ReferenceError/SyntaxError/RangeError/URIError/EvalError
- Prototype chain with name/message, Error.prototype.toString
## Global functions
- parseInt/parseFloat/isNaN/isFinite
37 new tests covering all built-in categories.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remaining define_local() calls in destructuring patterns, catch
parameters, and class declarations did not check captured_names,
causing closures that capture these variables to fail at runtime.
Replace all with define_local_ext() + proper cell allocation, and
remove the now-unused define_local() method.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Object literal shorthand ({ x }) and for-in loop variable bindings
used find_local + Move, which would copy cell GcRefs instead of values
for captured variables. Updated both paths to use find_local_info with
proper CellLoad/CellStore/upvalue handling. Removed now-unused
find_local method.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add upvalue-based closure system using GC-allocated cells:
- New bytecode ops: NewCell, CellLoad, CellStore, LoadUpvalue, StoreUpvalue
- UpvalueDef metadata on Function for closure capture resolution
- HeapObject::Cell variant for mutable captured variable storage
- Free variable analysis with transitive capture support
- Captured parameters are boxed into cells at function entry
- const declarations enforce immutability at compile time
- Method calls (obj.method()) set this before invocation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add proper try/catch compilation (PushExceptionHandler/PopExceptionHandler
bytecode ops) — previously try/catch was a stub that compiled blocks
sequentially without exception handling
- Add function property support (functions are objects in JS and can have
arbitrary properties like assert.sameValue)
- Implement Test262 harness preamble with assert, assert.sameValue,
assert.notSameValue, assert.throws, and Test262Error helpers
- Add evaluate_with_preamble API for running tests with harness globals
- Add instruction limit to VM to prevent infinite loops in test suite
- Implement test metadata parsing (features, flags, includes, negative tests)
- Add feature-based test skipping for unimplemented features
- Report pass/fail/skip grouped by category with pass rate percentages
Initial pass rate: 3406/8929 executed (38%), 14455 skipped.
Notable: keywords 100%, punctuators 100%, ASI 95%, block-scope 88%.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add property descriptors with writable/enumerable/configurable flags,
replacing the plain HashMap<String, Value> with HashMap<String, Property>.
This gives correct JavaScript semantics for property access, deletion,
and enumeration.
Key changes:
- Property struct with data descriptor flags (writable, enumerable, configurable)
- ObjectData gains extensible flag for future Object.preventExtensions
- FunctionData gains prototype_obj for instanceof support
- instanceof walks the prototype chain checking constructor.prototype
- delete respects the configurable flag (non-configurable = returns false)
- Compiler properly emits Delete bytecode for member expressions
- for-in loops fully implemented with ForInInit/ForInNext bytecode ops
- Property enumeration: integer indices first (sorted), then string keys
- Non-enumerable properties (e.g. array length) excluded from for-in
- SetPrototype/GetPrototype bytecode ops for prototype manipulation
- CreateClosure creates a .prototype object with constructor back-reference
15 new tests covering property descriptors, prototype chain, typeof,
instanceof, in, delete, for-in, enumeration order, and reference semantics.
All 241 JS tests pass (was 226).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a generic GC module (gc.rs) with tri-color marking (white/gray/black),
heap allocation via Vec with free-list reuse, and stop-the-world collection
triggered when live object count exceeds a configurable threshold.
Refactor VM to use GcRef handles for heap objects (plain objects and
functions) instead of owned values. This gives correct JS reference
semantics — object assignment shares identity rather than deep-cloning.
The GC traces through object properties and prototype chains to find all
reachable objects, and correctly collects cycles.
Key changes:
- gc.rs: Generic Gc<T: Traceable> with alloc/get/collect, HeapSlot with
color metadata, mark phase with gray stack, sweep with free-list
- vm.rs: Value::Object(GcRef) and Value::Function(GcRef) replace owned
data; VM allocates through self.gc and triggers collection after
allocations; root collection scans registers and globals
- lib.rs: evaluate() uses to_js_string(&gc) for GC-aware string conversion
8 new GC tests (alloc, collect, transitive reachability, cycle collection,
free-list reuse, threshold, stress) plus 3 integration tests. All 226
existing tests continue to pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the core VM execution engine for the JavaScript bytecode compiler:
- Value type with all JS primitives (Number, String, Boolean, Null,
Undefined, Object, Function)
- Register file with call frame base offsets for nested calls
- Instruction dispatch loop executing all ~50 bytecode opcodes
- Arithmetic with type coercion (ToNumber), string concatenation
- Comparison with abstract/strict equality (ECMA-262 §7.2.14/15)
- Bitwise operations with ToInt32/ToUint32 conversion
- Control flow: jumps, conditional branches, loops
- Function calls: push/pop call frames, argument passing, returns
- Native function support (fn(&[Value]) -> Result<Value, RuntimeError>)
- Object property get/set (plain objects with prototype chain)
- Exception handling with throw and handler stack unwinding
- typeof, instanceof, in, void, delete operators
- Global variable storage via HashMap
- Stack overflow protection (512 frame limit)
Also store function declarations as globals so recursive calls work,
update evaluate() to return completion values, and fix test262 harness
for new signature.
40+ unit tests and end-to-end tests including fibonacci, factorial,
loops, objects, string concat, and type coercion.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix five correctness bugs in the bytecode compiler:
1. Switch default case corrupted bytecode — patch_jump(0) overwrote the
first instruction when a default case was present. Rewrote switch
compilation to use separate tracking for case jumps vs default fallthrough.
2. For-loop continue jumped to wrong target — continue inside a for-loop
body jumped before the body instead of to the update expression. Changed
continue to use forward-jump patching (like break) so the target is
resolved after body compilation.
3. Do-while continue jumped to wrong target — continue jumped to the body
start instead of the condition check. Same forward-jump patching fix.
4. Empty constructor had no Return instruction — classes without explicit
constructors created a Function with empty bytecode. Now emits
LoadUndefined + Return.
5. Class expression didn't compile methods — only the constructor was
compiled for class expressions. Now compiles methods as properties,
matching class declaration behavior.
Also adds patch_jump_to(pos, target) to BytecodeBuilder for patching
jumps to arbitrary targets (not just current offset).
6 new regression tests. All 182 JS tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add register-based bytecode instruction set designed for JIT compilation
and a recursive-descent compiler that transforms the parser AST into
bytecode functions.
New files:
- bytecode.rs — Instruction set (50+ opcodes), constant pool, function
objects, bytecode builder with jump patching, and disassembler
- compiler.rs — AST → bytecode compiler with greedy register allocation,
scope-aware local variable binding, and support for all statement and
expression types
Instruction categories: register loads, arithmetic, bitwise, comparison,
logical, control flow (jumps, calls, returns), object/property access,
closures, and small-integer optimization (LoadInt8).
Compiler handles: variable declarations, function/class/arrow declarations,
if/else, for/while/do-while loops with break/continue/labels, switch,
try/catch, member access, assignment (simple and compound), logical
short-circuit, conditional expressions, template literals, destructuring,
object/array literals, and nested function compilation.
52 unit tests covering bytecode encoding, constant pool dedup, jump
patching, disassembler output, and compilation of all major grammar
productions. All 176 workspace JS tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
export default function() {} and export default class {} are valid
JavaScript but the parser incorrectly required a name. Check whether
the function/class has a name and route to expression parsing when
anonymous.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a recursive-descent JavaScript parser with Pratt expression parsing
for ECMAScript 2024. Transforms the token stream from the lexer into an
Abstract Syntax Tree.
AST node types cover:
- All expression types (literals, binary, unary, assignment, member access,
call, new, arrow functions, template literals, spread, yield, await)
- All statement types (if, for/for-in/for-of, while, do-while, switch,
try/catch/finally, return, throw, break, continue, labeled, with)
- Variable declarations (var/let/const) with destructuring patterns
- Function declarations (sync, async, generators)
- Class declarations (constructor, methods, getters/setters, static)
- Import/export declarations (default, named, namespace, re-export)
Features:
- Operator precedence via Pratt parsing with binding power table
- Automatic Semicolon Insertion (ASI) using lexer newline tracking
- Arrow function detection with expression-to-pattern reinterpretation
- Destructuring patterns (array, object, default values, rest)
- for-in/for-of disambiguation with allow_in flag
- 73 unit tests covering all grammar productions and error cases
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
\<newline> in string/template literals is a line continuation per
ECMAScript spec — it should produce no character, not a newline.
Changed scan_escape_sequence to return Option<char>, returning None
for line continuations. Added test for this behavior.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a full JavaScript lexer to the we-js crate supporting all ES2024
token types: keywords, identifiers (including Unicode), numeric literals
(decimal, hex, octal, binary with separators), string literals with full
escape sequences, template literals with ${} substitution tracking,
regular expression literals with context-based disambiguation, and all
punctuators/operators. Includes source position tracking (line/column)
and newline tracking for automatic semicolon insertion.
48 unit tests covering all token types, edge cases, and error handling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a container has only float children and bare inline content (no
in-flow block siblings), normalize_children returned early without
wrapping the inline content in anonymous blocks. This caused the text
to be silently dropped during layout_block_children since compute_layout
is a no-op for TextRun/Inline boxes.
Include floated children in the has_block check so that inline content
gets properly wrapped in anonymous blocks and laid out through the
inline formatting context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add float layout support to the layout engine:
- Parse float (none/left/right) and clear (none/left/right/both) CSS properties
- Float positioning: left floats at left edge, right floats at right edge
- Float stacking: multiple floats stack horizontally, wrapping when full
- Line box shortening: inline content flows around active floats
- Clear property: elements move below cleared floats
- BFC containment: overflow:hidden/scroll containers expand to contain floats
- Floated inline elements are blockified per CSS2 §9.7
Implements issue 3mhlhnjkxcr2x
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Sticky variant to Position enum and parse "sticky" keyword
- Sticky elements participate in normal flow (like relative positioning)
- Store sticky_constraint rect on LayoutBox (parent's content area)
- Compute sticky paint-time offset in render crate based on scroll state
- Support top stickiness with containing block constraint clamping
- Update scroll container reference point tracking through paint recursion
- Add tests: parsing, normal flow layout, constraint rect, scroll sticking,
and parent constraint behavior
Implements issue 3mhlhoituxu2u
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add z_index field to ComputedStyle and parse CSS z-index property
- Remove absolute/fixed elements from normal flow (block, inline, flex layout)
- Position absolute elements relative to nearest positioned ancestor's padding box
- Position fixed elements relative to viewport
- Support left/right/top/bottom offsets with percentage resolution
- Support width/height stretching when both sides are specified
- Implement stacking context paint order: negative z-index, in-flow, non-negative z-index
- Update normalize_children and margin collapsing to exclude out-of-flow elements
- Add tests for absolute positioning, fixed positioning, z-index, stretching, and
bottom/right positioning
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per CSS Box Alignment §8, row-gap applies between rows and column-gap
between columns. In a column flex container the main axis is vertical,
so the gap between items should use row-gap (not column-gap) and the
gap between flex lines should use column-gap (not row-gap).
Introduces main_gap/cross_gap variables that swap based on flex direction.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add full flexbox support with flex container and item properties:
CSS parsing:
- Parse display: flex/inline-flex
- Parse flex container props: flex-direction, flex-wrap, justify-content,
align-items, align-content, gap/row-gap/column-gap
- Parse flex item props: flex-grow, flex-shrink, flex-basis, align-self, order
- Expand flex, flex-flow, and gap shorthands
Layout algorithm (CSS Flexbox Level 1 §9):
- Determine main/cross axes from flex-direction
- Content-based flex-basis sizing for auto basis
- Distribute free space via flex-grow/flex-shrink
- Line wrapping (flex-wrap: wrap/wrap-reverse)
- Main axis justification (all justify-content modes)
- Cross axis alignment (all align-items/align-self modes)
- Multi-line align-content distribution
- Visual ordering via order property
- Gap spacing between items
- Reverse direction support (row-reverse, column-reverse)
Tests: 10 new flex layout tests covering row/column direction,
grow/shrink, justify-content, align-items, wrap, gap, and order.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add scrollable overflow regions for overflow:scroll and overflow:auto
boxes, with rendered scroll bars and mouse wheel event support.
Layout crate:
- Add content_height field to LayoutBox tracking natural content height
before CSS height override (used for overflow detection)
- Reserve SCROLLBAR_WIDTH (15px) from content area for overflow:scroll
- Export SCROLLBAR_WIDTH constant
Render crate:
- Add ScrollState type (HashMap<NodeId, (f32, f32)>) for scroll offsets
- Modify display list builder to accept scroll state and translate offset
- Apply scroll offset to child coordinates in scrollable containers
- Render vertical scroll bars (track + proportional thumb) for
overflow:scroll (always) and overflow:auto (when content overflows)
- Add page-level scroll support via paint_with_scroll()
- Add build_display_list_with_page_scroll() for viewport scrolling
- 6 new tests: scrollbar rendering, scroll offset, thumb proportionality,
overflow:auto conditional scrollbar, page scroll
Platform crate:
- Add scrollWheel: event handler to WeView class
- Add set_scroll_handler() for registering scroll callbacks
- Forward scroll delta (dx, dy) and mouse position to handler
Browser crate:
- Add page_scroll_y, content_height, scroll_offsets to BrowserState
- Handle scroll wheel events: update page scroll, clamp to bounds,
re-render
- Pass scroll state through rendering pipeline
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add clip rect support to the rendering pipeline so that boxes with
overflow != visible clip their children's content to the padding box.
Render crate changes:
- Add PushClip/PopClip variants to PaintCommand
- Maintain a clip rect stack in Renderer that intersects nested clips
- Apply active clip rect in fill_rect, composite_glyph, and draw_image
- overflow:hidden, overflow:auto, and overflow:scroll all clip content
- overflow:visible (default) continues to render without clipping
Layout crate fix:
- Fix is_empty_block to not treat blocks with explicit CSS height as
empty (they should not self-collapse per CSS2 §8.3.1)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Thread viewport dimensions through style resolution so viewport units
resolve correctly: 1vw = 1% of viewport width, 1vh = 1% of viewport
height, vmin/vmax use the smaller/larger dimension.
For layout properties (width, height, margin, padding), percentages are
now preserved as LengthOrAuto::Percentage through style computation and
resolved during layout against the containing block width. Height
percentages resolve against viewport height. Per CSS spec, even vertical
margins and padding resolve against containing block width.
Changes:
- Add Percentage(f32) variant to LengthOrAuto
- Change ComputedStyle padding fields from f32 to LengthOrAuto
- Add viewport parameter to resolve_styles, threaded through resolution
- resolve_length_unit now computes vw/vh/vmin/vmax from viewport dims
- Layout resolves percentage width/height/margin/padding against
containing block; nested percentages compound correctly
- Store css_margin/css_padding/css_offsets on LayoutBox for deferred
resolution during layout
- 9 new tests covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire up visibility property through the layout and render pipeline:
- Add visibility field to LayoutBox, populated from ComputedStyle
- Renderer skips painting (background, borders, text, images) for
hidden/collapse elements but still recurses into children
- Children can override with visibility:visible per CSS spec
- display:none already worked (excluded from layout tree); verified
9 new tests: 5 layout tests (display:none exclusion, hidden preserves
space, inheritance, visible override, collapse behavior) and 4 render
tests (hidden not painted, visible child of hidden parent painted,
collapse not painted, display:none not in display list).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add BoxSizing enum and box_sizing field to ComputedStyle with CSS
parsing support. Layout engine now respects explicit CSS width/height
and adjusts content dimensions based on box-sizing mode:
- content-box (default): width/height apply to content area only
- border-box: width/height include padding and border
Content area clamps to 0 when padding+border exceeds specified size
in border-box mode. Property is not inherited per spec.
9 new tests covering both modes, clamping, non-inheritance, and height.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements CSS2 §8.3.1 margin collapsing:
- Adjacent sibling margins collapse (gap = max, not sum)
- Parent-child margin collapsing via pre_collapse_margins pass
- Empty block self-collapsing (top+bottom margins fold together)
- Negative margin handling (positive+negative=sum, both negative=min)
- Collapsing blocked by border, padding, or overflow!=visible (BFC)
Adds overflow field to LayoutBox for BFC detection. Updates existing
tests to reflect correct collapsed margin behavior and adds 9 new
tests covering all collapsing scenarios.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add relative positioning support to the layout engine. After normal-flow
layout, elements with position: relative are visually shifted by their
top/right/bottom/left offset values without affecting surrounding elements.
- Add position and relative_offset fields to LayoutBox
- Resolve offset conflicts per CSS spec (top wins over bottom, left over right)
- Recursively shift box rect, text lines, and all descendants
- Add 7 tests covering offsets, sibling independence, conflicts, and auto values
Wire together all Phase 8 components into the browser's navigation flow:
- Use css_loader::collect_stylesheets for external <link> and inline <style>
- Use img_loader::collect_images to fetch and decode <img> elements
- Store pre-fetched PageState (DOM, stylesheet, images) so window resizes
only re-style/re-layout/re-render without re-fetching
- Show error page for network failures instead of process::exit
- Preserve base URL from HTTP response for resolving relative subresources
- Generate file:// base URL for local file paths
Implements issue 3mhktaciaf42q.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add about: scheme handling to ResourceLoader:
- Recognize about:blank and return a minimal empty HTML document
(<!DOCTYPE html><html><head></head><body></body></html>)
- UTF-8 encoding, no network requests
- Unsupported about: URLs return InvalidUrl error
Update browser main to use about:blank as default:
- No URL argument opens about:blank instead of hardcoded demo page
- URL arguments (http://, https://, about:, data:) load via ResourceLoader
- File path arguments still work as before
4 tests covering fetch/fetch_url paths, DOM structure validation,
and unsupported about: URL rejection.
Implements issue 3mhkt7vaxsb23
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add data_url module to the url crate:
- Base64 decoder (RFC 4648): standard alphabet, whitespace stripping, padding
- Data URL parser: extract MIME type, charset, base64/percent-encoded payload
- Default MIME type text/plain;charset=US-ASCII when omitted
Integrate with ResourceLoader in browser crate:
- Handle data: URLs in both fetch() and fetch_url() without network access
- Classify decoded content into Html/Css/Image/Other resource types
- Decode text resources using charset from data URL parameters
44 tests covering base64 decoding, data URL parsing, MIME extraction,
percent decoding, and ResourceLoader integration.
Implements issue 3mhkt7m45472x
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add img_loader module to the browser crate that loads images from the DOM:
- Scan DOM for <img src="..."> elements in document order
- Fetch image data via ResourceLoader with URL resolution
- Detect format from magic bytes (PNG: 89504E47, JPEG: FFD8, GIF: GIF8)
- Decode using image crate decoders (PNG, JPEG, GIF)
- Parse width/height attributes with proportional scaling
- Graceful degradation: failed loads store alt text, no crash
Layout integration:
- Add replaced_size field to LayoutBox for replaced elements
- Accept image_sizes map in layout() for intrinsic/attribute dimensions
- Replaced elements use their dimensions instead of child layout
Render integration:
- Add DrawImage variant to PaintCommand
- Nearest-neighbor scaling with RGBA→BGRA conversion
- Alpha compositing for semi-transparent image pixels
37 tests covering format detection, dimension parsing/resolution,
DOM scanning, graceful failure, error display, and PNG decoding.
Implements issue 3mhkt7br4jx25
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add css_loader module to the browser crate that collects CSS from the DOM:
- Scan DOM for <style> elements (inline CSS) and <link rel="stylesheet"> (external)
- Fetch external stylesheets via ResourceLoader with encoding detection
- Resolve @import rules recursively (max depth 5 to prevent cycles)
- Basic media attribute support (screen, all)
- Type attribute validation (text/css default)
- Graceful degradation: failed loads are silently skipped
- Merge all rules into a single Stylesheet in document order
37 tests covering DOM scanning, classification, media matching, text
collection, import resolution, error handling, and edge cases.
Implements issue 3mhkt6vtv3q2g
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add ResourceLoader to the browser crate that integrates the net, encoding,
url, and image crates into a unified resource fetching API:
- ResourceLoader wraps HttpClient for HTTP/HTTPS fetching
- Content-Type parsing determines resource type (HTML, CSS, image, other)
- WHATWG encoding sniffing for HTML (BOM > HTTP > meta prescan > default)
- BOM/HTTP charset detection for non-HTML text resources (default UTF-8)
- Relative URL resolution via base URL support
- HTTP error status handling (4xx, 5xx)
- Resource enum: Html, Css, Image, Other with appropriate metadata
30 tests covering MIME classification, text decoding (BOM, HTTP charset,
meta prescan, Windows-1252 special chars), URL resolution, and error types.
Implements issue 3mhkt6hnbhp25
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add encoding detection per WHATWG Encoding Standard and HTML spec:
- BOM sniffing for UTF-8, UTF-16LE, UTF-16BE
- HTTP Content-Type charset extraction (quoted/unquoted values)
- HTML meta prescan: scan first 1024 bytes for <meta charset> and
<meta http-equiv="Content-Type" content="...;charset=...">
- Priority: BOM > HTTP header > meta prescan > default (Windows-1252)
- UTF-16 from HTTP/meta overridden to UTF-8 per spec
- EncodingSource enum for tracking detection method confidence
39 new tests covering all detection methods and priority ordering.
Implements issue 3mhkt62ryxo2l
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add all 27 WHATWG single-byte encodings to the encoding crate:
- Windows-1252 (with ISO-8859-1 and US-ASCII aliases per WHATWG spec)
- ISO-8859-2 through ISO-8859-16 (excluding 8859-9 which maps to Windows-1254)
- Windows-874, Windows-1250 through Windows-1258
- KOI8-R, KOI8-U
- macintosh, x-mac-cyrillic
- IBM866
Each encoding uses a 128-entry u16 lookup table for bytes 0x80-0xFF.
All WHATWG label aliases are registered for case-insensitive lookup.
32 new tests covering per-encoding correctness and error handling.
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure Rust implementation of UTF-8 and UTF-16 text encoding/decoding
per the WHATWG Encoding Standard:
- UTF-8 decoder (streaming state machine with replacement/fatal modes)
- UTF-8 encoder
- UTF-16LE/BE decoders with surrogate pair handling and BOM stripping
- Encoding label lookup (case-insensitive, whitespace-trimmed)
- BOM sniffing utility
- Public API: decode(), decode_strict(), encode(), lookup(), bom_sniff()
- 93 unit tests covering edge cases (overlong, surrogates, truncated, BOM)
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure Rust baseline JPEG decoder in the image crate supporting:
- JFIF marker parsing (SOI, APP0/APP1, DQT, SOF0, DHT, SOS, DRI, EOI)
- Huffman entropy decoding (DC and AC coefficients)
- 8x8 block-based inverse DCT (Loeffler algorithm, integer fixed-point)
- Dequantization with DQT tables
- Chroma subsampling: 4:4:4, 4:2:2, 4:2:0
- YCbCr to RGB color conversion (BT.601 fixed-point)
- Restart marker support
- Grayscale JPEG support
- 28 unit tests covering Huffman, IDCT, color conversion, parsing, and
end-to-end decoding of hand-crafted JPEG streams
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GIF LZW uses "early change" — the code size must bump when next_code
reaches (1 << code_size), not after it exceeds it. Without this fix,
the decoder would read codes with the wrong bit width for GIFs with
enough unique codes to trigger a code size increase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust GIF decoder in the image crate supporting:
- GIF87a and GIF89a format parsing
- LZW decompression with variable-width codes, clear/EOI codes
- Global and local color tables
- Graphic Control Extension (transparency, delay, disposal methods)
- Multi-frame animated GIFs with canvas compositing
- Interlaced image support (4-pass Adam7-style deinterlacing)
- Sub-frame positioning (frames smaller than logical screen)
- Application, comment, and plain text extension skipping
- API: decode_gif() for first frame, decode_gif_frames() for all frames
31 unit tests covering LZW decompression, deinterlacing, frame decoding,
transparency, animation, local color tables, extensions, and error cases.
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust PNG decoder supporting all color types (grayscale, RGB,
indexed, grayscale+alpha, RGBA), bit depths 1-16, scanline filtering
(None/Sub/Up/Average/Paeth), Adam7 interlacing, tRNS transparency,
CRC-32 validation, and multiple IDAT chunk concatenation.
40+ unit tests covering all color types, bit depths, filter types,
interlacing, transparency, error cases, and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Image struct (always RGBA8) with conversions from grayscale,
grayscale+alpha, RGB, RGBA, indexed color, and indexed+alpha.
29 unit tests covering all conversion paths and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse zlib header (CMF/FLG), validate header checksum, delegate to
DEFLATE for compressed data, verify Adler-32 checksum of output.
21 unit tests covering Adler-32, header validation, round-trip
decompression, error propagation, and all window sizes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust DEFLATE decompression supporting all three block types:
- Non-compressed blocks (BTYPE=00) with LEN/NLEN validation
- Fixed Huffman codes (BTYPE=01) per RFC 1951 §3.2.6
- Dynamic Huffman codes (BTYPE=10) with code length decoding
Implementation details:
- LSB-first bit reader with peek/consume pattern for Huffman decoding
- Two-level Huffman lookup table (primary + subtable for long codes)
- LZ77 back-reference decoding with overlapping copy support
- Handles end-of-stream gracefully when final code needs fewer bits
than the primary table width
33 unit tests covering BitReader, Huffman trees, all block types,
back-references, error cases, and round-trip verification against
zlib-generated test vectors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace strip_prefix-based header matching (only matched exact case and
lowercase) with a proper case-insensitive helper that splits on the
first colon and compares the header name using eq_ignore_ascii_case.
Adds tests for all-caps header names (CONTENT-LENGTH, TRANSFER-ENCODING).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
High-level HTTP client in the net crate bringing together TCP, TLS 1.3,
DNS, URL parsing, and HTTP message handling:
- HttpClient with get(), post(), request() methods
- Scheme handling: http:// (plain TCP) and https:// (TLS)
- Connection pooling by (host, port, is_tls) with max idle time and
max connections per host
- Redirect following (301, 302, 307, 308) with configurable max
- Configurable connect and read timeouts
- Streaming response reader: header detection, Content-Length,
chunked Transfer-Encoding, and read-until-close strategies
- std::io::Read and Write trait impls for TcpConnection
30+ unit tests covering error types, configuration, connection pool,
URL path building, header parsing, body strategy selection, and
chunked terminator detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add async/await support to the JavaScript engine:
- Add `Await` opcode (0x82) to bytecode format
- Add `is_async` flag to bytecode Function struct
- Compile async function declarations, expressions, arrows, and methods
- Compile `await expr` to emit Await opcode
- Parse `for await...of` syntax
- VM creates internal generator for async functions, driven by promises
- Await suspends generator and sets up promise reactions for resume
- Rejected await throws into generator (preserving try/catch)
- Save/restore exception handlers across yield/await suspension points
- Async generators return async iterator wrappers
- 16 unit tests covering all async patterns
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Yield and Spread bytecode opcodes, is_generator flag on Function
- Implement generator functions: function*, yield, yield*, next/return/throw
- Generator objects with suspend/resume via saved registers and IP
- Compile for...of loops using the iterator protocol (@@iterator, .next())
- Add @@iterator to built-in types: Array, String, Map, Set
- Array.prototype.keys/values/entries returning proper iterators
- String.prototype[@@iterator] iterating over characters
- Fix array/object destructuring register allocation (LIFO compliance)
- Add rest element support for array destructuring ([a, ...rest])
- Add rest property support for object destructuring ({a, ...rest})
- Implement spread operator in array literals ([...arr])
- Spread opcode iterates via @@iterator protocol
- Custom iterables work with for...of
- Generator-based iterables work with for...of
- Remove 'generators' from test262 unsupported features list
- 25 new tests covering all features
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Make PROMISE_FULFILLED, PROMISE_REJECTED, PROMISE_RESULT_KEY pub
so drain_microtasks can use named constants instead of magic values
- Remove redundant add_reaction call in promise_native_resolve
(chain_promise already handles pending thenable propagation)
- Add test_promise_all_settled integration test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Promise constructor, prototype methods, and static methods to the
JavaScript engine, with a microtask queue for asynchronous execution:
- Promise constructor (via JS preamble so executor runs as bytecode)
- Promise.prototype.then/catch/finally with chaining
- Promise.resolve/reject static methods
- Promise.all/allSettled/race/any static methods
- Microtask queue: thread-local queue drained after each vm.execute()
- VM.call_function: invoke GC-managed functions (native or bytecode)
from outside the execution loop, used by microtask drain
- SameValueZero key equality preserved, insertion order maintained
Internal storage uses hidden properties (__promise_state__,
__promise_result__, __promise_reactions__) on GC-heap objects.
Promise.prototype stored as a GC root on the VM to survive collection.
29 new integration tests covering resolve/reject, constructor,
executor synchronous execution, then chaining, catch/finally,
error propagation, Promise.all/race/any/allSettled, identity
passthrough, and double-resolve prevention.
Removes Promise from test262 unsupported features list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Map, Set, WeakMap, and WeakSet constructors with prototype
methods to the JavaScript engine:
- Map: constructor (from iterable), set/get/has/delete/clear,
size property, forEach, keys/values/entries iterators.
SameValueZero key equality, insertion order preserved.
- Set: constructor (from iterable), add/has/delete/clear,
size property, forEach, keys/values/entries iterators.
SameValueZero value equality, insertion order preserved.
- WeakMap: constructor, set/get/has/delete. Keys must be objects.
- WeakSet: constructor, add/has/delete. Values must be objects.
Internal storage uses indexed entry objects on the GC heap with
deleted-slot markers for stable insertion-order iteration.
30 new integration tests covering all methods and edge cases
(NaN keys, object keys, chaining, uniqueness, constructor from
arrays, insertion order preservation).
Also removes Map/Set from test262 unsupported features list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- search() now saves/restores lastIndex so global/sticky regexps
always search from position 0 per the ES spec
- Remove 'v' (UnicodeSets) and 'd' (HasIndices) from lexer's accepted
regex flags since they're not implemented in the regex engine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a from-scratch regex engine and wire it into the JS runtime:
- regex.rs: Pattern parser (character classes, quantifiers, anchors,
groups, alternation, backreferences, lookahead, escape sequences)
and backtracking matcher with proper continuation-based sequence
matching for greedy/lazy quantifiers.
- RegExp constructor and prototype methods (test, exec, toString)
with support for g/i/m/s/u/y flags, lastIndex tracking, and
named capture groups.
- Compiler emits RegExp(pattern, flags) calls for regex literals.
- String.prototype gains match, matchAll, search methods; replace,
replaceAll, split updated to handle RegExp arguments with capture
group substitution ($1, $&, etc.).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Math
- Not a constructor (static methods only)
- Constants: E, LN2, LN10, LOG2E, LOG10E, PI, SQRT1_2, SQRT2
- Methods: abs, ceil, floor, round, trunc, max, min, pow, sqrt, cbrt,
hypot, sin, cos, tan, asin, acos, atan, atan2, exp, log, log2, log10,
expm1, log1p, sign, clz32, fround, random, imul
## Date
- Constructor: Date(), Date(ms), Date(string), Date(y, m, d, h, min, s, ms)
- Static: Date.now(), Date.parse(string), Date.UTC(...)
- Getters: getFullYear, getMonth, getDate, getDay, getHours, getMinutes,
getSeconds, getMilliseconds, getTime, getTimezoneOffset + UTC variants
- Setters: setFullYear, setMonth, setDate, setHours, setMinutes,
setSeconds, setMilliseconds, setTime
- Formatting: toString, toISOString, toUTCString, toLocaleDateString, toJSON
- valueOf returns milliseconds since epoch
## JSON
- JSON.parse(text): full JSON tokenizer and recursive descent parser
supporting objects, arrays, strings, numbers, booleans, null, and
escape sequences including \uXXXX unicode escapes
- JSON.stringify(value, replacer?, space?): recursive serialization with
pretty-print support, circular reference detection (throws TypeError),
handles NaN/Infinity as null, Date toJSON support
## VM Changes
- Added date_prototype field to Vm
- Added RuntimeError::syntax_error constructor
- Made js_number_to_string pub(crate) for JSON.stringify
41 new tests (369 total JS tests, all passing)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## String
- Constructor: String(), String.fromCharCode(), String.fromCodePoint()
- Prototype: charAt, charCodeAt, codePointAt, concat, slice, substring,
substr, indexOf, lastIndexOf, includes, startsWith, endsWith, trim,
trimStart, trimEnd, padStart, padEnd, repeat, split, replace,
replaceAll, toLowerCase, toUpperCase, at, toString, valueOf
## Number
- Constructor: Number()
- Static: isNaN, isFinite, isInteger, isSafeInteger, parseInt, parseFloat
- Constants: EPSILON, MAX_SAFE_INTEGER, MIN_SAFE_INTEGER, MAX_VALUE,
MIN_VALUE, NaN, POSITIVE_INFINITY, NEGATIVE_INFINITY
- Prototype: toString(radix), valueOf, toFixed, toPrecision, toExponential
## Boolean
- Constructor: Boolean() with truthiness coercion
- Prototype: toString, valueOf
## Symbol
- Factory: Symbol(description) producing unique string-based identifiers
- Well-known: Symbol.iterator, toPrimitive, toStringTag, hasInstance
- Registry: Symbol.for(key), Symbol.keyFor(sym)
## VM Changes
- Added string_prototype, number_prototype, boolean_prototype to Vm
- Primitive auto-boxing: GetProperty/GetPropertyByName now look up
prototype methods for String, Number, and Boolean values
- Global constants: NaN, Infinity, undefined
37 new tests (328 total JS tests, all passing)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add comprehensive built-in object support for the JavaScript engine:
## Infrastructure
- NativeContext passed to native callbacks (GC access + this binding)
- Object.prototype and Array.prototype stored in VM
- CreateObject/CreateArray set prototype chains
- Array literals now set length property
## Object built-ins
- Constructor, Object.keys/values/entries/assign/create/is
- Object.getPrototypeOf/getOwnPropertyNames/getOwnPropertyDescriptor
- Object.defineProperty/freeze/seal/isFrozen/isSealed
- Object.fromEntries/hasOwn
- Object.prototype: hasOwnProperty/toString/valueOf
## Array built-ins
- Native: push/pop/shift/unshift, indexOf/lastIndexOf/includes
- Native: join/slice/concat/reverse/splice/fill/at/toString
- Static: Array.isArray/from/of
- JS preamble: map/filter/reduce/reduceRight/forEach
- JS preamble: find/findIndex/some/every/sort/flat/flatMap
## Error built-ins
- Error/TypeError/ReferenceError/SyntaxError/RangeError/URIError/EvalError
- Prototype chain with name/message, Error.prototype.toString
## Global functions
- parseInt/parseFloat/isNaN/isFinite
37 new tests covering all built-in categories.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remaining define_local() calls in destructuring patterns, catch
parameters, and class declarations did not check captured_names,
causing closures that capture these variables to fail at runtime.
Replace all with define_local_ext() + proper cell allocation, and
remove the now-unused define_local() method.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Object literal shorthand ({ x }) and for-in loop variable bindings
used find_local + Move, which would copy cell GcRefs instead of values
for captured variables. Updated both paths to use find_local_info with
proper CellLoad/CellStore/upvalue handling. Removed now-unused
find_local method.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add upvalue-based closure system using GC-allocated cells:
- New bytecode ops: NewCell, CellLoad, CellStore, LoadUpvalue, StoreUpvalue
- UpvalueDef metadata on Function for closure capture resolution
- HeapObject::Cell variant for mutable captured variable storage
- Free variable analysis with transitive capture support
- Captured parameters are boxed into cells at function entry
- const declarations enforce immutability at compile time
- Method calls (obj.method()) set this before invocation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add proper try/catch compilation (PushExceptionHandler/PopExceptionHandler
bytecode ops) — previously try/catch was a stub that compiled blocks
sequentially without exception handling
- Add function property support (functions are objects in JS and can have
arbitrary properties like assert.sameValue)
- Implement Test262 harness preamble with assert, assert.sameValue,
assert.notSameValue, assert.throws, and Test262Error helpers
- Add evaluate_with_preamble API for running tests with harness globals
- Add instruction limit to VM to prevent infinite loops in test suite
- Implement test metadata parsing (features, flags, includes, negative tests)
- Add feature-based test skipping for unimplemented features
- Report pass/fail/skip grouped by category with pass rate percentages
Initial pass rate: 3406/8929 executed (38%), 14455 skipped.
Notable: keywords 100%, punctuators 100%, ASI 95%, block-scope 88%.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add property descriptors with writable/enumerable/configurable flags,
replacing the plain HashMap<String, Value> with HashMap<String, Property>.
This gives correct JavaScript semantics for property access, deletion,
and enumeration.
Key changes:
- Property struct with data descriptor flags (writable, enumerable, configurable)
- ObjectData gains extensible flag for future Object.preventExtensions
- FunctionData gains prototype_obj for instanceof support
- instanceof walks the prototype chain checking constructor.prototype
- delete respects the configurable flag (non-configurable = returns false)
- Compiler properly emits Delete bytecode for member expressions
- for-in loops fully implemented with ForInInit/ForInNext bytecode ops
- Property enumeration: integer indices first (sorted), then string keys
- Non-enumerable properties (e.g. array length) excluded from for-in
- SetPrototype/GetPrototype bytecode ops for prototype manipulation
- CreateClosure creates a .prototype object with constructor back-reference
15 new tests covering property descriptors, prototype chain, typeof,
instanceof, in, delete, for-in, enumeration order, and reference semantics.
All 241 JS tests pass (was 226).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a generic GC module (gc.rs) with tri-color marking (white/gray/black),
heap allocation via Vec with free-list reuse, and stop-the-world collection
triggered when live object count exceeds a configurable threshold.
Refactor VM to use GcRef handles for heap objects (plain objects and
functions) instead of owned values. This gives correct JS reference
semantics — object assignment shares identity rather than deep-cloning.
The GC traces through object properties and prototype chains to find all
reachable objects, and correctly collects cycles.
Key changes:
- gc.rs: Generic Gc<T: Traceable> with alloc/get/collect, HeapSlot with
color metadata, mark phase with gray stack, sweep with free-list
- vm.rs: Value::Object(GcRef) and Value::Function(GcRef) replace owned
data; VM allocates through self.gc and triggers collection after
allocations; root collection scans registers and globals
- lib.rs: evaluate() uses to_js_string(&gc) for GC-aware string conversion
8 new GC tests (alloc, collect, transitive reachability, cycle collection,
free-list reuse, threshold, stress) plus 3 integration tests. All 226
existing tests continue to pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the core VM execution engine for the JavaScript bytecode compiler:
- Value type with all JS primitives (Number, String, Boolean, Null,
Undefined, Object, Function)
- Register file with call frame base offsets for nested calls
- Instruction dispatch loop executing all ~50 bytecode opcodes
- Arithmetic with type coercion (ToNumber), string concatenation
- Comparison with abstract/strict equality (ECMA-262 §7.2.14/15)
- Bitwise operations with ToInt32/ToUint32 conversion
- Control flow: jumps, conditional branches, loops
- Function calls: push/pop call frames, argument passing, returns
- Native function support (fn(&[Value]) -> Result<Value, RuntimeError>)
- Object property get/set (plain objects with prototype chain)
- Exception handling with throw and handler stack unwinding
- typeof, instanceof, in, void, delete operators
- Global variable storage via HashMap
- Stack overflow protection (512 frame limit)
Also store function declarations as globals so recursive calls work,
update evaluate() to return completion values, and fix test262 harness
for new signature.
40+ unit tests and end-to-end tests including fibonacci, factorial,
loops, objects, string concat, and type coercion.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix five correctness bugs in the bytecode compiler:
1. Switch default case corrupted bytecode — patch_jump(0) overwrote the
first instruction when a default case was present. Rewrote switch
compilation to use separate tracking for case jumps vs default fallthrough.
2. For-loop continue jumped to wrong target — continue inside a for-loop
body jumped before the body instead of to the update expression. Changed
continue to use forward-jump patching (like break) so the target is
resolved after body compilation.
3. Do-while continue jumped to wrong target — continue jumped to the body
start instead of the condition check. Same forward-jump patching fix.
4. Empty constructor had no Return instruction — classes without explicit
constructors created a Function with empty bytecode. Now emits
LoadUndefined + Return.
5. Class expression didn't compile methods — only the constructor was
compiled for class expressions. Now compiles methods as properties,
matching class declaration behavior.
Also adds patch_jump_to(pos, target) to BytecodeBuilder for patching
jumps to arbitrary targets (not just current offset).
6 new regression tests. All 182 JS tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add register-based bytecode instruction set designed for JIT compilation
and a recursive-descent compiler that transforms the parser AST into
bytecode functions.
New files:
- bytecode.rs — Instruction set (50+ opcodes), constant pool, function
objects, bytecode builder with jump patching, and disassembler
- compiler.rs — AST → bytecode compiler with greedy register allocation,
scope-aware local variable binding, and support for all statement and
expression types
Instruction categories: register loads, arithmetic, bitwise, comparison,
logical, control flow (jumps, calls, returns), object/property access,
closures, and small-integer optimization (LoadInt8).
Compiler handles: variable declarations, function/class/arrow declarations,
if/else, for/while/do-while loops with break/continue/labels, switch,
try/catch, member access, assignment (simple and compound), logical
short-circuit, conditional expressions, template literals, destructuring,
object/array literals, and nested function compilation.
52 unit tests covering bytecode encoding, constant pool dedup, jump
patching, disassembler output, and compilation of all major grammar
productions. All 176 workspace JS tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a recursive-descent JavaScript parser with Pratt expression parsing
for ECMAScript 2024. Transforms the token stream from the lexer into an
Abstract Syntax Tree.
AST node types cover:
- All expression types (literals, binary, unary, assignment, member access,
call, new, arrow functions, template literals, spread, yield, await)
- All statement types (if, for/for-in/for-of, while, do-while, switch,
try/catch/finally, return, throw, break, continue, labeled, with)
- Variable declarations (var/let/const) with destructuring patterns
- Function declarations (sync, async, generators)
- Class declarations (constructor, methods, getters/setters, static)
- Import/export declarations (default, named, namespace, re-export)
Features:
- Operator precedence via Pratt parsing with binding power table
- Automatic Semicolon Insertion (ASI) using lexer newline tracking
- Arrow function detection with expression-to-pattern reinterpretation
- Destructuring patterns (array, object, default values, rest)
- for-in/for-of disambiguation with allow_in flag
- 73 unit tests covering all grammar productions and error cases
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
\<newline> in string/template literals is a line continuation per
ECMAScript spec — it should produce no character, not a newline.
Changed scan_escape_sequence to return Option<char>, returning None
for line continuations. Added test for this behavior.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a full JavaScript lexer to the we-js crate supporting all ES2024
token types: keywords, identifiers (including Unicode), numeric literals
(decimal, hex, octal, binary with separators), string literals with full
escape sequences, template literals with ${} substitution tracking,
regular expression literals with context-based disambiguation, and all
punctuators/operators. Includes source position tracking (line/column)
and newline tracking for automatic semicolon insertion.
48 unit tests covering all token types, edge cases, and error handling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a container has only float children and bare inline content (no
in-flow block siblings), normalize_children returned early without
wrapping the inline content in anonymous blocks. This caused the text
to be silently dropped during layout_block_children since compute_layout
is a no-op for TextRun/Inline boxes.
Include floated children in the has_block check so that inline content
gets properly wrapped in anonymous blocks and laid out through the
inline formatting context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add float layout support to the layout engine:
- Parse float (none/left/right) and clear (none/left/right/both) CSS properties
- Float positioning: left floats at left edge, right floats at right edge
- Float stacking: multiple floats stack horizontally, wrapping when full
- Line box shortening: inline content flows around active floats
- Clear property: elements move below cleared floats
- BFC containment: overflow:hidden/scroll containers expand to contain floats
- Floated inline elements are blockified per CSS2 §9.7
Implements issue 3mhlhnjkxcr2x
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Sticky variant to Position enum and parse "sticky" keyword
- Sticky elements participate in normal flow (like relative positioning)
- Store sticky_constraint rect on LayoutBox (parent's content area)
- Compute sticky paint-time offset in render crate based on scroll state
- Support top stickiness with containing block constraint clamping
- Update scroll container reference point tracking through paint recursion
- Add tests: parsing, normal flow layout, constraint rect, scroll sticking,
and parent constraint behavior
Implements issue 3mhlhoituxu2u
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add z_index field to ComputedStyle and parse CSS z-index property
- Remove absolute/fixed elements from normal flow (block, inline, flex layout)
- Position absolute elements relative to nearest positioned ancestor's padding box
- Position fixed elements relative to viewport
- Support left/right/top/bottom offsets with percentage resolution
- Support width/height stretching when both sides are specified
- Implement stacking context paint order: negative z-index, in-flow, non-negative z-index
- Update normalize_children and margin collapsing to exclude out-of-flow elements
- Add tests for absolute positioning, fixed positioning, z-index, stretching, and
bottom/right positioning
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per CSS Box Alignment §8, row-gap applies between rows and column-gap
between columns. In a column flex container the main axis is vertical,
so the gap between items should use row-gap (not column-gap) and the
gap between flex lines should use column-gap (not row-gap).
Introduces main_gap/cross_gap variables that swap based on flex direction.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add full flexbox support with flex container and item properties:
CSS parsing:
- Parse display: flex/inline-flex
- Parse flex container props: flex-direction, flex-wrap, justify-content,
align-items, align-content, gap/row-gap/column-gap
- Parse flex item props: flex-grow, flex-shrink, flex-basis, align-self, order
- Expand flex, flex-flow, and gap shorthands
Layout algorithm (CSS Flexbox Level 1 §9):
- Determine main/cross axes from flex-direction
- Content-based flex-basis sizing for auto basis
- Distribute free space via flex-grow/flex-shrink
- Line wrapping (flex-wrap: wrap/wrap-reverse)
- Main axis justification (all justify-content modes)
- Cross axis alignment (all align-items/align-self modes)
- Multi-line align-content distribution
- Visual ordering via order property
- Gap spacing between items
- Reverse direction support (row-reverse, column-reverse)
Tests: 10 new flex layout tests covering row/column direction,
grow/shrink, justify-content, align-items, wrap, gap, and order.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add scrollable overflow regions for overflow:scroll and overflow:auto
boxes, with rendered scroll bars and mouse wheel event support.
Layout crate:
- Add content_height field to LayoutBox tracking natural content height
before CSS height override (used for overflow detection)
- Reserve SCROLLBAR_WIDTH (15px) from content area for overflow:scroll
- Export SCROLLBAR_WIDTH constant
Render crate:
- Add ScrollState type (HashMap<NodeId, (f32, f32)>) for scroll offsets
- Modify display list builder to accept scroll state and translate offset
- Apply scroll offset to child coordinates in scrollable containers
- Render vertical scroll bars (track + proportional thumb) for
overflow:scroll (always) and overflow:auto (when content overflows)
- Add page-level scroll support via paint_with_scroll()
- Add build_display_list_with_page_scroll() for viewport scrolling
- 6 new tests: scrollbar rendering, scroll offset, thumb proportionality,
overflow:auto conditional scrollbar, page scroll
Platform crate:
- Add scrollWheel: event handler to WeView class
- Add set_scroll_handler() for registering scroll callbacks
- Forward scroll delta (dx, dy) and mouse position to handler
Browser crate:
- Add page_scroll_y, content_height, scroll_offsets to BrowserState
- Handle scroll wheel events: update page scroll, clamp to bounds,
re-render
- Pass scroll state through rendering pipeline
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add clip rect support to the rendering pipeline so that boxes with
overflow != visible clip their children's content to the padding box.
Render crate changes:
- Add PushClip/PopClip variants to PaintCommand
- Maintain a clip rect stack in Renderer that intersects nested clips
- Apply active clip rect in fill_rect, composite_glyph, and draw_image
- overflow:hidden, overflow:auto, and overflow:scroll all clip content
- overflow:visible (default) continues to render without clipping
Layout crate fix:
- Fix is_empty_block to not treat blocks with explicit CSS height as
empty (they should not self-collapse per CSS2 §8.3.1)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Thread viewport dimensions through style resolution so viewport units
resolve correctly: 1vw = 1% of viewport width, 1vh = 1% of viewport
height, vmin/vmax use the smaller/larger dimension.
For layout properties (width, height, margin, padding), percentages are
now preserved as LengthOrAuto::Percentage through style computation and
resolved during layout against the containing block width. Height
percentages resolve against viewport height. Per CSS spec, even vertical
margins and padding resolve against containing block width.
Changes:
- Add Percentage(f32) variant to LengthOrAuto
- Change ComputedStyle padding fields from f32 to LengthOrAuto
- Add viewport parameter to resolve_styles, threaded through resolution
- resolve_length_unit now computes vw/vh/vmin/vmax from viewport dims
- Layout resolves percentage width/height/margin/padding against
containing block; nested percentages compound correctly
- Store css_margin/css_padding/css_offsets on LayoutBox for deferred
resolution during layout
- 9 new tests covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire up visibility property through the layout and render pipeline:
- Add visibility field to LayoutBox, populated from ComputedStyle
- Renderer skips painting (background, borders, text, images) for
hidden/collapse elements but still recurses into children
- Children can override with visibility:visible per CSS spec
- display:none already worked (excluded from layout tree); verified
9 new tests: 5 layout tests (display:none exclusion, hidden preserves
space, inheritance, visible override, collapse behavior) and 4 render
tests (hidden not painted, visible child of hidden parent painted,
collapse not painted, display:none not in display list).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add BoxSizing enum and box_sizing field to ComputedStyle with CSS
parsing support. Layout engine now respects explicit CSS width/height
and adjusts content dimensions based on box-sizing mode:
- content-box (default): width/height apply to content area only
- border-box: width/height include padding and border
Content area clamps to 0 when padding+border exceeds specified size
in border-box mode. Property is not inherited per spec.
9 new tests covering both modes, clamping, non-inheritance, and height.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements CSS2 §8.3.1 margin collapsing:
- Adjacent sibling margins collapse (gap = max, not sum)
- Parent-child margin collapsing via pre_collapse_margins pass
- Empty block self-collapsing (top+bottom margins fold together)
- Negative margin handling (positive+negative=sum, both negative=min)
- Collapsing blocked by border, padding, or overflow!=visible (BFC)
Adds overflow field to LayoutBox for BFC detection. Updates existing
tests to reflect correct collapsed margin behavior and adds 9 new
tests covering all collapsing scenarios.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add relative positioning support to the layout engine. After normal-flow
layout, elements with position: relative are visually shifted by their
top/right/bottom/left offset values without affecting surrounding elements.
- Add position and relative_offset fields to LayoutBox
- Resolve offset conflicts per CSS spec (top wins over bottom, left over right)
- Recursively shift box rect, text lines, and all descendants
- Add 7 tests covering offsets, sibling independence, conflicts, and auto values
Wire together all Phase 8 components into the browser's navigation flow:
- Use css_loader::collect_stylesheets for external <link> and inline <style>
- Use img_loader::collect_images to fetch and decode <img> elements
- Store pre-fetched PageState (DOM, stylesheet, images) so window resizes
only re-style/re-layout/re-render without re-fetching
- Show error page for network failures instead of process::exit
- Preserve base URL from HTTP response for resolving relative subresources
- Generate file:// base URL for local file paths
Implements issue 3mhktaciaf42q.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add about: scheme handling to ResourceLoader:
- Recognize about:blank and return a minimal empty HTML document
(<!DOCTYPE html><html><head></head><body></body></html>)
- UTF-8 encoding, no network requests
- Unsupported about: URLs return InvalidUrl error
Update browser main to use about:blank as default:
- No URL argument opens about:blank instead of hardcoded demo page
- URL arguments (http://, https://, about:, data:) load via ResourceLoader
- File path arguments still work as before
4 tests covering fetch/fetch_url paths, DOM structure validation,
and unsupported about: URL rejection.
Implements issue 3mhkt7vaxsb23
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add data_url module to the url crate:
- Base64 decoder (RFC 4648): standard alphabet, whitespace stripping, padding
- Data URL parser: extract MIME type, charset, base64/percent-encoded payload
- Default MIME type text/plain;charset=US-ASCII when omitted
Integrate with ResourceLoader in browser crate:
- Handle data: URLs in both fetch() and fetch_url() without network access
- Classify decoded content into Html/Css/Image/Other resource types
- Decode text resources using charset from data URL parameters
44 tests covering base64 decoding, data URL parsing, MIME extraction,
percent decoding, and ResourceLoader integration.
Implements issue 3mhkt7m45472x
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add img_loader module to the browser crate that loads images from the DOM:
- Scan DOM for <img src="..."> elements in document order
- Fetch image data via ResourceLoader with URL resolution
- Detect format from magic bytes (PNG: 89504E47, JPEG: FFD8, GIF: GIF8)
- Decode using image crate decoders (PNG, JPEG, GIF)
- Parse width/height attributes with proportional scaling
- Graceful degradation: failed loads store alt text, no crash
Layout integration:
- Add replaced_size field to LayoutBox for replaced elements
- Accept image_sizes map in layout() for intrinsic/attribute dimensions
- Replaced elements use their dimensions instead of child layout
Render integration:
- Add DrawImage variant to PaintCommand
- Nearest-neighbor scaling with RGBA→BGRA conversion
- Alpha compositing for semi-transparent image pixels
37 tests covering format detection, dimension parsing/resolution,
DOM scanning, graceful failure, error display, and PNG decoding.
Implements issue 3mhkt7br4jx25
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add css_loader module to the browser crate that collects CSS from the DOM:
- Scan DOM for <style> elements (inline CSS) and <link rel="stylesheet"> (external)
- Fetch external stylesheets via ResourceLoader with encoding detection
- Resolve @import rules recursively (max depth 5 to prevent cycles)
- Basic media attribute support (screen, all)
- Type attribute validation (text/css default)
- Graceful degradation: failed loads are silently skipped
- Merge all rules into a single Stylesheet in document order
37 tests covering DOM scanning, classification, media matching, text
collection, import resolution, error handling, and edge cases.
Implements issue 3mhkt6vtv3q2g
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add ResourceLoader to the browser crate that integrates the net, encoding,
url, and image crates into a unified resource fetching API:
- ResourceLoader wraps HttpClient for HTTP/HTTPS fetching
- Content-Type parsing determines resource type (HTML, CSS, image, other)
- WHATWG encoding sniffing for HTML (BOM > HTTP > meta prescan > default)
- BOM/HTTP charset detection for non-HTML text resources (default UTF-8)
- Relative URL resolution via base URL support
- HTTP error status handling (4xx, 5xx)
- Resource enum: Html, Css, Image, Other with appropriate metadata
30 tests covering MIME classification, text decoding (BOM, HTTP charset,
meta prescan, Windows-1252 special chars), URL resolution, and error types.
Implements issue 3mhkt6hnbhp25
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add encoding detection per WHATWG Encoding Standard and HTML spec:
- BOM sniffing for UTF-8, UTF-16LE, UTF-16BE
- HTTP Content-Type charset extraction (quoted/unquoted values)
- HTML meta prescan: scan first 1024 bytes for <meta charset> and
<meta http-equiv="Content-Type" content="...;charset=...">
- Priority: BOM > HTTP header > meta prescan > default (Windows-1252)
- UTF-16 from HTTP/meta overridden to UTF-8 per spec
- EncodingSource enum for tracking detection method confidence
39 new tests covering all detection methods and priority ordering.
Implements issue 3mhkt62ryxo2l
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add all 27 WHATWG single-byte encodings to the encoding crate:
- Windows-1252 (with ISO-8859-1 and US-ASCII aliases per WHATWG spec)
- ISO-8859-2 through ISO-8859-16 (excluding 8859-9 which maps to Windows-1254)
- Windows-874, Windows-1250 through Windows-1258
- KOI8-R, KOI8-U
- macintosh, x-mac-cyrillic
- IBM866
Each encoding uses a 128-entry u16 lookup table for bytes 0x80-0xFF.
All WHATWG label aliases are registered for case-insensitive lookup.
32 new tests covering per-encoding correctness and error handling.
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure Rust implementation of UTF-8 and UTF-16 text encoding/decoding
per the WHATWG Encoding Standard:
- UTF-8 decoder (streaming state machine with replacement/fatal modes)
- UTF-8 encoder
- UTF-16LE/BE decoders with surrogate pair handling and BOM stripping
- Encoding label lookup (case-insensitive, whitespace-trimmed)
- BOM sniffing utility
- Public API: decode(), decode_strict(), encode(), lookup(), bom_sniff()
- 93 unit tests covering edge cases (overlong, surrogates, truncated, BOM)
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure Rust baseline JPEG decoder in the image crate supporting:
- JFIF marker parsing (SOI, APP0/APP1, DQT, SOF0, DHT, SOS, DRI, EOI)
- Huffman entropy decoding (DC and AC coefficients)
- 8x8 block-based inverse DCT (Loeffler algorithm, integer fixed-point)
- Dequantization with DQT tables
- Chroma subsampling: 4:4:4, 4:2:2, 4:2:0
- YCbCr to RGB color conversion (BT.601 fixed-point)
- Restart marker support
- Grayscale JPEG support
- 28 unit tests covering Huffman, IDCT, color conversion, parsing, and
end-to-end decoding of hand-crafted JPEG streams
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GIF LZW uses "early change" — the code size must bump when next_code
reaches (1 << code_size), not after it exceeds it. Without this fix,
the decoder would read codes with the wrong bit width for GIFs with
enough unique codes to trigger a code size increase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust GIF decoder in the image crate supporting:
- GIF87a and GIF89a format parsing
- LZW decompression with variable-width codes, clear/EOI codes
- Global and local color tables
- Graphic Control Extension (transparency, delay, disposal methods)
- Multi-frame animated GIFs with canvas compositing
- Interlaced image support (4-pass Adam7-style deinterlacing)
- Sub-frame positioning (frames smaller than logical screen)
- Application, comment, and plain text extension skipping
- API: decode_gif() for first frame, decode_gif_frames() for all frames
31 unit tests covering LZW decompression, deinterlacing, frame decoding,
transparency, animation, local color tables, extensions, and error cases.
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust PNG decoder supporting all color types (grayscale, RGB,
indexed, grayscale+alpha, RGBA), bit depths 1-16, scanline filtering
(None/Sub/Up/Average/Paeth), Adam7 interlacing, tRNS transparency,
CRC-32 validation, and multiple IDAT chunk concatenation.
40+ unit tests covering all color types, bit depths, filter types,
interlacing, transparency, error cases, and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse zlib header (CMF/FLG), validate header checksum, delegate to
DEFLATE for compressed data, verify Adler-32 checksum of output.
21 unit tests covering Adler-32, header validation, round-trip
decompression, error propagation, and all window sizes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust DEFLATE decompression supporting all three block types:
- Non-compressed blocks (BTYPE=00) with LEN/NLEN validation
- Fixed Huffman codes (BTYPE=01) per RFC 1951 §3.2.6
- Dynamic Huffman codes (BTYPE=10) with code length decoding
Implementation details:
- LSB-first bit reader with peek/consume pattern for Huffman decoding
- Two-level Huffman lookup table (primary + subtable for long codes)
- LZ77 back-reference decoding with overlapping copy support
- Handles end-of-stream gracefully when final code needs fewer bits
than the primary table width
33 unit tests covering BitReader, Huffman trees, all block types,
back-references, error cases, and round-trip verification against
zlib-generated test vectors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace strip_prefix-based header matching (only matched exact case and
lowercase) with a proper case-insensitive helper that splits on the
first colon and compares the header name using eq_ignore_ascii_case.
Adds tests for all-caps header names (CONTENT-LENGTH, TRANSFER-ENCODING).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
High-level HTTP client in the net crate bringing together TCP, TLS 1.3,
DNS, URL parsing, and HTTP message handling:
- HttpClient with get(), post(), request() methods
- Scheme handling: http:// (plain TCP) and https:// (TLS)
- Connection pooling by (host, port, is_tls) with max idle time and
max connections per host
- Redirect following (301, 302, 307, 308) with configurable max
- Configurable connect and read timeouts
- Streaming response reader: header detection, Content-Length,
chunked Transfer-Encoding, and read-until-close strategies
- std::io::Read and Write trait impls for TcpConnection
30+ unit tests covering error types, configuration, connection pool,
URL path building, header parsing, body strategy selection, and
chunked terminator detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>