Clean up codebase: rename stdlib layer, strip porting residue, fix tooling
Rename src/jolt -> stdlib (the runtime-loaded layer; jolt-core stays the seed-baked layer) and update the loader / emit-image / doc paths. Drop dead code: the spike/ experiments, the duplicate clojuredocs-export.edn (json moves to tools/), the Janet-era jolt.http binding, and the orphaned persistent_vector.clj whose ns/path didn't even match. Strip porting residue from comments and docstrings across host/chez, jolt-core, stdlib, tests, and docs: internal issue ids, "Phase N" markers, and the "vs Janet" historical exposition, leaving present-tense descriptions and the real JVM-Clojure semantic contrasts. Same pass over the corpus suite labels. The seed is unchanged (docstrings/comments aren't emitted), so the self-host fixpoint and corpus are untouched. Port tools/spec_coverage.py off the dead janet probe to bin/joltc and regenerate coverage.md; drop the dead :host/janet rule from certify.clj and regenerate the conformance profile. Add docs/host-interop.md (the JVM shims and how to register your own host class from a library) and a writing-style note in CLAUDE.md. Stabilize the four racy concurrency corpus cases (future-cancel and agent send/send-off): give the future a sleeping body and the agent a slow action, so cancel reliably catches an in-flight future and deref reliably reads the pre-update snapshot. They certify deterministically now, so drop their :flaky allowlist entries and the orphaned legend.
This commit is contained in:
parent
c18f8087f0
commit
33eff7c7d8
112 changed files with 970 additions and 1621 deletions
|
|
@ -3,10 +3,11 @@
|
|||
===========================================================================
|
||||
|
||||
This grammar specifies the surface syntax accepted by Jolt's reader
|
||||
(src/jolt/reader.janet) — the text that `read`/`parse-string`/`load-string`
|
||||
turn into data/forms. It is the syntactic half of Jolt's contract; the
|
||||
behavioural half lives in test/spec/. Where Jolt diverges from Clojure the
|
||||
difference is called out in a comment.
|
||||
(host/chez/reader.ss, with the portable half in jolt-core/jolt/reader.clj) —
|
||||
the text that `read`/`read-string`/`load-string` turn into data/forms. It is
|
||||
the syntactic half of Jolt's contract; the behavioural half lives in the
|
||||
conformance corpus (test/chez/corpus.edn, see docs/spec/02-reader.md). Where
|
||||
Jolt diverges from Clojure the difference is called out in a comment.
|
||||
|
||||
Notation (ISO-ish EBNF):
|
||||
= definition | alternation
|
||||
|
|
@ -128,7 +129,7 @@ meta-form = map | keyword | symbol | string ;
|
|||
a keyword -> {keyword true}; a map is used as-is. A keyword/symbol/string
|
||||
meta-form on a symbol rides ON the symbol (it stays a bare symbol, so a hint
|
||||
like ^String is transparent in params/lets/bodies). A MAP meta-form routes
|
||||
through a runtime (with-meta form ...) even on a symbol (jolt-8w2), so a name
|
||||
through a runtime (with-meta form ...) even on a symbol, so a name
|
||||
with ^{:map} metadata reads as a form, not a bare symbol — def/defn/defmacro/ns
|
||||
unwrap that to the bare name (and attach the metadata). *)
|
||||
|
||||
|
|
@ -152,7 +153,7 @@ anon-arg = "%" | "%" , digit , { digit } | "%&" ;
|
|||
|
||||
var-quote = "#'" , symbol ; (* (var symbol) *)
|
||||
|
||||
(* Regex literal -> a Janet PEG-backed regex value.
|
||||
(* Regex literal -> an irregex-backed regex value.
|
||||
Supported: groups, greedy/lazy quantifiers, (?:..), lookahead (?=..)/(?!..),
|
||||
alternation, anchors ^ $ \b \B, classes, (?i). NOT: lookbehind,
|
||||
backreferences, named groups. *)
|
||||
|
|
|
|||
175
docs/host-interop.md
Normal file
175
docs/host-interop.md
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# Host interop and JVM standard-library shims
|
||||
|
||||
Jolt runs on Chez Scheme, not the JVM, so there are no real Java classes behind
|
||||
interop forms. Instead the runtime ships shims for the slice of the JVM standard
|
||||
library that portable Clojure code reaches for, so libraries written against
|
||||
`clojure.core` and common `java.*` classes run unchanged. The Clojure interop
|
||||
syntax works against these shims:
|
||||
|
||||
```clojure
|
||||
(Math/sqrt 2) ; static call
|
||||
Math/PI ; static field
|
||||
(StringBuilder.) ; constructor
|
||||
(.append sb "x") ; instance method
|
||||
(instance? String "hi") ; class token
|
||||
```
|
||||
|
||||
A class token (`String`, `java.util.UUID`, …) resolves to a name; there is no
|
||||
reflection and no class hierarchy. `(class x)` returns the JVM class name for the
|
||||
scalar/collection types Clojure programs compare against (`"java.lang.Long"`,
|
||||
`"java.lang.String"`, and so on).
|
||||
|
||||
## What's shimmed
|
||||
|
||||
This is the surface today, not the whole JVM. Methods not listed generally
|
||||
aren't implemented; a few are accepted but no-ops (noted inline).
|
||||
|
||||
### Numbers and language
|
||||
|
||||
- **`java.lang.Math`** — `sqrt` `cbrt` `pow` `exp` `log` `log10` `floor` `ceil`
|
||||
`round` `abs` `max` `min` `sin` `cos` `tan` `asin` `acos` `atan` `signum`
|
||||
`random`; fields `PI`, `E`. (`clojure.math` mirrors these as functions.)
|
||||
- **`Long` / `Integer`** — `parseLong`/`parseInt`/`valueOf` (optional radix),
|
||||
`MAX_VALUE`, `MIN_VALUE`; `(Integer. x)`.
|
||||
- **`Double` / `Float`** — `parseDouble`, `valueOf`, `toString`, `isNaN`,
|
||||
`isInfinite`, the `*_VALUE`/`*_INFINITY`/`NaN` fields; `(Double. s)`.
|
||||
- **`Boolean`** — `parseBoolean`, `TRUE`, `FALSE`.
|
||||
- **`Character`** — `isUpperCase` `isLowerCase` `isDigit` `isWhitespace` (ASCII).
|
||||
- **Boxed-number methods** — every number answers `.intValue` `.longValue`
|
||||
`.doubleValue` `.floatValue` `.byteValue` `.shortValue` `.toString`
|
||||
`.hashCode` (integer projections wrap modulo their width, as on the JVM).
|
||||
- **`java.lang.System`** — `currentTimeMillis` `nanoTime` `exit` `getProperty`
|
||||
`setProperty` `clearProperty` `getProperties` `getenv`.
|
||||
- **`java.lang.Thread`** — `sleep` (real), `yield`/`interrupted` (no-ops),
|
||||
`currentThread`.
|
||||
- **`java.lang.Object`** — `(Object.)` as a fresh-identity sentinel; `.toString`
|
||||
`.hashCode` `.equals` `.getClass` work on any value.
|
||||
- **`java.lang.Class`** — `forName`.
|
||||
|
||||
### Strings and text
|
||||
|
||||
- **`java.lang.String`** statics — `valueOf`, `format` (the `clojure.core/format`
|
||||
engine; `String/format` with a leading locale is accepted). Instance methods
|
||||
go through `clojure.string` / the native string ops.
|
||||
- **`StringBuilder`** — `append` `toString` `length` `charAt` `setLength`.
|
||||
- **`java.text.NumberFormat`** — `getInstance` `getNumberInstance`
|
||||
`getIntegerInstance`; `.format`, `.setGroupingUsed`,
|
||||
`.setMinimum/MaximumFractionDigits`.
|
||||
- **`java.util.StringTokenizer`** — `hasMoreTokens` `countTokens` `nextToken`.
|
||||
- **`java.util.regex.Pattern`** — `compile` (with `Pattern/MULTILINE`), `quote`;
|
||||
`.split`, `.pattern`. (`#"…"` literals and `clojure.string` regex fns are the
|
||||
usual entry points.)
|
||||
|
||||
### Collections (mutable)
|
||||
|
||||
- **`java.util.ArrayList`** — `add` `get` `set` `size` `isEmpty` `remove` `clear`
|
||||
`contains` `toArray` `iterator`.
|
||||
- **`java.util.HashMap`** — `put` `get` `getOrDefault` `containsKey`
|
||||
`containsValue` `size` `isEmpty` `remove` `clear` `putAll` `keySet` `values`
|
||||
`entrySet`.
|
||||
|
||||
### I/O
|
||||
|
||||
- **`java.io.File`** — `(File. path)` / `(File. parent child)`; `getPath`
|
||||
`getName` `getAbsolutePath` `getCanonicalPath` `toURI` `toURL` `exists`
|
||||
`isDirectory` `isFile` `listFiles` `getParent`.
|
||||
- **`java.io.StringReader` / `StringWriter` / `PushbackReader`** — the
|
||||
`read`/`readLine`/`mark`/`reset`/`unread`/`write`/`append`/`toString` surface
|
||||
the reader and `with-out-str` rely on.
|
||||
- **`java.lang.ClassLoader`** — `getSystemClassLoader`, `.getResource`,
|
||||
`.getResourceAsStream` (resolved against the source roots).
|
||||
|
||||
### Time and date
|
||||
|
||||
- **`java.util.Date`** — `(Date.)` / `(Date. ms)`; `getTime` `toInstant`
|
||||
`toLocalDate(Time)` `before` `after` `equals` `toString` (RFC 3339).
|
||||
- **`java.time`** — `Instant` (`now`, `ofEpochMilli`, `toEpochMilli`, `atZone`),
|
||||
`LocalDateTime`, `ZoneId`, `DateTimeFormatter` (`ofPattern`, `ISO_LOCAL_*`,
|
||||
localized styles), `FormatStyle`.
|
||||
- **`java.text.SimpleDateFormat`** — `(SimpleDateFormat. pattern)`; `parse`
|
||||
`format` `toPattern` `applyPattern` (`setTimeZone`/`setLenient` accepted but
|
||||
ignored — formatting is UTC).
|
||||
- **`java.util.TimeZone`** / **`java.util.Locale`** — constructed and passed
|
||||
through; only UTC is honored for formatting.
|
||||
|
||||
### Net, encoding, misc
|
||||
|
||||
- **`java.net.URL`** — `(URL. spec)`; `toString` `toExternalForm` `getProtocol`
|
||||
`getPath` `getFile`.
|
||||
- **`java.net.URI`** — full component accessors (`getScheme` `getHost` `getPort`
|
||||
`getPath` `getQuery` `getFragment`, raw variants, `isAbsolute`).
|
||||
- **`java.util.Base64`** — `getEncoder`/`getDecoder` with `encode`,
|
||||
`encodeToString`, `decode`.
|
||||
- **`java.nio.charset.Charset`** — `forName`.
|
||||
- **`java.util.UUID`** — `randomUUID`, `fromString`; `(UUID. s)`.
|
||||
- **Exceptions** — `Throwable` `Exception` `RuntimeException`
|
||||
`IllegalArgumentException` `IllegalStateException` `IOException`
|
||||
`NumberFormatException` `ArithmeticException` `NullPointerException`
|
||||
`ClassCastException` `IndexOutOfBoundsException` `FileNotFoundException`
|
||||
`UnsupportedOperationException` and the common network exceptions, each with
|
||||
the `(E.)` / `(E. msg)` / `(E. msg cause)` / `(E. cause)` constructors.
|
||||
|
||||
What's deliberately absent: STM (`clojure.lang.LockingTransaction/isRunning`
|
||||
returns `false`), reflection, `gen-class`/`proxy` of Java classes, and
|
||||
`BigDecimal`.
|
||||
|
||||
## Adding your own shim from a library
|
||||
|
||||
The built-in shims above are baked into the seed. A library or project can
|
||||
register its **own** host classes at load time — no seed re-mint, no host edits.
|
||||
Put the registration calls at the top level of a namespace your code requires.
|
||||
Four functions (in `clojure.core`) plus the tagged-table seam (in `jolt.host`)
|
||||
cover it.
|
||||
|
||||
`__register-class-ctor!` makes `(Name. …)` work; `__register-class-statics!`
|
||||
makes `Name/field` and `(Name/method …)` work; `__register-class-methods!`
|
||||
attaches instance methods to a tagged value; `__register-instance-check!` teaches
|
||||
`instance?` about your class. **Method and static names are strings** (they match
|
||||
the literal name in the interop form).
|
||||
|
||||
A stateful object is a *tagged table* — `jolt.host/tagged-table` creates one,
|
||||
`ref-put!`/`ref-get` set and read its fields. Read the tag back with
|
||||
`jolt.host/ref-get` (or test it with `jolt.host/table?`); a plain `get` /
|
||||
keyword lookup deliberately can't see a wrapper's own `:jolt/type`.
|
||||
|
||||
```clojure
|
||||
(ns mylib.greeter
|
||||
(:require [jolt.host :as host]))
|
||||
|
||||
;; (Greeter. name) -> a tagged value carrying its name
|
||||
(__register-class-ctor! "Greeter"
|
||||
(fn [name] (-> (host/tagged-table :greeter)
|
||||
(host/ref-put! :name name))))
|
||||
|
||||
;; (.hello g) -> instance method, keyed by the literal method name
|
||||
(__register-class-methods! :greeter
|
||||
{"hello" (fn [self] (str "hi " (host/ref-get self :name)))})
|
||||
|
||||
;; Greeter/VERSION (field) and (Greeter/make x) (static method)
|
||||
(__register-class-statics! "Greeter"
|
||||
{"VERSION" "1.0"
|
||||
"make" (fn [name] (Greeter. name))})
|
||||
|
||||
;; (instance? Greeter x)
|
||||
(__register-instance-check!
|
||||
(fn [class-name v]
|
||||
(when (= class-name "Greeter")
|
||||
(and (host/table? v) (= :greeter (host/ref-get v :jolt/type))))))
|
||||
```
|
||||
|
||||
```clojure
|
||||
(.hello (Greeter. "ada")) ;=> "hi ada"
|
||||
Greeter/VERSION ;=> "1.0"
|
||||
(.hello (Greeter/make "bob")) ;=> "hi bob"
|
||||
(instance? Greeter (Greeter. "x")) ;=> true
|
||||
```
|
||||
|
||||
An instance-check predicate returns `true`/`false` to decide, or `nil` to defer
|
||||
to the next registered check and the built-ins — so several libraries can
|
||||
register checks without clobbering each other. This is the mechanism jolt's
|
||||
HTTP client library uses to emulate `java.net.URL` and `HttpURLConnection` so
|
||||
`clj-http-lite` runs unchanged.
|
||||
|
||||
Extending a *built-in* class instead (adding a method to core's `String` shim,
|
||||
say) means editing the relevant `host/chez/*.ss` file and running `make remint`
|
||||
— see [building-and-deps.md](building-and-deps.md).
|
||||
|
|
@ -77,6 +77,6 @@ per-context opt-in, exactly how the SCI bootstrap now loads
|
|||
- Loading clj-ecosystem libraries via deps requires deciding their feature
|
||||
set; the deps loader currently inherits the process default — a future
|
||||
refinement is per-dependency feature configuration (filed with the deps
|
||||
work, jolt-dw4).
|
||||
work).
|
||||
- `.cljc` authors targeting jolt can write `:jolt` branches and rely on
|
||||
`:default` fallbacks.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# RFC 0005 — Structural collection-type inference
|
||||
|
||||
- **Status**: Implemented (jolt-5uj). Ray tracer 12.8s to 11.0s hint-free,
|
||||
- **Status**: Implemented. Ray tracer 12.8s to 11.0s hint-free,
|
||||
matching the explicit `^:struct` version; render checksum unchanged.
|
||||
- **Champions**: jolt maintainers
|
||||
- **Created**: 2026-06-13
|
||||
|
|
@ -14,7 +14,7 @@ function its parameter and return types, recursively. A keyword lookup returns
|
|||
the looked-up field's type, so nested access like `(:r (:direction ray))` is
|
||||
typed end to end. This unifies the two facts the current inference tracks
|
||||
inconsistently (a vector's element type, but not a map's field types), subsumes
|
||||
the existing inference phases (jolt-99x Phases 0 to 3) as special cases, and
|
||||
the existing inference passes as special cases, and
|
||||
closes the remaining ray-tracer gap without a hint. The system is a
|
||||
soft-typing-style inference: it never rejects a program, it assigns a concrete
|
||||
type only when it can prove one, and it falls back to `:any` (and the existing
|
||||
|
|
@ -22,7 +22,7 @@ runtime guard) everywhere else.
|
|||
|
||||
## Motivation
|
||||
|
||||
The inference added in jolt-99x specializes a collection access (drops the
|
||||
The existing inference specializes a collection access (drops the
|
||||
`:jolt/type` guard, emits `pv-count`, and so on) when it can prove the
|
||||
collection's type. It works, it is sound, and it is fully dynamic-fallback
|
||||
safe. But its type lattice grew ad hoc:
|
||||
|
|
@ -96,7 +96,7 @@ are depth 2 to 3, well inside the cap.
|
|||
|
||||
Inference is a forward pass producing `[type node']` for each IR node (the
|
||||
existing shape), threaded with a local type environment and the
|
||||
inter-procedural state from Phase 1. The rules are uniform over the structural
|
||||
inter-procedural state. The rules are uniform over the structural
|
||||
type:
|
||||
|
||||
- **Literals.** `{:k v ...}` with constant scalar keys and struct-safe values
|
||||
|
|
@ -115,9 +115,9 @@ type:
|
|||
signature: core fns from a fixed signature table (below), user fns from the
|
||||
inter-procedural fixpoint's inferred signature.
|
||||
|
||||
The Phase 1 inter-procedural fixpoint, recompile, escape gate, and closed-world
|
||||
assumption (RFC to follow / jolt-767) are unchanged. They now propagate
|
||||
structural types instead of flat tags.
|
||||
The inter-procedural fixpoint, recompile, escape gate, and closed-world
|
||||
assumption are unchanged. They now propagate structural types instead of flat
|
||||
tags.
|
||||
|
||||
## Core function signatures
|
||||
|
||||
|
|
@ -266,8 +266,8 @@ plus a signature table.
|
|||
tables and HOF handling).
|
||||
4. The back end keeps reading the use-site type to specialize (guard drop for
|
||||
`{:struct}`, `pv-count`/`pv-nth` for `{:vec}`), now uniformly.
|
||||
5. Keep the Phase 1 fixpoint, recompile, escape gate, and triggering as is; they
|
||||
propagate structural types.
|
||||
5. Keep the inter-procedural fixpoint, recompile, escape gate, and triggering as
|
||||
is; they propagate structural types.
|
||||
|
||||
The phases land incrementally behind the same optimization-mode gate, each
|
||||
verified against conformance (three modes), the full test gate, and the
|
||||
|
|
@ -298,5 +298,6 @@ ray-tracer benchmark, exactly as the current phases were.
|
|||
param/return inference is enough for the collection-specialization goal;
|
||||
full function types matter more for the type-checker (RFC 0006) and could be
|
||||
deferred.
|
||||
- **Closed-world boundary.** Inherited from Phase 1: param/return inference
|
||||
assumes the compiled unit is the whole program. Documented there; unchanged.
|
||||
- **Closed-world boundary.** Inherited from the inter-procedural pass:
|
||||
param/return inference assumes the compiled unit is the whole program.
|
||||
Documented there; unchanged.
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
- **Status**: Implemented. Core-fn error domains (arithmetic on non-numbers,
|
||||
count/first/rest/next/seq/nth on non-seqable scalars), `JOLT_TYPE_CHECK=
|
||||
off|warn|error`. Follow-ups landed: bounded scalar **unions** (jolt-pz5) so a
|
||||
off|warn|error`. Follow-ups landed: bounded scalar **unions** so a
|
||||
use is reported only when every member is in the error domain; **user-fn
|
||||
error domains** behind `JOLT_TYPE_CHECK_USER` (jolt-zo1, closed-world);
|
||||
precise **file:line:col** locations (jolt-fqy). The checker is now one
|
||||
error domains** behind `JOLT_TYPE_CHECK_USER` (closed-world);
|
||||
precise **file:line:col** locations. The checker is now one
|
||||
inference walk (folded into `infer`), and is **on by default in direct-link
|
||||
builds** — where it piggybacks on the specialization inference for ~free —
|
||||
and opt-in (`JOLT_TYPE_CHECK`) in plain builds.
|
||||
|
|
@ -203,22 +203,22 @@ smallest high-confidence table (arithmetic and seq/count/nth/first), and grow.
|
|||
destroys trust. Mitigation: start tiny, test each entry against the runtime,
|
||||
grow slowly. Open question: derive the table from the same machinery the
|
||||
runtime uses, to avoid drift?
|
||||
- **Unions.** *Resolved (jolt-pz5).* The lattice has a bounded scalar union
|
||||
- **Unions.** *Resolved.* The lattice has a bounded scalar union
|
||||
`{:union #{T...}}` (cap 4); differing if-branches form a union instead of
|
||||
collapsing to `:any`, and a use is reported only when *every* member is in the
|
||||
error domain. Unions are opaque to structural specialization, so codegen is
|
||||
unchanged.
|
||||
- **User-function signatures.** *Resolved (jolt-zo1), opt-in.* Behind
|
||||
- **User-function signatures.** *Resolved, opt-in.* Behind
|
||||
`JOLT_TYPE_CHECK_USER`: the checker re-checks a registered non-redefinable
|
||||
user fn's body with one parameter bound to its concrete argument type; a
|
||||
diagnostic the all-`:any` body did not have means that argument is provably
|
||||
wrong. Monotonic, so still no false positives; closed-world, hence opt-in.
|
||||
- **Negative/never types.** *Resolved (jolt-wwy).* Calling a provably
|
||||
- **Negative/never types.** *Resolved.* Calling a provably
|
||||
non-callable value (`:num`/`:str` — keywords/maps/vectors/sets are IFn) is
|
||||
reported at the default level; wrong-arity to a registered single-fixed-arity
|
||||
user fn is reported under the `JOLT_TYPE_CHECK_USER` opt-in. A union callee is
|
||||
flagged only when every member is non-callable.
|
||||
- **Position vs intent.** *Resolved (jolt-fqy).* The reader records each list
|
||||
- **Position vs intent.** *Resolved.* The reader records each list
|
||||
form's absolute offset (identity-keyed, so positions survive macroexpansion
|
||||
exactly when the user's sub-form is spliced through); the analyzer stamps it
|
||||
onto `:invoke` nodes, the checker carries it into each diagnostic, and the
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ So a name's *home* is determined by two facts:
|
|||
`clojure.core` is compiled ahead of time into the checked-in seed
|
||||
(`host/chez/seed/{prelude,image}.ss`) as Scheme `def-var!` forms. The seed's
|
||||
source twin is the overlay (`jolt-core/clojure/core/*.clj` plus the stdlib
|
||||
namespaces under `src/jolt/clojure/`); `host/chez/emit-image.ss` re-emits the
|
||||
namespaces under `stdlib/clojure/`); `host/chez/emit-image.ss` re-emits the
|
||||
prelude from those sources on Chez. The build is a byte-fixpoint: rebuilding from
|
||||
an up-to-date seed reproduces it exactly.
|
||||
|
||||
|
|
|
|||
|
|
@ -12,29 +12,29 @@ sources, and process: [`../rfc/0001-language-specification.md`](../rfc/0001-lang
|
|||
| Doc | Content | Status |
|
||||
|---|---|---|
|
||||
| [`00-front-matter.md`](00-front-matter.md) | conformance terms, entry format, host classification | drafted |
|
||||
| `01-evaluation.md` … `08-macros.md` | see chapter plan in front matter | planned |
|
||||
| [`02-reader.md`](02-reader.md) | token grammar + reader-macro catalog | drafted |
|
||||
| `01`, `04`–`08` | see chapter plan in front matter | planned |
|
||||
| [`03-special-forms.md`](03-special-forms.md) | special-form catalog + normative exemplars (`if`, `let*`) | exemplars |
|
||||
| [`09-core-library.md`](09-core-library.md) | per-var entry format + exemplars (`first`, `reduce`, `parse-uuid`) | exemplars |
|
||||
| [`coverage.md`](coverage.md) | generated dashboard over the 694-var surface | generated |
|
||||
| [`../grammar.ebnf`](../grammar.ebnf) | reader surface syntax (EBNF), companion to `02-reader.md` | reference |
|
||||
|
||||
Regenerate the dashboard after surface changes:
|
||||
`python3 tools/spec_coverage.py` (requires `clojuredocs-export.json` in the
|
||||
repo root and a working jolt checkout).
|
||||
`python3 tools/spec_coverage.py` (reads `tools/clojuredocs-export.json` and
|
||||
probes a working jolt checkout via `bin/joltc`).
|
||||
|
||||
## Current numbers (2026-06-10)
|
||||
## Current numbers (2026-06-22)
|
||||
|
||||
Of the 694 `clojure.core` vars in the ClojureDocs inventory:
|
||||
Of the 694 `clojure.core` vars in the ClojureDocs inventory, jolt interns 574.
|
||||
Broadly:
|
||||
|
||||
- **380** implemented in jolt *and* exercised by the behavioral suites
|
||||
- **154** implemented but not directly tested — each gets a test with its spec entry
|
||||
- **35** portable but missing from jolt (`parse-long`/`parse-double`/
|
||||
`parse-boolean`, `update-keys`/`update-vals`, `macroexpand`, `time`,
|
||||
`partitionv`/`partitionv-all`/`splitv-at`, `with-redefs`, `with-open`,
|
||||
reader fns, ns-introspection stragglers, …) — tracked as implementation gaps
|
||||
- **22** resolvable in code but invisible to ns introspection
|
||||
(`resolve`/`ns-publics` can't see seed-fallback names like `compare`,
|
||||
`gensym`, `type`) — a conformance finding in its own right
|
||||
- the rest classified host/JVM/concurrency (see dashboard)
|
||||
- **568** implemented in jolt *and* exercised by the behavioral suites
|
||||
- **6** implemented but not directly tested — each gets a test with its spec entry
|
||||
- **6** portable but absent from jolt's resolvable surface (the REPL history
|
||||
vars `*1`/`*2`/`*3`/`*e`, plus `letfn`/`re-groups`, which work but aren't
|
||||
interned where `resolve` can see them) — tracked as gaps
|
||||
- the rest classified host/JVM/concurrency (see the dashboard for the full
|
||||
per-var breakdown — it is the source of truth)
|
||||
|
||||
## How this connects to the test suites
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
# Appendix A — Coverage Dashboard (generated)
|
||||
|
||||
Generated 2026-06-10 by `tools/spec_coverage.py` — do not edit by hand.
|
||||
Generated 2026-06-22 by `tools/spec_coverage.py` — do not edit by hand.
|
||||
|
||||
Surface: **694** clojure.core vars (ClojureDocs export; 648 with
|
||||
community examples). jolt interns 564 of them.
|
||||
community examples). jolt interns 574 of them.
|
||||
|
||||
| Status | Count | Meaning |
|
||||
|---|---|---|
|
||||
| implemented+tested | 564 | in jolt and exercised by spec/conformance |
|
||||
| implemented-untested | 0 | in jolt, no direct test — spec entries will add them |
|
||||
| implemented+tested | 568 | in jolt and exercised by spec/conformance |
|
||||
| implemented-untested | 6 | in jolt, no direct test — spec entries will add them |
|
||||
| resolvable-not-interned | 0 | works in code but invisible to ns introspection (conformance finding) |
|
||||
| missing-portable | 0 | portable semantics, jolt lacks it — implementation gap |
|
||||
| special-form | 15 | specified in §3, not a library var |
|
||||
| dynamic-var | 29 | classification needed: portable default vs host-dependent |
|
||||
| agents-taps | 22 | out of scope pending concurrency design note |
|
||||
| missing-portable | 6 | portable semantics, jolt lacks it — implementation gap |
|
||||
| special-form | 16 | specified in §3, not a library var |
|
||||
| dynamic-var | 24 | classification needed: portable default vs host-dependent |
|
||||
| agents-taps | 16 | out of scope pending concurrency design note |
|
||||
| stm-refs | 11 | out of scope pending concurrency design note |
|
||||
| jvm-specific | 53 | catalogued, not specified |
|
||||
| jvm-specific | 47 | catalogued, not specified |
|
||||
|
||||
Classifications are initial and mechanical — reclassifying is an ordinary
|
||||
spec change. A var is *Verified* only when its §9 entry exists and carries no
|
||||
|
|
@ -27,12 +27,12 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
|---|---|---|
|
||||
| `*` | implemented+tested | ✓ |
|
||||
| `*'` | implemented+tested | ✓ |
|
||||
| `*1` | implemented+tested | ✓ |
|
||||
| `*2` | implemented+tested | ✓ |
|
||||
| `*3` | implemented+tested | ✓ |
|
||||
| `*1` | missing-portable | ✓ |
|
||||
| `*2` | missing-portable | ✓ |
|
||||
| `*3` | missing-portable | ✓ |
|
||||
| `*agent*` | dynamic-var | ✓ |
|
||||
| `*allow-unresolved-vars*` | dynamic-var | ✓ |
|
||||
| `*assert*` | dynamic-var | ✓ |
|
||||
| `*assert*` | implemented+tested | ✓ |
|
||||
| `*clojure-version*` | implemented+tested | ✓ |
|
||||
| `*command-line-args*` | dynamic-var | ✓ |
|
||||
| `*compile-files*` | dynamic-var | ✓ |
|
||||
|
|
@ -40,21 +40,21 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `*compiler-options*` | dynamic-var | ✓ |
|
||||
| `*data-readers*` | dynamic-var | ✓ |
|
||||
| `*default-data-reader-fn*` | dynamic-var | ✓ |
|
||||
| `*e` | implemented+tested | ✓ |
|
||||
| `*err*` | dynamic-var | ✓ |
|
||||
| `*e` | missing-portable | ✓ |
|
||||
| `*err*` | implemented-untested | ✓ |
|
||||
| `*file*` | dynamic-var | ✓ |
|
||||
| `*flush-on-newline*` | dynamic-var | |
|
||||
| `*fn-loader*` | dynamic-var | |
|
||||
| `*in*` | implemented+tested | |
|
||||
| `*math-context*` | dynamic-var | |
|
||||
| `*ns*` | implemented+tested | ✓ |
|
||||
| `*out*` | dynamic-var | ✓ |
|
||||
| `*out*` | implemented-untested | ✓ |
|
||||
| `*print-dup*` | dynamic-var | ✓ |
|
||||
| `*print-length*` | dynamic-var | ✓ |
|
||||
| `*print-level*` | dynamic-var | ✓ |
|
||||
| `*print-meta*` | dynamic-var | ✓ |
|
||||
| `*print-namespace-maps*` | dynamic-var | ✓ |
|
||||
| `*print-readably*` | dynamic-var | ✓ |
|
||||
| `*print-readably*` | implemented+tested | ✓ |
|
||||
| `*read-eval*` | dynamic-var | ✓ |
|
||||
| `*reader-resolver*` | dynamic-var | |
|
||||
| `*repl*` | dynamic-var | |
|
||||
|
|
@ -63,7 +63,7 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `*unchecked-math*` | implemented+tested | ✓ |
|
||||
| `*use-context-classloader*` | dynamic-var | ✓ |
|
||||
| `*verbose-defrecords*` | dynamic-var | |
|
||||
| `*warn-on-reflection*` | dynamic-var | ✓ |
|
||||
| `*warn-on-reflection*` | implemented-untested | ✓ |
|
||||
| `+` | implemented+tested | ✓ |
|
||||
| `+'` | implemented+tested | ✓ |
|
||||
| `-` | implemented+tested | ✓ |
|
||||
|
|
@ -77,7 +77,7 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `->VecSeq` | jvm-specific | |
|
||||
| `-cache-protocol-fn` | jvm-specific | |
|
||||
| `-reset-methods` | jvm-specific | |
|
||||
| `.` | implemented+tested | ✓ |
|
||||
| `.` | special-form | ✓ |
|
||||
| `..` | implemented+tested | ✓ |
|
||||
| `/` | implemented+tested | ✓ |
|
||||
| `<` | implemented+tested | ✓ |
|
||||
|
|
@ -98,8 +98,8 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `add-classpath` | jvm-specific | ✓ |
|
||||
| `add-tap` | agents-taps | ✓ |
|
||||
| `add-watch` | implemented+tested | ✓ |
|
||||
| `agent` | agents-taps | ✓ |
|
||||
| `agent-error` | agents-taps | ✓ |
|
||||
| `agent` | implemented+tested | ✓ |
|
||||
| `agent-error` | implemented+tested | ✓ |
|
||||
| `agent-errors` | agents-taps | |
|
||||
| `aget` | implemented+tested | ✓ |
|
||||
| `alength` | implemented+tested | ✓ |
|
||||
|
|
@ -131,7 +131,7 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `assoc-in` | implemented+tested | ✓ |
|
||||
| `associative?` | implemented+tested | ✓ |
|
||||
| `atom` | implemented+tested | ✓ |
|
||||
| `await` | agents-taps | ✓ |
|
||||
| `await` | implemented-untested | ✓ |
|
||||
| `await-for` | agents-taps | ✓ |
|
||||
| `await1` | agents-taps | |
|
||||
| `bases` | jvm-specific | ✓ |
|
||||
|
|
@ -183,7 +183,7 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `chunk-rest` | implemented+tested | ✓ |
|
||||
| `chunked-seq?` | implemented+tested | ✓ |
|
||||
| `class` | implemented+tested | ✓ |
|
||||
| `class?` | jvm-specific | ✓ |
|
||||
| `class?` | implemented+tested | ✓ |
|
||||
| `clear-agent-errors` | agents-taps | |
|
||||
| `clojure-version` | implemented+tested | ✓ |
|
||||
| `coll?` | implemented+tested | ✓ |
|
||||
|
|
@ -375,13 +375,13 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `lazy-cat` | implemented+tested | ✓ |
|
||||
| `lazy-seq` | implemented+tested | ✓ |
|
||||
| `let` | implemented+tested | ✓ |
|
||||
| `letfn` | implemented+tested | ✓ |
|
||||
| `letfn` | missing-portable | ✓ |
|
||||
| `line-seq` | implemented+tested | ✓ |
|
||||
| `list` | implemented+tested | ✓ |
|
||||
| `list*` | implemented+tested | ✓ |
|
||||
| `list?` | implemented+tested | ✓ |
|
||||
| `load` | jvm-specific | ✓ |
|
||||
| `load-file` | jvm-specific | ✓ |
|
||||
| `load` | implemented+tested | ✓ |
|
||||
| `load-file` | implemented-untested | ✓ |
|
||||
| `load-reader` | jvm-specific | ✓ |
|
||||
| `load-string` | implemented+tested | ✓ |
|
||||
| `loaded-libs` | jvm-specific | ✓ |
|
||||
|
|
@ -464,10 +464,10 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `partition-by` | implemented+tested | ✓ |
|
||||
| `partitionv` | implemented+tested | |
|
||||
| `partitionv-all` | implemented+tested | |
|
||||
| `pcalls` | jvm-specific | ✓ |
|
||||
| `pcalls` | implemented+tested | ✓ |
|
||||
| `peek` | implemented+tested | ✓ |
|
||||
| `persistent!` | implemented+tested | ✓ |
|
||||
| `pmap` | jvm-specific | ✓ |
|
||||
| `pmap` | implemented+tested | ✓ |
|
||||
| `pop` | implemented+tested | ✓ |
|
||||
| `pop!` | implemented+tested | ✓ |
|
||||
| `pop-thread-bindings` | implemented+tested | |
|
||||
|
|
@ -496,7 +496,7 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `proxy-name` | jvm-specific | |
|
||||
| `proxy-super` | implemented+tested | ✓ |
|
||||
| `push-thread-bindings` | implemented+tested | |
|
||||
| `pvalues` | jvm-specific | ✓ |
|
||||
| `pvalues` | implemented+tested | ✓ |
|
||||
| `qualified-ident?` | implemented+tested | ✓ |
|
||||
| `qualified-keyword?` | implemented+tested | ✓ |
|
||||
| `qualified-symbol?` | implemented+tested | ✓ |
|
||||
|
|
@ -512,7 +512,7 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `rational?` | implemented+tested | ✓ |
|
||||
| `rationalize` | implemented+tested | ✓ |
|
||||
| `re-find` | implemented+tested | ✓ |
|
||||
| `re-groups` | implemented+tested | ✓ |
|
||||
| `re-groups` | missing-portable | ✓ |
|
||||
| `re-matcher` | implemented+tested | ✓ |
|
||||
| `re-matches` | implemented+tested | ✓ |
|
||||
| `re-pattern` | implemented+tested | ✓ |
|
||||
|
|
@ -558,7 +558,7 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `reset-vals!` | implemented+tested | ✓ |
|
||||
| `resolve` | implemented+tested | ✓ |
|
||||
| `rest` | implemented+tested | ✓ |
|
||||
| `restart-agent` | agents-taps | ✓ |
|
||||
| `restart-agent` | implemented-untested | ✓ |
|
||||
| `resultset-seq` | jvm-specific | ✓ |
|
||||
| `reverse` | implemented+tested | ✓ |
|
||||
| `reversible?` | implemented+tested | ✓ |
|
||||
|
|
@ -568,8 +568,8 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `satisfies?` | implemented+tested | ✓ |
|
||||
| `second` | implemented+tested | ✓ |
|
||||
| `select-keys` | implemented+tested | ✓ |
|
||||
| `send` | agents-taps | ✓ |
|
||||
| `send-off` | agents-taps | ✓ |
|
||||
| `send` | implemented+tested | ✓ |
|
||||
| `send-off` | implemented+tested | ✓ |
|
||||
| `send-via` | agents-taps | ✓ |
|
||||
| `seq` | implemented+tested | ✓ |
|
||||
| `seq-to-map-for-destructuring` | implemented+tested | ✓ |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue