Files
rust_browser/_bmad-output/implementation-artifacts/3-6-built-in-completeness-date-regexp-map-set.md
Zachary D. Rowitsch fb64ca1d34
All checks were successful
ci / fast (linux) (push) Successful in 7m9s
Create story files for Epic 3 stories 3.5-3.10
Create comprehensive implementation-ready story files for the remaining
Epic 3 (JavaScript Engine Maturity) stories and update sprint status
from backlog to ready-for-dev:

- 3.5: Built-in Completeness (Array/String/Object)
- 3.6: Built-in Completeness (Date/RegExp/Map/Set)
- 3.7: WeakRef, FinalizationRegistry & Strict Mode Edge Cases
- 3.8: DOM Bindings via web_api
- 3.9: Event Dispatch Completeness
- 3.10: Web API Exposure (fetch, Math, setInterval, rAF)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 08:06:03 -04:00

28 KiB

Story 3.6: Built-in Completeness -- Date/RegExp/Map/Set

Status: ready-for-dev

Story

As a web developer using JavaScript, I want Date, RegExp, Map, Set, WeakMap, and WeakSet to work completely, So that date handling, pattern matching, and collection types function correctly.

Acceptance Criteria

  1. Date construction and methods: new Date(), new Date(value), new Date(year, month, ...), Date.now(), Date.parse(), Date.UTC() all construct dates correctly. Getter methods (getFullYear, getMonth, getDate, getDay, getHours, getMinutes, getSeconds, getMilliseconds, getTime, getTimezoneOffset) and their UTC variants return correct values. Setter methods (setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime) modify dates correctly. Conversion methods (toISOString, toJSON, toDateString, toTimeString, toString, valueOf) produce spec-compliant output. Invalid dates return NaN from getTime() and "Invalid Date" from toString(). Per ECMAScript §21.4.

  2. RegExp completeness: Extend existing RegExp with: function replacers in String.prototype.replace(), named capture groups (?<name>...) with $<name> substitution (requires regress crate support check), RegExp.prototype[Symbol.match], [Symbol.replace], [Symbol.search], [Symbol.split] well-known symbol methods. Per ECMAScript §22.2.

  3. Map complete: new Map(iterable?) constructor. Methods: .get(key), .set(key, value), .has(key), .delete(key), .clear(), .forEach(callback, thisArg). Property: .size. Iterators: .entries(), .keys(), .values(), [Symbol.iterator]. Keys use SameValueZero equality (NaN === NaN, -0 === +0). Insertion order preserved. Per ECMAScript §24.1.

  4. Set complete: new Set(iterable?) constructor. Methods: .add(value), .has(value), .delete(value), .clear(), .forEach(callback, thisArg). Property: .size. Iterators: .entries(), .keys(), .values(), [Symbol.iterator]. Values use SameValueZero equality. Insertion order preserved. Per ECMAScript §24.2.

  5. WeakSet complete: new WeakSet(iterable?) constructor. Methods: .add(value), .has(value), .delete(value). Object-only keys (TypeError for primitives). Per ECMAScript §24.4.

  6. WeakMap enhancements: Constructor accepts iterable of [key, value] pairs: new WeakMap(iterable?). Existing get/set/has/delete methods already implemented -- verify function keys work correctly (current limitation: function keys may throw TypeError).

  7. Callback error propagation: Map.forEach, Set.forEach, and Array.from(map/set) correctly propagate thrown errors from callbacks without corrupting collection internal state.

  8. Test262 tests promoted: All relevant vendored and full-suite Test262 tests for Date, RegExp, Map, Set, WeakMap, WeakSet are promoted. docs/JavaScript_Implementation_Checklist.md and docs/js_feature_matrix.md updated. just ci passes.

What NOT to Implement

  • No Intl.DateTimeFormat -- locale-sensitive Date formatting (toLocaleDateString, toLocaleTimeString, toLocaleString) return English-only fixed format. Full Intl support out of scope.
  • No timezone database -- timezone offset uses the host system's local timezone via chrono or std::time. Named timezone support (IANA) deferred.
  • No RegExp lookbehind -- (?<=...) and (?<!...) depend on regress crate support. If regress doesn't support them, document as known limitation.
  • No RegExp d flag (hasIndices) -- ES2022 match indices deferred unless regress provides match positions (it likely does via Match::start()/Match::end() -- investigate).
  • No RegExp.prototype.compile() -- deprecated legacy method, skip.
  • No Map/Set subclassing -- class MyMap extends Map and Symbol.species deferred.
  • No garbage collection for WeakMap/WeakSet -- entries remain until explicit deletion. Documenting as known limitation (Rust's Rc<RefCell<>> prevents true weak references without architectural changes).

Files to Modify

File Change
crates/js_vm/src/value.rs Add PrimitiveValue::Date(f64) variant for Date internal time value. Add map_data: Option<OrderedMap> and set_data: Option<OrderedSet> and weak_set_data: Option<HashSet<usize>> fields to JsObjectData.
crates/js_vm/src/interpreter/date_builtins.rs New file -- Date constructor, all Date prototype methods (getters, setters, conversion), Date static methods (now, parse, UTC).
crates/js_vm/src/interpreter/map_builtins.rs New file -- Map constructor, prototype methods (get, set, has, delete, clear, forEach, entries, keys, values, size), setup function.
crates/js_vm/src/interpreter/set_builtins.rs New file -- Set constructor, prototype methods (add, has, delete, clear, forEach, entries, keys, values, size), setup function.
crates/js_vm/src/interpreter/weakmap_builtins.rs Add iterable constructor support. Fix function-as-key limitation.
crates/js_vm/src/interpreter/weakset_builtins.rs New file -- WeakSet constructor (with iterable), add, has, delete. Same pointer-identity pattern as WeakMap.
crates/js_vm/src/interpreter/regexp_builtins.rs Add Symbol.match/replace/search/split well-known symbol methods.
crates/js_vm/src/interpreter/builtins.rs Add function replacer support to String.prototype.replace(). Add named capture group $<name> substitution.
crates/js_vm/src/interpreter/mod.rs Add setup_date_builtins(), setup_map_builtins(), setup_set_builtins(), setup_weakset_builtins() calls.
crates/js_vm/src/interpreter/expressions/calls.rs Add Map/Set/WeakSet method dispatch alongside existing WeakMap dispatch.
crates/js_vm/src/interpreter/tests/date_tests.rs New file -- Date unit tests.
crates/js_vm/src/interpreter/tests/map_tests.rs New file -- Map unit tests.
crates/js_vm/src/interpreter/tests/set_tests.rs New file -- Set unit tests.
crates/js_vm/src/interpreter/tests/weakset_tests.rs New file -- WeakSet unit tests.
crates/js_vm/src/interpreter/tests/regexp_tests.rs Add tests for function replacers, Symbol methods.
tests/external/js262/js262_manifest.toml Promote passing tests.
docs/JavaScript_Implementation_Checklist.md Check off Phase 20 (Map, Set, WeakSet) and Phase 22 (Date) items.
docs/old/js_feature_matrix.md Update built-in coverage.

Tasks / Subtasks

  • Task 1: Map implementation (AC: #3, #7)

    • 1.1 Add ordered map storage to crates/js_vm/src/value.rs:
      • Add map_data: Option<IndexMap<MapKey, JsValue>> field to JsObjectData
      • MapKey enum: wraps JsValue with custom Eq/Hash using SameValueZero semantics
      • SameValueZero: NaN == NaN (true), +0 == -0 (true), otherwise strict equality
      • For object keys: use Rc::as_ptr() identity (same as WeakMap)
      • For NaN: canonical hash/eq so all NaN variants match
      • Use indexmap crate (already a workspace dependency) for insertion-order preservation
      • Add init_map(), is_map() helpers on JsObject
    • 1.2 Create crates/js_vm/src/interpreter/map_builtins.rs:
      • setup_map_builtins(env: &mut Environment) -- registers Map constructor and prototype
      • Constructor: new Map() creates empty map. new Map(iterable) iterates entries and calls .set() for each [key, value] pair.
      • TypeError if called without new
    • 1.3 Implement Map prototype methods:
      • .set(key, value) -- insert/update, return this for chaining (ECMAScript §24.1.3.9)
      • .get(key) -- return value or undefined (ECMAScript §24.1.3.6)
      • .has(key) -- return boolean (ECMAScript §24.1.3.7)
      • .delete(key) -- remove and return boolean (ECMAScript §24.1.3.3)
      • .clear() -- remove all entries (ECMAScript §24.1.3.2)
      • .size -- getter returning entry count (ECMAScript §24.1.3.10)
    • 1.4 Implement Map callback and iterator methods:
      • .forEach(callback, thisArg) -- call callback(value, key, map) for each entry in insertion order. Propagate errors from callback without corrupting map state.
      • .entries() -- return iterator yielding [key, value] arrays (ECMAScript §24.1.3.4)
      • .keys() -- return iterator yielding keys (ECMAScript §24.1.3.8)
      • .values() -- return iterator yielding values (ECMAScript §24.1.3.11)
      • Map.prototype[Symbol.iterator] = Map.prototype.entries (ECMAScript §24.1.3.12)
      • Iterators reuse generator/iterator protocol from Story 3.2
    • 1.5 Wire Map dispatch in crates/js_vm/src/interpreter/expressions/calls.rs:
      • Follow WeakMap dispatch pattern (check obj.is_map(), then fast-path method resolution)
    • 1.6 Add setup_map_builtins() call in crates/js_vm/src/interpreter/mod.rs
    • 1.7 Add unit tests in crates/js_vm/src/interpreter/tests/map_tests.rs:
      • Basic CRUD operations, constructor with iterable, size, chaining
      • NaN key equality (map.set(NaN, 1); map.get(NaN) === 1)
      • -0 and +0 treated as same key
      • Object key identity (two {} are different keys)
      • Insertion order preservation in iteration
      • forEach error propagation
      • Iterator protocol compliance
  • Task 2: Set implementation (AC: #4, #7)

    • 2.1 Add ordered set storage to crates/js_vm/src/value.rs:
      • Add set_data: Option<IndexSet<MapKey>> field to JsObjectData
      • Reuse MapKey from Map implementation (same SameValueZero equality)
      • Use indexmap::IndexSet for insertion-order preservation
      • Add init_set(), is_set() helpers on JsObject
    • 2.2 Create crates/js_vm/src/interpreter/set_builtins.rs:
      • setup_set_builtins(env: &mut Environment) -- registers Set constructor and prototype
      • Constructor: new Set() creates empty set. new Set(iterable) iterates and calls .add() for each value.
      • TypeError if called without new
    • 2.3 Implement Set prototype methods:
      • .add(value) -- insert value, return this for chaining (ECMAScript §24.2.3.1)
      • .has(value) -- return boolean (ECMAScript §24.2.3.5)
      • .delete(value) -- remove and return boolean (ECMAScript §24.2.3.4)
      • .clear() -- remove all values (ECMAScript §24.2.3.2)
      • .size -- getter returning count (ECMAScript §24.2.3.9)
    • 2.4 Implement Set callback and iterator methods:
      • .forEach(callback, thisArg) -- call callback(value, value, set) (note: value passed as both args per spec). Propagate errors.
      • .entries() -- return iterator yielding [value, value] (ECMAScript §24.2.3.5)
      • .keys() -- alias for .values() (ECMAScript §24.2.3.8)
      • .values() -- return iterator yielding values (ECMAScript §24.2.3.10)
      • Set.prototype[Symbol.iterator] = Set.prototype.values (ECMAScript §24.2.3.11)
    • 2.5 Wire Set dispatch in crates/js_vm/src/interpreter/expressions/calls.rs
    • 2.6 Add setup_set_builtins() call in crates/js_vm/src/interpreter/mod.rs
    • 2.7 Add unit tests in crates/js_vm/src/interpreter/tests/set_tests.rs:
      • Basic add/has/delete/clear, constructor with iterable, size
      • NaN equality, -0/+0 treated as same, object identity
      • Insertion order preservation
      • forEach with (value, value, set) args
      • Deduplication (adding same value twice keeps one entry)
  • Task 3: WeakSet implementation (AC: #5)

    • 3.1 Add weak set storage to crates/js_vm/src/value.rs:
      • Add weak_set_data: Option<HashSet<usize>> field to JsObjectData
      • Use Rc::as_ptr() identity (same pattern as WeakMap)
      • Add init_weakset(), is_weakset() helpers on JsObject
    • 3.2 Create crates/js_vm/src/interpreter/weakset_builtins.rs:
      • setup_weakset_builtins(env: &mut Environment)
      • Constructor: new WeakSet() / new WeakSet(iterable) -- iterable items must be objects
    • 3.3 Implement WeakSet prototype methods:
      • .add(value) -- TypeError if not object. Add by pointer identity. Return this.
      • .has(value) -- return boolean
      • .delete(value) -- remove and return boolean
    • 3.4 Wire WeakSet dispatch alongside WeakMap in calls.rs
    • 3.5 Add setup_weakset_builtins() call in mod.rs
    • 3.6 Add unit tests in crates/js_vm/src/interpreter/tests/weakset_tests.rs:
      • Basic add/has/delete, TypeError on primitive values
      • Constructor with iterable of objects
      • Object identity semantics
  • Task 4: WeakMap enhancements (AC: #6)

    • 4.1 Add iterable constructor to WeakMap in weakmap_builtins.rs:
      • new WeakMap(iterable) -- iterate [key, value] pairs, key must be object
    • 4.2 Fix function-as-key limitation:
      • JsValue::Function should be accepted as a WeakMap/WeakSet key (functions are objects per spec)
      • Use function pointer identity for keying
    • 4.3 Add unit tests for iterable constructor and function keys
  • Task 5: Date implementation (AC: #1)

    • 5.1 Add Date internal value storage to crates/js_vm/src/value.rs:
      • Add PrimitiveValue::Date(f64) variant -- stores milliseconds since epoch (or NaN for invalid)
      • Add init_date(time_value: f64), is_date(), date_value() -> f64 helpers on JsObject
    • 5.2 Create crates/js_vm/src/interpreter/date_builtins.rs:
      • setup_date_builtins(env: &mut Environment) -- registers Date constructor and prototype
    • 5.3 Implement Date constructors (ECMAScript §21.4.2):
      • Date() (no new) -- return current date as string
      • new Date() -- current time in milliseconds (std::time::SystemTime::now())
      • new Date(value) -- if number, use as milliseconds. If string, parse (ISO 8601 subset)
      • new Date(year, month, date?, hours?, minutes?, seconds?, ms?) -- component constructor
      • Month is 0-indexed (0=January), year 0-99 maps to 1900-1999
    • 5.4 Implement Date static methods:
      • Date.now() -- return current time in ms (ECMAScript §21.4.3.1)
      • Date.parse(string) -- parse ISO 8601 date string, return ms or NaN (ECMAScript §21.4.3.2)
      • Date.UTC(year, month, ...) -- like component constructor but in UTC (ECMAScript §21.4.3.4)
    • 5.5 Implement Date prototype getter methods (ECMAScript §21.4.4):
      • Local time getters: getFullYear(), getMonth(), getDate(), getDay(), getHours(), getMinutes(), getSeconds(), getMilliseconds()
      • getTime() -- return internal time value (ms since epoch)
      • getTimezoneOffset() -- return local timezone offset in minutes
      • UTC getters: getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCDay(), getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds()
      • All getters return NaN if internal time value is NaN (Invalid Date)
    • 5.6 Implement Date prototype setter methods:
      • setTime(time), setMilliseconds(ms), setSeconds(sec, ms?), setMinutes(min, sec?, ms?), setHours(hour, min?, sec?, ms?), setDate(date), setMonth(month, date?), setFullYear(year, month?, date?)
      • UTC setters: setUTCFullYear(), setUTCMonth(), setUTCDate(), setUTCHours(), setUTCMinutes(), setUTCSeconds(), setUTCMilliseconds()
      • Each setter recalculates the internal time value and returns it
    • 5.7 Implement Date conversion methods:
      • toString() -- e.g. "Sun Mar 16 2026 12:30:00 GMT-0400 (Eastern Daylight Time)" (simplified format acceptable)
      • toDateString() -- e.g. "Sun Mar 16 2026"
      • toTimeString() -- e.g. "12:30:00 GMT-0400"
      • toISOString() -- e.g. "2026-03-16T16:30:00.000Z" (always UTC, throws RangeError if invalid)
      • toJSON() -- calls toISOString(), returns null if invalid (ECMAScript §21.4.4.37)
      • toUTCString() -- e.g. "Sun, 16 Mar 2026 16:30:00 GMT"
      • valueOf() -- return getTime() (enables numeric comparison with <, >)
      • [Symbol.toPrimitive](hint) -- "default"/"number" returns valueOf, "string" returns toString
    • 5.8 Implement Date internal helpers:
      • ms_to_components(time_value: f64) -> DateComponents -- decompose ms to year/month/day/hour/min/sec/ms in local time
      • ms_to_utc_components(time_value: f64) -> DateComponents -- same but UTC
      • components_to_ms(year, month, day, hour, min, sec, ms) -> f64 -- recompose to ms
      • local_tz_offset_ms() -> f64 -- get system local timezone offset
      • Use std::time::SystemTime for Date.now(). Use manual arithmetic for component decomposition (avoid adding chrono dependency -- it's large).
      • Date math reference: ECMAScript §21.4.1 defines Day(t), TimeWithinDay(t), DaysInYear(y), DayFromYear(y), TimeFromYear(y), YearFromTime(t), InLeapYear(t), MonthFromTime(t), DateFromTime(t), WeekDay(t), LocalTime(t), UTC(t), MakeTime(), MakeDay(), MakeDate(), TimeClip(). Implement these helper functions.
    • 5.9 Wire Date dispatch in calls.rs and add setup_date_builtins() in mod.rs
    • 5.10 Add unit tests in crates/js_vm/src/interpreter/tests/date_tests.rs:
      • All constructor forms (no args, ms, string, components)
      • Invalid date detection (new Date("invalid").getTime() === NaN)
      • All getters for a known date (e.g., new Date(2024, 0, 15, 10, 30, 45, 500))
      • All setters modifying a date and reading back
      • toISOString() output format
      • Date.now() returns a reasonable value
      • Date.parse() for ISO strings
      • Date.UTC() constructor
      • Comparison operators work via valueOf()
      • Edge cases: leap years, month overflow, year 0-99 mapping, negative timestamps
  • Task 6: RegExp enhancements (AC: #2)

    • 6.1 Add function replacer support to String.prototype.replace() in builtins.rs:
      • When second argument is a function, call it with (match, ...captures, index, fullString)
      • Return value of function becomes replacement string
      • Works with both string and regex patterns
      • For regex with /g flag: call function for each match
    • 6.2 Add $<name> named capture group substitution in String.prototype.replace():
      • Check if regress crate supports named capture groups first
      • If supported: extract group name, look up in match captures
      • If not supported: document as known limitation, skip
    • 6.3 Add RegExp Symbol method implementations in regexp_builtins.rs:
      • RegExp.prototype[Symbol.match](string) -- same behavior as current String.prototype.match() delegation (ECMAScript §22.2.6.8)
      • RegExp.prototype[Symbol.replace](string, replaceValue) -- (ECMAScript §22.2.6.10)
      • RegExp.prototype[Symbol.search](string) -- (ECMAScript §22.2.6.11)
      • RegExp.prototype[Symbol.split](string, limit) -- (ECMAScript §22.2.6.12)
      • Wire these as Symbol-keyed properties on RegExp.prototype
    • 6.4 Add unit tests for function replacers and Symbol methods in regexp_tests.rs
  • Task 7: Testing and validation (AC: #8)

    • 7.1 Run vendored Test262 suite and promote passing tests:
      • cargo test -p rust_browser --test js262_harness js262_suite_matches_manifest_expectations -- --nocapture
      • just js262-status promote --id <test-id> for each newly passing test
    • 7.2 Run full Test262 suite and triage:
      • just test262-full
      • just triage-test262-full
    • 7.3 Run all existing JS test suites to verify no regressions:
      • cargo test -p js_vm (all unit tests)
      • cargo test -p rust_browser --test js_tests
      • cargo test -p rust_browser --test js_dom_tests
      • cargo test -p rust_browser --test js_events
      • cargo test -p rust_browser --test js_scheduling
      • cargo test -p rust_browser --test js_async
      • cargo test -p rust_browser --test js_modules
    • 7.4 Update docs/JavaScript_Implementation_Checklist.md:
      • Check off Phase 20 items (Map, Set, WeakSet)
      • Check off Phase 22 items (Date)
      • Update RegExp section with new features
    • 7.5 Update docs/old/js_feature_matrix.md with expanded coverage
    • 7.6 Run just ci -- full validation pass

Dev Notes

Key Architecture Decisions

Map/Set use indexmap crate (already a dependency). IndexMap and IndexSet preserve insertion order, which is required by the spec. Do NOT use HashMap/HashSet -- they don't preserve order. The indexmap crate is already in [workspace.dependencies].

Date stores f64 milliseconds since epoch. This is the internal [[DateValue]] per ECMAScript §21.4.1. Use PrimitiveValue::Date(f64) on the JsObject, following the same pattern as PrimitiveValue::RegExp(RegExpData). NaN represents an Invalid Date.

No chrono dependency for Date. Implement ECMAScript date math helpers directly per §21.4.1. The spec defines all the conversion functions (Day(t), YearFromTime(t), MonthFromTime(t), etc.) using simple arithmetic. std::time::SystemTime::now() provides milliseconds for Date.now(). This avoids adding a large dependency.

MapKey wrapper for SameValueZero equality. Map and Set keys need custom equality: NaN === NaN (unlike ===), +0 === -0 (like ===). Create a MapKey wrapper around JsValue that implements Hash and Eq with these semantics. For object keys, hash/eq by pointer identity (Rc::as_ptr()).

WeakSet follows WeakMap pattern exactly. WeakMap already uses HashMap<usize, JsValue> keyed by Rc::as_ptr(). WeakSet is simply HashSet<usize> with the same pattern. Both lack true weak reference semantics (no GC integration), which is a documented limitation.

Implementation Patterns from Existing Code

WeakMap dispatch pattern (in calls.rs:401-447):

// Check if object is a special type, dispatch method before prototype lookup
if obj.is_weakmap() {
    match method_name.as_str() {
        "get" => { /* ... */ }
        "set" => { /* ... */ }
        // ...
    }
}

Map, Set, WeakSet, and Date should follow this same dispatch pattern.

Builtin setup pattern (in mod.rs):

regexp_builtins::setup_regexp_builtins(self.env);
weakmap_builtins::setup_weakmap_builtins(self.env);
// Add:
map_builtins::setup_map_builtins(self.env);
set_builtins::setup_set_builtins(self.env);
weakset_builtins::setup_weakset_builtins(self.env);
date_builtins::setup_date_builtins(self.env);

PrimitiveValue pattern (in value.rs):

pub enum PrimitiveValue {
    Number(f64),
    String(String),
    Boolean(bool),
    RegExp(RegExpData),
    // Add: Date(f64),
}

Critical Implementation Details

Date math is pure arithmetic, not library calls. ECMAScript §21.4.1 defines:

  • msPerDay = 86_400_000
  • Day(t) = floor(t / msPerDay)
  • TimeWithinDay(t) = t % msPerDay (use t.rem_euclid(msPerDay) for negative timestamps)
  • Leap year calculation, month/day decomposition, etc. -- all spec-defined formulas
  • For local time: LocalTime(t) = t + local_tz_offset_ms. Get offset via libc::localtime_r or by comparing SystemTime epoch math.

Map/Set forEach must handle mutation during iteration. Per spec, entries added during forEach are visited; entries deleted before being visited are skipped. IndexMap's index-based iteration handles this naturally if you iterate by index rather than by iterator.

Constructor new enforcement. Map, Set, WeakSet, Date must throw TypeError when called without new. Check the new_target or use a flag in the NativeFunction setup. Follow the pattern used by existing constructors.

Map.prototype.size is a getter, not a data property. It must be defined via Object.defineProperty with a getter function (or the internal equivalent once property descriptors are available from Story 3.5). If property descriptors aren't landed yet, implement as a regular method call -- the dispatch in calls.rs can handle .size specially.

Dependency on Story 3.5

Property descriptors (Story 3.5 Task 1) are NOT required for this story's core functionality. Map/Set/Date can be implemented using the existing .set()/.get() API. However:

  • .size as a getter property ideally needs property descriptors. Workaround: handle in method dispatch.
  • Object.freeze on Map/Set is a Story 3.5 concern, not this story.
  • Iterator methods depend on Story 3.2 (generators/iterator protocol) which is already done.

This story can proceed independently of Story 3.5.

Previous Story Intelligence

From Story 3.5 (Array/String/Object):

  • Property descriptor changes are high-risk foundational work -- this story should NOT depend on them
  • Iterator protocol from Story 3.2 is available and working
  • indexmap is already a workspace dependency -- confirmed available

From Story 3.4 (ES modules) review patterns:

  • Don't create stub/dead code -- wire everything into actual execution paths
  • Integration tests must test the right code paths
  • Run just ci after each task

Risk Assessment

HIGH: Date math complexity. ECMAScript date arithmetic with local time conversions, leap years, month boundaries, and pre-epoch negative timestamps is intricate. Many edge cases (Feb 29, month overflow, year 0-99 mapping). Must implement per-spec formulas carefully.

MEDIUM: MapKey hash/eq for arbitrary JsValue types. Hashing JsValues (especially objects by pointer) requires careful Hash/Eq implementation. NaN handling must be special-cased. Consider that JsValue may not derive Hash natively -- MapKey wrapper handles this.

MEDIUM: Date.parse() string parsing. ISO 8601 parsing has many edge cases. Implement a focused subset: YYYY-MM-DDTHH:mm:ss.sssZ and common variants. Don't try to handle all date string formats browsers support (those are implementation-defined).

LOW: Map/Set core operations. Straightforward CRUD with IndexMap/IndexSet. Well-defined spec behavior.

LOW: WeakSet. Near-identical to WeakMap with simpler API.

Phased Implementation Strategy

Phase A -- Map + Set (Tasks 1-2): Implement together -- they share MapKey infrastructure and follow identical patterns. Can start immediately.

Phase B -- WeakSet + WeakMap fixes (Tasks 3-4): Quick additions. WeakSet mirrors WeakMap. Fix function-as-key for both.

Phase C -- Date (Task 5): Largest task. Independent of Map/Set. Implement date math helpers first, then constructors, then methods.

Phase D -- RegExp enhancements (Task 6): Independent of other tasks. Function replacers are the highest-value addition.

Phase E -- Testing + Validation (Task 7): After all implementations complete.

Project Structure Notes

  • All implementation in crates/js_vm/src/interpreter/ (Layer 1) -- no layer violations
  • New files: date_builtins.rs, map_builtins.rs, set_builtins.rs, weakset_builtins.rs (4 new)
  • New test files: date_tests.rs, map_tests.rs, set_tests.rs, weakset_tests.rs (4 new)
  • Value type changes in crates/js_vm/src/value.rs (Layer 1)
  • No unsafe code needed
  • No new external dependencies (indexmap already available)

References

Dev Agent Record

Agent Model Used

{{agent_model_name_version}}

Debug Log References

Completion Notes List

File List