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:
parent
094152a8c3
commit
e58be2fbd2
10 changed files with 169 additions and 17 deletions
|
|
@ -193,6 +193,13 @@
|
|||
["macroexpand" "true" "(= (quote if) (first (macroexpand (quote (when-not false 1)))))"]
|
||||
["require bare symbol" "\"a,b\"" "(do (require (quote clojure.string)) (clojure.string/join \",\" [\"a\" \"b\"]))"]
|
||||
["ns-publics lookup" "true" "(do (def cnp 7) (some? (get (ns-publics (quote user)) (quote cnp))))"]
|
||||
|
||||
### ---- #inst + syntax-quote literal collapse (spec 2.4/2.3) ----
|
||||
["inst? + inst-ms" "0" "(inst-ms #inst \"1970-01-01T00:00:00Z\")"]
|
||||
["inst partial = full" "true" "(= #inst \"2020\" #inst \"2020-01-01T00:00:00Z\")"]
|
||||
["inst offset normalized" "true" "(= #inst \"2020-01-01T01:00:00+01:00\" #inst \"2020-01-01T00:00:00Z\")"]
|
||||
["sq literal collapse" "true" "(= \"meow\" ```\"meow\")"]
|
||||
["sq number collapse" "42" "``42"]
|
||||
["macroexpand-1 when" "2" "(count (rest (macroexpand-1 (quote (when true 1)))))"]
|
||||
|
||||
### ---- HIGH: aliased namespace calls ----
|
||||
|
|
|
|||
30
test/spec/inst-spec.janet
Normal file
30
test/spec/inst-spec.janet
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Specification: #inst literals — instants as values (spec 02-reader S20).
|
||||
# An instant is an immutable tagged struct {:jolt/type :jolt/inst :ms <epoch-ms>}:
|
||||
# value equality by instant (offset-normalized), usable as map keys.
|
||||
# The reader accepts RFC3339 with Clojure's partial-timestamp defaults
|
||||
# (#inst "2020" == #inst "2020-01-01T00:00:00.000-00:00").
|
||||
(use ../support/harness)
|
||||
|
||||
(defspec "inst / reading & identity"
|
||||
["reads to inst" "true" "(inst? #inst \"2020-01-01T00:00:00Z\")"]
|
||||
["inst? false on string" "false" "(inst? \"2020-01-01\")"]
|
||||
["epoch zero" "0" "(inst-ms #inst \"1970-01-01T00:00:00Z\")"]
|
||||
["one second" "1000" "(inst-ms #inst \"1970-01-01T00:00:01Z\")"]
|
||||
["millis" "123" "(inst-ms #inst \"1970-01-01T00:00:00.123Z\")"]
|
||||
["a real date" "1577836800000" "(inst-ms #inst \"2020-01-01T00:00:00Z\")"]
|
||||
["inst-ms throws on non-inst" :throws "(inst-ms 42)"])
|
||||
|
||||
(defspec "inst / partial timestamps & offsets"
|
||||
["year only" "true" "(= #inst \"2020\" #inst \"2020-01-01T00:00:00.000Z\")"]
|
||||
["year-month" "true" "(= #inst \"2020-03\" #inst \"2020-03-01T00:00:00Z\")"]
|
||||
["date only" "true" "(= #inst \"2020-03-15\" #inst \"2020-03-15T00:00:00Z\")"]
|
||||
["positive offset" "true" "(= #inst \"2020-01-01T01:00:00+01:00\" #inst \"2020-01-01T00:00:00Z\")"]
|
||||
["negative offset" "true" "(= #inst \"2019-12-31T23:00:00-01:00\" #inst \"2020-01-01T00:00:00Z\")"]
|
||||
["-00:00 offset" "true" "(= #inst \"2020-01-01T00:00:00-00:00\" #inst \"2020-01-01T00:00:00Z\")"]
|
||||
["bad timestamp throws" :throws "#inst \"garbage\""])
|
||||
|
||||
(defspec "inst / value semantics & printing"
|
||||
["equal by instant" "true" "(= #inst \"2020-01-01T00:00:00Z\" #inst \"2020-01-01T00:00:00.000Z\")"]
|
||||
["unequal instants" "false" "(= #inst \"2020-01-01T00:00:00Z\" #inst \"2020-01-01T00:00:01Z\")"]
|
||||
["works as map key" ":v" "(get {#inst \"2020-01-01T00:00:00Z\" :v} #inst \"2020-01-01T00:00:00.000Z\")"]
|
||||
["pr-str round-trips" "\"#inst \\\"2020-01-01T00:00:00.000-00:00\\\"\"" "(pr-str #inst \"2020-01-01T00:00:00Z\")"])
|
||||
|
|
@ -63,3 +63,18 @@
|
|||
["var-quote qualified" "true" "(= (var clojure.core/str) #'clojure.core/str)"]
|
||||
["gensym stable in template" "true" "(let [syms `[meow# meow#]] (= (first syms) (second syms)))"]
|
||||
["gensym fresh across templates" "false" "(= `meow# `meow#)"])
|
||||
|
||||
# Spec 02-reader S25: syntax-quote of a self-evaluating literal is the literal
|
||||
# (read-time collapse), so adjacent/nested backticks over literals are inert.
|
||||
(defspec "reader / syntax-quote literal collapse (spec 2.4 S25)"
|
||||
["string once" "true" "(= \"meow\" `\"meow\")"]
|
||||
["string nested" "true" "(= \"meow\" ``\"meow\")"]
|
||||
["string triple" "true" "(= \"meow\" ```\"meow\")"]
|
||||
["number nested" "true" "(= 42 ``42)"]
|
||||
["keyword nested" "true" "(= :k ``:k)"]
|
||||
["nil nested" "true" "(nil? ``nil)"]
|
||||
["char nested" "true" "(= \\a ``\\a)"]
|
||||
["bool nested" "true" "(= true ``true)"]
|
||||
# collapse must NOT apply to symbols (they qualify) or collections (templates)
|
||||
["symbol still qualifies" "true" "(= (quote clojure.core/map) `map)"]
|
||||
["vector still templates" "true" "(= [1 2] `[1 ~(inc 1)])"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue