core: Stage 3 turn 2a — close the implicit Janet root-env leak
resolve-sym's last resort silently resolved any unknown Clojure symbol against Janet's root environment — leaking Janet builtins with JANET semantics into Clojure code: (type 1) was Janet's :number, (gensym) returned Janet symbols (the long-documented (symbol (str (gensym))) macro landmine existed BECAUSE of this), compare/slurp/int?/any? likewise. The explicit janet/ prefix is the deliberate interop channel; the implicit fallback is gone — an unresolved symbol is an error. What the leak was masking, now proper interned vars: - gensym: jolt's own (already existed, never interned) — returns real jolt symbols; the macro landmine is dead - compare: full Clojure total order (nil-first, numbers, strings, keywords, symbols by ns/name, booleans, chars, uuid/inst, vectors by length then elementwise; cross-type throws) - type: :type metadata override, deftype/record tag as symbol, else a taxonomy keyword (host-classified) - int?: core-integer? — which had a latent bug the leak hid: (integer? ##Inf) was true (floor of inf is inf); NaN/infinities now excluded - any?: constantly true (Clojure 1.9; SCI's namespaces.cljc needs it) - jolt.interop/janet-type now uses the explicit (janet/type x) channel - evaluator-test uses init (a bare make-ctx resolved EVERYTHING via the leak) Suite 4470 -> 4532+ pass / 86-87 clean (proper compare unlocks the sort files); baselines raised. Conformance 326x3 (+5 rows), +22 predicate spec rows, stdlib battery green, all specs+unit. Coverage dashboard now counts previously-leak-resolvable names honestly (missing-portable 19 -> 27).
This commit is contained in:
parent
d0c605ac9d
commit
c7b0ad9d84
9 changed files with 150 additions and 37 deletions
|
|
@ -43,7 +43,7 @@
|
|||
# Raised 4004 -> 4034 / clean 66 -> 67 porting partition-all + repeatedly to the
|
||||
# overlay, which required fixing two leniencies (a char is not callable; take
|
||||
# validates its count) — correct beyond those fns, so the suite rose broadly.
|
||||
(def baseline-pass 4470)
|
||||
(def baseline-pass 4532)
|
||||
# A file is "clean" when it ran with zero failures AND zero errors.
|
||||
(def baseline-clean-files 86)
|
||||
# Per-file wall-clock budget (seconds). Normal files finish in well under 1s, so
|
||||
|
|
|
|||
|
|
@ -200,6 +200,13 @@
|
|||
["inst offset normalized" "true" "(= #inst \"2020-01-01T01:00:00+01:00\" #inst \"2020-01-01T00:00:00Z\")"]
|
||||
["sq literal collapse" "true" "(= \"meow\" ```\"meow\")"]
|
||||
["sq number collapse" "42" "``42"]
|
||||
|
||||
### ---- stage 3: proper vars replace the Janet root-env leak ----
|
||||
["compare total order" "[-1 0 1]" "[(compare nil 1) (compare :a :a) (compare \"b\" \"a\")]"]
|
||||
["compare vectors" "-1" "(compare [1 2] [1 3])"]
|
||||
["gensym jolt symbol" "true" "(symbol? (gensym))"]
|
||||
["any? anything" "true" "(and (any? nil) (any? 1) (any? :k))"]
|
||||
["int? excludes Inf" "false" "(int? ##Inf)"]
|
||||
["macroexpand-1 when" "2" "(count (rest (macroexpand-1 (quote (when true 1)))))"]
|
||||
|
||||
### ---- HIGH: aliased namespace calls ----
|
||||
|
|
|
|||
|
|
@ -157,3 +157,30 @@
|
|||
["not-empty full" "[1]" "(not-empty [1])"]
|
||||
["not-empty empty" "nil" "(not-empty [])"]
|
||||
["not-empty string" "nil" "(not-empty \"\")"])
|
||||
|
||||
# Stage 3 turn 2a: the implicit Janet root-env fallback is GONE — these are now
|
||||
# proper interned clojure.core vars with Clojure semantics (compare's total
|
||||
# order, meta-aware type, any?, gensym returning jolt symbols).
|
||||
(defspec "predicates / compare, type, any? (stage 3)"
|
||||
["compare =" "0" "(compare 1 1)"]
|
||||
["compare <" "-1" "(compare 1 2)"]
|
||||
["compare nil first" "-1" "(compare nil 1)"]
|
||||
["compare nil nil" "0" "(compare nil nil)"]
|
||||
["compare strings" "-1" "(compare \"a\" \"b\")"]
|
||||
["compare keywords" "-1" "(compare :a :b)"]
|
||||
["compare symbols" "-1" "(compare (quote a) (quote b))"]
|
||||
["compare bools" "-1" "(compare false true)"]
|
||||
["compare vec length" "-1" "(compare [1 2] [1 2 3])"]
|
||||
["compare vec elems" "-1" "(compare [1 2] [1 3])"]
|
||||
["compare cross-type throws" :throws "(compare 1 \"a\")"]
|
||||
["sort with compare" "[nil 1 3]" "(sort compare [3 nil 1])"]
|
||||
["type meta override" ":custom" "(type (with-meta [1] {:type :custom}))"]
|
||||
["type of record" "true" "(do (defrecord TyR [a]) (= (symbol (str (type (->TyR 1)))) (type (->TyR 1))))"]
|
||||
["any? value" "true" "(any? 5)"]
|
||||
["any? nil" "true" "(any? nil)"]
|
||||
["gensym is symbol" "true" "(symbol? (gensym))"]
|
||||
["gensym prefix" "true" "(do (require (quote [clojure.string :as s])) (s/starts-with? (str (gensym \"p_\")) \"p_\"))"]
|
||||
["gensym distinct" "false" "(= (gensym) (gensym))"]
|
||||
["int? Inf false" "false" "(int? ##Inf)"]
|
||||
["integer? Inf false" "false" "(integer? ##Inf)"]
|
||||
["integer? NaN false" "false" "(integer? ##NaN)"])
|
||||
|
|
|
|||
|
|
@ -12,10 +12,11 @@
|
|||
{:jolt/type :symbol :ns nil :name name})))
|
||||
|
||||
# Helper: parse and eval
|
||||
# init, not bare make-ctx: with the implicit Janet root-env fallback removed
|
||||
# (Stage 3), a context without clojure.core interned can't resolve inc/+/etc.
|
||||
(def- shared-ctx (init))
|
||||
(defn eval-str [s]
|
||||
(let [ctx (make-ctx)
|
||||
form (parse-string s)]
|
||||
(eval-form ctx @{} form)))
|
||||
(eval-form shared-ctx @{} (parse-string s)))
|
||||
|
||||
(print "1: literals...")
|
||||
(assert (= 42 (eval-str "42")) "integer")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue