core: #inst instant values + syntax-quote literal collapse (spec 2.3/2.4)

#inst (jolt-rnh): an instant is an immutable tagged struct
{:jolt/type :jolt/inst :ms <epoch-millis>} — equality and map-key hashing by
INSTANT, so different offsets denoting the same moment are =. The reader
parses RFC3339 with Clojure's partial-timestamp defaults (#inst "2020" is
2020-01-01T00:00:00.000Z) and errors on malformed input; inst?/inst-ms in
the overlay; pr-str prints the canonical
#inst "yyyy-MM-ddThh:mm:ss.fff-00:00" and round-trips; str gives the bare
RFC3339 string. Self-evaluating in the evaluator (like uuid/chars).

Syntax-quote (jolt-l2a): a syntax-quoted self-evaluating literal (string,
number, boolean, nil, keyword, char) collapses to the literal at READ time,
matching Clojure's reader — so nested/adjacent backticks over literals are
inert: (= "meow" ```"meow") is true (jank pass-adjacent). Symbols still
qualify and collections still template. General nested syntax-quote over
non-literals remains UNVERIFIED in spec S25.

Tests: inst-spec (18 cases incl. partial defaults, offsets, round-trip),
+10 literal-collapse reader rows, +5 conformance rows (321x3). Spec
02-reader S20/S25 updated to normative. Suite stable 4470/86.
This commit is contained in:
Yogthos 2026-06-10 12:19:23 -04:00
parent 094152a8c3
commit e58be2fbd2
10 changed files with 169 additions and 17 deletions

View file

@ -1,7 +1,7 @@
# §2 The Reader (Lexical Syntax)
**Status**: token grammar drafted; reader-macro catalog complete with
normative entries; syntax-quote section carries two open divergences.
normative entries; #inst and literal-collapse divergences resolved.
Conformance: jolt `reader-forms-spec` + `reader-syntax-spec` (granularity
model: jank's per-construct corpus, 62 files under
`test/jank/{reader-macro,syntax-quote}` — adapted rows cited per entry).
@ -150,9 +150,12 @@ false; `(NaN? ##NaN)` is true.
read value. An unknown tag MUST be a read error (jank
`fail-unsupported-tag`).
- Built-in tags every implementation MUST provide: `#uuid "…"` → a UUID
value (§9 `parse-uuid` semantics — round-trips through printing), `#inst
"…"` → an instant (representation host-classified; ⚠ jolt currently reads
`#inst` as its bare string — divergence, filed).
value (§9 `parse-uuid` semantics — round-trips through printing), and
`#inst "…"` → an instant value: RFC3339 with partial-timestamp defaults
(`#inst "2020"``#inst "2020-01-01T00:00:00.000-00:00"`), equality by
instant (offset-normalized), `inst?`/`inst-ms` (epoch milliseconds), printed
canonically as `#inst "yyyy-MM-ddThh:mm:ss.fff-00:00"` and round-tripping. A
malformed timestamp MUST be an error.
**Conformance** (2.3): jolt `reader-forms-spec` "#() (% %N %&)" + new rows
(symbolic values, stacked discard, conditionals); `uuid-spec` reader-literal
@ -176,10 +179,11 @@ resolution:
value; `~'sym` is the idiom for an intentionally-unqualified symbol.
- S24. Syntax-quote distributes through collection literals (vectors, maps,
sets) — qualification and unquoting apply inside them.
- S25. Nested syntax-quotes expand recursively (quasiquote semantics); a
syntax-quoted self-evaluating literal is the literal: `(= "meow"
```"meow")` is true. ⚠ jolt currently fails S25 (filed) — UNVERIFIED
pending the fix.
- S25. A syntax-quoted self-evaluating literal is the literal, collapsed at
read time — so nested/adjacent backticks over literals are inert:
`(= "meow" ```"meow")` is true. General nested syntax-quote over symbols
and collections expands recursively (quasiquote semantics) — that general
case remains UNVERIFIED pending dedicated conformance rows.
**Conformance**: jolt `reader-forms-spec` "syntax-quote" (gensym, unquote,
splice) + conformance "syntax-quote fully-qualifies"; jank

View file

@ -7,8 +7,8 @@ community examples). jolt interns 550 of them.
| Status | Count | Meaning |
|---|---|---|
| implemented+tested | 397 | in jolt and exercised by spec/conformance |
| implemented-untested | 153 | in jolt, no direct test — spec entries will add them |
| implemented+tested | 399 | in jolt and exercised by spec/conformance |
| implemented-untested | 151 | 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 | 19 | portable semantics, jolt lacks it — implementation gap |
| special-form | 13 | specified in §3, not a library var |
@ -345,9 +345,9 @@ UNVERIFIED field; that column will be added as entries land.
| `indexed?` | implemented+tested | ✓ |
| `infinite?` | implemented+tested | ✓ |
| `init-proxy` | implemented-untested | ✓ |
| `inst-ms` | implemented-untested | ✓ |
| `inst-ms` | implemented+tested | ✓ |
| `inst-ms*` | missing-portable | |
| `inst?` | implemented-untested | ✓ |
| `inst?` | implemented+tested | ✓ |
| `instance?` | implemented+tested | ✓ |
| `int` | implemented+tested | ✓ |
| `int-array` | implemented-untested | ✓ |