diff --git a/jolt-core/jolt/analyzer.clj b/jolt-core/jolt/analyzer.clj index d820318..66ac5e7 100644 --- a/jolt-core/jolt/analyzer.clj +++ b/jolt-core/jolt/analyzer.clj @@ -14,7 +14,7 @@ Definitions are ordered so only `analyze` (mutually recursive) is forward declared — the bootstrap compiles forward refs through var cells, but keeping them to one keeps the compiled namespace simple." - (:require [jolt.ir :refer [const local var-ref host-ref if-node do-node invoke + (: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]] [jolt.host :refer [form-sym? form-sym-name form-sym-ns form-list? @@ -28,7 +28,7 @@ (def ^:private handled #{"quote" "if" "do" "def" "fn*" "let*" "loop*" "recur" "throw" "try" - "syntax-quote"}) + "syntax-quote" "var"}) (defn- uncompilable [why] (throw (str "jolt/uncompilable: " why))) @@ -163,6 +163,11 @@ ;; Lower the backtick to construction code (zero runtime cost), then analyze ;; it — the macroexpand/compile-time step, per read -> macroexpand -> compile. "syntax-quote" (analyze ctx (form-syntax-quote-lower ctx (second items)) env) + "var" (let [sym (second items) + r (resolve-global ctx sym)] + (if (= :var (:kind r)) + (the-var (:ns r) (:name r)) + (uncompilable (str "var of non-var " (form-sym-name sym))))) (uncompilable (str "special form " op)))) (defn- analyze-symbol [ctx form env] diff --git a/jolt-core/jolt/ir.clj b/jolt-core/jolt/ir.clj index af34cdb..b869f24 100644 --- a/jolt-core/jolt/ir.clj +++ b/jolt-core/jolt/ir.clj @@ -16,6 +16,10 @@ ;; A global var reference, by name. The back end resolves it to a host var. (defn var-ref [ns name] {:op :var :ns ns :name name}) +;; The var object itself — (var x) / #'x. Unlike var-ref (which derefs), the back +;; end emits the embedded var cell so `binding`'s thread-binding frame can key on it. +(defn the-var [ns name] {:op :the-var :ns ns :name name}) + ;; A runtime primitive (cons, +, get, apply, …) the back end maps to the host RT. (defn rt [name] {:op :rt :name name}) diff --git a/src/jolt/backend.janet b/src/jolt/backend.janet index 9352517..767d8af 100644 --- a/src/jolt/backend.janet +++ b/src/jolt/backend.janet @@ -250,6 +250,9 @@ # reference (a bare table in arg position would be re-evaluated as # a constructor — deep-copying it, and any atom in :root, each call). (tuple var-get (tuple 'quote cell)))) + # (var x): the var object itself (not its value) — the embedded cell, by + # reference. binding keys its thread-binding frame on this exact cell. + :the-var (tuple 'quote (cell-for ctx (node :ns) (node :name))) :if ['if (emit ctx (node :test)) (emit ctx (node :then)) (emit ctx (node :else))] :do (emit-seq ctx node) :loop (emit-loop ctx node) diff --git a/src/jolt/host_iface.janet b/src/jolt/host_iface.janet index 5e86d1a..0edf6db 100644 --- a/src/jolt/host_iface.janet +++ b/src/jolt/host_iface.janet @@ -71,7 +71,7 @@ (def- special-names (let [t @{}] (each n ["quote" "syntax-quote" "unquote" "unquote-splicing" "do" "if" "def" - "defmacro" "fn*" "let*" "loop*" "recur" "throw" "try" "set!" "var" + "defmacro" "fn*" "let*" "loop*" "recur" "throw" "try" "set!" "locking" "eval" "instance?" "defmulti" "defmethod" "deftype" "new" "." "var-get" "var-set" "var?" "alter-var-root" "find-var" "intern" "alter-meta!" "reset-meta!" "satisfies?" @@ -89,7 +89,7 @@ "gen-class" # letfn stays: its let* expansion needs letrec semantics (mutual # recursion between the fns), which compiled sequential let* lacks. - "monitor-enter" "monitor-exit" "binding" "letfn"] + "monitor-enter" "monitor-exit" "letfn"] (put t n true)) t)) diff --git a/src/jolt/loader.janet b/src/jolt/loader.janet index f7608ea..36b5edc 100644 --- a/src/jolt/loader.janet +++ b/src/jolt/loader.janet @@ -17,7 +17,7 @@ (= head-name "deftype") (= head-name "defmulti") (= head-name "defmethod") (= head-name "require") (= head-name "in-ns") (= head-name "set!") - (= head-name "var") (= head-name ".") (= head-name "new") + (= head-name ".") (= head-name "new") (= head-name "eval"))) (defn- form-head-name [form]