reflective: extract class-chain.sx — Smalltalk + CLOS method dispatch share parent-walk
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 35s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 35s
lib/guest/reflective/class-chain.sx — class inheritance walker with
adapter cfg for single-parent (Smalltalk) and multi-parent (CLOS)
hierarchies. Three primitives:
- refl-class-chain-find-with CFG CN PROBE
DFS through parents, returns first non-nil probe result.
Smalltalk method lookup uses this.
- refl-class-chain-depth-with CFG CN ANCESTOR
Min hop distance via any parent path, or nil if unreachable.
CLOS method specificity uses this.
- refl-class-chain-ancestors-with CFG CN
Flat DFS-ordered list of all reachable ancestor names.
Adapter cfg has two keys: :parents-of (CN → list of parent names,
possibly empty) and :class? (predicate; short-circuits walk on
non-existent class names mid-chain).
Migrations:
- lib/smalltalk/runtime.sx: st-method-lookup-walk now a 9-line
thin probe through the kit (was 20 lines of inline recursion);
st-class-cfg wraps the single-parent :superclass field into a
1-element list for the cfg.
- lib/common-lisp/clos.sx: clos-specificity is a one-line wrapper
around refl-class-chain-depth-with (was 28 lines); clos-class-cfg
reads the multi-parent :parents field.
Both consumers green:
- Smalltalk: 847/847 (unchanged)
- CL: 222/240 (unchanged baseline; 18 pre-existing failures, all
in stdlib functions like cl-set-memberp, unrelated to CLOS).
This is the second extracted reflective kit (env.sx was first).
The adapter-cfg pattern continues to bridge structurally divergent
consumers (Smalltalk single-inheritance vs CLOS multiple-inheritance
with method-precedence distance) via a uniform :parents-of callback.
This commit is contained in:
@@ -221,30 +221,37 @@
|
||||
(st-ic-bump-generation!)
|
||||
true))))))))))
|
||||
|
||||
;; Smalltalk-side adapter for lib/guest/reflective/class-chain.sx.
|
||||
;; Smalltalk has single inheritance: :parents-of returns a 1-element
|
||||
;; list (or empty) wrapping the single :superclass field.
|
||||
(define st-class-cfg
|
||||
{:parents-of (fn (cn)
|
||||
(let ((p (st-class-superclass cn)))
|
||||
(cond ((nil? p) (list))
|
||||
(:else (list p)))))
|
||||
:class? (fn (n) (st-class-exists? n))})
|
||||
|
||||
;; Walk-only lookup. Returns the method record (with :defining-class) or nil.
|
||||
;; class-side? = true searches :class-methods, false searches :methods.
|
||||
;; Parent-chain walk delegates to refl-class-chain-find-with; the probe
|
||||
;; tests this class's method dict and returns the entry (or nil).
|
||||
(define
|
||||
st-method-lookup-walk
|
||||
(fn
|
||||
(cls-name selector class-side?)
|
||||
(let
|
||||
((found nil))
|
||||
(begin
|
||||
(define
|
||||
ml-loop
|
||||
(fn
|
||||
(cur)
|
||||
(when
|
||||
(and (= found nil) (not (= cur nil)) (st-class-exists? cur))
|
||||
(let
|
||||
((c (st-class-get cur)))
|
||||
(let
|
||||
((dict (if class-side? (get c :class-methods) (get c :methods))))
|
||||
(cond
|
||||
((has-key? dict selector) (set! found (get dict selector)))
|
||||
(else (ml-loop (get c :superclass)))))))))
|
||||
(ml-loop cls-name)
|
||||
found))))
|
||||
(fn (cls-name selector class-side?)
|
||||
(refl-class-chain-find-with
|
||||
st-class-cfg
|
||||
cls-name
|
||||
(fn (cn)
|
||||
(let ((c (st-class-get cn)))
|
||||
(cond
|
||||
((nil? c) nil)
|
||||
(:else
|
||||
(let ((dict (if class-side?
|
||||
(get c :class-methods)
|
||||
(get c :methods))))
|
||||
(cond
|
||||
((has-key? dict selector) (get dict selector))
|
||||
(:else nil))))))))))
|
||||
|
||||
;; Cached lookup. Misses are stored as :not-found so doesNotUnderstand paths
|
||||
;; don't re-walk on every send.
|
||||
|
||||
Reference in New Issue
Block a user