js-on-sx: 10 new Object.* globals (getPrototypeOf, create, is, hasOwn, defineProperty, ...)

Extends the Object global dict with:
- getPrototypeOf / setPrototypeOf — read/write __proto__ chain
- create(proto, props?) — builds new obj with proto and optional descriptors
- defineProperty / defineProperties — descriptor.value only (no getters/setters)
- getOwnPropertyNames / getOwnPropertyDescriptor(s) — simple shapes
- isExtensible / isFrozen / isSealed (permissive stubs)
- seal / preventExtensions (no-ops)
- is — SameValue (NaN is NaN, -0 vs +0 distinguished via inspect string)
- fromEntries — inverse of entries
- hasOwn — explicit owner check for string keys

9 new unit tests, 506/508 total.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 07:47:34 +00:00
parent db7a3d10dd
commit d294443627
2 changed files with 173 additions and 1 deletions

View File

@@ -2307,7 +2307,148 @@
(define js-object-freeze (fn (o) o))
(define Object {:entries js-object-entries :values js-object-values :freeze js-object-freeze :assign js-object-assign :keys js-object-keys})
(define
js-object-get-prototype-of
(fn
(o)
(cond
((= o nil) (error "TypeError: Cannot convert null to object"))
((js-undefined? o)
(error "TypeError: Cannot convert undefined to object"))
((dict? o)
(if (contains? (keys o) "__proto__") (get o "__proto__") nil))
(else nil))))
(define
js-object-set-prototype-of
(fn
(o proto)
(begin (when (dict? o) (dict-set! o "__proto__" proto)) o)))
(define
js-object-create
(fn
(&rest args)
(let
((proto (if (empty? args) nil (nth args 0))))
(let
((obj (dict)))
(begin
(when (not (= proto nil)) (dict-set! obj "__proto__" proto))
(when
(and (>= (len args) 2) (dict? (nth args 1)))
(for-each
(fn
(k)
(dict-set! obj k (get (get (nth args 1) k) "value")))
(keys (nth args 1))))
obj)))))
(define
js-object-define-property
(fn
(o key desc)
(begin
(when
(and (dict? o) (dict? desc) (contains? (keys desc) "value"))
(dict-set! o (js-to-string key) (get desc "value")))
o)))
(define
js-object-define-properties
(fn
(o descs)
(begin
(when
(and (dict? o) (dict? descs))
(for-each
(fn (k) (js-object-define-property o k (get descs k)))
(keys descs)))
o)))
(define
js-object-get-own-property-names
(fn
(o)
(cond
((list? o) (let ((r (list))) (begin (js-list-keys-loop o 0 r) r)))
((dict? o) (js-object-keys o))
(else (list)))))
(define
js-object-get-own-property-descriptor
(fn
(o key)
(if
(and (dict? o) (contains? (keys o) (js-to-string key)))
{:writable true :value (get o (js-to-string key)) :enumerable true :configurable true}
:js-undefined)))
(define
js-object-get-own-property-descriptors
(fn
(o)
(let
((out (dict)))
(begin
(when
(dict? o)
(for-each
(fn
(k)
(dict-set! out k (js-object-get-own-property-descriptor o k)))
(keys o)))
out))))
(define js-object-is-extensible (fn (o) (not (js-undefined? o))))
(define js-object-is-frozen (fn (o) false))
(define js-object-is-sealed (fn (o) false))
(define js-object-prevent-extensions (fn (o) o))
(define js-object-seal (fn (o) o))
(define
js-object-is
(fn
(a b)
(cond
((and (js-number-is-nan a) (js-number-is-nan b)) true)
((and (= a 0) (= b 0))
(let ((ia (inspect a)) (ib (inspect b))) (= ia ib)))
(else (js-strict-eq a b)))))
(define
js-object-from-entries
(fn
(iter)
(let
((out (dict)) (lst (js-iterable-to-list iter)))
(begin
(for-each
(fn
(pair)
(when
(and (list? pair) (>= (len pair) 2))
(dict-set! out (js-to-string (nth pair 0)) (nth pair 1))))
lst)
out))))
(define
js-object-has-own
(fn
(o key)
(cond
((dict? o) (contains? (keys o) (js-to-string key)))
((list? o)
(let
((idx (js-to-number key)))
(and (>= idx 0) (< idx (len o)) (integer? idx))))
(else false))))
(define Object {:entries js-object-entries :defineProperties js-object-define-properties :preventExtensions js-object-prevent-extensions :prototype {} :values js-object-values :hasOwn js-object-has-own :freeze js-object-freeze :assign js-object-assign :isFrozen js-object-is-frozen :getOwnPropertyDescriptor js-object-get-own-property-descriptor :fromEntries js-object-from-entries :defineProperty js-object-define-property :setPrototypeOf js-object-set-prototype-of :getOwnPropertyNames js-object-get-own-property-names :getOwnPropertyDescriptors js-object-get-own-property-descriptors :create js-object-create :isExtensible js-object-is-extensible :is js-object-is :keys js-object-keys :getPrototypeOf js-object-get-prototype-of :isSealed js-object-is-sealed :seal js-object-seal})
(define
js-delete-prop

View File

@@ -1213,6 +1213,26 @@ cat > "$TMPFILE" << 'EPOCHS'
(epoch 3709)
(eval "(js-eval \"var a=[1,2,3]; a.keys().join(',')\")")
;; ── Phase 11.objglobal: Object.getPrototypeOf, .create, .is, .hasOwn etc. ──
(epoch 3900)
(eval "(js-eval \"var o = Object.create(null); o.x=5; o.x\")")
(epoch 3901)
(eval "(js-eval \"Object.is(NaN, NaN)\")")
(epoch 3902)
(eval "(js-eval \"Object.is(0, 0)\")")
(epoch 3903)
(eval "(js-eval \"Object.hasOwn({a:1}, 'a')\")")
(epoch 3904)
(eval "(js-eval \"Object.hasOwn({a:1}, 'b')\")")
(epoch 3905)
(eval "(js-eval \"Object.fromEntries([['a',1],['b',2]]).a\")")
(epoch 3906)
(eval "(js-eval \"var o = {a:1}; Object.defineProperty(o,'b',{value:42}); o.b\")")
(epoch 3907)
(eval "(js-eval \"var o = {a:1}; Object.getOwnPropertyNames(o).length\")")
(epoch 3908)
(eval "(js-eval \"Object.isExtensible({})\")")
;; ── Phase 11.globals: NaN / Infinity / strict-eq ─────────────
(epoch 3750)
(eval "(js-eval \"typeof NaN\")")
@@ -1927,6 +1947,17 @@ check 3707 "arr.toReversed" '"2,1,3"'
check 3708 "arr.toSorted" '"1,1,3,4,5"'
check 3709 "arr.keys" '"0,1,2"'
# ── Phase 11.objglobal: Object.getPrototypeOf, .create, .is, .hasOwn ──
check 3900 "Object.create(null)" '5'
check 3901 "Object.is(NaN,NaN)" 'true'
check 3902 "Object.is(0,0)" 'true'
check 3903 "Object.hasOwn a" 'true'
check 3904 "Object.hasOwn missing" 'false'
check 3905 "Object.fromEntries" '1'
check 3906 "Object.defineProperty" '42'
check 3907 "Object.getOwnPropertyNames" '1'
check 3908 "Object.isExtensible" 'true'
# ── Phase 11.globals: NaN / Infinity / strict-eq ─────────────
check 3750 "typeof NaN" '"number"'
check 3751 "isNaN(NaN)" 'true'