docs: language specification RFC + spec skeleton with normative exemplars
RFC 0001 proposes a normative, implementation-independent Clojure language spec (the reader, evaluation model, special forms, data types, seq/laziness contracts, namespaces/vars, and the portable clojure.core surface) to the standard of R7RS/Racket — Clojure has none, and every alternative implementation re-derives semantics from the reference and folklore. The spec is executable-first: every numbered normative statement cites its conformance test or is marked UNVERIFIED. docs/spec/ carries the front matter (conformance terms, entry format, host classification), the special-form catalog with worked normative entries for if and let*, the core-library entry format with worked entries for first, reduce, and parse-uuid, and a generated coverage dashboard over the 694-var ClojureDocs inventory (tools/spec_coverage.py cross-references the surface against jolt's interned+resolvable vars and the test suites). Measured baseline: 380 implemented+tested, 154 implemented-untested, 35 portable-but-missing (filed), 22 resolvable-but-not-interned (filed — seed fns invisible to resolve/ns-publics), rest classified host/JVM/concurrency.
This commit is contained in:
parent
bd5142abac
commit
7003926eda
7 changed files with 1478 additions and 0 deletions
179
docs/rfc/0001-language-specification.md
Normal file
179
docs/rfc/0001-language-specification.md
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# RFC 0001 — A Specification for the Clojure Language
|
||||
|
||||
- **Status**: Draft
|
||||
- **Champions**: jolt maintainers
|
||||
- **Created**: 2026-06-10
|
||||
|
||||
## Summary
|
||||
|
||||
Produce a normative, implementation-independent specification of the Clojure
|
||||
language — the reader, the evaluation model, the special forms, the data types
|
||||
and their equality/hashing/ordering contracts, sequences and laziness, and the
|
||||
`clojure.core` library — to the standard set by R7RS Scheme and the Racket
|
||||
reference. The specification is developed *in this repository*, validated
|
||||
continuously by jolt's executable conformance suite, and intended to be useful
|
||||
to every alternative implementation (ClojureScript, jank, babashka/sci,
|
||||
Basilisp, ClojureCLR, jolt).
|
||||
|
||||
## Motivation
|
||||
|
||||
Clojure has no specification. The language is defined by:
|
||||
|
||||
1. the reference JVM implementation's source,
|
||||
2. docstrings (frequently silent on edge cases),
|
||||
3. community folklore (ClojureDocs examples, mailing-list threads),
|
||||
4. each alternative implementation's reverse-engineering effort.
|
||||
|
||||
Every alternative implementation independently re-derives answers to the same
|
||||
questions — *what does `(nth coll nil)` do? is `(first "")` an error? does
|
||||
`conj` on `nil` produce a list or vector? in what order does `reduce-kv` visit
|
||||
a map?* — and they routinely diverge. The cross-dialect
|
||||
[clojure-test-suite](https://github.com/jank-lang/clojure-test-suite) exists
|
||||
precisely because these divergences are real and frequent: it currently
|
||||
encodes hundreds of edge-case assertions that no normative document captures.
|
||||
|
||||
Building jolt's self-hosted compiler forced us to answer these questions
|
||||
one at a time (the conformance harness runs every behavior through three
|
||||
independent execution paths and demands agreement). That work product — over
|
||||
300 three-way-validated conformance assertions, ~1,500 behavioral spec cases,
|
||||
and a frozen catalog of which forms are language vs. host — is the seed of a
|
||||
specification, currently trapped in test files. This RFC proposes promoting it
|
||||
into prose with normative force.
|
||||
|
||||
### Why us / why now
|
||||
|
||||
A useful spec needs an implementation that can *afford* to be strict. The
|
||||
reference implementation can't adopt a spec retroactively without breaking
|
||||
changes; an alternative implementation chasing drop-in compatibility can't
|
||||
deviate from the reference even where the reference is accidental. jolt's
|
||||
goals (self-hosted, minimal seed, multiple execution paths that must agree)
|
||||
already require us to decide, for every form, *what the contract is* — we are
|
||||
writing the spec anyway, in test form. The marginal cost of writing it down
|
||||
properly is small; the value to the ecosystem is large.
|
||||
|
||||
## Goals
|
||||
|
||||
1. **Normative core**: reader grammar, evaluation model, all special forms,
|
||||
data types with equality/hashing/ordering contracts, seq/laziness
|
||||
contracts, namespaces/vars, and per-var entries for the portable
|
||||
`clojure.core` surface.
|
||||
2. **Executable**: every normative statement is paired with at least one
|
||||
conformance test. The spec and the suite are maintained together; a spec
|
||||
claim without a test is marked `unverified`.
|
||||
3. **Host classification**: every `clojure.core` var is classified
|
||||
**portable** (specified normatively), **host-dependent** (interface
|
||||
specified, behavior host-defined — e.g. `slurp`, `*out*`), or
|
||||
**JVM-specific** (documented as outside the portable language — e.g.
|
||||
`bases`, `definline`, agents/STM as currently scoped).
|
||||
4. **Versioned against reference Clojure**: each spec edition states the
|
||||
reference version it describes (initially 1.12) and records *deliberate*
|
||||
divergences (e.g. where reference behavior is accidental — these become
|
||||
labeled "implementation-defined" with the reference behavior noted).
|
||||
5. **Useful to other implementations**: no jolt-specific concepts in
|
||||
normative text. jolt appears only in conformance-suite references.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Specifying the JVM interop surface (`proxy`, `gen-class`, `.`-forms beyond
|
||||
their syntax), agents, STM refs, or the Java class hierarchy mapping.
|
||||
These are catalogued as host/JVM surface, not specified.
|
||||
- Specifying `clojure.spec`, `core.async`, or other contrib libraries
|
||||
(candidates for later, separate documents).
|
||||
- Changing the language. The spec describes Clojure as it is; divergence
|
||||
decisions document reality, they don't invent semantics.
|
||||
- Replacing clojure-test-suite — we contribute to it and cite it.
|
||||
|
||||
## The specification document
|
||||
|
||||
Lives in `docs/spec/`. Shape (mirroring R7RS chapters):
|
||||
|
||||
| § | Document | Content |
|
||||
|---|---|---|
|
||||
| 0 | `00-front-matter.md` | conformance terms (RFC 2119), entry format, host classification |
|
||||
| 1 | `01-evaluation.md` | evaluation model: forms, environments, vars, macroexpansion order |
|
||||
| 2 | `02-reader.md` | lexical syntax: formal grammar, all reader macros, reader conditionals |
|
||||
| 3 | `03-special-forms.md` | the special forms, one normative entry each |
|
||||
| 4 | `04-data-types.md` | nil/booleans/numbers/strings/chars/keywords/symbols/colls; equality, hashing, ordering |
|
||||
| 5 | `05-sequences.md` | the seq abstraction, laziness contract, realization boundaries |
|
||||
| 6 | `06-namespaces-vars.md` | namespaces, vars, dynamic binding, resolution |
|
||||
| 7 | `07-polymorphism.md` | protocols, records/types, multimethods, hierarchies |
|
||||
| 8 | `08-macros.md` | defmacro, syntax-quote/hygiene, `&env`/`&form` |
|
||||
| 9 | `09-core-library.md` | normative per-var entries for the portable surface |
|
||||
| A | `coverage.md` | generated status dashboard: 694 vars × {specified, tested, implemented, classification} |
|
||||
|
||||
### The normative entry format
|
||||
|
||||
Every special form and library var gets an entry with these fields
|
||||
(exemplars in `03-special-forms.md` and `09-core-library.md`):
|
||||
|
||||
```
|
||||
### name
|
||||
Signature(s), since-version
|
||||
1. Semantics — numbered MUST/SHOULD statements
|
||||
2. Edge cases — nil, empty, bounds, wrong-type behavior (normative)
|
||||
3. Errors — what MUST throw, and when error type is implementation-defined
|
||||
4. Examples — executable, drawn from ClojureDocs where community-validated
|
||||
5. Conformance — test IDs that verify each numbered statement
|
||||
```
|
||||
|
||||
### Evidence sources, in priority order
|
||||
|
||||
1. **Differential testing** against reference Clojure 1.12 (the ground truth
|
||||
for behavior questions).
|
||||
2. **clojure-test-suite** (cross-dialect agreement = portable semantics;
|
||||
dialect splits = host-dependent candidates).
|
||||
3. **ClojureDocs export** (`clojuredocs-export.edn`, 694 core vars, 648 with
|
||||
community examples) — examples become spec examples after verification.
|
||||
4. **jank's language test corpus** (~800 per-form tests under
|
||||
`test/jank/{form,call,metadata,reader-macro,syntax-quote,var}`) — the
|
||||
per-construct granularity model for §2–§3 conformance.
|
||||
5. Reference implementation source — last resort, for intent.
|
||||
|
||||
## Current baseline (measured 2026-06-10)
|
||||
|
||||
- ClojureDocs inventory: **694** `clojure.core` vars (648 with examples).
|
||||
- jolt implements **572**; **373 (66%)** are exercised by the behavioral
|
||||
spec/conformance suites; 139 implemented-but-untested.
|
||||
- Initial classification of the 182 unimplemented: ~31 dynamic vars, ~20
|
||||
agents/taps, ~11 STM, ~15 special-form docs, ~105 to adjudicate
|
||||
(genuinely-portable gaps spotted already: `compare`, `any?`, `update-keys`,
|
||||
`update-vals`, `parse-long`, `parse-double`, `parse-boolean`,
|
||||
`partitionv`, `splitv-at`, `macroexpand`, `time`, `with-redefs`).
|
||||
- Conformance: 302 assertions × 3 execution paths; ~1,500 behavioral cases;
|
||||
clojure-test-suite ≥ 4081/4707 assertions.
|
||||
|
||||
## Process
|
||||
|
||||
1. **Section by section**, in chapter order. §2 (reader) and §3 (special
|
||||
forms) first — they are the smallest closed sets and jank's corpus gives
|
||||
per-construct conformance shape immediately.
|
||||
2. Each PR that adds/edits normative text MUST add or cite the conformance
|
||||
tests for every numbered statement, and update `coverage.md`.
|
||||
3. Divergences from reference Clojure discovered during writing get filed,
|
||||
then either fixed in jolt or recorded as a labeled divergence — never
|
||||
silently spec'd to jolt's behavior.
|
||||
4. Editions: spec snapshots versioned independently of jolt releases
|
||||
(`Clojure Language Specification, Draft N`).
|
||||
5. When a chapter stabilizes, solicit review from other implementations
|
||||
(jank, babashka, Basilisp maintainers) before marking it Stable.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
- **Contribute prose to clojure-test-suite instead**: the suite is the right
|
||||
*conformance* home but tests can't express rationale, classification, or
|
||||
grammar; both are needed and they cross-reference.
|
||||
- **Spec only what jolt implements**: rejected — the host classification of
|
||||
the *full* 694-var surface is half the value.
|
||||
- **EDN/data-format spec only** (edn already has a loose spec): far too
|
||||
narrow; the evaluation model and core library are where divergence lives.
|
||||
|
||||
## Open questions
|
||||
|
||||
1. Numerics: the reference has longs/doubles/ratios/BigInt with promotion
|
||||
rules; CLJS has JS numbers; jolt has Janet numbers. Likely answer: specify
|
||||
an integer/float core with a host-numeric-tower extension point — needs
|
||||
its own design note in §4.
|
||||
2. Where do `*print-length*`-style dynamic vars land — host-dependent
|
||||
interface or portable with defaults?
|
||||
3. License/venue if the spec outgrows this repo (likely CC-BY; separate repo
|
||||
once §1–§3 stabilize).
|
||||
87
docs/spec/00-front-matter.md
Normal file
87
docs/spec/00-front-matter.md
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
# Clojure Language Specification — Front Matter
|
||||
|
||||
**Edition**: Draft 1 · **Describes**: Clojure 1.12 (reference) · **Status**: in progress
|
||||
|
||||
This document specifies the Clojure programming language independently of any
|
||||
implementation. See `docs/rfc/0001-language-specification.md` for motivation,
|
||||
process, and scope.
|
||||
|
||||
## 1. Conformance terminology
|
||||
|
||||
The key words **MUST**, **MUST NOT**, **SHOULD**, **SHOULD NOT**, and **MAY**
|
||||
are to be interpreted as described in RFC 2119.
|
||||
|
||||
- A statement marked **MUST** is normative: a conforming implementation
|
||||
exhibits exactly this behavior, and the conformance suite tests it.
|
||||
- **implementation-defined** marks behavior a conforming implementation must
|
||||
document but may choose (e.g. the concrete error type thrown where the
|
||||
reference throws a JVM exception class).
|
||||
- **host-defined** marks behavior delegated to the host platform (e.g. what
|
||||
`slurp` accepts as a source).
|
||||
- **⚠ reference-divergence** marks a place where this spec deliberately
|
||||
differs from observed reference behavior, with rationale; the reference
|
||||
behavior is always recorded alongside.
|
||||
|
||||
## 2. Classification of the core surface
|
||||
|
||||
Every `clojure.core` var carries exactly one classification (dashboard:
|
||||
`coverage.md`):
|
||||
|
||||
| Class | Meaning | Spec treatment |
|
||||
|---|---|---|
|
||||
| **portable** | semantics independent of host | full normative entry (§9) |
|
||||
| **host-dependent** | portable *interface*, host-defined behavior | interface entry; behavior host-defined |
|
||||
| **JVM-specific** | meaningful only on the JVM | catalogued in Appendix; not specified |
|
||||
|
||||
Initial classifications are mechanical and reviewable; reclassification is an
|
||||
ordinary spec change.
|
||||
|
||||
## 3. The normative entry format
|
||||
|
||||
Each special form (§3) and portable var (§9) is specified as:
|
||||
|
||||
```
|
||||
### name — since <version>
|
||||
(signature ...) (signature ...)
|
||||
|
||||
Semantics
|
||||
S1. <numbered normative statement, MUST/SHOULD/MAY>
|
||||
S2. ...
|
||||
Edge cases
|
||||
E1. <nil / empty / bounds / wrong-type behavior — normative>
|
||||
Errors
|
||||
X1. <what MUST throw; error TYPE is implementation-defined unless stated>
|
||||
Examples
|
||||
<executable; verified against the reference; sourced from ClojureDocs
|
||||
where community-validated>
|
||||
Conformance
|
||||
S1 → <suite>/<test id>; E1 → ... (statements without a test: UNVERIFIED)
|
||||
```
|
||||
|
||||
The **Conformance** field is load-bearing: every numbered statement names the
|
||||
test(s) that verify it. A normative statement with no test is labeled
|
||||
`UNVERIFIED` and is a defect in the spec.
|
||||
|
||||
## 4. Evidence and verification
|
||||
|
||||
Behavioral questions are settled in this order: differential testing against
|
||||
the reference implementation → cross-dialect agreement in clojure-test-suite
|
||||
→ ClojureDocs community examples (verified before inclusion) → reference
|
||||
source (for intent). Conformance tests live in this repository
|
||||
(`test/integration/conformance-test.janet` runs each assertion through three
|
||||
independent execution paths) and in the cross-dialect clojure-test-suite.
|
||||
|
||||
## 5. Chapter plan
|
||||
|
||||
| § | File | Status |
|
||||
|---|---|---|
|
||||
| 1 | `01-evaluation.md` | planned |
|
||||
| 2 | `02-reader.md` | planned (first: jank's reader corpus gives conformance shape) |
|
||||
| 3 | `03-special-forms.md` | **exemplars written** (`if`, `let*`); catalog complete |
|
||||
| 4 | `04-data-types.md` | planned (numeric-tower design note required) |
|
||||
| 5 | `05-sequences.md` | planned (laziness contract from jolt Phase-5 work) |
|
||||
| 6 | `06-namespaces-vars.md` | planned |
|
||||
| 7 | `07-polymorphism.md` | planned |
|
||||
| 8 | `08-macros.md` | planned |
|
||||
| 9 | `09-core-library.md` | **exemplars written** (`first`, `reduce`, `parse-uuid`) |
|
||||
| A | `coverage.md` | **generated** (regenerate: `python3 tools/spec_coverage.py`) |
|
||||
143
docs/spec/03-special-forms.md
Normal file
143
docs/spec/03-special-forms.md
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
# §3 Special Forms
|
||||
|
||||
**Status**: catalog complete; normative exemplars for `if` and `let*`; the
|
||||
remaining entries follow the same format (tracked in `coverage.md`).
|
||||
|
||||
A *special form* is a form whose head symbol is evaluated by rule rather than
|
||||
by function application or macroexpansion. The special forms of Clojure are:
|
||||
|
||||
> `def` · `if` · `do` · `let*` · `fn*` · `loop*` · `recur` · `quote` · `var`
|
||||
> · `throw` · `try`/`catch`/`finally` · `set!` · `monitor-enter` ·
|
||||
> `monitor-exit` (host) · the interop forms `.` and `new` (host)
|
||||
|
||||
`let`, `fn`, `loop`, `and`, `or`, `when`, … are **macros** over these (§8);
|
||||
implementations MUST treat them as redefinable macros, not additional special
|
||||
forms. `monitor-enter`/`monitor-exit`, `.` and `new` are host forms: their
|
||||
syntax is specified here, their behavior is host-defined.
|
||||
|
||||
Special-form head symbols are not shadowable: a binding named `if` does not
|
||||
change the meaning of `(if ...)` in operator position. ⚠ This matches the
|
||||
reference; it differs from Scheme.
|
||||
|
||||
---
|
||||
|
||||
### if — since 1.0
|
||||
|
||||
```
|
||||
(if test then)
|
||||
(if test then else)
|
||||
```
|
||||
|
||||
**Semantics**
|
||||
|
||||
- S1. `test` MUST be evaluated first, exactly once.
|
||||
- S2. Every value other than `nil` and `false` is *logically true*. If the
|
||||
value of `test` is logically true, `then` MUST be evaluated and its value
|
||||
returned; otherwise `else` (or `nil` when absent) MUST be evaluated and its
|
||||
value returned.
|
||||
- S3. The branch not taken MUST NOT be evaluated.
|
||||
- S4. `if` MUST be usable in tail position with respect to `recur` (§3
|
||||
`recur`): an `if` whose branch is a `recur` form is a valid recur target
|
||||
path.
|
||||
|
||||
**Edge cases**
|
||||
|
||||
- E1. `(if test then)` with a logically false `test` evaluates to `nil`.
|
||||
- E2. The empty collections (`()`, `[]`, `{}`, `#{}`), the number `0`, and
|
||||
the empty string `""` are logically **true** (only `nil`/`false` are
|
||||
false). ⚠ This differs from several Lisps and is a frequent divergence
|
||||
source in alternative implementations.
|
||||
|
||||
**Errors**
|
||||
|
||||
- X1. `(if)` and `(if test)` with fewer than two argument forms, or more
|
||||
than three, MUST be a compile-time error.
|
||||
|
||||
**Examples**
|
||||
|
||||
```clojure
|
||||
(if 0 :t :f) ;=> :t
|
||||
(if "" :t :f) ;=> :t
|
||||
(if nil :t :f) ;=> :f
|
||||
(if false :t) ;=> nil
|
||||
```
|
||||
|
||||
**Conformance**
|
||||
|
||||
S1–S3, E1–E2 → jolt `forms-spec` "if/do/def" group; truthiness group in
|
||||
`truthiness-spec`; clojure-test-suite `core_test/if.cljc`. S4 → `forms-spec`
|
||||
fn/loop recur cases. X1 → UNVERIFIED (arity-error case to add).
|
||||
|
||||
---
|
||||
|
||||
### let* — since 1.0
|
||||
|
||||
```
|
||||
(let* [sym₁ init₁ … symₙ initₙ] body…)
|
||||
```
|
||||
|
||||
`let*` is the primitive sequential-binding form. The user-facing `let` macro
|
||||
adds destructuring and expands to `let*` (§8); `let*` itself accepts **only
|
||||
simple symbols** in binding positions.
|
||||
|
||||
**Semantics**
|
||||
|
||||
- S1. Each `initᵢ` MUST be evaluated in order, exactly once, in an
|
||||
environment where `sym₁…symᵢ₋₁` are bound to their values (sequential
|
||||
scope, as Scheme `let*`).
|
||||
- S2. The body forms MUST be evaluated in order with all bindings in scope;
|
||||
the value of the last body form is the value of the `let*` form. An empty
|
||||
body evaluates to `nil`.
|
||||
- S3. A later binding MAY rebind the same symbol; each binding creates a new
|
||||
lexical binding visible from the next init onward (no mutation of the
|
||||
earlier binding is implied).
|
||||
- S4. Bindings are lexical and immutable: there is no form that assigns to a
|
||||
`let*`-bound local. (Closures capture bindings by value; see §3 `fn*`.)
|
||||
- S5. The binding vector MUST be a vector literal with an even number of
|
||||
forms.
|
||||
|
||||
**Edge cases**
|
||||
|
||||
- E1. `(let* [] body)` is valid and equivalent to `(do body…)`.
|
||||
- E2. Binding a symbol that names a var shadows the var for the lexical
|
||||
extent of the body; `(var sym)` within that extent still denotes the var.
|
||||
|
||||
**Errors**
|
||||
|
||||
- X1. An odd number of binding forms MUST be a compile-time error.
|
||||
- X2. A non-symbol in a binding position (e.g. a destructuring pattern) MUST
|
||||
be a compile-time error for `let*` — destructuring belongs to the `let`
|
||||
macro. ("Bad binding form, expected symbol" in the reference.)
|
||||
|
||||
**Examples**
|
||||
|
||||
```clojure
|
||||
(let* [a 1 b (+ a 1)] (* a b)) ;=> 2
|
||||
(let* [x 1 x (inc x)] x) ;=> 2
|
||||
(let* [] 42) ;=> 42
|
||||
```
|
||||
|
||||
**Conformance**
|
||||
|
||||
S1–S3, E1 → jolt `forms-spec` let group; clojure-test-suite
|
||||
`core_test/let.cljc`; jank corpus `form/let/*`. X2 → jolt
|
||||
`destructuring-spec` "primitives reject patterns". S4, X1 → UNVERIFIED
|
||||
(cases to add).
|
||||
|
||||
---
|
||||
|
||||
## Remaining entries (format above; status in coverage.md)
|
||||
|
||||
| Form | Notes for the entry author |
|
||||
|---|---|
|
||||
| `def` | var creation vs re-binding; metadata on the name; `(def x)` unbound; return value is the var |
|
||||
| `do` | empty `(do)` → nil; top-level `do` splices for compilation units (important and under-documented) |
|
||||
| `fn*` | arities, variadic `&`, closure capture, self-name, simple-symbol params only, recur target |
|
||||
| `loop*` | recur arity must match bindings; recur rebinds in place |
|
||||
| `recur` | tail-position rule (normative definition of tail position needed), across `if`/`do`/`let*`/`try` interactions |
|
||||
| `quote` | self-evaluation table: which literals are self-evaluating unquoted |
|
||||
| `var` | `#'` reader sugar; resolution at compile time |
|
||||
| `throw` | any value vs Throwable — host question; jolt/cljs allow data, reference requires Throwable → classification needed |
|
||||
| `try/catch/finally` | catch dispatch order, `:default`-style catch-all is a dialect extension (⚠ divergence note), finally evaluation guarantees, value of try |
|
||||
| `set!` | host-dependent (dynamic vars + host fields) |
|
||||
| `.` / `new` | syntax only; behavior host-defined |
|
||||
174
docs/spec/09-core-library.md
Normal file
174
docs/spec/09-core-library.md
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
# §9 The Core Library
|
||||
|
||||
**Status**: entry format fixed; exemplars for `first`, `reduce`, `parse-uuid`.
|
||||
The full portable surface (≈500 vars after classification, dashboard in
|
||||
`coverage.md`) is filled in chapter-by-chapter using this format.
|
||||
|
||||
Entries specify *behavioral contracts*, not implementations. Performance
|
||||
characteristics are specified only where the language community relies on
|
||||
them (e.g. vector `nth` is "effectively constant time" — SHOULD-level).
|
||||
|
||||
---
|
||||
|
||||
### first — since 1.0
|
||||
|
||||
```
|
||||
(first coll)
|
||||
```
|
||||
|
||||
**Semantics**
|
||||
|
||||
- S1. MUST return the first element of `(seq coll)`.
|
||||
- S2. If `(seq coll)` is `nil` (i.e. `coll` is empty or `nil`), MUST return
|
||||
`nil`.
|
||||
- S3. MUST accept anything *seqable* (§5): seqs, lists, vectors, maps
|
||||
(yielding map entries), sets, strings (yielding characters), `nil`.
|
||||
- S4. On a lazy sequence, MUST realize at most the first element (§5
|
||||
laziness contract).
|
||||
|
||||
**Edge cases**
|
||||
|
||||
- E1. `(first nil)` ⇒ `nil`; `(first [])` ⇒ `nil`; `(first "")` ⇒ `nil`.
|
||||
- E2. A `nil` or `false` first *element* is returned as-is — callers cannot
|
||||
distinguish "empty" from "first element is nil" via `first` alone (that is
|
||||
what `seq` is for).
|
||||
- E3. On a map, the element is a map entry; on an unordered collection (map,
|
||||
set) *which* element is first is implementation-defined but MUST be
|
||||
consistent with that collection's seq order for the same collection value.
|
||||
|
||||
**Errors**
|
||||
|
||||
- X1. A non-seqable argument (e.g. a number) MUST throw.
|
||||
|
||||
**Examples**
|
||||
|
||||
```clojure
|
||||
(first [1 2 3]) ;=> 1
|
||||
(first '()) ;=> nil
|
||||
(first "ab") ;=> \a
|
||||
(first {:a 1}) ;=> [:a 1]
|
||||
(first [nil 2]) ;=> nil
|
||||
```
|
||||
|
||||
**Conformance**
|
||||
|
||||
S1–S3, E1–E2 → jolt `sequences-spec` "seq / access"; clojure-test-suite
|
||||
`core_test/first.cljc`. S4 → jolt `lazy-seqs-spec` counter cases. X1 →
|
||||
clojure-test-suite `core_test/first.cljc` (throwing cases).
|
||||
|
||||
---
|
||||
|
||||
### reduce — since 1.0
|
||||
|
||||
```
|
||||
(reduce f coll)
|
||||
(reduce f init coll)
|
||||
```
|
||||
|
||||
**Semantics**
|
||||
|
||||
- S1. With `init`: MUST return `init` if `(seq coll)` is nil; otherwise MUST
|
||||
return `(f … (f (f init e₁) e₂) … eₙ)`, applying `f` left-to-right over the
|
||||
elements, exactly once each.
|
||||
- S2. Without `init`: if `coll` is empty, MUST return `(f)` (f called with
|
||||
no arguments); if `coll` has one element, MUST return that element
|
||||
*without calling `f`*; otherwise as S1 with `init = e₁` over `e₂…eₙ`.
|
||||
- S3. **Reduced short-circuit**: if any intermediate result is a `reduced`
|
||||
value, iteration MUST stop and the dereferenced value MUST be returned
|
||||
immediately; `f` MUST NOT be called again.
|
||||
- S4. `reduce` is eager: it MUST fully realize the consumed portion of a
|
||||
lazy `coll` (to the end, or to the `reduced` point).
|
||||
|
||||
**Edge cases**
|
||||
|
||||
- E1. `(reduce f nil)` ⇒ `(f)`; `(reduce f init nil)` ⇒ `init`.
|
||||
- E2. A `reduced` value as the *initial* `init` is NOT unwrapped before the
|
||||
first call in the reference — ⚠ under-documented; differential result to
|
||||
pin down and test before this entry is marked verified.
|
||||
- E3. Visit order over maps is entry order of the map's seq;
|
||||
over vectors/lists/seqs it is sequential order (normative).
|
||||
|
||||
**Errors**
|
||||
|
||||
- X1. Without `init`, on an empty coll, if `f` has no zero-arg arity the
|
||||
call `(f)` MUST throw (arity error).
|
||||
|
||||
**Examples**
|
||||
|
||||
```clojure
|
||||
(reduce + [1 2 3 4]) ;=> 10
|
||||
(reduce + 10 [1 2 3 4]) ;=> 20
|
||||
(reduce + []) ;=> 0 ; (+) is 0
|
||||
(reduce + [5]) ;=> 5 ; f not called
|
||||
(reduce (fn [a x] (if (> a 2) (reduced a) (+ a x))) 0 [1 2 3 4 5]) ;=> 3
|
||||
```
|
||||
|
||||
**Conformance**
|
||||
|
||||
S1–S3, E1 → jolt `sequences-spec` "map filter reduce" group +
|
||||
`transducers-spec` "reduce honors reduced"; clojure-test-suite
|
||||
`core_test/reduce.cljc`. S2 (single-element, f-not-called) → jolt conformance
|
||||
"reduce single no init". E2 → UNVERIFIED (differential test to add). S4 →
|
||||
`lazy-seqs-spec`.
|
||||
|
||||
---
|
||||
|
||||
### parse-uuid — since 1.11
|
||||
|
||||
```
|
||||
(parse-uuid s)
|
||||
```
|
||||
|
||||
**Semantics**
|
||||
|
||||
- S1. If `s` is a string in canonical UUID form — five groups of hex digits
|
||||
of lengths 8, 4, 4, 4, 12 separated by `-` — MUST return a UUID value `u`
|
||||
such that `(uuid? u)` is true and `(str u)` is the lowercase form of `s`.
|
||||
- S2. Parsing MUST be case-insensitive and equality on the results
|
||||
case-insensitive: `(= (parse-uuid s) (parse-uuid (upper-case s)))` is true.
|
||||
- S3. If `s` is a string not in canonical form, MUST return `nil`.
|
||||
⚠ reference-divergence: reference Clojure (java.util.UUID) additionally
|
||||
accepts non-canonical forms like `"0-0-0-0-0"`; ClojureScript and other
|
||||
dialects are strict. This spec adopts **strict** (the cross-dialect
|
||||
behavior); the reference's permissiveness is recorded as host leniency.
|
||||
- S4. UUID values MUST support value equality, hashing (usable as map keys
|
||||
and set members), `str` (lowercase canonical form), and print as the
|
||||
tagged literal `#uuid "…"` such that the printed form reads back equal
|
||||
(§2 tagged literals).
|
||||
|
||||
**Edge cases**
|
||||
|
||||
- E1. `""`, over-long, truncated, non-hex characters, and misplaced dashes
|
||||
⇒ `nil`.
|
||||
|
||||
**Errors**
|
||||
|
||||
- X1. A non-string argument MUST throw.
|
||||
|
||||
**Examples**
|
||||
|
||||
```clojure
|
||||
(parse-uuid "b6883c0a-0342-4007-9966-bc2dfa6b109e") ;=> #uuid "b6883c0a-…"
|
||||
(uuid? *1) ;=> true
|
||||
(parse-uuid "df0993") ;=> nil
|
||||
(parse-uuid 1000) ;; throws
|
||||
```
|
||||
|
||||
**Conformance**
|
||||
|
||||
S1–S4, E1, X1 → jolt `uuid-spec` (30 cases) + 6 three-path conformance
|
||||
cases; clojure-test-suite `core_test/parse_uuid.cljc`,
|
||||
`core_test/uuid_qmark.cljc`, `core_test/random_uuid.cljc`.
|
||||
|
||||
---
|
||||
|
||||
## Authoring notes
|
||||
|
||||
- Source examples from the ClojureDocs export (`clojuredocs-export.edn`,
|
||||
648 core vars have community examples) — but every example is verified
|
||||
against the reference before inclusion.
|
||||
- When writing an entry surfaces a behavior question, settle it by
|
||||
differential test first; if dialects split, that's a classification
|
||||
decision (host-dependent / divergence note), not a coin flip.
|
||||
- An entry is **Verified** when no field carries UNVERIFIED; `coverage.md`
|
||||
tracks per-var status.
|
||||
52
docs/spec/README.md
Normal file
52
docs/spec/README.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# The Clojure Language Specification (Draft)
|
||||
|
||||
A normative, implementation-independent specification of the Clojure
|
||||
language, developed alongside jolt's self-hosted compiler and validated by
|
||||
its executable conformance suites. **Why**: Clojure has no spec — every
|
||||
alternative implementation re-derives semantics from the reference
|
||||
implementation and folklore. See the RFC for motivation, scope, evidence
|
||||
sources, and process: [`../rfc/0001-language-specification.md`](../rfc/0001-language-specification.md).
|
||||
|
||||
## Documents
|
||||
|
||||
| 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 |
|
||||
| [`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 |
|
||||
|
||||
Regenerate the dashboard after surface changes:
|
||||
`python3 tools/spec_coverage.py` (requires `clojuredocs-export.json` in the
|
||||
repo root and a working jolt checkout).
|
||||
|
||||
## Current numbers (2026-06-10)
|
||||
|
||||
Of the 694 `clojure.core` vars in the ClojureDocs inventory:
|
||||
|
||||
- **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)
|
||||
|
||||
## How this connects to the test suites
|
||||
|
||||
- `test/integration/conformance-test.janet` — 302 assertions, each run
|
||||
through three independent execution paths (interpreter, bootstrap
|
||||
compiler, self-hosted compiler) that must agree. Spec entries cite these.
|
||||
- `test/spec/*.janet` — ~1,500 behavioral cases organized by topic.
|
||||
- `vendor/clojure-test-suite` — the cross-dialect suite (≥4081 assertions
|
||||
passing); dialect splits there are classification evidence.
|
||||
- jank's per-construct corpus (`~/src/jank/compiler+runtime/test/jank`) is
|
||||
the granularity model for §2/§3 conformance.
|
||||
|
||||
The invariant: **every numbered normative statement names its conformance
|
||||
test**, or is marked UNVERIFIED. The spec cannot drift from the
|
||||
implementations that check it.
|
||||
721
docs/spec/coverage.md
Normal file
721
docs/spec/coverage.md
Normal file
|
|
@ -0,0 +1,721 @@
|
|||
# Appendix A — Coverage Dashboard (generated)
|
||||
|
||||
Generated 2026-06-10 by `tools/spec_coverage.py` — do not edit by hand.
|
||||
|
||||
Surface: **694** clojure.core vars (ClojureDocs export; 648 with
|
||||
community examples). jolt interns 534 of them.
|
||||
|
||||
| Status | Count | Meaning |
|
||||
|---|---|---|
|
||||
| implemented+tested | 380 | in jolt and exercised by spec/conformance |
|
||||
| implemented-untested | 154 | in jolt, no direct test — spec entries will add them |
|
||||
| resolvable-not-interned | 22 | works in code but invisible to ns introspection (conformance finding) |
|
||||
| missing-portable | 35 | portable semantics, jolt lacks it — implementation gap |
|
||||
| special-form | 13 | 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 |
|
||||
| stm-refs | 11 | out of scope pending concurrency design note |
|
||||
| jvm-specific | 50 | 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
|
||||
UNVERIFIED field; that column will be added as entries land.
|
||||
|
||||
## Per-var status
|
||||
|
||||
| Var | Status | ClojureDocs examples |
|
||||
|---|---|---|
|
||||
| `*` | implemented+tested | ✓ |
|
||||
| `*'` | implemented-untested | ✓ |
|
||||
| `*1` | implemented-untested | ✓ |
|
||||
| `*2` | implemented-untested | ✓ |
|
||||
| `*3` | implemented-untested | ✓ |
|
||||
| `*agent*` | dynamic-var | ✓ |
|
||||
| `*allow-unresolved-vars*` | dynamic-var | ✓ |
|
||||
| `*assert*` | dynamic-var | ✓ |
|
||||
| `*clojure-version*` | implemented-untested | ✓ |
|
||||
| `*command-line-args*` | dynamic-var | ✓ |
|
||||
| `*compile-files*` | dynamic-var | ✓ |
|
||||
| `*compile-path*` | dynamic-var | ✓ |
|
||||
| `*compiler-options*` | dynamic-var | ✓ |
|
||||
| `*data-readers*` | dynamic-var | ✓ |
|
||||
| `*default-data-reader-fn*` | dynamic-var | ✓ |
|
||||
| `*e` | implemented-untested | ✓ |
|
||||
| `*err*` | implemented-untested | ✓ |
|
||||
| `*file*` | dynamic-var | ✓ |
|
||||
| `*flush-on-newline*` | dynamic-var | |
|
||||
| `*fn-loader*` | dynamic-var | |
|
||||
| `*in*` | dynamic-var | |
|
||||
| `*math-context*` | dynamic-var | |
|
||||
| `*ns*` | 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 | ✓ |
|
||||
| `*read-eval*` | dynamic-var | ✓ |
|
||||
| `*reader-resolver*` | dynamic-var | |
|
||||
| `*repl*` | dynamic-var | |
|
||||
| `*source-path*` | dynamic-var | ✓ |
|
||||
| `*suppress-read*` | dynamic-var | |
|
||||
| `*unchecked-math*` | implemented-untested | ✓ |
|
||||
| `*use-context-classloader*` | dynamic-var | ✓ |
|
||||
| `*verbose-defrecords*` | dynamic-var | |
|
||||
| `*warn-on-reflection*` | dynamic-var | ✓ |
|
||||
| `+` | implemented+tested | ✓ |
|
||||
| `+'` | implemented-untested | ✓ |
|
||||
| `-` | implemented+tested | ✓ |
|
||||
| `-'` | implemented-untested | ✓ |
|
||||
| `->` | implemented+tested | ✓ |
|
||||
| `->>` | implemented+tested | ✓ |
|
||||
| `->ArrayChunk` | jvm-specific | |
|
||||
| `->Eduction` | implemented-untested | |
|
||||
| `->Vec` | jvm-specific | |
|
||||
| `->VecNode` | jvm-specific | |
|
||||
| `->VecSeq` | jvm-specific | |
|
||||
| `-cache-protocol-fn` | jvm-specific | |
|
||||
| `-reset-methods` | jvm-specific | |
|
||||
| `.` | implemented-untested | ✓ |
|
||||
| `..` | implemented-untested | ✓ |
|
||||
| `/` | implemented-untested | ✓ |
|
||||
| `<` | implemented+tested | ✓ |
|
||||
| `<=` | implemented+tested | ✓ |
|
||||
| `=` | implemented+tested | ✓ |
|
||||
| `==` | implemented+tested | ✓ |
|
||||
| `>` | implemented+tested | ✓ |
|
||||
| `>=` | implemented+tested | ✓ |
|
||||
| `EMPTY-NODE` | jvm-specific | |
|
||||
| `Inst` | jvm-specific | |
|
||||
| `NaN?` | implemented+tested | ✓ |
|
||||
| `PrintWriter-on` | jvm-specific | ✓ |
|
||||
| `StackTraceElement->vec` | jvm-specific | ✓ |
|
||||
| `Throwable->map` | jvm-specific | ✓ |
|
||||
| `abs` | implemented+tested | ✓ |
|
||||
| `accessor` | jvm-specific | ✓ |
|
||||
| `aclone` | implemented-untested | ✓ |
|
||||
| `add-classpath` | jvm-specific | ✓ |
|
||||
| `add-tap` | agents-taps | ✓ |
|
||||
| `add-watch` | implemented+tested | ✓ |
|
||||
| `agent` | agents-taps | ✓ |
|
||||
| `agent-error` | agents-taps | ✓ |
|
||||
| `agent-errors` | agents-taps | |
|
||||
| `aget` | implemented+tested | ✓ |
|
||||
| `alength` | implemented+tested | ✓ |
|
||||
| `alias` | missing-portable | ✓ |
|
||||
| `all-ns` | implemented-untested | ✓ |
|
||||
| `alter` | stm-refs | ✓ |
|
||||
| `alter-meta!` | implemented+tested | ✓ |
|
||||
| `alter-var-root` | implemented+tested | ✓ |
|
||||
| `amap` | jvm-specific | ✓ |
|
||||
| `ancestors` | implemented+tested | ✓ |
|
||||
| `and` | implemented+tested | ✓ |
|
||||
| `any?` | implemented-untested | ✓ |
|
||||
| `apply` | implemented+tested | ✓ |
|
||||
| `areduce` | jvm-specific | ✓ |
|
||||
| `array-map` | implemented-untested | ✓ |
|
||||
| `as->` | implemented+tested | ✓ |
|
||||
| `aset` | implemented+tested | ✓ |
|
||||
| `aset-boolean` | implemented-untested | ✓ |
|
||||
| `aset-byte` | implemented-untested | ✓ |
|
||||
| `aset-char` | implemented-untested | ✓ |
|
||||
| `aset-double` | implemented-untested | ✓ |
|
||||
| `aset-float` | implemented-untested | ✓ |
|
||||
| `aset-int` | implemented-untested | ✓ |
|
||||
| `aset-long` | implemented-untested | ✓ |
|
||||
| `aset-short` | implemented-untested | ✓ |
|
||||
| `assert` | implemented+tested | ✓ |
|
||||
| `assoc` | implemented+tested | ✓ |
|
||||
| `assoc!` | implemented+tested | ✓ |
|
||||
| `assoc-in` | implemented+tested | ✓ |
|
||||
| `associative?` | implemented+tested | ✓ |
|
||||
| `atom` | implemented+tested | ✓ |
|
||||
| `await` | agents-taps | ✓ |
|
||||
| `await-for` | agents-taps | ✓ |
|
||||
| `await1` | agents-taps | |
|
||||
| `bases` | jvm-specific | ✓ |
|
||||
| `bean` | implemented-untested | ✓ |
|
||||
| `bigdec` | implemented+tested | ✓ |
|
||||
| `bigint` | implemented+tested | ✓ |
|
||||
| `biginteger` | implemented-untested | ✓ |
|
||||
| `binding` | implemented+tested | ✓ |
|
||||
| `bit-and` | implemented+tested | ✓ |
|
||||
| `bit-and-not` | implemented-untested | ✓ |
|
||||
| `bit-clear` | implemented+tested | ✓ |
|
||||
| `bit-flip` | implemented-untested | ✓ |
|
||||
| `bit-not` | implemented-untested | ✓ |
|
||||
| `bit-or` | implemented+tested | ✓ |
|
||||
| `bit-set` | implemented+tested | ✓ |
|
||||
| `bit-shift-left` | implemented+tested | ✓ |
|
||||
| `bit-shift-right` | implemented+tested | ✓ |
|
||||
| `bit-test` | implemented+tested | ✓ |
|
||||
| `bit-xor` | implemented+tested | ✓ |
|
||||
| `boolean` | implemented+tested | ✓ |
|
||||
| `boolean-array` | implemented-untested | ✓ |
|
||||
| `boolean?` | implemented+tested | ✓ |
|
||||
| `booleans` | implemented-untested | ✓ |
|
||||
| `bound-fn` | missing-portable | ✓ |
|
||||
| `bound-fn*` | missing-portable | ✓ |
|
||||
| `bound?` | missing-portable | ✓ |
|
||||
| `bounded-count` | implemented+tested | ✓ |
|
||||
| `butlast` | implemented+tested | ✓ |
|
||||
| `byte` | implemented-untested | ✓ |
|
||||
| `byte-array` | implemented-untested | ✓ |
|
||||
| `bytes` | implemented-untested | ✓ |
|
||||
| `bytes?` | implemented-untested | ✓ |
|
||||
| `case` | implemented+tested | ✓ |
|
||||
| `cast` | jvm-specific | ✓ |
|
||||
| `cat` | implemented-untested | ✓ |
|
||||
| `catch` | special-form | ✓ |
|
||||
| `char` | implemented+tested | ✓ |
|
||||
| `char-array` | implemented-untested | ✓ |
|
||||
| `char-escape-string` | implemented-untested | ✓ |
|
||||
| `char-name-string` | implemented-untested | ✓ |
|
||||
| `char?` | implemented+tested | ✓ |
|
||||
| `chars` | implemented-untested | ✓ |
|
||||
| `chunk` | implemented-untested | ✓ |
|
||||
| `chunk-append` | implemented-untested | ✓ |
|
||||
| `chunk-buffer` | implemented-untested | ✓ |
|
||||
| `chunk-cons` | implemented-untested | ✓ |
|
||||
| `chunk-first` | implemented-untested | ✓ |
|
||||
| `chunk-next` | implemented-untested | ✓ |
|
||||
| `chunk-rest` | implemented-untested | ✓ |
|
||||
| `chunked-seq?` | implemented+tested | ✓ |
|
||||
| `class` | implemented-untested | ✓ |
|
||||
| `class?` | jvm-specific | ✓ |
|
||||
| `clear-agent-errors` | agents-taps | |
|
||||
| `clojure-version` | implemented-untested | ✓ |
|
||||
| `coll?` | implemented+tested | ✓ |
|
||||
| `comment` | implemented+tested | ✓ |
|
||||
| `commute` | stm-refs | ✓ |
|
||||
| `comp` | implemented+tested | ✓ |
|
||||
| `comparator` | implemented+tested | ✓ |
|
||||
| `compare` | implemented+tested | ✓ |
|
||||
| `compare-and-set!` | implemented+tested | ✓ |
|
||||
| `compile` | implemented-untested | ✓ |
|
||||
| `complement` | implemented+tested | ✓ |
|
||||
| `completing` | implemented+tested | ✓ |
|
||||
| `concat` | implemented+tested | ✓ |
|
||||
| `cond` | implemented+tested | ✓ |
|
||||
| `cond->` | implemented+tested | ✓ |
|
||||
| `cond->>` | implemented+tested | ✓ |
|
||||
| `condp` | implemented+tested | ✓ |
|
||||
| `conj` | implemented+tested | ✓ |
|
||||
| `conj!` | implemented+tested | ✓ |
|
||||
| `cons` | implemented+tested | ✓ |
|
||||
| `constantly` | implemented+tested | ✓ |
|
||||
| `construct-proxy` | implemented-untested | ✓ |
|
||||
| `contains?` | implemented+tested | ✓ |
|
||||
| `count` | implemented+tested | ✓ |
|
||||
| `counted?` | implemented+tested | ✓ |
|
||||
| `create-ns` | implemented+tested | ✓ |
|
||||
| `create-struct` | jvm-specific | ✓ |
|
||||
| `cycle` | implemented+tested | ✓ |
|
||||
| `dec` | implemented+tested | ✓ |
|
||||
| `dec'` | implemented-untested | ✓ |
|
||||
| `decimal?` | implemented+tested | ✓ |
|
||||
| `declare` | implemented+tested | ✓ |
|
||||
| `dedupe` | implemented+tested | ✓ |
|
||||
| `def` | special-form | ✓ |
|
||||
| `default-data-readers` | jvm-specific | ✓ |
|
||||
| `definline` | jvm-specific | |
|
||||
| `definterface` | implemented-untested | ✓ |
|
||||
| `defmacro` | implemented+tested | ✓ |
|
||||
| `defmethod` | implemented+tested | ✓ |
|
||||
| `defmulti` | implemented+tested | ✓ |
|
||||
| `defn` | implemented+tested | ✓ |
|
||||
| `defn-` | implemented+tested | ✓ |
|
||||
| `defonce` | implemented+tested | ✓ |
|
||||
| `defprotocol` | implemented+tested | ✓ |
|
||||
| `defrecord` | implemented+tested | ✓ |
|
||||
| `defstruct` | jvm-specific | ✓ |
|
||||
| `deftype` | implemented+tested | ✓ |
|
||||
| `delay` | implemented+tested | ✓ |
|
||||
| `delay?` | implemented-untested | ✓ |
|
||||
| `deliver` | implemented+tested | ✓ |
|
||||
| `denominator` | implemented+tested | ✓ |
|
||||
| `deref` | implemented+tested | ✓ |
|
||||
| `derive` | implemented+tested | ✓ |
|
||||
| `descendants` | implemented+tested | ✓ |
|
||||
| `destructure` | implemented-untested | ✓ |
|
||||
| `disj` | implemented+tested | ✓ |
|
||||
| `disj!` | implemented+tested | ✓ |
|
||||
| `dissoc` | implemented+tested | ✓ |
|
||||
| `dissoc!` | implemented+tested | ✓ |
|
||||
| `distinct` | implemented+tested | ✓ |
|
||||
| `distinct?` | implemented+tested | ✓ |
|
||||
| `do` | special-form | ✓ |
|
||||
| `doall` | implemented+tested | ✓ |
|
||||
| `dorun` | implemented+tested | ✓ |
|
||||
| `doseq` | implemented+tested | ✓ |
|
||||
| `dosync` | stm-refs | ✓ |
|
||||
| `dotimes` | implemented+tested | ✓ |
|
||||
| `doto` | implemented+tested | ✓ |
|
||||
| `double` | implemented-untested | ✓ |
|
||||
| `double-array` | implemented-untested | ✓ |
|
||||
| `double?` | implemented+tested | ✓ |
|
||||
| `doubles` | implemented-untested | ✓ |
|
||||
| `drop` | implemented+tested | ✓ |
|
||||
| `drop-last` | implemented+tested | ✓ |
|
||||
| `drop-while` | implemented+tested | ✓ |
|
||||
| `eduction` | implemented+tested | ✓ |
|
||||
| `empty` | implemented+tested | ✓ |
|
||||
| `empty?` | implemented+tested | ✓ |
|
||||
| `ensure` | stm-refs | ✓ |
|
||||
| `ensure-reduced` | implemented-untested | ✓ |
|
||||
| `enumeration-seq` | implemented-untested | ✓ |
|
||||
| `error-handler` | agents-taps | ✓ |
|
||||
| `error-mode` | agents-taps | ✓ |
|
||||
| `eval` | implemented+tested | ✓ |
|
||||
| `even?` | implemented+tested | ✓ |
|
||||
| `every-pred` | implemented+tested | ✓ |
|
||||
| `every?` | implemented+tested | ✓ |
|
||||
| `ex-cause` | implemented+tested | ✓ |
|
||||
| `ex-data` | implemented+tested | ✓ |
|
||||
| `ex-info` | implemented+tested | ✓ |
|
||||
| `ex-message` | implemented+tested | ✓ |
|
||||
| `extend` | implemented-untested | ✓ |
|
||||
| `extend-protocol` | implemented+tested | ✓ |
|
||||
| `extend-type` | implemented+tested | ✓ |
|
||||
| `extenders` | missing-portable | ✓ |
|
||||
| `extends?` | implemented-untested | ✓ |
|
||||
| `false?` | implemented+tested | ✓ |
|
||||
| `ffirst` | implemented+tested | ✓ |
|
||||
| `file-seq` | missing-portable | ✓ |
|
||||
| `filter` | implemented+tested | ✓ |
|
||||
| `filterv` | implemented+tested | ✓ |
|
||||
| `finally` | special-form | ✓ |
|
||||
| `find` | implemented+tested | ✓ |
|
||||
| `find-keyword` | missing-portable | ✓ |
|
||||
| `find-ns` | implemented+tested | ✓ |
|
||||
| `find-protocol-impl` | jvm-specific | |
|
||||
| `find-protocol-method` | implemented-untested | |
|
||||
| `find-var` | implemented+tested | ✓ |
|
||||
| `first` | implemented+tested | ✓ |
|
||||
| `flatten` | implemented+tested | ✓ |
|
||||
| `float` | implemented-untested | ✓ |
|
||||
| `float-array` | implemented-untested | ✓ |
|
||||
| `float?` | implemented+tested | ✓ |
|
||||
| `floats` | implemented-untested | ✓ |
|
||||
| `flush` | implemented-untested | ✓ |
|
||||
| `fn` | implemented+tested | ✓ |
|
||||
| `fn?` | implemented+tested | ✓ |
|
||||
| `fnext` | implemented+tested | ✓ |
|
||||
| `fnil` | implemented+tested | ✓ |
|
||||
| `for` | implemented+tested | ✓ |
|
||||
| `force` | implemented+tested | ✓ |
|
||||
| `format` | implemented+tested | ✓ |
|
||||
| `frequencies` | implemented+tested | ✓ |
|
||||
| `future` | implemented+tested | ✓ |
|
||||
| `future-call` | implemented-untested | ✓ |
|
||||
| `future-cancel` | implemented+tested | ✓ |
|
||||
| `future-cancelled?` | implemented+tested | ✓ |
|
||||
| `future-done?` | implemented+tested | ✓ |
|
||||
| `future?` | implemented+tested | ✓ |
|
||||
| `gen-class` | jvm-specific | ✓ |
|
||||
| `gen-interface` | jvm-specific | ✓ |
|
||||
| `gensym` | implemented+tested | ✓ |
|
||||
| `get` | implemented+tested | ✓ |
|
||||
| `get-in` | implemented+tested | ✓ |
|
||||
| `get-method` | implemented+tested | ✓ |
|
||||
| `get-proxy-class` | implemented-untested | ✓ |
|
||||
| `get-thread-bindings` | missing-portable | ✓ |
|
||||
| `get-validator` | implemented+tested | ✓ |
|
||||
| `group-by` | implemented+tested | ✓ |
|
||||
| `halt-when` | implemented-untested | ✓ |
|
||||
| `hash` | implemented-untested | ✓ |
|
||||
| `hash-combine` | implemented-untested | ✓ |
|
||||
| `hash-map` | implemented+tested | ✓ |
|
||||
| `hash-ordered-coll` | implemented-untested | ✓ |
|
||||
| `hash-set` | implemented+tested | ✓ |
|
||||
| `hash-unordered-coll` | implemented-untested | ✓ |
|
||||
| `ident?` | implemented+tested | ✓ |
|
||||
| `identical?` | implemented+tested | ✓ |
|
||||
| `identity` | implemented+tested | ✓ |
|
||||
| `if` | special-form | ✓ |
|
||||
| `if-let` | implemented+tested | ✓ |
|
||||
| `if-not` | implemented+tested | ✓ |
|
||||
| `if-some` | implemented+tested | ✓ |
|
||||
| `ifn?` | implemented+tested | ✓ |
|
||||
| `import` | implemented+tested | ✓ |
|
||||
| `in-ns` | implemented+tested | ✓ |
|
||||
| `inc` | implemented+tested | ✓ |
|
||||
| `inc'` | implemented-untested | ✓ |
|
||||
| `indexed?` | implemented+tested | ✓ |
|
||||
| `infinite?` | implemented+tested | ✓ |
|
||||
| `init-proxy` | implemented-untested | ✓ |
|
||||
| `inst-ms` | implemented-untested | ✓ |
|
||||
| `inst-ms*` | missing-portable | |
|
||||
| `inst?` | implemented-untested | ✓ |
|
||||
| `instance?` | implemented+tested | ✓ |
|
||||
| `int` | implemented+tested | ✓ |
|
||||
| `int-array` | implemented-untested | ✓ |
|
||||
| `int?` | implemented+tested | ✓ |
|
||||
| `integer?` | implemented+tested | ✓ |
|
||||
| `interleave` | implemented+tested | ✓ |
|
||||
| `intern` | implemented+tested | ✓ |
|
||||
| `interpose` | implemented+tested | ✓ |
|
||||
| `into` | implemented+tested | ✓ |
|
||||
| `into-array` | implemented-untested | ✓ |
|
||||
| `ints` | implemented-untested | ✓ |
|
||||
| `io!` | stm-refs | ✓ |
|
||||
| `isa?` | implemented+tested | ✓ |
|
||||
| `iterate` | implemented+tested | ✓ |
|
||||
| `iteration` | jvm-specific | ✓ |
|
||||
| `iterator-seq` | implemented-untested | ✓ |
|
||||
| `juxt` | implemented+tested | ✓ |
|
||||
| `keep` | implemented+tested | ✓ |
|
||||
| `keep-indexed` | implemented+tested | ✓ |
|
||||
| `key` | implemented+tested | ✓ |
|
||||
| `keys` | implemented+tested | ✓ |
|
||||
| `keyword` | implemented+tested | ✓ |
|
||||
| `keyword?` | implemented+tested | ✓ |
|
||||
| `last` | implemented+tested | ✓ |
|
||||
| `lazy-cat` | implemented+tested | ✓ |
|
||||
| `lazy-seq` | implemented+tested | ✓ |
|
||||
| `let` | implemented+tested | ✓ |
|
||||
| `letfn` | implemented+tested | ✓ |
|
||||
| `line-seq` | implemented-untested | ✓ |
|
||||
| `list` | implemented+tested | ✓ |
|
||||
| `list*` | implemented+tested | ✓ |
|
||||
| `list?` | implemented+tested | ✓ |
|
||||
| `load` | jvm-specific | ✓ |
|
||||
| `load-file` | jvm-specific | ✓ |
|
||||
| `load-reader` | jvm-specific | ✓ |
|
||||
| `load-string` | implemented-untested | ✓ |
|
||||
| `loaded-libs` | jvm-specific | ✓ |
|
||||
| `locking` | implemented+tested | ✓ |
|
||||
| `long` | implemented-untested | ✓ |
|
||||
| `long-array` | implemented-untested | ✓ |
|
||||
| `longs` | implemented-untested | ✓ |
|
||||
| `loop` | implemented+tested | ✓ |
|
||||
| `macroexpand` | missing-portable | ✓ |
|
||||
| `macroexpand-1` | implemented+tested | ✓ |
|
||||
| `make-array` | implemented-untested | ✓ |
|
||||
| `make-hierarchy` | implemented+tested | ✓ |
|
||||
| `map` | implemented+tested | ✓ |
|
||||
| `map-entry?` | implemented+tested | ✓ |
|
||||
| `map-indexed` | implemented+tested | ✓ |
|
||||
| `map?` | implemented+tested | ✓ |
|
||||
| `mapcat` | implemented+tested | ✓ |
|
||||
| `mapv` | implemented+tested | ✓ |
|
||||
| `max` | implemented+tested | ✓ |
|
||||
| `max-key` | implemented+tested | ✓ |
|
||||
| `memfn` | implemented-untested | ✓ |
|
||||
| `memoize` | implemented+tested | ✓ |
|
||||
| `merge` | implemented+tested | ✓ |
|
||||
| `merge-with` | implemented+tested | ✓ |
|
||||
| `meta` | implemented+tested | ✓ |
|
||||
| `method-sig` | jvm-specific | ✓ |
|
||||
| `methods` | implemented+tested | ✓ |
|
||||
| `min` | implemented+tested | ✓ |
|
||||
| `min-key` | implemented+tested | ✓ |
|
||||
| `mix-collection-hash` | jvm-specific | |
|
||||
| `mod` | implemented+tested | ✓ |
|
||||
| `monitor-enter` | special-form | |
|
||||
| `monitor-exit` | special-form | |
|
||||
| `munge` | implemented-untested | ✓ |
|
||||
| `name` | implemented+tested | ✓ |
|
||||
| `namespace` | implemented+tested | ✓ |
|
||||
| `namespace-munge` | implemented+tested | ✓ |
|
||||
| `nat-int?` | implemented+tested | ✓ |
|
||||
| `neg-int?` | implemented+tested | ✓ |
|
||||
| `neg?` | implemented+tested | ✓ |
|
||||
| `new` | special-form | ✓ |
|
||||
| `newline` | missing-portable | ✓ |
|
||||
| `next` | implemented+tested | ✓ |
|
||||
| `nfirst` | implemented-untested | ✓ |
|
||||
| `nil?` | implemented+tested | ✓ |
|
||||
| `nnext` | implemented+tested | ✓ |
|
||||
| `not` | implemented+tested | ✓ |
|
||||
| `not-any?` | implemented+tested | ✓ |
|
||||
| `not-empty` | implemented+tested | ✓ |
|
||||
| `not-every?` | implemented+tested | ✓ |
|
||||
| `not=` | implemented+tested | ✓ |
|
||||
| `ns` | implemented+tested | ✓ |
|
||||
| `ns-aliases` | implemented-untested | ✓ |
|
||||
| `ns-imports` | implemented-untested | ✓ |
|
||||
| `ns-interns` | implemented-untested | ✓ |
|
||||
| `ns-map` | implemented-untested | ✓ |
|
||||
| `ns-name` | implemented+tested | ✓ |
|
||||
| `ns-publics` | missing-portable | ✓ |
|
||||
| `ns-refers` | missing-portable | ✓ |
|
||||
| `ns-resolve` | implemented+tested | ✓ |
|
||||
| `ns-unalias` | missing-portable | ✓ |
|
||||
| `ns-unmap` | implemented-untested | ✓ |
|
||||
| `nth` | implemented+tested | ✓ |
|
||||
| `nthnext` | implemented+tested | ✓ |
|
||||
| `nthrest` | implemented+tested | ✓ |
|
||||
| `num` | implemented+tested | ✓ |
|
||||
| `number?` | implemented+tested | ✓ |
|
||||
| `numerator` | implemented+tested | ✓ |
|
||||
| `object-array` | implemented+tested | ✓ |
|
||||
| `odd?` | implemented+tested | ✓ |
|
||||
| `or` | implemented+tested | ✓ |
|
||||
| `parents` | implemented+tested | ✓ |
|
||||
| `parse-boolean` | missing-portable | ✓ |
|
||||
| `parse-double` | missing-portable | ✓ |
|
||||
| `parse-long` | missing-portable | ✓ |
|
||||
| `parse-uuid` | implemented+tested | ✓ |
|
||||
| `partial` | implemented+tested | ✓ |
|
||||
| `partition` | implemented+tested | ✓ |
|
||||
| `partition-all` | implemented+tested | ✓ |
|
||||
| `partition-by` | implemented+tested | ✓ |
|
||||
| `partitionv` | missing-portable | |
|
||||
| `partitionv-all` | missing-portable | |
|
||||
| `pcalls` | jvm-specific | ✓ |
|
||||
| `peek` | implemented+tested | ✓ |
|
||||
| `persistent!` | implemented+tested | ✓ |
|
||||
| `pmap` | jvm-specific | ✓ |
|
||||
| `pop` | implemented+tested | ✓ |
|
||||
| `pop!` | implemented+tested | ✓ |
|
||||
| `pop-thread-bindings` | implemented-untested | |
|
||||
| `pos-int?` | implemented+tested | ✓ |
|
||||
| `pos?` | implemented+tested | ✓ |
|
||||
| `pr` | implemented+tested | ✓ |
|
||||
| `pr-str` | implemented+tested | ✓ |
|
||||
| `prefer-method` | implemented+tested | ✓ |
|
||||
| `prefers` | implemented-untested | ✓ |
|
||||
| `primitives-classnames` | jvm-specific | ✓ |
|
||||
| `print` | implemented+tested | ✓ |
|
||||
| `print-ctor` | jvm-specific | ✓ |
|
||||
| `print-dup` | implemented-untested | ✓ |
|
||||
| `print-method` | implemented-untested | ✓ |
|
||||
| `print-simple` | jvm-specific | ✓ |
|
||||
| `print-str` | implemented+tested | ✓ |
|
||||
| `printf` | implemented+tested | ✓ |
|
||||
| `println` | implemented+tested | ✓ |
|
||||
| `println-str` | implemented+tested | ✓ |
|
||||
| `prn` | implemented+tested | ✓ |
|
||||
| `prn-str` | implemented+tested | ✓ |
|
||||
| `promise` | implemented+tested | ✓ |
|
||||
| `proxy` | implemented-untested | ✓ |
|
||||
| `proxy-call-with-super` | implemented-untested | |
|
||||
| `proxy-mappings` | implemented-untested | ✓ |
|
||||
| `proxy-name` | jvm-specific | |
|
||||
| `proxy-super` | implemented-untested | ✓ |
|
||||
| `push-thread-bindings` | implemented-untested | |
|
||||
| `pvalues` | jvm-specific | ✓ |
|
||||
| `qualified-ident?` | implemented+tested | ✓ |
|
||||
| `qualified-keyword?` | implemented+tested | ✓ |
|
||||
| `qualified-symbol?` | implemented+tested | ✓ |
|
||||
| `quot` | implemented+tested | ✓ |
|
||||
| `quote` | special-form | ✓ |
|
||||
| `rand` | implemented+tested | ✓ |
|
||||
| `rand-int` | implemented+tested | ✓ |
|
||||
| `rand-nth` | implemented+tested | ✓ |
|
||||
| `random-sample` | implemented-untested | ✓ |
|
||||
| `random-uuid` | implemented+tested | ✓ |
|
||||
| `range` | implemented+tested | ✓ |
|
||||
| `ratio?` | implemented+tested | ✓ |
|
||||
| `rational?` | implemented+tested | ✓ |
|
||||
| `rationalize` | implemented+tested | ✓ |
|
||||
| `re-find` | implemented+tested | ✓ |
|
||||
| `re-groups` | implemented-untested | ✓ |
|
||||
| `re-matcher` | implemented-untested | ✓ |
|
||||
| `re-matches` | implemented+tested | ✓ |
|
||||
| `re-pattern` | implemented+tested | ✓ |
|
||||
| `re-seq` | implemented+tested | ✓ |
|
||||
| `read` | missing-portable | ✓ |
|
||||
| `read+string` | missing-portable | ✓ |
|
||||
| `read-line` | missing-portable | ✓ |
|
||||
| `read-string` | implemented+tested | ✓ |
|
||||
| `reader-conditional` | implemented-untested | ✓ |
|
||||
| `reader-conditional?` | implemented+tested | ✓ |
|
||||
| `realized?` | implemented+tested | ✓ |
|
||||
| `record?` | implemented+tested | ✓ |
|
||||
| `recur` | special-form | ✓ |
|
||||
| `reduce` | implemented+tested | ✓ |
|
||||
| `reduce-kv` | implemented+tested | ✓ |
|
||||
| `reduced` | implemented+tested | ✓ |
|
||||
| `reduced?` | implemented+tested | ✓ |
|
||||
| `reductions` | implemented+tested | ✓ |
|
||||
| `ref` | stm-refs | ✓ |
|
||||
| `ref-history-count` | stm-refs | ✓ |
|
||||
| `ref-max-history` | stm-refs | |
|
||||
| `ref-min-history` | stm-refs | ✓ |
|
||||
| `ref-set` | stm-refs | ✓ |
|
||||
| `refer` | implemented-untested | ✓ |
|
||||
| `refer-clojure` | implemented-untested | ✓ |
|
||||
| `reify` | implemented+tested | ✓ |
|
||||
| `release-pending-sends` | agents-taps | ✓ |
|
||||
| `rem` | implemented+tested | ✓ |
|
||||
| `remove` | implemented+tested | ✓ |
|
||||
| `remove-all-methods` | implemented+tested | ✓ |
|
||||
| `remove-method` | implemented+tested | ✓ |
|
||||
| `remove-ns` | implemented+tested | ✓ |
|
||||
| `remove-tap` | agents-taps | |
|
||||
| `remove-watch` | implemented+tested | ✓ |
|
||||
| `repeat` | implemented+tested | ✓ |
|
||||
| `repeatedly` | implemented+tested | ✓ |
|
||||
| `replace` | implemented+tested | ✓ |
|
||||
| `replicate` | implemented+tested | ✓ |
|
||||
| `require` | implemented+tested | ✓ |
|
||||
| `requiring-resolve` | jvm-specific | ✓ |
|
||||
| `reset!` | implemented+tested | ✓ |
|
||||
| `reset-meta!` | implemented-untested | ✓ |
|
||||
| `reset-vals!` | implemented+tested | ✓ |
|
||||
| `resolve` | implemented+tested | ✓ |
|
||||
| `rest` | implemented+tested | ✓ |
|
||||
| `restart-agent` | agents-taps | ✓ |
|
||||
| `resultset-seq` | jvm-specific | ✓ |
|
||||
| `reverse` | implemented+tested | ✓ |
|
||||
| `reversible?` | implemented+tested | ✓ |
|
||||
| `rseq` | implemented+tested | ✓ |
|
||||
| `rsubseq` | implemented+tested | ✓ |
|
||||
| `run!` | implemented+tested | ✓ |
|
||||
| `satisfies?` | implemented+tested | ✓ |
|
||||
| `second` | implemented+tested | ✓ |
|
||||
| `select-keys` | implemented+tested | ✓ |
|
||||
| `send` | agents-taps | ✓ |
|
||||
| `send-off` | agents-taps | ✓ |
|
||||
| `send-via` | agents-taps | ✓ |
|
||||
| `seq` | implemented+tested | ✓ |
|
||||
| `seq-to-map-for-destructuring` | implemented-untested | ✓ |
|
||||
| `seq?` | implemented+tested | ✓ |
|
||||
| `seqable?` | implemented+tested | ✓ |
|
||||
| `seque` | implemented-untested | ✓ |
|
||||
| `sequence` | implemented+tested | ✓ |
|
||||
| `sequential?` | implemented+tested | ✓ |
|
||||
| `set` | implemented+tested | ✓ |
|
||||
| `set!` | special-form | ✓ |
|
||||
| `set-agent-send-executor!` | agents-taps | ✓ |
|
||||
| `set-agent-send-off-executor!` | agents-taps | ✓ |
|
||||
| `set-error-handler!` | agents-taps | ✓ |
|
||||
| `set-error-mode!` | agents-taps | ✓ |
|
||||
| `set-validator!` | implemented+tested | ✓ |
|
||||
| `set?` | implemented+tested | ✓ |
|
||||
| `short` | implemented-untested | ✓ |
|
||||
| `short-array` | implemented-untested | ✓ |
|
||||
| `shorts` | implemented-untested | ✓ |
|
||||
| `shuffle` | implemented+tested | ✓ |
|
||||
| `shutdown-agents` | agents-taps | ✓ |
|
||||
| `simple-ident?` | implemented+tested | ✓ |
|
||||
| `simple-keyword?` | implemented+tested | ✓ |
|
||||
| `simple-symbol?` | implemented+tested | ✓ |
|
||||
| `slurp` | implemented-untested | ✓ |
|
||||
| `some` | implemented+tested | ✓ |
|
||||
| `some->` | implemented+tested | ✓ |
|
||||
| `some->>` | implemented+tested | ✓ |
|
||||
| `some-fn` | implemented+tested | ✓ |
|
||||
| `some?` | implemented+tested | ✓ |
|
||||
| `sort` | implemented+tested | ✓ |
|
||||
| `sort-by` | implemented+tested | ✓ |
|
||||
| `sorted-map` | implemented+tested | ✓ |
|
||||
| `sorted-map-by` | implemented+tested | ✓ |
|
||||
| `sorted-set` | implemented+tested | ✓ |
|
||||
| `sorted-set-by` | implemented+tested | ✓ |
|
||||
| `sorted?` | implemented+tested | ✓ |
|
||||
| `special-symbol?` | implemented-untested | ✓ |
|
||||
| `spit` | implemented-untested | ✓ |
|
||||
| `split-at` | implemented+tested | ✓ |
|
||||
| `split-with` | implemented+tested | ✓ |
|
||||
| `splitv-at` | missing-portable | |
|
||||
| `str` | implemented+tested | ✓ |
|
||||
| `stream-into!` | jvm-specific | |
|
||||
| `stream-reduce!` | jvm-specific | |
|
||||
| `stream-seq!` | jvm-specific | |
|
||||
| `stream-transduce!` | jvm-specific | |
|
||||
| `string?` | implemented+tested | ✓ |
|
||||
| `struct` | implemented-untested | ✓ |
|
||||
| `struct-map` | jvm-specific | ✓ |
|
||||
| `subs` | implemented+tested | ✓ |
|
||||
| `subseq` | implemented+tested | ✓ |
|
||||
| `subvec` | implemented+tested | ✓ |
|
||||
| `supers` | implemented-untested | ✓ |
|
||||
| `swap!` | implemented+tested | ✓ |
|
||||
| `swap-vals!` | implemented+tested | ✓ |
|
||||
| `symbol` | implemented+tested | ✓ |
|
||||
| `symbol?` | implemented+tested | ✓ |
|
||||
| `sync` | stm-refs | |
|
||||
| `tagged-literal` | implemented+tested | ✓ |
|
||||
| `tagged-literal?` | implemented+tested | |
|
||||
| `take` | implemented+tested | ✓ |
|
||||
| `take-last` | implemented+tested | ✓ |
|
||||
| `take-nth` | implemented+tested | ✓ |
|
||||
| `take-while` | implemented+tested | ✓ |
|
||||
| `tap>` | agents-taps | ✓ |
|
||||
| `test` | implemented-untested | ✓ |
|
||||
| `the-ns` | implemented+tested | ✓ |
|
||||
| `thread-bound?` | missing-portable | ✓ |
|
||||
| `throw` | special-form | ✓ |
|
||||
| `time` | missing-portable | ✓ |
|
||||
| `to-array` | implemented-untested | ✓ |
|
||||
| `to-array-2d` | implemented+tested | ✓ |
|
||||
| `trampoline` | implemented+tested | ✓ |
|
||||
| `transduce` | implemented+tested | ✓ |
|
||||
| `transient` | implemented+tested | ✓ |
|
||||
| `tree-seq` | implemented+tested | ✓ |
|
||||
| `true?` | implemented+tested | ✓ |
|
||||
| `try` | implemented+tested | ✓ |
|
||||
| `type` | implemented-untested | ✓ |
|
||||
| `unchecked-add` | implemented-untested | ✓ |
|
||||
| `unchecked-add-int` | implemented-untested | ✓ |
|
||||
| `unchecked-byte` | implemented-untested | ✓ |
|
||||
| `unchecked-char` | implemented-untested | |
|
||||
| `unchecked-dec` | implemented-untested | ✓ |
|
||||
| `unchecked-dec-int` | implemented-untested | ✓ |
|
||||
| `unchecked-divide-int` | implemented-untested | ✓ |
|
||||
| `unchecked-double` | implemented-untested | ✓ |
|
||||
| `unchecked-float` | implemented-untested | ✓ |
|
||||
| `unchecked-inc` | implemented-untested | ✓ |
|
||||
| `unchecked-inc-int` | implemented-untested | ✓ |
|
||||
| `unchecked-int` | implemented-untested | ✓ |
|
||||
| `unchecked-long` | implemented-untested | ✓ |
|
||||
| `unchecked-multiply` | implemented-untested | ✓ |
|
||||
| `unchecked-multiply-int` | implemented-untested | |
|
||||
| `unchecked-negate` | implemented-untested | ✓ |
|
||||
| `unchecked-negate-int` | implemented-untested | ✓ |
|
||||
| `unchecked-remainder-int` | implemented-untested | |
|
||||
| `unchecked-short` | implemented-untested | ✓ |
|
||||
| `unchecked-subtract` | implemented-untested | ✓ |
|
||||
| `unchecked-subtract-int` | implemented-untested | ✓ |
|
||||
| `underive` | implemented-untested | ✓ |
|
||||
| `unquote` | jvm-specific | ✓ |
|
||||
| `unquote-splicing` | jvm-specific | ✓ |
|
||||
| `unreduced` | implemented+tested | ✓ |
|
||||
| `unsigned-bit-shift-right` | implemented-untested | ✓ |
|
||||
| `update` | implemented+tested | ✓ |
|
||||
| `update-in` | implemented+tested | ✓ |
|
||||
| `update-keys` | missing-portable | ✓ |
|
||||
| `update-proxy` | implemented-untested | ✓ |
|
||||
| `update-vals` | missing-portable | ✓ |
|
||||
| `uri?` | implemented-untested | ✓ |
|
||||
| `use` | implemented+tested | ✓ |
|
||||
| `uuid?` | implemented+tested | ✓ |
|
||||
| `val` | implemented+tested | ✓ |
|
||||
| `vals` | implemented+tested | ✓ |
|
||||
| `var` | special-form | ✓ |
|
||||
| `var-get` | implemented+tested | ✓ |
|
||||
| `var-set` | implemented+tested | ✓ |
|
||||
| `var?` | implemented+tested | ✓ |
|
||||
| `vary-meta` | implemented+tested | ✓ |
|
||||
| `vec` | implemented+tested | ✓ |
|
||||
| `vector` | implemented+tested | ✓ |
|
||||
| `vector-of` | jvm-specific | ✓ |
|
||||
| `vector?` | implemented+tested | ✓ |
|
||||
| `volatile!` | implemented+tested | ✓ |
|
||||
| `volatile?` | implemented+tested | ✓ |
|
||||
| `vreset!` | implemented+tested | ✓ |
|
||||
| `vswap!` | implemented+tested | ✓ |
|
||||
| `when` | implemented+tested | ✓ |
|
||||
| `when-first` | implemented+tested | ✓ |
|
||||
| `when-let` | implemented+tested | ✓ |
|
||||
| `when-not` | implemented+tested | ✓ |
|
||||
| `when-some` | implemented+tested | ✓ |
|
||||
| `while` | implemented+tested | ✓ |
|
||||
| `with-bindings` | missing-portable | ✓ |
|
||||
| `with-bindings*` | missing-portable | ✓ |
|
||||
| `with-in-str` | missing-portable | ✓ |
|
||||
| `with-loading-context` | jvm-specific | |
|
||||
| `with-local-vars` | missing-portable | ✓ |
|
||||
| `with-meta` | implemented+tested | ✓ |
|
||||
| `with-open` | missing-portable | ✓ |
|
||||
| `with-out-str` | implemented+tested | ✓ |
|
||||
| `with-precision` | missing-portable | ✓ |
|
||||
| `with-redefs` | missing-portable | ✓ |
|
||||
| `with-redefs-fn` | missing-portable | ✓ |
|
||||
| `xml-seq` | implemented-untested | ✓ |
|
||||
| `zero?` | implemented+tested | ✓ |
|
||||
| `zipmap` | implemented+tested | ✓ |
|
||||
122
tools/spec_coverage.py
Normal file
122
tools/spec_coverage.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generate docs/spec/coverage.md — the spec status dashboard.
|
||||
|
||||
Cross-references three sources:
|
||||
1. clojuredocs-export.json — the clojure.core var inventory (the surface)
|
||||
2. jolt's interned clojure.core mappings (via janet)
|
||||
3. symbols exercised by test/spec/* + the 3-path conformance suite
|
||||
|
||||
Run from the repo root: python3 tools/spec_coverage.py
|
||||
"""
|
||||
import json, re, subprocess, glob, datetime
|
||||
from collections import Counter
|
||||
|
||||
# --- 1. the surface --------------------------------------------------------
|
||||
data = json.load(open('clojuredocs-export.json'))
|
||||
core = sorted(v['name'] for v in data['vars'] if v['ns'] == 'clojure.core')
|
||||
examples = {v['name'] for v in data['vars']
|
||||
if v['ns'] == 'clojure.core' and v.get('examples')}
|
||||
|
||||
# --- 2. what jolt provides ---------------------------------------------------
|
||||
# Two notions: INTERNED (in clojure.core's mappings — visible to ns
|
||||
# introspection) and RESOLVABLE (usable in code; some seed fns resolve through
|
||||
# fallback paths without being interned — itself a conformance finding).
|
||||
janet_prog = '''(use ./src/jolt/api) (use ./src/jolt/types) (use ./src/jolt/reader)
|
||||
(def ctx (init))
|
||||
(def core (ctx-find-ns ctx "clojure.core"))
|
||||
(each n (sort (keys (core :mappings))) (print "I " n))
|
||||
(def names (string/split "\\n" (slurp "/tmp/spec-surface-names.txt")))
|
||||
(each n names
|
||||
(when (> (length n) 0)
|
||||
# value-position probe: seed fns resolve through the core fallback even
|
||||
# when not interned (and jolt resolve can't see them — a finding itself).
|
||||
(def r (protect (do (def form (parse-string n))
|
||||
(when (and (struct? form) (= :symbol (form :jolt/type)))
|
||||
(eval-string ctx n) true))))
|
||||
(when (and (r 0) (= true (r 1))) (print "R " n))))'''
|
||||
open('/tmp/spec-surface-names.txt','w').write('\n'.join(core))
|
||||
out = subprocess.run(['janet', '-e', janet_prog], capture_output=True, text=True)
|
||||
interned = {l[2:] for l in out.stdout.splitlines() if l.startswith('I ')}
|
||||
resolvable = {l[2:] for l in out.stdout.splitlines() if l.startswith('R ')}
|
||||
jolt = interned | resolvable
|
||||
|
||||
# --- 3. what the tests exercise --------------------------------------------
|
||||
tested = set()
|
||||
sym = re.compile(r'\(([a-zA-Z*+!?<>=_-][a-zA-Z0-9*+!?<>=_./-]*)')
|
||||
for f in glob.glob('test/spec/*.janet') + ['test/integration/conformance-test.janet']:
|
||||
tested |= set(sym.findall(open(f).read()))
|
||||
|
||||
# --- classification ---------------------------------------------------------
|
||||
SPECIAL = {'catch','finally','do','def','defmacro','fn','if','let','loop','quote',
|
||||
'recur','throw','try','var','new','set!','monitor-enter','monitor-exit'}
|
||||
AGENTS = {'agent','send','send-off','send-via','await','await-for','await1',
|
||||
'agent-error','agent-errors','clear-agent-errors','error-handler',
|
||||
'error-mode','set-agent-send-executor!','set-agent-send-off-executor!',
|
||||
'restart-agent','shutdown-agents','release-pending-sends','add-tap',
|
||||
'tap>','remove-tap','set-error-handler!','set-error-mode!'}
|
||||
STM = {'dosync','ref','ref-set','alter','commute','ensure','ref-history-count',
|
||||
'ref-max-history','ref-min-history','sync','io!'}
|
||||
JVM = {'class','class?','cast','bases','supers','compile','add-classpath',
|
||||
'definline','bean','accessor','create-struct','defstruct','struct',
|
||||
'struct-map','amap','areduce','memfn','enumeration-seq','iterator-seq',
|
||||
'resultset-seq','print-ctor','print-dup','print-method','print-simple',
|
||||
'primitives-classnames','vector-of','PrintWriter-on',
|
||||
'StackTraceElement->vec','Throwable->map','Inst','->ArrayChunk','->Vec',
|
||||
'->VecNode','->VecSeq','-cache-protocol-fn','-reset-methods','EMPTY-NODE',
|
||||
'method-sig','proxy-name','gen-class','gen-interface','find-protocol-impl',
|
||||
'find-protocol-method','with-loading-context','load','load-file',
|
||||
'load-reader','loaded-libs','requiring-resolve','default-data-readers',
|
||||
'..','.','pcalls','pmap','pvalues','stream-into!','stream-reduce!',
|
||||
'stream-seq!','stream-transduce!','mix-collection-hash','iteration',
|
||||
'unquote','unquote-splicing'}
|
||||
|
||||
def classify(n):
|
||||
if n in jolt:
|
||||
return 'implemented+tested' if n in tested else 'implemented-untested'
|
||||
if re.match(r'^\*.*\*$', n): return 'dynamic-var'
|
||||
if n in SPECIAL: return 'special-form'
|
||||
if n in AGENTS: return 'agents-taps'
|
||||
if n in STM: return 'stm-refs'
|
||||
if n in JVM: return 'jvm-specific'
|
||||
return 'missing-portable'
|
||||
|
||||
cls = {n: classify(n) for n in core}
|
||||
counts = Counter(cls.values())
|
||||
stamp = datetime.date.today().isoformat()
|
||||
|
||||
rows = []
|
||||
for n in core:
|
||||
rows.append(f"| `{n}` | {cls[n]} | {'✓' if n in examples else ''} |")
|
||||
|
||||
md = f"""# Appendix A — Coverage Dashboard (generated)
|
||||
|
||||
Generated {stamp} by `tools/spec_coverage.py` — do not edit by hand.
|
||||
|
||||
Surface: **{len(core)}** clojure.core vars (ClojureDocs export; {len(examples)} with
|
||||
community examples). jolt interns {len(jolt & set(core))} of them.
|
||||
|
||||
| Status | Count | Meaning |
|
||||
|---|---|---|
|
||||
| implemented+tested | {counts['implemented+tested']} | in jolt and exercised by spec/conformance |
|
||||
| implemented-untested | {counts['implemented-untested']} | in jolt, no direct test — spec entries will add them |
|
||||
| resolvable-not-interned | {len((resolvable - interned) & set(core))} | works in code but invisible to ns introspection (conformance finding) |
|
||||
| missing-portable | {counts['missing-portable']} | portable semantics, jolt lacks it — implementation gap |
|
||||
| special-form | {counts['special-form']} | specified in §3, not a library var |
|
||||
| dynamic-var | {counts['dynamic-var']} | classification needed: portable default vs host-dependent |
|
||||
| agents-taps | {counts['agents-taps']} | out of scope pending concurrency design note |
|
||||
| stm-refs | {counts['stm-refs']} | out of scope pending concurrency design note |
|
||||
| jvm-specific | {counts['jvm-specific']} | 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
|
||||
UNVERIFIED field; that column will be added as entries land.
|
||||
|
||||
## Per-var status
|
||||
|
||||
| Var | Status | ClojureDocs examples |
|
||||
|---|---|---|
|
||||
{chr(10).join(rows)}
|
||||
"""
|
||||
open('docs/spec/coverage.md', 'w').write(md)
|
||||
print(f"wrote docs/spec/coverage.md — {len(core)} vars")
|
||||
for k, v in counts.most_common(): print(f" {k}: {v}")
|
||||
Loading…
Add table
Add a link
Reference in a new issue