Chez Phase 2 (inc R): . / .-field dot-form desugar (jolt-kuic)

The analyzer lowers the `.` special form (. target member arg*) and the
.-field field-access head to a :host-call instead of leaving them
uncompilable. Janet behaviour is unchanged — its back end punts :host-call
to the interpreter, which re-runs the original `.` form via eval-dot.

The Chez back end routes a non-shimmed :host-call through
record-method-dispatch, extended by a new host/chez/dot-forms.ss with the
arms dispatch-member covers but the record/string base did not, mirroring
src/jolt/interop/collections.janet precedence:

  - collection interop first (count/seq/nth/get/valAt/containsKey on a
    vector/map/set), so (. {:count 9} count) is the entry count like the seed
  - field access for a "-name" member (records and maps)
  - the seed's universal object-methods (getMessage/getCause/toString/
    hashCode/equals) on a non-record map, winning over a field lookup
  - non-record map member: a stored fn is a method called with self, else
    the field value

Raw seqs are excluded from coll interop — the seed's behaviour there is
representation-dependent (plain (seq v) vs a lazy-seq) and a normalized cseq
can't mirror it. Also added getMessage/getLocalizedMessage/equals to the
string method surface so a thrown string / Exception. ctor (which keeps the
message string) answers .getMessage.

Parity 2134 -> 2150, 0 new divergences. New test/chez/_dotform.janet 26/26;
emit-test 331/331.
This commit is contained in:
Yogthos 2026-06-19 00:32:30 -04:00
parent c90c4cb610
commit 1f96351acb
8 changed files with 224 additions and 2 deletions

View file

@ -336,6 +336,21 @@
(let [scm (protect (emit/emit (backend/analyze-form ctx (in (r/parse-next src) 0))))]
(ok label (and (scm 0) (string/find needle (scm 1))) (string/format "%p" scm))))
# 3l'') the `.` special form + `.-field` desugar (jolt-kuic). (. target member
# arg*) and (.-field target) lower to a :host-call routed through
# record-method-dispatch (a non-shimmed method); the dash on a field member
# survives in the method name so dot-forms.ss reads it as a field access. The
# Janet back end punts :host-call (interpreter re-runs the original `.` form);
# runtime behaviour is covered by test/chez/_dotform.janet.
(each [label src needle]
[["emit (. obj method) -> record-method-dispatch" "(fn [o] (. o frob))" "record-method-dispatch"]
["emit (. obj method) keeps method name" "(fn [o] (. o frob))" "\"frob\""]
["emit (. obj method arg) passes args" "(fn [o a] (. o frob a))" "record-method-dispatch"]
["emit (.-field obj) keeps dash" "(fn [o] (.-value o))" "\"-value\""]
["emit (. obj -field) keeps dash" "(fn [o] (. o -value))" "\"-value\""]]
(let [scm (protect (emit/emit (backend/analyze-form ctx (in (r/parse-next src) 0))))]
(ok label (and (scm 0) (string/find needle (scm 1))) (string/format "%p" scm))))
# 3m) regex (jolt-i0s3): the #"…" literal lowers to a jolt-regex value over the
# vendored irregex; re-pattern/re-matches/re-find/re-seq/regex? are def-var!'d
# into clojure.core (not subset native-ops — irregex's Unicode/property