commits
Prevents potential out-of-bounds read by checking that the data slice
is at least bytes_per_row * height before passing it to Metal's
replaceRegion:withBytes:bytesPerRow: API.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add GPU texture creation for RGBA8 images and R8 grayscale glyph bitmaps,
nearest-neighbor sampler for pixel-accurate rendering, and TextureCache
to avoid redundant GPU uploads across frames.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add MSL shaders (vertex + fragment) for 2D quad rendering with pixel-to-NDC
coordinate transform and dual-mode fragment shader (solid color + textured).
Create MTLRenderPipelineState with alpha blending, define Vertex/Uniforms/Quad
structs, and implement MetalRenderer for batched draw call encoding.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 7 event handler callbacks (isFlipped, acceptsFirstResponder, keyDown:,
mouseDown:, mouseUp:, mouseMoved:, scrollWheel:) were duplicated verbatim
between WeView and WeMetalView class registrations (~120 lines). Extract
them to module-level extern "C" functions and a shared
register_view_event_handlers() helper.
Also rename MetalView._state to MetalView.state since the field is actively
used (not just kept alive for drop).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Metal GPU framework bindings to the platform crate and integrate
a CAMetalLayer-backed view into the browser for GPU-accelerated rendering.
- metal.rs: FFI bindings for MTLDevice, MTLCommandQueue, MTLCommandBuffer,
MTLRenderCommandEncoder, CAMetalLayer, and render pass descriptor helpers
- MetalView in appkit.rs: custom NSView subclass (WeMetalView) using
CAMetalLayer with updateLayer for clear-to-color rendering
- Browser falls back to BitmapView when Metal is unavailable
- Double-buffered presentation via CAMetalLayer.nextDrawable
- 6 new Metal tests (device, queue, layer creation and configuration)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When parse_attribute returns None (e.g., malformed HTML with bare '='
or '/' not followed by '>'), the previously collected charset info
should be preserved rather than discarded. Using break instead of ?
ensures already-parsed charset/http-equiv attributes are still
evaluated at the end of the function.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove duplicate TEST_TIMEOUT_INSTRUCTIONS constant (identical to
INSTRUCTION_LIMIT), use INSTRUCTION_LIMIT everywhere
- Fix potential panic when truncating failure messages containing
multi-byte UTF-8 characters by using floor_char_boundary
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a Web Platform Tests runner that discovers HTML test files,
executes inline scripts with a testharness.js shim, and reports
pass/fail/skip counts grouped by test directory.
Includes:
- testharness.js preamble: test(), async_test(), promise_test(),
assert_equals, assert_true, assert_false, assert_not_equals,
assert_throws_js, assert_throws_dom, assert_array_equals
- Test runner with panic isolation and instruction-count timeouts
- Results collection via tab-separated serialization from the VM
- 16 embedded WPT-style HTML test files covering dom/nodes,
dom/events, dom/collections, html/dom, and console APIs
- Initial pass rate: 48/48 subtests passing (100%)
Run with: cargo test -p we-browser --test wpt -- --nocapture
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add script execution to the page loading pipeline: after HTML parsing,
walk the DOM for <script> elements and execute them in a shared JS VM
with full DOM access. Scripts can modify the DOM before CSS/image
collection.
Key changes:
- New script_loader module: discovers scripts in document order,
fetches external scripts, handles defer/async/type attributes
- VM.detach_document(): reclaim Document after script execution
- Top-level var declarations now emit StoreGlobal so variables
persist across multiple execute() calls (shared global scope)
- Resource::Script variant for JavaScript MIME types
- Exhaustive match updates in css_loader and img_loader
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace check-then-take double-lock pattern with a single lock().take()
call, eliminating unnecessary mutex re-acquisition.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add fetch() global function that returns a Promise<Response>, backed by
the existing HTTP/1.1 client and TLS implementation in the net crate.
- fetch(url, options?) spawns a background thread for non-blocking I/O
- Response object: status, statusText, ok, url, headers, text(), json()
- Headers object: get(), has(), set(), delete() with case-insensitive matching
- Event loop integration: pending fetches polled alongside timers
- GC roots for pending fetch promises prevent premature collection
- Promise rejects on network errors (DNS failure, connection refused, etc.)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add timers.rs module with thread-local timer registry, ID generation,
and timer lifecycle management (schedule, cancel, take due timers)
- Register global functions: setTimeout, clearTimeout, setInterval,
clearInterval, requestAnimationFrame, cancelAnimationFrame
- Integrate timer execution with VM event loop: drain_due_timers runs
after microtasks, pump_event_loop and run_event_loop for external use
- Timer callbacks registered as GC roots to survive garbage collection
- Microtask queue drains after each timer callback (Promise integration)
- 15 tests covering: ID generation, deferred execution, cancellation,
interval repetition, requestAnimationFrame timestamps, GC survival,
Promise-timer interaction, edge cases
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Check is_propagation_stopped before entering bubble phase in
run_event_dispatch (not just inside the loop)
- Remove redundant is_propagation_stopped check from invoke_listeners
(stopPropagation should not prevent remaining listeners on the same
node from firing, only stopImmediatePropagation does that)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements the W3C DOM event model connecting JavaScript event handlers
to the DOM tree with full capture/target/bubble phase propagation.
- Event constructor: new Event(type, options) with bubbles/cancelable
- Event methods: preventDefault, stopPropagation, stopImmediatePropagation
- EventTarget methods on all node wrappers and document:
addEventListener, removeEventListener, dispatchEvent
- Event propagation: capture phase -> at-target -> bubble phase
- Support for capture option (boolean or options object)
- Support for once option (auto-remove after first invocation)
- Event listener GcRefs registered as GC roots
- 20 new tests covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove unused `val_str` variable in `handle_style_set`
- Remove `let _ = bridge;` dead code suppression in `create_class_list`,
prefix param with underscore instead
- Move `collect_roots` doc comment to correct method (was accidentally
attached to `resolve_dom_property`)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add comprehensive DOM node manipulation methods and property access
from JavaScript, building on the existing DOM-JS bridge architecture.
Tree manipulation: appendChild, removeChild, insertBefore, replaceChild,
cloneNode, hasChildNodes. Content properties: textContent (get/set),
innerHTML (get/set with HTML parsing), outerHTML. Attribute methods:
getAttribute, setAttribute, removeAttribute, hasAttribute, attributes.
Navigation: parentNode, parentElement, childNodes, children, firstChild,
lastChild, firstElementChild, lastElementChild, nextSibling,
previousSibling, nextElementSibling, previousElementSibling.
Style: element.style object with camelCase CSS property access that
syncs to the inline style attribute. classList: add, remove, toggle,
contains methods that modify the class attribute.
Dynamic properties are resolved via VM interception in GetProperty and
SetProperty handlers, ensuring navigation and content properties always
reflect the current DOM state after modifications.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The node_wrappers identity cache in DomBridge holds GcRef values that
were not included in collect_roots(), meaning the GC could collect
wrapper objects and break wrapper identity (same DOM node returning
different JS objects across calls). Add cached wrappers as GC roots
so identity is preserved across garbage collection cycles.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the bridge between the JS engine and the DOM crate (Phase 11, issue 2 of 8).
- DomBridge struct holds shared Document and wrapper identity cache
- Vm::attach_document() registers document global with structural properties
- document.documentElement, .head, .body, .title properties
- document.getElementById, getElementsByTagName, getElementsByClassName
- document.querySelector/querySelectorAll (reuses css/style selector matching)
- document.createElement, createTextNode factory methods
- Element wrappers with tagName, nodeName, nodeType, id, className
- Wrapper identity: same NodeId always returns same JS object
- NodeId::from_index added to dom crate
- Parser::parse_selectors added to css crate
- 20 tests covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the Console API as built-in JS globals (Phase 11, issue 1 of 8).
- ConsoleOutput trait with configurable output sink (default: stdout/stderr)
- console.log/info/debug write to the log channel
- console.error writes to the error channel
- console.warn writes to the warn channel
- Rich formatting: arrays show contents, objects show properties
- Cycle detection and depth limiting for nested structures
- Vm::set_console_output() for redirecting output (dev tools, testing)
- 14 tests covering all methods, formatting, and channel routing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove stream-of-consciousness comments in async_resume_callback, replace
with concise doc explaining the actual mechanism
- Rename misleading test_async_arrow_* tests to test_async_function_expression*
(they tested function expressions, not arrows)
- Add real async arrow function tests using `async x => ...` syntax
- Add Executing state guard to throw_into_generator for consistency with
run_generator (prevents re-entrancy)
Co-Authored-By: Claude Opus 4.6 (1M context) <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>
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>
Prevents potential out-of-bounds read by checking that the data slice
is at least bytes_per_row * height before passing it to Metal's
replaceRegion:withBytes:bytesPerRow: API.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add MSL shaders (vertex + fragment) for 2D quad rendering with pixel-to-NDC
coordinate transform and dual-mode fragment shader (solid color + textured).
Create MTLRenderPipelineState with alpha blending, define Vertex/Uniforms/Quad
structs, and implement MetalRenderer for batched draw call encoding.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 7 event handler callbacks (isFlipped, acceptsFirstResponder, keyDown:,
mouseDown:, mouseUp:, mouseMoved:, scrollWheel:) were duplicated verbatim
between WeView and WeMetalView class registrations (~120 lines). Extract
them to module-level extern "C" functions and a shared
register_view_event_handlers() helper.
Also rename MetalView._state to MetalView.state since the field is actively
used (not just kept alive for drop).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Metal GPU framework bindings to the platform crate and integrate
a CAMetalLayer-backed view into the browser for GPU-accelerated rendering.
- metal.rs: FFI bindings for MTLDevice, MTLCommandQueue, MTLCommandBuffer,
MTLRenderCommandEncoder, CAMetalLayer, and render pass descriptor helpers
- MetalView in appkit.rs: custom NSView subclass (WeMetalView) using
CAMetalLayer with updateLayer for clear-to-color rendering
- Browser falls back to BitmapView when Metal is unavailable
- Double-buffered presentation via CAMetalLayer.nextDrawable
- 6 new Metal tests (device, queue, layer creation and configuration)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When parse_attribute returns None (e.g., malformed HTML with bare '='
or '/' not followed by '>'), the previously collected charset info
should be preserved rather than discarded. Using break instead of ?
ensures already-parsed charset/http-equiv attributes are still
evaluated at the end of the function.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove duplicate TEST_TIMEOUT_INSTRUCTIONS constant (identical to
INSTRUCTION_LIMIT), use INSTRUCTION_LIMIT everywhere
- Fix potential panic when truncating failure messages containing
multi-byte UTF-8 characters by using floor_char_boundary
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a Web Platform Tests runner that discovers HTML test files,
executes inline scripts with a testharness.js shim, and reports
pass/fail/skip counts grouped by test directory.
Includes:
- testharness.js preamble: test(), async_test(), promise_test(),
assert_equals, assert_true, assert_false, assert_not_equals,
assert_throws_js, assert_throws_dom, assert_array_equals
- Test runner with panic isolation and instruction-count timeouts
- Results collection via tab-separated serialization from the VM
- 16 embedded WPT-style HTML test files covering dom/nodes,
dom/events, dom/collections, html/dom, and console APIs
- Initial pass rate: 48/48 subtests passing (100%)
Run with: cargo test -p we-browser --test wpt -- --nocapture
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add script execution to the page loading pipeline: after HTML parsing,
walk the DOM for <script> elements and execute them in a shared JS VM
with full DOM access. Scripts can modify the DOM before CSS/image
collection.
Key changes:
- New script_loader module: discovers scripts in document order,
fetches external scripts, handles defer/async/type attributes
- VM.detach_document(): reclaim Document after script execution
- Top-level var declarations now emit StoreGlobal so variables
persist across multiple execute() calls (shared global scope)
- Resource::Script variant for JavaScript MIME types
- Exhaustive match updates in css_loader and img_loader
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add fetch() global function that returns a Promise<Response>, backed by
the existing HTTP/1.1 client and TLS implementation in the net crate.
- fetch(url, options?) spawns a background thread for non-blocking I/O
- Response object: status, statusText, ok, url, headers, text(), json()
- Headers object: get(), has(), set(), delete() with case-insensitive matching
- Event loop integration: pending fetches polled alongside timers
- GC roots for pending fetch promises prevent premature collection
- Promise rejects on network errors (DNS failure, connection refused, etc.)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add timers.rs module with thread-local timer registry, ID generation,
and timer lifecycle management (schedule, cancel, take due timers)
- Register global functions: setTimeout, clearTimeout, setInterval,
clearInterval, requestAnimationFrame, cancelAnimationFrame
- Integrate timer execution with VM event loop: drain_due_timers runs
after microtasks, pump_event_loop and run_event_loop for external use
- Timer callbacks registered as GC roots to survive garbage collection
- Microtask queue drains after each timer callback (Promise integration)
- 15 tests covering: ID generation, deferred execution, cancellation,
interval repetition, requestAnimationFrame timestamps, GC survival,
Promise-timer interaction, edge cases
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Check is_propagation_stopped before entering bubble phase in
run_event_dispatch (not just inside the loop)
- Remove redundant is_propagation_stopped check from invoke_listeners
(stopPropagation should not prevent remaining listeners on the same
node from firing, only stopImmediatePropagation does that)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements the W3C DOM event model connecting JavaScript event handlers
to the DOM tree with full capture/target/bubble phase propagation.
- Event constructor: new Event(type, options) with bubbles/cancelable
- Event methods: preventDefault, stopPropagation, stopImmediatePropagation
- EventTarget methods on all node wrappers and document:
addEventListener, removeEventListener, dispatchEvent
- Event propagation: capture phase -> at-target -> bubble phase
- Support for capture option (boolean or options object)
- Support for once option (auto-remove after first invocation)
- Event listener GcRefs registered as GC roots
- 20 new tests covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove unused `val_str` variable in `handle_style_set`
- Remove `let _ = bridge;` dead code suppression in `create_class_list`,
prefix param with underscore instead
- Move `collect_roots` doc comment to correct method (was accidentally
attached to `resolve_dom_property`)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add comprehensive DOM node manipulation methods and property access
from JavaScript, building on the existing DOM-JS bridge architecture.
Tree manipulation: appendChild, removeChild, insertBefore, replaceChild,
cloneNode, hasChildNodes. Content properties: textContent (get/set),
innerHTML (get/set with HTML parsing), outerHTML. Attribute methods:
getAttribute, setAttribute, removeAttribute, hasAttribute, attributes.
Navigation: parentNode, parentElement, childNodes, children, firstChild,
lastChild, firstElementChild, lastElementChild, nextSibling,
previousSibling, nextElementSibling, previousElementSibling.
Style: element.style object with camelCase CSS property access that
syncs to the inline style attribute. classList: add, remove, toggle,
contains methods that modify the class attribute.
Dynamic properties are resolved via VM interception in GetProperty and
SetProperty handlers, ensuring navigation and content properties always
reflect the current DOM state after modifications.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The node_wrappers identity cache in DomBridge holds GcRef values that
were not included in collect_roots(), meaning the GC could collect
wrapper objects and break wrapper identity (same DOM node returning
different JS objects across calls). Add cached wrappers as GC roots
so identity is preserved across garbage collection cycles.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the bridge between the JS engine and the DOM crate (Phase 11, issue 2 of 8).
- DomBridge struct holds shared Document and wrapper identity cache
- Vm::attach_document() registers document global with structural properties
- document.documentElement, .head, .body, .title properties
- document.getElementById, getElementsByTagName, getElementsByClassName
- document.querySelector/querySelectorAll (reuses css/style selector matching)
- document.createElement, createTextNode factory methods
- Element wrappers with tagName, nodeName, nodeType, id, className
- Wrapper identity: same NodeId always returns same JS object
- NodeId::from_index added to dom crate
- Parser::parse_selectors added to css crate
- 20 tests covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the Console API as built-in JS globals (Phase 11, issue 1 of 8).
- ConsoleOutput trait with configurable output sink (default: stdout/stderr)
- console.log/info/debug write to the log channel
- console.error writes to the error channel
- console.warn writes to the warn channel
- Rich formatting: arrays show contents, objects show properties
- Cycle detection and depth limiting for nested structures
- Vm::set_console_output() for redirecting output (dev tools, testing)
- 14 tests covering all methods, formatting, and channel routing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove stream-of-consciousness comments in async_resume_callback, replace
with concise doc explaining the actual mechanism
- Rename misleading test_async_arrow_* tests to test_async_function_expression*
(they tested function expressions, not arrows)
- Add real async arrow function tests using `async x => ...` syntax
- Add Executing state guard to throw_into_generator for consistency with
run_generator (prevents re-entrancy)
Co-Authored-By: Claude Opus 4.6 (1M context) <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>