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:
parent
c90c4cb610
commit
1f96351acb
8 changed files with 224 additions and 2 deletions
70
test/chez/_dotform.janet
Normal file
70
test/chez/_dotform.janet
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# jolt-kuic — the `.` special form + `.-field` field-access desugar on Chez. The
|
||||
# analyzer lowers (. target member arg*) and (.-field target) to a :host-call;
|
||||
# the Chez emit routes a non-shimmed :host-call through record-method-dispatch,
|
||||
# which dot-forms.ss extends with field access + map/vector member dispatch.
|
||||
# Expectations are the build/jolt (seed) oracle, captured per case.
|
||||
#
|
||||
# janet test/chez/_dotform.janet
|
||||
(def jolt-bin (or (os/getenv "JOLT_BIN") "bin/jolt-chez"))
|
||||
|
||||
(def exprs
|
||||
[# strings: method calls via the String surface
|
||||
"(. \"HI\" toLowerCase)"
|
||||
"(. \"abc\" length)"
|
||||
"(. \"abc\" toUpperCase)"
|
||||
# vectors / maps: collection interop (count/nth/get/containsKey)
|
||||
"(. [1 2 3] count)"
|
||||
"(. [10 20 30] nth 1)"
|
||||
"(. {:a 1 :b 2} count)"
|
||||
"(. {:a 1 :b 2} get :b)"
|
||||
"(. {:a 1} containsKey :a)"
|
||||
"(. {:count 99} count)"
|
||||
# map member: stored fn called with self (+ args), else field value
|
||||
"(. {:value 41 :describe (fn [self] (str \"v=\" (:value self)))} describe)"
|
||||
"(. {:greet (fn [self n] (str \"Hello \" n))} greet \"Alice\")"
|
||||
"(. {:value 41} value)"
|
||||
# field access via .-field head
|
||||
"(.-value {:value 41})"
|
||||
"(.-x {:x 7 :y 9})"
|
||||
# field access via (. obj -field)
|
||||
"(. {:value 41} -value)"
|
||||
# records: .-field reads a field, .method dispatches the protocol method
|
||||
"(do (defrecord Rf [x]) (.-x (->Rf 7)))"
|
||||
"(do (defrecord Rg [a b]) (.-b (->Rg 1 2)))"
|
||||
"(do (defprotocol Greet (hi [_])) (defrecord Rh [nm] Greet (hi [_] (str \"hi \" nm))) (. (->Rh \"x\") hi))"
|
||||
# universal object-methods on a non-record map win over a field lookup
|
||||
"(try (throw (ex-info \"bad\" {})) (catch Throwable e (.getMessage e)))"
|
||||
"(try (throw (ex-info \"bad\" {:k 1})) (catch Throwable e (.getMessage e)))"
|
||||
"(try (throw \"boom\") (catch Throwable e (.getMessage e)))"
|
||||
"(try (throw (Exception. \"boom\")) (catch Throwable e (.getMessage e)))"
|
||||
"(try (throw (IllegalArgumentException. \"bad\")) (catch Exception e (.getMessage e)))"
|
||||
"(.equals \"a\" \"a\")"
|
||||
"(.equals \"a\" \"b\")"
|
||||
"(. {:value 41 :describe (fn [self] (str \"v=\" (:value self)))} describe)"])
|
||||
|
||||
(defn run-capture [bin expr]
|
||||
(def proc (os/spawn [bin "-e" expr] :p {:out :pipe :err :pipe}))
|
||||
(def out (ev/read (proc :out) 0x100000))
|
||||
(def err (ev/read (proc :err) 0x100000))
|
||||
(def code (os/proc-wait proc))
|
||||
(def lines (filter (fn [l] (not (empty? l)))
|
||||
(string/split "\n" (string/trim (if out (string out) "")))))
|
||||
[code (if (empty? lines) "" (last lines)) (string/trim (if err (string err) ""))])
|
||||
|
||||
(var pass 0)
|
||||
(def fails @[])
|
||||
(each expr exprs
|
||||
(def [ocode oracle _] (run-capture "build/jolt" expr))
|
||||
(def [code got err] (run-capture jolt-bin expr))
|
||||
(cond
|
||||
(not= ocode 0) (array/push fails [expr (string "ORACLE FAILED exit " ocode)])
|
||||
(not= code 0) (array/push fails [expr (string "exit " code "; err: " err)])
|
||||
(= got oracle) (++ pass)
|
||||
(array/push fails [expr (string "want `" oracle "`, got `" got "`")])))
|
||||
|
||||
(printf "\n_dotform parity [%s]: %d/%d passed" jolt-bin pass (length exprs))
|
||||
(when (> (length fails) 0)
|
||||
(printf "%d FAIL(s):" (length fails))
|
||||
(each [e m] fails (printf " FAIL %s\n %s" e m)))
|
||||
(flush)
|
||||
(os/exit (if (empty? fails) 0 1))
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -233,8 +233,15 @@
|
|||
# exception constructors. Also emit now evaluates collection-literal elements
|
||||
# left-to-right (emit-ordered), which un-allowlisted the 6 eval-order cases.
|
||||
# java.time formatting / edn-read-over-readers / slurp-over-readers deferred) 2134.
|
||||
# jolt-kuic (the `.` special form + `.-field` desugar — the analyzer lowers
|
||||
# (. target member arg*) and (.-field target) to :host-call; the Chez RT
|
||||
# dispatches them through record-method-dispatch, extended by dot-forms.ss with
|
||||
# collection interop (count/nth/get/valAt/containsKey), field access, non-record
|
||||
# map member dispatch, and the seed's universal object-methods getMessage/getCause/
|
||||
# toString/hashCode/equals. Also added getMessage/getLocalizedMessage/equals to the
|
||||
# string method surface so a thrown string / Exception. ctor answers .getMessage) 2150.
|
||||
# Strided runs scale down.
|
||||
(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_PRELUDE_FLOOR") "2134")))
|
||||
(def base-floor (scan-number (or (os/getenv "JOLT_CHEZ_PRELUDE_FLOOR") "2150")))
|
||||
(def floor (if (os/getenv "JOLT_CORPUS_LIMIT") 0 base-floor))
|
||||
(when (or (> (length diverged) 0) (< pass floor))
|
||||
(printf "REGRESSION: pass %d < floor %d or %d new divergence(s)" pass floor (length diverged)))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue