feat: run the real clojure.tools.logging (defmacro/syntax-quote/ns + host shims)
Pivot from a jolt reimplementation to running the upstream library verbatim.
Vendors the real clojure/tools/logging.clj; jolt provides the backend and the
host primitives it needs. Language features (broadly useful for real Clojure
libs), all covered in 3-mode conformance + spec suites:
- defmacro: multi-arity dispatch (jolt-q8l) and a docstring + attr-map + params
head (jolt-qnr) — the 4-arity log macro and every level macro need these.
- syntax-quote resolves an alias-qualified symbol to its target ns (jolt-9av),
so a macro template (impl/get-logger) resolves at the use site.
- the ns macro unwraps ^{:map} metadata on the ns name (jolt-8w2 workaround,
matching def/defn/defmacro).
- a namespace object self-evaluates, so ~*ns* can be spliced into a template.
Host shims (ported from / modeled on clojure where applicable):
- clojure.string/trim-newline (ported, CharSequence interop -> count/subs)
- agent/send-off/send (minimal synchronous stubs; jolt has no thread pool/STM)
- clojure.lang.LockingTransaction/isRunning -> false
- a minimal clojure.pprint (pprint/with-pprint-dispatch/code-dispatch, for spy)
- clojure.tools.logging.impl: a jolt stderr LoggerFactory backend (the library's
designed pluggable extension point)
docs/libraries.md lists tools.logging; grammar.ebnf metadata note clarified.
Conformance 355/355 x3 modes; full jpm test gate green.
This commit is contained in:
parent
72e36f46de
commit
cf1fdfdb24
14 changed files with 556 additions and 95 deletions
|
|
@ -495,6 +495,25 @@
|
|||
# ns (jolt-9pu — it used to see an empty table).
|
||||
["cross-ns methods visible" "[:sql]"
|
||||
"(do (ns cf.mm) (defmulti ext identity) (defmethod ext :default [_] :d) (defn allk [] (vec (for [[k v] (methods ext) :when (not= k :default)] k))) (ns cf.mmi) (defmethod cf.mm/ext :sql [_] :s) (in-ns (quote user)) (cf.mm/allk))"]
|
||||
|
||||
### ---- defmacro surface + syntax-quote/ns (enabling real clojure libs) ----
|
||||
# multi-arity defmacro (clojure.tools.logging/log has 4 arities)
|
||||
["defmacro multi-arity" "[6 5 6]"
|
||||
"(do (defmacro mar ([a] (list (quote +) a 1)) ([a b] (list (quote +) a b)) ([a b c] (list (quote +) a b c))) [(mar 5) (mar 2 3) (mar 1 2 3)])"]
|
||||
# defmacro with docstring AND attr-map before the params (every tools.logging
|
||||
# level macro is shaped this way)
|
||||
["defmacro doc + attr-map" "10"
|
||||
"(do (defmacro mam \"doc\" {:arglists (quote ([x]))} [x] (list (quote inc) x)) (mam 9))"]
|
||||
# syntax-quote resolves a namespace ALIAS to its target ns, so a macro's
|
||||
# template resolves at the USE site (jolt-9av)
|
||||
["syntax-quote resolves alias" "\"HI\""
|
||||
"(do (ns sq.lib (:require [clojure.string :as s])) (defmacro up [x] `(s/upper-case ~x)) (in-ns (quote user)) (sq.lib/up \"hi\"))"]
|
||||
# ^{:map} metadata on an ns name (jolt-8w2): the ns name is the bare symbol
|
||||
["ns name with ^{:map} meta" "5"
|
||||
"(do (ns ^{:author \"a\" :doc \"d\"} nm.meta) (def q 5) (in-ns (quote user)) nm.meta/q)"]
|
||||
# ~*ns* splices the live namespace object into a template (it self-evaluates)
|
||||
["unquote *ns* in template" "true"
|
||||
"(do (defmacro cur-ns [] `(str ~*ns*)) (string? (cur-ns)))"]
|
||||
])
|
||||
|
||||
# Run every case under a given context factory and return the failures. The same
|
||||
|
|
|
|||
|
|
@ -259,8 +259,12 @@
|
|||
["file-seq finds files" "true"
|
||||
"(do (require '[clojure.java.io :as io]) (pos? (count (filter (fn [f] (.isFile f)) (file-seq (io/file \"docs\"))))))"])
|
||||
|
||||
# clojure.tools.logging shim (jolt-nzg): the macro surface works, debug/trace
|
||||
# are suppressed (no-op nil) by default, and the impl protocol layer is present.
|
||||
# The REAL clojure.tools.logging (vendored verbatim) runs on jolt: a jolt
|
||||
# clojure.tools.logging.impl backend (stderr LoggerFactory) plus host shims
|
||||
# (agent/send-off, clojure.lang.LockingTransaction/isRunning, a clojure.pprint
|
||||
# subset, clojure.string/trim-newline) and the defmacro/syntax-quote/ns fixes.
|
||||
# These cases assert the public API behaves; the level rows return nil because
|
||||
# the real level macros return the (nil) result of log* when enabled.
|
||||
(defspec "host-interop / clojure.tools.logging"
|
||||
["info returns nil" "nil" "(do (require '[clojure.tools.logging :as log]) (log/info \"hi\" 42))"]
|
||||
["debug suppressed" "nil" "(do (require '[clojure.tools.logging :as log]) (log/debug \"x\"))"]
|
||||
|
|
@ -269,4 +273,20 @@
|
|||
["enabled? debug" "false" "(do (require '[clojure.tools.logging :as log]) (log/enabled? :debug))"]
|
||||
["spy returns value" "3" "(do (require '[clojure.tools.logging :as log]) (log/spy :info (+ 1 2)))"]
|
||||
["impl factory name" "\"jolt/stderr\""
|
||||
"(do (require '[clojure.tools.logging.impl :as impl]) (impl/name (impl/find-factory)))"])
|
||||
"(do (require '[clojure.tools.logging.impl :as impl]) (impl/name (impl/find-factory)))"]
|
||||
# vars that exist only in the real library (not in a hand-rolled shim)
|
||||
["real lib *tx-agent-levels*" "#{:info :warn}"
|
||||
"(do (require '[clojure.tools.logging :as log]) log/*tx-agent-levels*)"]
|
||||
["real lib log-capture! present" "true"
|
||||
"(do (require '[clojure.tools.logging :as log]) (fn? log/log-capture!))"]
|
||||
["real lib spyf present" "true"
|
||||
"(do (require '[clojure.tools.logging :as log]) (boolean (resolve 'log/spyf)))"])
|
||||
|
||||
# Host shims that let the real clojure.tools.logging load: no STM (a transaction
|
||||
# is never running) and a minimal clojure.pprint (used by spy).
|
||||
(defspec "host-interop / logging host shims"
|
||||
["LockingTransaction/isRunning" "false" "(clojure.lang.LockingTransaction/isRunning)"]
|
||||
["pprint writes value" "\"[1 2 3]\\n\""
|
||||
"(do (require '[clojure.pprint :as pp]) (with-out-str (pp/pprint [1 2 3])))"]
|
||||
["with-pprint-dispatch runs body" "42"
|
||||
"(do (require '[clojure.pprint :as pp]) (pp/with-pprint-dispatch pp/code-dispatch 42))"])
|
||||
|
|
|
|||
|
|
@ -93,3 +93,16 @@
|
|||
["docstring + arity" "15" "(do (defmacro th \"triple\" ([x] (list (quote *) x 3))) (th 5))"]
|
||||
["^{:map} name meta" "7" "(do (defmacro ^{:private true} pm [] 7) (pm))"]
|
||||
["multi-form body" "6" "(do (defmacro mb ([a b] (list (quote +) a b))) (mb 2 4))"])
|
||||
|
||||
# Multi-arity defmacro (dispatch on arg count) and the docstring + attr-map +
|
||||
# params form — both needed to run real Clojure macros, e.g.
|
||||
# clojure.tools.logging/log (4 arities) and its level macros (jolt-q8l, jolt-qnr).
|
||||
(defspec "macros / defmacro multi-arity & attr-map"
|
||||
["multi-arity 1" "6" "(do (defmacro ma ([a] (list (quote +) a 1)) ([a b] (list (quote +) a b))) (ma 5))"]
|
||||
["multi-arity 2" "5" "(do (defmacro ma ([a] (list (quote +) a 1)) ([a b] (list (quote +) a b))) (ma 2 3))"]
|
||||
["arity delegates" "[:d nil 9]"
|
||||
"(do (defmacro lg ([m] `(lg :d nil ~m)) ([l t m] (list (quote vector) l t m))) (lg 9))"]
|
||||
["doc + attr-map + params" "10"
|
||||
"(do (defmacro am \"doc\" {:arglists (quote ([x]))} [x] (list (quote inc) x)) (am 9))"]
|
||||
["doc + attr-map + variadic" "6"
|
||||
"(do (defmacro vg \"d\" {:arglists (quote ([& a]))} [& xs] `(+ ~@xs)) (vg 1 2 3))"])
|
||||
|
|
|
|||
|
|
@ -37,3 +37,12 @@
|
|||
(defspec "state / promises"
|
||||
["promise deliver" "5" "(let [p (promise)] (deliver p 5) @p)"]
|
||||
["promise undelivered" "nil" "(let [p (promise)] @p)"])
|
||||
|
||||
# Minimal synchronous agent shim (jolt has no thread pool/STM) — enough for
|
||||
# libraries that hold an agent without depending on async dispatch.
|
||||
(defspec "state / agents (synchronous shim)"
|
||||
["agent deref" "0" "(deref (agent 0))"]
|
||||
["agent with opts" "0" "(deref (agent 0 :error-mode :continue))"]
|
||||
["send-off applies" "5" "(let [a (agent 0)] (send-off a + 5) (deref a))"]
|
||||
["send applies" "7" "(let [a (agent 1)] (send a + 6) (deref a))"]
|
||||
["agent-error nil" "nil" "(agent-error (agent 0))"])
|
||||
|
|
|
|||
|
|
@ -62,3 +62,11 @@
|
|||
["get out of range nil" "nil" "(get \"abc\" 9)"]
|
||||
["get negative nil" "nil" "(get \"abc\" -1)"]
|
||||
["get default honored" ":none" "(get \"abc\" 9 :none)"])
|
||||
|
||||
# clojure.string/trim-newline (ported from clojure.string): strips trailing \n/\r.
|
||||
(defspec "clojure.string / trim-newline"
|
||||
["trailing newline" "\"x\"" "(do (require (quote [clojure.string :as s])) (s/trim-newline \"x\\n\"))"]
|
||||
["trailing \\r\\n" "\"x\"" "(do (require (quote [clojure.string :as s])) (s/trim-newline \"x\\r\\n\"))"]
|
||||
["no trailing" "\"ab\"" "(do (require (quote [clojure.string :as s])) (s/trim-newline \"ab\"))"]
|
||||
["only newlines" "\"\"" "(do (require (quote [clojure.string :as s])) (s/trim-newline \"\\n\\n\"))"]
|
||||
["interior kept" "\"a\\nb\"" "(do (require (quote [clojure.string :as s])) (s/trim-newline \"a\\nb\\n\"))"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue