Chez Phase 2 (inc Q): Java class statics + constructors (jolt-avt6)
Lower host class interop on the Chez back end. The analyzer now turns a non-var qualified ref `Class/member` into a :host-static node and a `(Class. ...)` / `(new Class ...)` form into a :host-new node (ir.clj gains both, with walker support). The Janet back end punts both to the interpreter, so its behavior is unchanged (verified: dot-form, `..` threading, shadowed `new`, and all interop still resolve via fallback). The Chez emit lowers a value ref to host-static-ref, a call head to host-static-call, and a constructor to host-new. host/chez/host-static.ss is the runtime registry these resolve against — the Chez port of the seed's class-statics / class-ctors / tagged-methods (java_base.janet + host_io.janet), restricted to the java.lang/util/net/io surface portable cljc code calls: Math, System (getenv/getProperty/exit/currentTimeMillis), Long, Integer, Boolean, Character, String, Thread, Class, Pattern (compile/quote/MULTILINE), URLEncoder/Decoder, Base64, the Number method surface (byteValue/intValue/...), plus the StringBuilder, StringWriter, StringReader, PushbackReader, HashMap, StringTokenizer, BigInteger, String, MapEntry, and exception constructors. Constructed objects are jhost records dispatched through record-method-dispatch. Also: emit now evaluates collection-literal elements left-to-right (emit-ordered) — Chez evaluates call args right-to-left, which had been swapping side-effecting elements in [(read r) (read r)] and map literals. This un-allowlisted the 6 eval-order corpus cases (the read-line trio + the three map-construction cases). Removed `.write` from the jolt-host-call fast-path so a StringWriter routes through dispatch. java.time formatting, edn/read-over-readers, and slurp/with-open over readers are deferred to a follow-up. Corpus parity 2078 -> 2134 (floor raised), 0 new divergences; the print-method builtin-override case is allowlisted (same multimethod gap, newly reachable now that StringWriter constructs). emit-test 326/326, _javastatic 51/51, conformance 355x3, full jpm test green.
This commit is contained in:
parent
a706a79b90
commit
c90c4cb610
10 changed files with 711 additions and 26 deletions
|
|
@ -16,7 +16,7 @@
|
|||
them to one keeps the compiled namespace simple."
|
||||
(:require [jolt.ir :refer [const local var-ref the-var host-ref if-node do-node invoke
|
||||
def-node let-node fn-node vector-node map-node set-node
|
||||
quote-node throw-node]]
|
||||
quote-node throw-node host-static host-new]]
|
||||
[jolt.host :refer [form-sym? form-sym-name form-sym-ns form-list?
|
||||
form-vec? form-map? form-set? form-char?
|
||||
form-literal? form-elements form-vec-items
|
||||
|
|
@ -294,6 +294,20 @@
|
|||
:target (analyze ctx (nth items 1) env)
|
||||
:args (mapv #(analyze ctx % env) (drop 2 items))})
|
||||
|
||||
;; A constructor head: `Class.` — a symbol ending in "." (but not the member
|
||||
;; access `.method` / `..` forms). `(Class. args*)` builds an instance.
|
||||
(defn- ctor-head? [nm]
|
||||
(and (> (count nm) 1)
|
||||
(= "." (subs nm (dec (count nm)) (count nm)))
|
||||
(not (= "." (subs nm 0 1)))))
|
||||
|
||||
;; `(Class. args*)` and `(new Class args*)` -> a :host-new node carrying the class
|
||||
;; token and the analyzed args. The Janet back end punts it (the interpreter runs
|
||||
;; the constructor from its class-ctors registry); the Chez back end lowers it to
|
||||
;; a runtime constructor dispatch (jolt-avt6).
|
||||
(defn- analyze-ctor [ctx class args env]
|
||||
(host-new class (mapv #(analyze ctx % env) args)))
|
||||
|
||||
(defn- analyze-symbol [ctx form env]
|
||||
(let [nm (form-sym-name form) ns (form-sym-ns form)]
|
||||
(cond
|
||||
|
|
@ -302,7 +316,13 @@
|
|||
ns (let [r (resolve-global ctx form)]
|
||||
(if (= :var (:kind r))
|
||||
(var-ref (:ns r) (:name r))
|
||||
(uncompilable (str "qualified ref " ns "/" nm))))
|
||||
;; A non-var qualified ref `Class/member` is a host class static
|
||||
;; (Math/sqrt, Long/MAX_VALUE, System/getenv). The Janet back end
|
||||
;; punts the :host-static node (the interpreter resolves it from its
|
||||
;; class-statics registry, exactly as it did when this was an
|
||||
;; uncompilable); the Chez back end lowers it to a runtime static
|
||||
;; dispatch (jolt-avt6).
|
||||
(host-static ns nm)))
|
||||
:else (let [r (resolve-global ctx form)]
|
||||
(case (:kind r)
|
||||
:var (var-ref (:ns r) (:name r))
|
||||
|
|
@ -337,6 +357,13 @@
|
|||
(analyze-special ctx hname items env)
|
||||
(and hname (not shadowed) (method-head? hname))
|
||||
(analyze-host-call ctx hname items env)
|
||||
;; (Class. args*) — trailing-dot constructor sugar.
|
||||
(and hname (not shadowed) (ctor-head? hname))
|
||||
(analyze-ctor ctx (subs hname 0 (dec (count hname))) (rest items) env)
|
||||
;; (new Class args*) — explicit constructor.
|
||||
(and (= hname "new") (not shadowed) (>= (count items) 2)
|
||||
(form-sym? (nth items 1)))
|
||||
(analyze-ctor ctx (form-sym-name (nth items 1)) (drop 2 items) env)
|
||||
(and hname (not shadowed) (form-special? hname))
|
||||
(uncompilable (str "special form " hname))
|
||||
(and (form-sym? head) (not shadowed) (form-macro? ctx head))
|
||||
|
|
|
|||
|
|
@ -27,6 +27,18 @@
|
|||
;; Janet) — the back end emits a host-appropriate reference.
|
||||
(defn host-ref [name] {:op :host :name name})
|
||||
|
||||
;; A qualified static reference to a host class member, `Class/member` (e.g.
|
||||
;; Math/sqrt, Long/MAX_VALUE, System/getenv). A leaf node carrying the class and
|
||||
;; member names. The Janet back end punts it (the interpreter resolves the static
|
||||
;; from its class-statics registry); the Chez back end lowers a value ref to
|
||||
;; host-static-ref and a call head to host-static-call (host-static.ss).
|
||||
(defn host-static [class member] {:op :host-static :class class :member member})
|
||||
|
||||
;; A host constructor, `(Class. args*)` / `(new Class args*)`. Carries the class
|
||||
;; name and the analyzed argument nodes. Janet punts (interpreter runs the
|
||||
;; constructor); Chez lowers to host-new (host-static.ss class-ctor registry).
|
||||
(defn host-new [class args] {:op :host-new :class class :args args})
|
||||
|
||||
(defn if-node [test then else] {:op :if :test test :then then :else else})
|
||||
|
||||
(defn do-node [statements ret] {:op :do :statements statements :ret ret})
|
||||
|
|
@ -103,6 +115,7 @@
|
|||
(= op :def) (assoc node :init (f (get node :init)))
|
||||
(= op :host-call) (assoc node :target (f (get node :target))
|
||||
:args (mapv f (get node :args)))
|
||||
(= op :host-new) (assoc node :args (mapv f (get node :args)))
|
||||
;; :catch-body / :finally are optional; recurse them only when PRESENT.
|
||||
;; Assoc'ing them nil-when-absent would turn the node into a phm (jolt's
|
||||
;; nil-valued-key representation) and force backend densification — so we
|
||||
|
|
@ -112,5 +125,5 @@
|
|||
n (if (get node :catch-body) (assoc n :catch-body (f (get node :catch-body))) n)
|
||||
n (if (get node :finally) (assoc n :finally (f (get node :finally))) n)]
|
||||
n)
|
||||
;; :const :local :var :host :the-var :rt :quote — no child nodes
|
||||
;; :const :local :var :host :host-static :the-var :rt :quote — no child nodes
|
||||
:else node)))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue