Skip to main content

Atom

Enum Atom 

Source
pub enum Atom {
    Symbol(String),
    Keyword(String),
    Str(String),
    Int(i64),
    Float(f64),
    Bool(bool),
}

Variants§

§

Symbol(String)

Plain symbol (foo, defpoint, seph.1).

§

Keyword(String)

Keyword (:parent, :attr) — a symbol bound to itself.

§

Str(String)

String literal.

§

Int(i64)

Integer literal.

§

Float(f64)

Floating literal.

§

Bool(bool)

Boolean literal (#t, #f).

Implementations§

Source§

impl Atom

Source

pub const KEYWORD_MARKER: &'static str = ":"

The canonical : marker prefix that a Self::Keyword payload projects THROUGH when rendered as / classified from its canonical-string surface across the substrate’s four Keyword-round-trip sites — the reader-entry classifier (Self::from_lexeme), the Lisp-canonical-form projection ([fmt::Display for Atom]), the JSON-canonical-form projection (Self::to_json), and the iac-forge-canonical-form projection (Atom::to_iac_forge_sexpr (removed)).

Pre-lift the same ":" byte lived inline at four sites: ':' (as a char pattern) at the Self::from_lexeme strip site and ":{s}" (three byte-identical format-string literals) at the three canonical-form projection sites. Post-lift the marker byte lives at ONE canonical constant on the Atom algebra that all four sites bind to; a future refactor that swaps the marker (e.g. a Racket-compat port to #:name, a Clojure-compat port to ::name) touches ONE line rather than four inline bytes that would silently drift out of round-trip agreement if one was updated without the others.

Load-bearing round-trip contract: Self::from_lexeme(&Self::keyword(name).to_string()) == Self::keyword(name) — the reader-entry classifier’s strip_prefix(Self::KEYWORD_MARKER) gate and the Lisp-canonical [Display]’s write!(f, "{}{name}", Self::KEYWORD_MARKER) emission both bind to THIS constant so the pair cannot drift. Cross-surface round-trip: Self::to_json and Atom::to_iac_forge_sexpr (removed) emit the same prefix so any BLAKE3 attestation over an iac-forge canonical form of a Keyword atom matches the JSON canonical form byte-for-byte on the prefix axis.

Sibling-shape lift to the workspace’s other prefix-marker constants: crate::error::UnquoteForm::ALL projects each template-marker variant to its punctuation prefix via crate::ast::QuoteForm::prefix ("'", ", ”,“, ”,@“) — a peer axis on the substrate's marker-byte algebra. This constant sits on the [Atom] algebra at the atomic-payload axis where the [QuoteForm::prefix`] projection sits at the homoiconic-wrapper axis.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Keyword payload, canonical : prefix) pairing now binds at ONE constant on the closed-set Atom algebra regardless of which of the four reader-entry / rendering surfaces reaches in. THEORY.md §VI.1 — generation over composition; the four byte-identical ":" / ":{s}" inline literals collapse onto ONE named constant, matching the substrate’s three-times rule (four occurrences, well past the ≥2 lift threshold). THEORY.md §V.1 — knowable platform; the canonical keyword-marker byte becomes a TYPE-level constant on the substrate algebra rather than four inline bytes at four consumer surfaces.

Source

pub const KEYWORD_MARKER_LEAD: char = ':'

Canonical : LEAD char of the Self::KEYWORD_MARKER prefix (":") — the ONE canonical char on the Atom algebra the substrate’s Keyword-prefix lead-byte disjointness contract binds to.

Sibling posture to the closed set of pub const reader-punctuation canonical char bytes on the substrate: Self::STR_DELIMITER ('"'), Self::STR_ESCAPE_LEAD ('\\'), Self::BOOL_LITERAL_LEAD ('#'), Sexp::LIST_OPEN ('('), Sexp::LIST_CLOSE (')'), Sexp::COMMENT_LEAD (';'), Sexp::COMMENT_TERM ('\n'), QuoteForm::SPLICE_DISCRIMINATOR ('@') — every canonical per-role byte the reader’s tokenizer specialises on is a pub const on its owning closed-set algebra. This constant closes the Keyword-prefix lead byte at the SAME algebra as its one-char Self::KEYWORD_MARKER &'static str projection — the ONE char that the &'static str projects to when the substrate’s consumer needs a char (not a &str) for cross-axis marker-byte comparisons or for the reader’s specific-arm outer-dispatch.

Structural round-trip contract: Self::KEYWORD_MARKER.starts_with(Self::KEYWORD_MARKER_LEAD) — pinned by atom_keyword_marker_lead_prefixes_keyword_marker. A regression that drifts EITHER the constant OR the Self::KEYWORD_MARKER spelling surfaces at the pin rather than at a silent Keyword- prefix reader drift where :foo classifies as Self::Symbol instead of Self::Keyword. Sibling-shape peer of Self::BOOL_LITERAL_LEAD’s Self::bool_literal(b).starts_with(Self::BOOL_LITERAL_LEAD) round-trip law: where that pin binds the Bool-family two spellings to their shared lead byte, this pin binds the Keyword-marker one-char prefix to its projected lead byte.

Disjointness contract: KEYWORD_MARKER_LEAD’s byte MUST differ from Self::STR_DELIMITER ('"'), Self::STR_ESCAPE_LEAD ('\\'), Self::BOOL_LITERAL_LEAD ('#'), Sexp::LIST_OPEN ('('), Sexp::LIST_CLOSE (')'), Sexp::COMMENT_LEAD (';'), Sexp::COMMENT_TERM ('\n'), every QuoteForm::lead_char projection AND QuoteForm::SPLICE_DISCRIMINATOR ('@') — every other closed-set outer-marker byte the reader’s tokenizer specialises on. A collision would silently break the reader’s outer dispatch: a :-prefixed bare atom :foo would collide with whichever marker it aliased. Pinned by atom_keyword_marker_lead_distinct_from_every_other_algebra_marker.

Consumer sites this constant closes: SEVEN test-surface sites that pre-lift each extracted the lead byte via Atom::KEYWORD_MARKER.chars().next().expect(_) (or .unwrap()) — the Keyword arm of the Sexp::is_bare_atom_boundary negative sweep AND the six cross-axis disjointness pins on the sibling marker-byte algebras (QuoteForm::SPLICE_DISCRIMINATOR, Self::BOOL_LITERAL_LEAD, Self::STR_DELIMITER, Self::STR_ESCAPE_LEAD, Sexp::LIST_OPEN / Sexp::LIST_CLOSE, Sexp::COMMENT_LEAD, Sexp::COMMENT_TERM) — collapse onto ONE named byte on the substrate algebra.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Keyword-prefix lead byte, canonical ':') pairing binds at ONE constant on the closed-set outer Atom algebra regardless of which reader-surface consumer reaches in. THEORY.md §II.1 invariant 5 — composition preserves proofs; the Self::KEYWORD_MARKER.starts_with(Self::KEYWORD_MARKER_LEAD) round-trip law is a coherence proof BETWEEN the paired projection (Self::KEYWORD_MARKER) AND its projected lead byte (this constant) on ONE algebra — a regression that drifts either side surfaces at the pin rather than as a silent Keyword-prefix reader drift. THEORY.md §V.1 — knowable platform; the canonical Keyword-prefix lead byte becomes a TYPE-level constant on the substrate algebra rather than an inline .chars().next().expect(_) extraction at every test surface AND an inline ':' mention across every docstring pinning the disjointness contract.

Frontier inspiration: Racket’s read-syntax colon-prefix reader hook (#:name for keyword args, ::name for module-scoped bindings in some dialects) — where the : prefix dispatches keyword-family reader-macros keyed on ONE typed lead byte on the port’s reader table. Translated to tatara-lisp: Atom::KEYWORD_MARKER_LEAD becomes the ONE typed lead byte on the closed-set outer Atom algebra that a future keyword-family peer method (e.g. a Clojure-compat port to ::foo namespaced keywords) can extend through — the paired-prefix discipline that Racket’s read-syntax table carries lands here as a pub const on the algebra rather than as an inline char literal at every consumer site.

Source

pub const TRUE_LITERAL: &'static str = "#t"

Canonical &'static str Scheme-bool spelling for the true element of the closed bool domain — the "#t" bytes Self::bool_literal projects true to, AND the Self::from_lexeme reader classifier gates on. Sibling posture to Self::FALSE_LITERAL ("#f") on the same bool-spelling algebra layer.

Pre-lift the same "#t" bytes lived inline at Self::bool_literal’s true-arm plus at five test-surface sites that pin the canonical spelling — the ≥2 PRIME-DIRECTIVE trigger. Post-lift the (true, canonical Scheme spelling) pairing binds at ONE pub const on the closed-set Atom algebra: the Self::bool_literal true-arm AND every consumer that pins the exact bytes route through this constant, so a spelling migration (e.g. a Common-Lisp-compat port to "T", a JSON-compat port to "true", a Racket-compat port to "#true") is ONE edit HERE with the Self::bool_literal projection AND every downstream reader/Display consumer mechanically picking it up.

Sibling posture to the closed set of per-role canonical pub const bytes on the substrate’s other closed-set outer algebras: Self::STR_DELIMITER ('"'), Self::KEYWORD_MARKER (":"), Sexp::LIST_OPEN ('('), crate::error::MacroDefHead::DEFMACRO_KEYWORD ("defmacro"), crate::macro_expand::MacroParams::REST_MARKER ("&rest"), crate::macro_expand::MacroParams::OPTIONAL_MARKER ("&optional").

Structural round-trip contract (composed with the algebra’s Self::BOOL_LITERAL_LEAD axis peer): Self::TRUE_LITERAL.starts_with(Self::BOOL_LITERAL_LEAD) — the lead-byte-prefixes-spelling law from atom_bool_literal_lead_prefixes_every_bool_literal_spelling specialises byte-for-byte to this constant, pinning the (BOOL_LITERAL_LEAD, TRUE_LITERAL) pairing on ONE typed algebra.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (true, canonical Scheme spelling) pairing binds at ONE pub const on the closed-set outer Atom algebra regardless of which of the reader/Display surface consumers reaches in. THEORY.md §VI.1 — generation over composition; the multi-site inline "#t" literal collapses onto ONE named pub const, matching the substrate’s three-times rule. THEORY.md §V.1 — knowable platform; the canonical true-spelling becomes a TYPE-level constant on the substrate algebra rather than an inline byte literal at every consumer surface.

Source

pub const FALSE_LITERAL: &'static str = "#f"

Canonical &'static str Scheme-bool spelling for the false element of the closed bool domain — the "#f" bytes Self::bool_literal projects false to, AND the Self::from_lexeme reader classifier gates on. Sibling posture to Self::TRUE_LITERAL ("#t") on the same bool-spelling algebra layer.

Pre-lift the same "#f" bytes lived inline at Self::bool_literal’s false-arm plus at five test-surface sites that pin the canonical spelling — the ≥2 PRIME-DIRECTIVE trigger. Post-lift the (false, canonical Scheme spelling) pairing binds at ONE pub const on the closed-set Atom algebra: the Self::bool_literal false-arm AND every consumer that pins the exact bytes route through this constant.

Structural round-trip contract (composed with the algebra’s Self::BOOL_LITERAL_LEAD axis peer): Self::FALSE_LITERAL.starts_with(Self::BOOL_LITERAL_LEAD).

Source

pub const BOOL_LITERALS: [&'static str; 2]

The closed set of two canonical &'static str Scheme-bool spellings — the Self::TRUE_LITERAL ("#t") canonical true spelling followed by the Self::FALSE_LITERAL ("#f") canonical false spelling. Canonical declaration order matches the [true, false] sweep order every existing sibling test in the crate uses (see e.g. the for b in [true, false] sweeps at atom_bool_literal_lead_prefixes_every_bool_literal_spelling) so Self::BOOL_LITERALS[i] == Self::bool_literal([true, false][i]) element-wise — pinned by atom_bool_literals_align_with_bool_literal_by_index.

Sibling posture to crate::error::MacroDefHead::KEYWORDS ([&'static str; 3]), crate::macro_expand::MacroParams::LAMBDA_LIST_KEYWORDS ([&'static str; 2]) — every closed-set spelling algebra now pins its projection ALL array at the declaration site via a forced-arity [&'static str; N] array whose length fails compilation if a new spelling lands without being added to the set. The closed bool domain admits exactly two spellings by construction (a hypothetical third would require extending the underlying bool type itself), so this array’s N == 2 is pinned by the mathematics — the forced-arity [_; 2] here records that invariant on the substrate algebra so a future tri-valued-logic extension surfaces at the array-arity check rather than as a silent drift.

Future consumers that compose against Self::BOOL_LITERALS: an LSP / REPL completion provider surfacing every #… partial input against the closed set (Self::BOOL_LITERALS.iter() is the ONE typed sweep over every legal bool spelling), a tatara-check coverage assertion (every workspace .lisp file’s bare-#-prefixed lexeme must classify to some entry of Self::BOOL_LITERALS OR be routed through the broader hash-prefix reader-macro family), any future audit-trail metric jointly labeled by the canonical Scheme spelling (e.g. tatara_lisp_bool_lexeme_total{literal="#t"}) — the metric label set IS Self::BOOL_LITERALS.

Source

pub const BOOL_LITERAL_LEAD: char = '#'

Canonical # LEAD byte shared across both Self::bool_literal spellings ("#t" for true, "#f" for false) — the ONE canonical char on the Atom algebra the substrate’s Bool- prefix disjointness contract binds to.

Sibling posture to the closed set of pub const reader-punctuation canonical bytes on the substrate: Self::STR_DELIMITER ('"'), Self::STR_ESCAPE_LEAD ('\\'), Sexp::LIST_OPEN ('('), Sexp::LIST_CLOSE (')'), Sexp::COMMENT_LEAD (';'), Sexp::COMMENT_TERM ('\n'), QuoteForm::SPLICE_DISCRIMINATOR ('@') — every canonical per-role byte the reader’s tokenizer specialises on is now a pub const on its owning closed-set algebra. This constant closes the Bool-family lead byte at the SAME algebra as its two-char Self::bool_literal projections so a delimiter swap (e.g. a Common-Lisp-compat port from Scheme #t/#f to CL T/NIL, a JSON-compat port to true/false, or an extension for the broader Scheme hash-prefix reader-macro family #\char / #(vector) / #|block-comment|# / #;datum-comment) lands at ONE constant on the algebra rather than at inline '#' char literals scattered across the test surface AND the docstrings pinning the disjointness contract.

Structural round-trip contract: Self::bool_literal(b).starts_with(Self::BOOL_LITERAL_LEAD) for every b: bool — pinned by atom_bool_literal_lead_prefixes_every_bool_literal_spelling. A regression that drifts EITHER the constant OR the two Self::bool_literal arms surfaces at the pin rather than at a silent bool-family reader drift where #t / #f classify as Self::Symbol instead of Self::Bool.

Disjointness contract: BOOL_LITERAL_LEAD’s byte MUST differ from Self::STR_DELIMITER ('"'), Self::STR_ESCAPE_LEAD ('\\'), Self::KEYWORD_MARKER’s lead byte (':'), Sexp::LIST_OPEN ('('), Sexp::LIST_CLOSE (')'), Sexp::COMMENT_LEAD (';'), Sexp::COMMENT_TERM ('\n'), every QuoteForm::lead_char projection AND QuoteForm::SPLICE_DISCRIMINATOR ('@') — every other closed-set outer-marker byte the reader’s tokenizer specialises on. A collision would silently break the reader’s outer dispatch: a #-prefixed bare atom #t would collide with whichever marker it aliased. Pinned by atom_bool_literal_lead_distinct_from_every_other_algebra_marker.

Consumer sites this constant closes: the three test-surface sites that pre-lift each extracted the lead byte via Self::bool_literal(b).chars().next().unwrap() (or .expect(_)) — the Bool-arm of Sexp::is_bare_atom_boundary’s negative sweep AND the two QuoteForm::SPLICE_DISCRIMINATOR disjointness assertions — collapse onto ONE named byte on the substrate algebra. The two SPLICE_DISCRIMINATOR assertions (one per bool_literal spelling) further collapse to ONE assertion since the lead byte is by construction the SAME across both spellings.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Bool-family lead byte, canonical '#') pairing binds at ONE constant on the closed-set outer Atom algebra regardless of which reader-surface consumer reaches in. THEORY.md §II.1 invariant 5 — composition preserves proofs; the [Self::bool_literal(b).starts_with(Self::BOOL_LITERAL_LEAD)] round-trip law is a coherence proof BETWEEN the paired projection (Self::bool_literal) AND the shared lead byte (this constant) on ONE algebra — a regression that drifts either side surfaces at the pin rather than as a silent hash-prefix reader-family drift. THEORY.md §V.1 — knowable platform; the canonical Bool-family lead byte becomes a TYPE-level constant on the substrate algebra rather than an inline .chars().next().unwrap() extraction at every test surface AND an inline '#' mention across every docstring pinning the disjointness contract.

Source

pub const STR_DELIMITER: char = '"'

Canonical " delimiter that opens AND closes a Self::Str atom in the reader’s tokenizer AND self-escapes inside a backslash-escape sequence — ONE canonical char on the Atom algebra the substrate’s FOUR "-round-trip inline char literals at [crate::reader::tokenize] bind to.

Sibling constant of Self::KEYWORD_MARKER on the atomic- payload marker/delimiter axis of the closed-set Atom algebra: where KEYWORD_MARKER is the ONE &'static str prefix a Self::Keyword payload composes WITH at four canonical-form round-trip sites (reader-entry classifier, Lisp-canonical Display, JSON canonical form, iac-forge canonical form) and Self::bool_literal is the ONE projection a Self::Bool payload composes THROUGH at its two Bool-round-trip sites, this constant is the ONE canonical delimiter a Self::Str payload pairs with at the reader’s four "-round-trip sites inside [crate::reader::tokenize]:

  1. The outer-match string-opening arm — the " byte that begins a [crate::reader::Token::Str] tokenization run.
  2. The escape-handler mapping — \" unescapes to a bare " character inside the accumulated string payload (the only self-escape arm on the reader’s five-arm escape table: \n → \n, \t → \t, \r → \r, \" → ", \\ → \\).
  3. The string-closing arm — the " byte that terminates the current [crate::reader::Token::Str] tokenization run and emits the accumulated payload.
  4. The bare-atom tokenizer’s break-disjunct — " is one of the seven characters that terminates a [crate::reader::Token::Atom] run so a bare atom followed by a string (e.g. foo"body") tokenizes as two distinct tokens rather than one Symbol payload.

Pre-lift the same " byte lived inline at four char literals scattered across crate::reader::tokenize: two outer- match arm patterns (opening + escape-handler), one inner-loop termination pattern (closing), one bare-atom termination disjunct. Post-lift the (Str payload, canonical " delimiter) pairing binds at ONE char constant on the Atom algebra that every reader consumer routes through; a refactor that swaps the delimiter (e.g. a Racket-compat port to #"…"# heredoc mode, a Python-compat port that also accepts ', a triple-quoted heredoc mode) touches ONE constant + one reader table rather than four inline byte literals that would silently drift out of round-trip agreement if one was updated without the others (e.g. an opening # without a matching closing # would round-trip a broken string with a silently-truncated payload).

Load-bearing round-trip contract: read(&format!("{}{s}{}", Atom::STR_DELIMITER, Atom::STR_DELIMITER))[0] == Sexp::Atom(Atom::string(s)) for every escape-free s: &str. The reader’s opening + closing arms both bind to THIS constant so the delimiter cannot drift silently between opener and closer; a regression that swaps ONE arm’s pattern to a different byte fails the round-trip even when the byte-value at the other arm still agrees at the surface. Guards the CLAUDE.md-implicit convention that operator-visible strings use ONE canonical delimiter across the reader entry surface — the delimiter is a first-class algebra fact rather than a per-callsite reader convention.

Sibling-shape peer of Self::KEYWORD_MARKER on the closed- set Atom algebra: where KEYWORD_MARKER (":") partitions bare-atom lexemes at reader-entry classifier strip_prefix gate into Keyword vs default Symbol, this constant ('"') partitions the reader’s outer tokenizer arm into Token::Str vs Token::Atom — both are the ONE canonical marker byte the reader binds to when discriminating an Atom variant’s typed-entry classification path. A Str payload takes the Token::Str reader branch (with THIS delimiter) NOT the Token::Atom reader branch (routed through Self::from_lexeme) — the two paths remain structurally disjoint through the reader’s delimiter dispatch.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Str payload, canonical " delimiter) pairing now binds at ONE constant on the closed-set Atom algebra regardless of which of the four reader tokenizer sites reaches in. THEORY.md §VI.1 — generation over composition; four byte- identical inline '"' char literals in crate::reader::tokenize collapse onto ONE named constant. Four occurrences, well past the ≥2 lift threshold — the substrate’s three-times rule at the Str-delimiter axis. THEORY.md §V.1 — knowable platform; the canonical string-delimiter byte becomes a TYPE-level constant on the substrate algebra rather than four inline bytes at four consumer sites inside one reader file.

Source

pub const STR_ESCAPE_LEAD: char = '\\'

Canonical \ escape-lead byte that OPENS a backslash-escape sequence inside a Self::Str payload AND self-escapes to the same byte inside that sequence — ONE canonical char on the Atom algebra the substrate’s TWO \-round-trip inline char literals at [crate::reader::tokenize] bind to.

Sibling constant of Self::STR_DELIMITER on the same Str-payload delimiter axis of the closed-set Atom algebra: where STR_DELIMITER is the ONE canonical delimiter that BOUNDS a Str payload from the outside (opener, closer, self- escape, bare-atom terminator), this constant is the ONE canonical escape lead that ESCAPES-IN a following byte from the INSIDE of the same payload. The two constants together span the Str-tokenization boundary — every char the reader’s Token::Str accumulation loop specialises on binds to one of them.

The reader’s TWO \-round-trip sites inside [crate::reader::tokenize]:

  1. The escape-lead outer arm — the \ byte that triggers the inner escape-handler branch that consumes the following byte as an escape sequence.
  2. The escape-handler’s self-escape arm — inside the reader’s six-arm escape table (\n → \n, \t → \t, \r → \r, \" → ", \\ → \, passthrough), the self-escape arm on the escape-lead axis: pattern AND mapped value both bind to THIS constant so \\ unescapes to a single \ byte in the accumulated payload. Sibling posture to the analogous self-escape arm on Self::STR_DELIMITER axis (\" unescapes to ") — the two self-escape arms are the escape table’s ONLY pattern-equals-value arms; every other arm is pattern-distinct-from-value.

Pre-lift the same \ byte lived inline at two char literals scattered across crate::reader::tokenize: one outer-arm pattern (escape-lead detection), one inner-loop escape-handler arm’s pattern + value pair (the self-escape mapping). Post- lift the (Str-payload escape lead, canonical \ byte) pairing binds at ONE char constant on the Atom algebra that every reader consumer routes through; a refactor that swaps the escape lead (e.g. a Rust-compat port to \\ byte-strings, a hypothetical Racket-compat port that adopts #\ prefix syntax as the escape lead, or a heredoc mode that suspends escaping altogether) touches ONE constant + one reader table rather than two inline byte literals that would silently drift out of round-trip agreement if one was updated without the other (e.g. the outer arm’s pattern updated without the inner self- escape’s pattern + value would leak a stale escape lead through the wrong branch).

Load-bearing round-trip contract: read(&format!("{}{}{}{}", Atom::STR_DELIMITER, Atom::STR_ESCAPE_LEAD, Atom::STR_ESCAPE_LEAD, Atom::STR_DELIMITER))[0] == Sexp::Atom(Atom::string(Atom::STR_ESCAPE_LEAD.to_string())). The \\ inside a STR_DELIMITER-wrapped payload unescapes to ONE \ byte on the accumulated payload — pinning the (self- escape pattern, self-escape mapped value) pair against re-inlining. A regression that swaps ONE side of the self- escape arm to a different byte fails this round-trip even when the pattern OR value at the other side still agrees at the surface, because both sides bind to THIS constant.

Sibling-shape peer of Self::STR_DELIMITER on the closed-set Atom algebra: where STR_DELIMITER partitions the outer- tokenizer arm into Token::Str vs Token::Atom, this constant partitions the inner-tokenizer arm (inside Token::Str accumulation) into the escape-handler branch vs the passthrough Some((_, ch)) branch — both are the ONE canonical marker byte the reader binds to when discriminating the Str-payload accumulation loop’s branch dispatch.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Str-payload escape lead, canonical \ byte) pairing now binds at ONE constant on the closed-set Atom algebra regardless of which of the two reader tokenizer sites reaches in. THEORY.md §VI.1 — generation over composition; two byte- identical inline '\\' char literals in crate::reader::tokenize collapse onto ONE named constant. Two occurrences at the ≥2 lift threshold — the substrate’s three-times rule at the Str-escape-lead axis. THEORY.md §V.1 — knowable platform; the canonical string-escape-lead byte becomes a TYPE-level constant on the substrate algebra rather than two inline bytes at two consumer sites inside one reader file.

Source

pub const NEWLINE_ESCAPE_SOURCE: char = 'n'

Canonical Str-payload escape-table projection — total closed-set decode from the ONE post-escape-lead source byte the reader’s escape-handler branch consumes to the ONE decoded byte pushed onto the accumulated Str payload. ONE typed projection on the closed-set Atom algebra that the substrate’s Str-escape decode boundary binds to; every consumer that reaches inside a Self::Str payload for a backslash-escape sequence routes through THIS method rather than a per-site inline match esc { … } table.

Closes the Str-payload tokenization boundary that Self::STR_DELIMITER + Self::STR_ESCAPE_LEAD began: where those two constants pin the ONE canonical delimiter byte AND the ONE canonical escape-lead byte the reader’s outer + inner branch dispatch specialises on, this method pins the ONE canonical decode table the escape-handler’s inner branch consumes AFTER the escape-lead byte fires. The three constants together span the Str-payload tokenization axis — every byte the reader’s Token::Str accumulation loop reads either terminates the payload (STR_DELIMITER), triggers the escape handler (STR_ESCAPE_LEAD), pushes through unchanged (passthrough), OR is fed into THIS method as the escape source byte AND its result pushed onto the payload.

Total function: EVERY char maps to exactly one decoded char. The five typed arms bind the substrate’s canonical escape shorthand:

esc sourcedecoded byte
'n''\n'
't''\t'
'r''\r'
Self::STR_DELIMITERSelf::STR_DELIMITER
Self::STR_ESCAPE_LEADSelf::STR_ESCAPE_LEAD
any other charitself (passthrough)

The two self-escape arms (STR_DELIMITER → STR_DELIMITER, STR_ESCAPE_LEAD → STR_ESCAPE_LEAD) are the ONLY pattern-equals-value arms in the table; both bind through the closed-set Atom algebra constants so a delimiter-swap or escape-lead-swap on the algebra propagates through pattern AND value at ONE site rather than as scattered inline byte literals that would silently drift out of round-trip agreement if one was updated without the other.

The three named-escape arms ('n' / 't' / 'r') are the substrate’s canonical whitespace shorthand — pattern-distinct- from-value on every arm (each maps a printable ASCII letter to its corresponding C0 control byte). Pre-lift the whole table lived inline at ONE site inside [crate::reader::tokenize]’s escape-handler branch; post-lift the table lives at ONE typed projection on the Atom algebra that the reader consumes through a single Self::decode_str_escape(esc) call. Adding a sixth named-escape arm (e.g. '0' → '\0' for the NUL byte, or an 'x' hex-byte-prefix arm) extends THIS method’s match rather than mutating the reader’s inline block.

Load-bearing round-trip contract: for every esc: char, read(&format!("{}{}{}{}", Atom::STR_DELIMITER, Atom::STR_ESCAPE_LEAD, esc, Atom::STR_DELIMITER))[0] == Sexp::Atom(Atom::string(Atom::decode_str_escape(esc) .to_string())). Every escape-source byte inside a STR_DELIMITER-wrapped payload decodes through THIS projection end-to-end — pinning the (reader escape-handler branch, this method) pairing against a silent drift at either side. A regression that re-inlines the reader’s table would break the pin the moment a new arm lands here but NOT there (or vice versa).

Sibling-shape peer of QuoteForm::from_lead_char on the closed-set QuoteForm algebra: where from_lead_char is the ONE typed dispatch on the outer-tokenizer quote-family axis (four homoiconic prefix chars decode to Option<Self>), this method is the ONE typed dispatch on the inner-tokenizer Str-escape axis (every escape-source char decodes to a resolved char). Both are the substrate’s canonical closed-set projections the reader consumes through ONE call site each; both close the reader’s per-char specialization point onto the algebra.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Str-escape source byte, decoded byte) pairing now binds at ONE typed projection on the closed-set Atom algebra regardless of which consumer reaches in. THEORY.md §VI.1 — generation over composition; the reader’s five-arm inline table plus one passthrough arm at [crate::reader::tokenize] collapses onto ONE named projection. THEORY.md §V.1 — knowable platform; the canonical Str-escape decode table becomes a TYPE-level method on the substrate algebra rather than an inline block inside one reader file — a future decoder (e.g. a Racket-compat port, a heredoc mode, a raw-string mode) plugs a peer projection onto the same algebra rather than forking the reader.

Canonical newline-escape SOURCE char — the ONE 'n' byte Self::decode_str_escape’s newline arm pattern-matches on. Sibling constant of Self::NEWLINE_ESCAPE_DECODED on the same (source, decoded) escape-arm axis: the ('n', '\n') pairing is the first of the substrate’s three named-escape arms; each pairing binds at ONE pub const per role rather than at an inline char literal at the match-arm pattern + value. Sibling posture to Self::STR_DELIMITER / Self::STR_ESCAPE_LEAD one axis over on the same Str-payload tokenization boundary — those two constants pin the ONE canonical delimiter byte AND the ONE canonical escape-lead byte the reader’s outer + inner branch dispatch specialises on; this constant + its five per-role peers close the (named-escape, self-escape) decode-arm surface at the same closed-set Atom algebra.

Source

pub const NEWLINE_ESCAPE_DECODED: char = '\n'

Canonical newline-escape DECODED byte — the ONE '\n' C0 control byte Self::decode_str_escape’s newline arm value-emits when the source char is Self::NEWLINE_ESCAPE_SOURCE. Peer of the SOURCE constant on the SAME (source, decoded) escape-arm axis; the pairing (NEWLINE_ESCAPE_SOURCE, NEWLINE_ESCAPE_DECODED) IS the first row of the Self::NAMED_ESCAPE_TABLE two-column algebra.

Source

pub const TAB_ESCAPE_SOURCE: char = 't'

Canonical tab-escape SOURCE char — the ONE 't' byte Self::decode_str_escape’s tab arm pattern-matches on. Second of the three named-escape SOURCE pub const peers.

Source

pub const TAB_ESCAPE_DECODED: char = '\t'

Canonical tab-escape DECODED byte — the ONE '\t' C0 control byte Self::decode_str_escape’s tab arm value-emits when the source char is Self::TAB_ESCAPE_SOURCE. Peer of the SOURCE constant on the SAME (source, decoded) escape-arm axis; the pairing (TAB_ESCAPE_SOURCE, TAB_ESCAPE_DECODED) IS the second row of the Self::NAMED_ESCAPE_TABLE two-column algebra.

Source

pub const CARRIAGE_RETURN_ESCAPE_SOURCE: char = 'r'

Canonical carriage-return-escape SOURCE char — the ONE 'r' byte Self::decode_str_escape’s carriage-return arm pattern-matches on. Third of the three named-escape SOURCE pub const peers.

Source

pub const CARRIAGE_RETURN_ESCAPE_DECODED: char = '\r'

Canonical carriage-return-escape DECODED byte — the ONE '\r' C0 control byte Self::decode_str_escape’s carriage-return arm value-emits when the source char is Self::CARRIAGE_RETURN_ESCAPE_SOURCE. Peer of the SOURCE constant on the SAME (source, decoded) escape-arm axis; the pairing (CARRIAGE_RETURN_ESCAPE_SOURCE, CARRIAGE_RETURN_ESCAPE_DECODED) IS the third row of the Self::NAMED_ESCAPE_TABLE two-column algebra.

Source

pub const NAMED_ESCAPE_TABLE: [(char, char); 3]

Canonical NAMED-escape table — the closed-set ALL array over the substrate’s three (SOURCE, DECODED) pairings the pattern-distinct-from-value named-escape arms of Self::decode_str_escape emit, in canonical declaration order (newline / tab / carriage-return). Forced-arity [(char, char); 3] composition — a hypothetical fourth named-escape arm (e.g. '0' → '\0' for the NUL byte, 'e' → '\x1b' for ESC, or a Racket-compat 'a' → '\x07' for BEL) extends Self::decode_str_escape’s match ONCE + this array ONCE + TWO new per-role pub consts (one on each axis) in lockstep; rustc’s forced-arity check on [(char, char); N] binds the extension through the array declaration site. Sibling posture to QuoteForm::PREFIXES / QuoteForm::IAC_FORGE_TAGS on the outer-tokenizer quote-family axis — where those ALL arrays close the reader-prefix + canonical-form byte vocabularies on the QuoteForm closed set, this array closes the named-escape (source, decoded) pairing vocabulary on the inner-tokenizer Str-escape axis of the Atom closed set.

The [(char, char); 3] shape (rather than a [char; 3] singleton) is load-bearing: the escape-arm is a projection from a source byte to a decoded byte, both bytes are typed data, and pinning them as a PAIR at the array declaration site closes the drift channel between pattern (source) and value (decoded) that a scalar array would leave open.

Excludes the two pattern-equals-value self-escape arms (Self::STR_DELIMITER → Self::STR_DELIMITER, Self::STR_ESCAPE_LEAD → Self::STR_ESCAPE_LEAD) because those bind through Self::STR_DELIMITER + Self::STR_ESCAPE_LEAD one axis over on the Str-payload delimiter axis — the (source, decoded) pairing there is definitionally the identity by algebra design (a delimiter- swap propagates through pattern AND value at ONE constant per axis). This array closes the OTHER three arms — the pattern-DISTINCT-from-value named-escape rows.

Source

pub const SELF_ESCAPE_TABLE: [char; 2]

Canonical SELF-escape table — the closed-set ALL array over the substrate’s TWO pattern-EQUALS-value arms of Self::decode_str_escape, in canonical declaration order (Self::STR_DELIMITER, Self::STR_ESCAPE_LEAD) matching the projection’s match-arm order. Forced-arity [char; 2] composition — a hypothetical third self-escape byte (e.g. a raw-string mode adopting '#' as an additional self-escaping delimiter, or a Racket-compat '|' verbatim-symbol boundary) extends Self::decode_str_escape’s match ONCE + this array ONCE + ONE new pub const on the closed-set Atom algebra in lockstep; rustc’s forced-arity check on [char; N] binds the extension through the array declaration site.

Peer to Self::NAMED_ESCAPE_TABLE on the SAME Str-payload tokenization boundary: where NAMED_ESCAPE_TABLE closes the THREE pattern-DISTINCT-from-value named-escape rows ('n' → '\n', 't' → '\t', 'r' → '\r'), this array closes the TWO pattern-EQUALS-value self-escape rows (STR_DELIMITER → STR_DELIMITER, STR_ESCAPE_LEAD → STR_ESCAPE_LEAD). The two arrays together span the FIVE non-passthrough arms of Self::decode_str_escape — every byte the reader’s Token::Str escape-handler branch specialises on lives in exactly ONE of the two closed-set arrays OR falls through the other => other passthrough at the algebra’s projection.

The [char; 2] shape (rather than a [(char, char); 2] pairing peer to NAMED_ESCAPE_TABLE) is load-bearing: the self-escape arm is definitionally the identity by algebra design (a delimiter-swap propagates through pattern AND value at ONE constant per axis), so the PAIRING collapses to a SCALAR on this sub-vocabulary. The SHAPE ASYMMETRY between the two peer arrays ([(char, char); N] vs [char; N]) IS the structural axis distinguishing the pattern-DISTINCT-from-value vocabulary from the pattern-EQUALS-value vocabulary — a consumer that reaches for the array shape encodes its vocabulary’s identity relation in the SHAPE it iterates.

Sibling posture to QuoteForm::PREFIXES + QuoteForm::IAC_FORGE_TAGS on the outer-tokenizer quote-family axis — where those ALL arrays close the TWO byte-vocabulary axes (reader prefix + iac-forge tag) of the outer-tokenizer QuoteForm closed set with parallel shapes, NAMED_ESCAPE_TABLE + SELF_ESCAPE_TABLE close the TWO sub-vocabularies (pattern-distinct + pattern-equals) of the inner-tokenizer Atom Str-escape closed set with asymmetric shapes reflecting the identity-relation asymmetry.

Source

pub const ESCAPE_SOURCES: [char; 5]

Canonical closed-set ALL array over every escape-SOURCE byte Self::decode_str_escape has a non-passthrough arm for — the SPAN of the two peer sub-vocabulary source columns (Self::NAMED_ESCAPE_TABLE’s three (SOURCE, DECODED) pairs’ SOURCE column + Self::SELF_ESCAPE_TABLE’s two rows) in canonical declaration order matching decode_str_escape’s match-arm order. Forced-arity [char; 5] composition — a hypothetical sixth non-passthrough arm (e.g. a '0' → '\0' NUL-byte extension, a Racket-compat 'a' → '\x07' BEL, a raw- string mode adopting '#' as an additional self-escaping delimiter) extends Self::decode_str_escape’s match ONCE + EITHER NAMED_ESCAPE_TABLE or SELF_ESCAPE_TABLE ONCE + this ALL array ONCE + one new per-role pub const (or pair) in lockstep; rustc’s forced-arity check on [char; N] binds the extension through the array declaration site.

Cross-sub-vocabulary SPAN peer to Self::NAMED_ESCAPE_TABLE + Self::SELF_ESCAPE_TABLE at the ALL-array level: where those two arrays partition the FIVE non-passthrough arms of Self::decode_str_escape into the pattern-DISTINCT-from-value sub-vocabulary (3 rows, [(char, char); 3]) AND the pattern- EQUALS-value sub-vocabulary (2 rows, [char; 2]), this array closes the UNION of the SOURCE columns at ONE typed [char; 5] on the SAME closed-set Atom algebra. Pre-lift the SPAN identity lived at TWO sites: the runtime iterator chain Atom::NAMED_ESCAPE_TABLE.iter().map(|&(src, _)| src) .chain(Atom::SELF_ESCAPE_TABLE.iter().copied()).collect() at atom_decode_str_escape_composes_end_to_end_through_reader_for_every_named_arm AND the prose docstring for Self::SELF_ESCAPE_TABLE naming “the FIVE non-passthrough arms” as a cardinality identity. Post- lift the SPAN binds at ONE forced-arity [char; 5] on the Atom algebra so consumers that want “every char for which decode_str_escape is not the identity passthrough” iterate the typed array rather than reassembling the two peer arrays at each callsite.

Also sibling-shape to Sexp::LIST_DELIMITERS ([char; 2] on the outer-structural paired-delimiter axis of the closed-set Sexp algebra), Sexp::COMMENT_DELIMITERS ([char; 2] on the reader-discard paired-delimiter axis of the SAME Sexp algebra), Atom::BOOL_LITERALS ([&'static str; 2] on the Scheme-bool spelling axis of this same Atom algebra), and QuoteForm::LEADS ([char; 3] on the DISTINCT-lead-byte sub-vocabulary axis of the closed-set QuoteForm algebra) — every closed-set outer projection on the substrate that carries a scalar [char; N] sub-vocabulary now pins its canonical bytes at ONE pub const per role plus a forced-arity ALL array for family-wide consumers.

Composition law (SPAN): ESCAPE_SOURCES == [NAMED_ESCAPE_TABLE[0].0, NAMED_ESCAPE_TABLE[1].0, NAMED_ESCAPE_TABLE[2].0, SELF_ESCAPE_TABLE[0], SELF_ESCAPE_TABLE[1]] AND ESCAPE_SOURCES.len() == NAMED_ESCAPE_TABLE.len() + SELF_ESCAPE_TABLE.len() — the forced-arity + canonical declaration order together pin every downstream index-sweep consumer to the (named-source-column prefix, self-source-column suffix) partition at rustc time; a reorder that broke the partition (e.g. interleaving the two sub-vocabularies’ rows) fails at the composition pin below.

Path-uniformity contract carried at the row level: for every esc in ESCAPE_SOURCES, Self::decode_str_escape(esc) != esc iff esc is a NAMED_ESCAPE_TABLE SOURCE row (the three pattern-DISTINCT-from-value arms), and Self::decode_str_escape (esc) == esc iff esc is a SELF_ESCAPE_TABLE row (the two pattern-EQUALS-value arms). The union is exhaustive over the FIVE non-passthrough arms so no ESCAPE_SOURCES row projects through the other => other passthrough branch — the arm-set closure is pinned structurally at atom_escape_sources_every_row_projects_through_a_non_passthrough_arm_of_decode_str_escape.

Pairwise disjointness: every row is distinct from every other row — the closed-set SPAN inherits pairwise disjointness from the two peer sub-vocabularies (each already pairwise distinct via atom_named_escape_table_sources_pairwise_distinct + atom_self_escape_table_pairwise_distinct) PLUS the cross- sub-vocabulary disjointness pinned by atom_self_escape_table_disjoint_from_named_escape_table. This ALL array’s own atom_escape_sources_pairwise_distinct test closes the disjointness contract at the SPAN-level so a future refactor that added a sixth arm whose SOURCE aliased an existing arm surfaces HERE rather than at a distant reader round-trip.

Future consumers that compose against Self::ESCAPE_SOURCES:

  • LSP / REPL completion for the escape-source vocabulary — the completion set IS Self::ESCAPE_SOURCES rather than a per-consumer chain over the two peer arrays.
  • tatara-check coverage assertions that a .lisp corpus exercises every non-passthrough escape arm — the sweep IS Self::ESCAPE_SOURCES.iter() rather than a runtime chain over NAMED_ESCAPE_TABLE.iter().map(|&(src, _)| src) .chain(SELF_ESCAPE_TABLE.iter().copied()).
  • Any future syntax-highlighter that colors escape sequences — the classifier binds through Self::ESCAPE_SOURCES rather than through two parallel per-sub-vocabulary lookups.
  • Any future fuzz-input generator that biases toward escape sequences — the source-byte pool IS Self::ESCAPE_SOURCES rather than reassembled from the two peer arrays.

Theory anchor: THEORY.md §III — the typescape; the FIVE non- passthrough source bytes now bind at ONE typed [char; 5] on the closed-set Atom algebra rather than at a runtime chain over the two peer sub-vocabulary arrays reassembled per consumer. THEORY.md §V.1 — knowable platform; the non- passthrough source-byte SPAN becomes load-bearing typed data at the algebra level. THEORY.md §VI.1 — generation over composition; the “FIVE non-passthrough arms” identity that lived as prose in the Self::SELF_ESCAPE_TABLE docstring AND as a runtime iterator chain at one test site regenerates identically through this ONE typed forced-arity array.

Source

pub const ESCAPE_DECODED: [char; 5]

Canonical closed-set ALL array over every DECODED byte Self::decode_str_escape can emit from a non-passthrough arm — the SPAN of the two peer sub-vocabulary DECODED columns (Self::NAMED_ESCAPE_TABLE’s three (SOURCE, DECODED) pairs’ DECODED column + Self::SELF_ESCAPE_TABLE’s two rows, which are pattern-EQUALS-value so their DECODED column is definitionally the row byte itself) in canonical declaration order matching decode_str_escape’s match-arm order. Forced-arity [char; 5] composition — a hypothetical sixth non-passthrough arm (e.g. a '0' → '\0' NUL-byte extension, a Racket-compat 'a' → '\x07' BEL, a raw-string mode adopting '#' as an additional self-escaping delimiter) extends Self::decode_str_escape’s match ONCE + EITHER NAMED_ESCAPE_TABLE or SELF_ESCAPE_TABLE ONCE + this ALL array ONCE + Self::ESCAPE_SOURCES ONCE + one new per-role pub const (or pair) in lockstep; rustc’s forced- arity check on [char; N] binds the extension through the array declaration site.

Column-dual peer to Self::ESCAPE_SOURCES on the SAME closed-set Atom algebra: where ESCAPE_SOURCES closes the SOURCE column of the FIVE non-passthrough arms at ONE typed [char; 5], this array closes the DECODED column at the SAME shape. Together the two arrays close the (SOURCE, DECODED) cross-product of decode_str_escape’s non-passthrough arm-set at two byte- identical [char; 5] shapes on the SAME closed-set Atom algebra — the shape symmetry across the two columns of the SAME arm-set is itself a typed load-bearing invariant carrying the column-dual identity relation on the algebra.

Cross-sub-vocabulary SPAN peer to Self::NAMED_ESCAPE_TABLE + Self::SELF_ESCAPE_TABLE at the ALL-array level: where those two arrays partition the FIVE non-passthrough arms of Self::decode_str_escape into the pattern-DISTINCT-from-value sub-vocabulary (3 rows, [(char, char); 3]) AND the pattern- EQUALS-value sub-vocabulary (2 rows, [char; 2]), this array closes the UNION of the DECODED columns at ONE typed [char; 5] on the SAME closed-set Atom algebra. Pre-lift the DECODED SPAN identity lived at ZERO callsites — the substrate had a typed SOURCE-column SPAN (Self::ESCAPE_SOURCES) but the DECODED-column SPAN was only reachable by iterating the two peer sub-vocabulary arrays’ DECODED columns per consumer OR by mapping ESCAPE_SOURCES through Self::decode_str_escape at runtime; post-lift the DECODED SPAN binds at ONE forced-arity [char; 5] on the Atom algebra so consumers that want “every byte decode_str_escape can emit from a typed non-passthrough arm” iterate the typed array rather than reassembling it per callsite.

Also sibling-shape to Sexp::LIST_DELIMITERS ([char; 2] on the outer-structural paired-delimiter axis of the closed-set Sexp algebra), Sexp::COMMENT_DELIMITERS ([char; 2] on the reader-discard paired-delimiter axis of the SAME Sexp algebra), Atom::BOOL_LITERALS ([&'static str; 2] on the Scheme-bool spelling axis of this same Atom algebra), and QuoteForm::LEADS ([char; 3] on the DISTINCT-lead-byte sub-vocabulary axis of the closed-set QuoteForm algebra) — every closed-set outer projection on the substrate that carries a scalar [char; N] sub-vocabulary now pins its canonical bytes at ONE pub const per role plus a forced-arity ALL array for family-wide consumers.

Composition law (SPAN): ESCAPE_DECODED == [NAMED_ESCAPE_TABLE[0].1, NAMED_ESCAPE_TABLE[1].1, NAMED_ESCAPE_TABLE[2].1, SELF_ESCAPE_TABLE[0], SELF_ESCAPE_TABLE[1]] AND ESCAPE_DECODED.len() == NAMED_ESCAPE_TABLE.len() + SELF_ESCAPE_TABLE.len() — the forced-arity + canonical declaration order together pin every downstream index-sweep consumer to the (named-decoded-column prefix, self-decoded-column suffix) partition at rustc time; a reorder that broke the partition (e.g. interleaving the two sub-vocabularies’ rows) fails at the composition pin below.

Column-dual pointwise projection law: for every index i in 0..5, ESCAPE_DECODED[i] == Self::decode_str_escape( ESCAPE_SOURCES[i]). The two forced-arity [char; 5] arrays are the SOURCE column and DECODED column of decode_str_escape’s non-passthrough arm-set — the pointwise projection identity is pinned structurally at atom_escape_decoded_projects_pointwise_from_escape_sources_through_decode_str_escape.

Pairwise disjointness: every row is distinct from every other row — '\n', '\t', '\r', '"', '\\' are five distinct C0-and-ASCII bytes. Distinctness on the DECODED column follows from (a) the NAMED sub-vocabulary’s DECODED-column pairwise distinctness at atom_named_escape_table_decoded_pairwise_distinct, (b) the SELF sub-vocabulary’s pairwise distinctness at atom_self_escape_table_pairwise_distinct, and (c) the fact that no NAMED-DECODED byte ('\n', '\t', '\r' — all C0 control bytes) can alias a SELF byte ('"', '\\' — printable ASCII bytes). The pairwise-distinctness pin below closes the contract at the SPAN level so a future refactor that added a sixth arm whose DECODED aliased an existing row surfaces HERE rather than at a distant reader round-trip.

Future consumers that compose against Self::ESCAPE_DECODED:

  • A Str-render / encoder consumer that needs to escape a DECODED byte back into its SOURCE form — the classifier IS “is this byte in Self::ESCAPE_DECODED?” rather than a per-consumer chain over the two peer sub-vocabularies’ DECODED columns.
  • LSP / REPL diagnostic rendering that needs to name every byte the substrate’s escape-handler can emit — the completion set IS Self::ESCAPE_DECODED rather than a runtime map through decode_str_escape from ESCAPE_SOURCES.
  • A syntax-highlighter that colors decoded-escape byte payloads — the classifier binds through Self::ESCAPE_DECODED rather than through two parallel per-sub-vocabulary lookups.
  • A fuzz-input generator that biases toward decoded-escape byte payloads (probing the reader’s error-recovery path when a raw C0 byte appears inside a Str payload) — the target-byte pool IS Self::ESCAPE_DECODED rather than reassembled from the two peer arrays.

Theory anchor: THEORY.md §III — the typescape; the FIVE DECODED bytes of the non-passthrough arm-set now bind at ONE typed [char; 5] on the closed-set Atom algebra rather than at a runtime map through decode_str_escape from ESCAPE_SOURCES. THEORY.md §V.1 — knowable platform; the non-passthrough DECODED-byte SPAN becomes load-bearing typed data at the algebra level. THEORY.md §VI.1 — generation over composition; the column-dual identity that lived only as a runtime decode_str_escape projection of the peer SOURCE-column SPAN regenerates identically through this ONE typed forced-arity array.

Source

pub const ESCAPE_TABLE: [(char, char); 5]

Canonical closed-set ALL array over every (SOURCE, DECODED) pair Self::decode_str_escape projects at a non-passthrough arm — the paired-column SPAN closing BOTH columns of the FIVE non-passthrough arms at ONE typed forced-arity [(char, char); 5] on the closed-set Atom algebra. Composes as NAMED_ESCAPE_TABLE’s three pattern-DISTINCT-from- value rows (which are already (char, char) shape) followed by SELF_ESCAPE_TABLE’s two pattern-EQUALS-value rows re-shaped as (row, row) pairs (the definitional-identity closure of the self-escape sub-vocabulary at the paired shape), in canonical declaration order matching decode_str_escape’s match-arm order.

Cross-column peer-collapse of Self::ESCAPE_SOURCES + Self::ESCAPE_DECODED — the two byte-identical [char; 5] column-dual arrays close the SOURCE column and DECODED column SEPARATELY at ONE forced-arity [char; 5] each; this array closes BOTH columns TOGETHER at ONE typed forced-arity [(char, char); 5] on the SAME closed-set Atom algebra. Together the three arrays close the FIVE non-passthrough arms at THREE typed forced-arity shapes: [char; 5] on the SOURCE column, [char; 5] on the DECODED column, and [(char, char); 5] on the paired-column composition. The shape symmetry (SOURCE, DECODED) pair at row i IS (ESCAPE_SOURCES[i], ESCAPE_DECODED[i]) is a load-bearing pointwise identity carrying the two-column composition relation on the algebra.

Paired-column SPAN peer to Self::NAMED_ESCAPE_TABLE + Self::SELF_ESCAPE_TABLE at the paired-shape level: where those two arrays partition the FIVE arms into the pattern- DISTINCT-from-value sub-vocabulary (3 rows already at [(char, char); 3] shape by algebra design) AND the pattern- EQUALS-value sub-vocabulary (2 rows at [char; 2] shape by definitional-identity collapse), this array closes the UNION of the two sub-vocabularies at ONE typed [(char, char); 5] — the self-escape rows re-shaped from char to (char, char) at the SPAN level via the definitional-identity (row, row) composition. Pre-lift the paired-column SPAN identity lived at ZERO callsites at the paired shape — consumers wanting “every (SOURCE, DECODED) pair decode_str_escape projects at a non- passthrough arm on the closed-set Atom algebra” had to zip the two column-dual [char; 5] peer arrays at their sites OR iterate NAMED_ESCAPE_TABLE and re-shape SELF_ESCAPE_TABLE’s rows to (row, row) per callsite. Post-lift the paired-column SPAN binds at ONE forced-arity [(char, char); 5] on the Atom algebra.

Also sibling-shape to Self::NAMED_ESCAPE_TABLE ([(char, char); 3] on the same paired-column axis, one sub- vocabulary over on the pattern-DISTINCT-from-value axis of the SAME closed-set Atom algebra) — the paired-column shape is the substrate-canonical shape for closing a (SOURCE, DECODED) cross-product at ONE typed array on the algebra; extending it from the NAMED sub-vocabulary’s 3-row shape to the SPAN’s 5-row shape is a mechanical arity extension. A hypothetical sixth non-passthrough arm (e.g. a '0' → '\0' NUL-byte extension, a Racket-compat 'a' → '\x07' BEL, a raw-string mode adopting '#' as an additional self-escaping delimiter) extends Self::decode_str_escape’s match ONCE plus EITHER NAMED_ESCAPE_TABLE or SELF_ESCAPE_TABLE ONCE plus this ALL array ONCE plus both column-dual [char; 5] peer arrays (Self::ESCAPE_SOURCES and Self::ESCAPE_DECODED) ONCE each plus one new per-role pub const (or pair) in lockstep; rustc’s forced-arity check on [(char, char); N] binds the extension through the array declaration site.

Composition law (paired SPAN): for every index i in 0..5, ESCAPE_TABLE[i] == (ESCAPE_SOURCES[i], ESCAPE_DECODED[i]). The forced-arity [(char, char); 5] + canonical declaration order pin every downstream index-sweep consumer to the (named prefix, self suffix) partition at rustc time. The paired-SPAN row identity is pinned structurally at atom_escape_table_composes_pointwise_from_escape_sources_and_escape_decoded_column_duals.

Sub-vocabulary partition law: ESCAPE_TABLE[0..3] == NAMED_ESCAPE_TABLE (the pattern-DISTINCT-from-value sub- vocabulary at its native paired shape passes through identically), AND for i in 3..5, ESCAPE_TABLE[i] == (SELF_ESCAPE_TABLE[i-3], SELF_ESCAPE_TABLE[i-3]) (the pattern- EQUALS-value sub-vocabulary re-shapes from char to (row, row) at the SPAN level via the definitional-identity collapse). Pinned structurally at atom_escape_table_partitions_into_named_paired_prefix_and_self_reshape_suffix.

Pattern-classification partition law: for every index i in 0..3, ESCAPE_TABLE[i].0 != ESCAPE_TABLE[i].1 (the NAMED pattern-DISTINCT-from-value prefix); for every index i in 3..5, ESCAPE_TABLE[i].0 == ESCAPE_TABLE[i].1 (the SELF pattern-EQUALS-value suffix). The classification carried in the row’s per-column identity relation IS the sub-vocabulary identity — a consumer classifying an escape arm reads the sub- vocabulary off row.0 == row.1 rather than off an index range or a separate tag. Pinned structurally at atom_escape_table_named_prefix_is_pattern_distinct_and_self_suffix_is_pattern_equals.

Pointwise projection law: for every (src, decoded) in ESCAPE_TABLE, Self::decode_str_escape(src) == decoded. The paired-column SPAN closes the (input, output) cross-product of decode_str_escape’s non-passthrough arm-set at ONE typed array so a refactor that drifted the arm-set (swapped rows, added a row without extending the array, or removed a row without extending the array) surfaces HERE at the first drifted pair rather than at a distant sweep site.

Future consumers that compose against Self::ESCAPE_TABLE:

  • A round-trip reader/renderer that pairs SOURCE bytes with their DECODED payloads — the paired vocabulary IS Self::ESCAPE_TABLE rather than a zip of the two column-dual peer arrays.
  • LSP / REPL diagnostic rendering that names both columns of every non-passthrough arm — the completion set IS Self::ESCAPE_TABLE rather than reassembled from the two sub-vocabulary arrays via a char → (char, char) re-shape on the SELF rows.
  • A syntax-highlighter that colors both the SOURCE byte and the DECODED payload of every escape arm — the classifier binds through Self::ESCAPE_TABLE rather than through two parallel per-column lookups.
  • A fuzz-input generator that exercises decode_str_escape’s projection round-trip — the input-output pool IS Self::ESCAPE_TABLE rather than a runtime zip of the peer arrays.
  • A hypothetical EscapeArm typed sum enumerating the FIVE non-passthrough arms at ONE closed-set enum on the algebra (with ESCAPE_TABLE becoming its .pair() projection).

Theory anchor: THEORY.md §III — the typescape; the FIVE (SOURCE, DECODED) pairs of the non-passthrough arm-set now bind at ONE typed [(char, char); 5] on the closed-set Atom algebra rather than at a runtime zip of the two peer column-dual arrays. THEORY.md §V.1 — knowable platform; the non-passthrough paired-column SPAN becomes load-bearing typed data at the algebra level. THEORY.md §VI.1 — generation over composition; the paired-column identity that lived only as a runtime zip of the peer column-dual [char; 5] SPANs regenerates identically through this ONE typed forced-arity pair-array. THEORY.md §II.1 invariant 5 — composition preserves proofs; the pointwise composition law ESCAPE_TABLE[i] == (ESCAPE_SOURCES[i], ESCAPE_DECODED[i]) is a load-bearing structural invariant carrying the two-column composition relation between the paired SPAN and its two column-dual peer SPANs. A refactor that drifted any of the three arrays’ declaration orders (paired SPAN, SOURCE-column SPAN, DECODED- column SPAN) OR drifted decode_str_escape’s match-arm ordering surfaces at the first drifted index across the three pointwise composition pins.

Source

pub fn keyword_qualified(name: &str) -> String

Project a bare keyword name to its canonical qualified rendering — format!("{}{name}", Self::KEYWORD_MARKER), i.e. the ONE canonical String on the Atom algebra that composes Self::KEYWORD_MARKER with a bare keyword name to produce the substrate-canonical ":name" spelling.

Sibling projection to Self::bool_literal on the atomic-payload canonical-rendering axis: where bool_literal(b) projects the closed-set bool domain to its canonical Scheme spelling "#t" / "#f" (&'static str because the set is finite), THIS method projects the open-set bare-name domain to its canonical qualified spelling ":name" (String because the set is unbounded). The Atom algebra’s atomic-payload canonical- rendering axis now carries a typed projection for BOTH the prefix-marked variable-payload variant (Keyword) and the self- marked closed-set-payload variant (Bool).

Pre-lift the same format!("{}{s}", Self::KEYWORD_MARKER) composition lived inline at THREE Keyword-arm sites on the atomic-payload rendering axis:

  1. Self::to_json’s Self::Keyword arm — serde_json::Value::String(format!(...)) for the JSON- canonical projection.
  2. Atom::to_iac_forge_sexpr (removed)’s Self::Keyword arm — SExpr::Symbol(format!(...)) for the iac-forge canonical- attestation projection.
  3. [fmt::Display for Atom]’s Self::Keyword arm — write!(f, "{}{s}", Self::KEYWORD_MARKER) for the Lisp- canonical-form Display projection.

Post-lift the two allocating sites (1) + (2) bind at ONE typed projection on the algebra; the [fmt::Display for Atom] site (3) keeps its allocation-free write! path but its byte output is pinned bit-identical to this projection by atom_display_keyword_arm_agrees_with_keyword_qualified_bytes so the three canonical-rendering surfaces cannot drift out of agreement. Adding a fourth Keyword-rendering site (e.g. a future YAML canonical projection, an LSP hover renderer) binds through THIS projection rather than composing Self::KEYWORD_MARKER inline — the (Keyword payload, canonical qualified rendering) pairing lives at ONE algebra layer.

Round-trip contract (with Self::from_lexeme): Self::from_lexeme(&Self::keyword_qualified(name)) == Self::Keyword(name.to_owned()) for every name: &str that does NOT itself parse as a Bool spelling, integer, or float (the four typed-entry classification arms preceding the Self::KEYWORD_MARKER-prefix arm). The classifier’s s.strip_prefix(Self::KEYWORD_MARKER) gate is the LEFT-inverse of THIS projection on the Keyword-payload subset — pinned by atom_from_lexeme_inverts_keyword_qualified_on_bare_name. Composition preserves proofs across the (typed-EXIT rendering, typed-ENTRY classification) round-trip at ONE algebra site.

Sibling posture to QuoteForm::prefix’s composition with homoiconic inner forms in [fmt::Display for Sexp]’s quote- family arm: where QuoteForm::prefix is the [&'static str] prefix a quote-family variant composes with an inner rendering via write!(f, "{}{inner}", qf.prefix()), THIS method is the composed String a Keyword atom composes with a bare name. Both projections close a (marker, payload) pair on their owning closed-set algebra.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Keyword payload, canonical qualified rendering) pairing binds at ONE projection on the closed-set Atom algebra regardless of which of the three canonical-rendering surfaces reaches in. THEORY.md §II.1 invariant 5 — composition preserves proofs; the round-trip law Self::from_lexeme(&Self::keyword_qualified(n)) == Self::Keyword(n.into()) is a coherence proof BETWEEN the paired typed-EXIT rendering (this method) AND the typed-ENTRY classification (Self::from_lexeme) on ONE algebra — a regression that drifts either side surfaces at the pin rather than as a silent Keyword-round-trip drift. THEORY.md §V.1 — knowable platform; the (Keyword payload → canonical qualified rendering) composition becomes a TYPE-level projection on the substrate algebra rather than an inline format!("{}{s}", Self::KEYWORD_MARKER) at every consumer site. THEORY.md §VI.1 — generation over composition; three byte-identical inline compositions collapse onto ONE named projection (two routed sites + one Display byte-identity pin), matching the substrate’s three-times rule.

Frontier inspiration: Racket’s syntax/parse keyword-form canonical-rendering hook — where #:name keyword args have ONE canonical printer that composes the port’s KEYWORD_PREFIX with the bare name rather than N per-consumer printf compositions. Translated to tatara-lisp: Atom::keyword_qualified becomes the ONE canonical-rendering projection on the closed-set outer Atom algebra so a future prefix migration (a Racket-compat port to #:name, a Clojure-compat port to ::name) touches ONE Self::KEYWORD_MARKER constant + zero rendering sites, rather than the pre-lift three inline format! compositions that would silently drift.

Source

pub fn bool_literal(b: bool) -> &'static str

Project the closed-set bool domain to its canonical Scheme- spelling &'static str"#t" for true, "#f" for false. ONE projection on the Atom algebra that the substrate’s FOUR Self::Bool-round-trip inline byte-literals across TWO consumer sites (the two-arm Bool(true|false) fork inside [fmt::Display for Atom] and the two-line if s == "#t" / if s == "#f" cascade inside Self::from_lexeme) collapse onto — parallel to how Self::KEYWORD_MARKER is the ONE canonical prefix the four Keyword-round-trip sites bind to.

Pre-lift the same "#t" / "#f" bytes lived inline at four sites: two f.write_str("#t"|"#f") arms at the Display impl and two if s == "#t"|"#f" gates at Self::from_lexeme. Post- lift the (typed bool, canonical Scheme spelling) pairing binds at ONE projection on the Atom algebra that every consumer routes through; a refactor that swaps the spelling (e.g. a Common-Lisp-compat port to T / NIL, a JSON-compat port to true / false) touches ONE method rather than four inline bytes that would silently drift out of round-trip agreement if one was updated without the others. The Display arm also collapses from TWO variant-branches (Bool(true) => "#t", Bool(false) => "#f") to ONE variant-branch (Bool(b) => Self::bool_literal(*b)) — the fork on bool happens at the projection, not at every consumer’s match body.

Load-bearing round-trip contract: Self::from_lexeme(&Self::boolean(b).to_string()) == Self::boolean(b) for every b: bool — the reader-entry classifier’s s == Self::bool_literal(true|false) gates and the Lisp-canonical [Display]’s f.write_str(Self::bool_literal(*b)) emission both bind to THIS projection so the pair cannot drift. Guards against the CLAUDE.md pin (“bare true/false are symbols → strings, not bools”) — the closed-set bool domain projects only through this typed method, so a reader extension that later accepts bare true/false extends the projection (or its reverse) at ONE algebra site rather than at every callsite in lockstep.

Sibling-shape peer of Self::KEYWORD_MARKER: where KEYWORD_MARKER is the ONE &'static str prefix a Keyword payload composes with at four round-trip sites, this method is the ONE projection a Bool payload composes THROUGH at its two round-trip sites. The Atom algebra’s atomic-payload axis now carries a canonical-marker/spelling for BOTH prefix-marked (Keyword) and self-marked (Bool) variants.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Bool payload, canonical Scheme spelling) pairing now binds at ONE projection on the closed-set Atom algebra regardless of which of the two reader-entry / rendering surfaces reaches in. THEORY.md §VI.1 — generation over composition; the four byte- identical "#t" / "#f" inline literals collapse onto ONE named projection, matching the substrate’s three-times rule. THEORY.md §V.1 — knowable platform; the canonical Scheme-bool spellings become a TYPE-level projection on the substrate algebra rather than four inline bytes at two consumer surfaces.

Source

pub fn escape_str_payload(s: &str) -> String

A string payload as source text, quoted and escaped so that Self::decode_str_escape (plus the reader’s \u{…} arm) reads back exactly these bytes.

The inverse of the reader, deliberately written as one: anything the reader cannot decode is emitted as \u{…} rather than as a shorter escape that would mean something different.

Source

pub const fn decode_str_escape(esc: char) -> char

Source

pub fn symbol(s: impl Into<String>) -> Atom

Canonical Self::Symbol constructor — first of the six per- variant typed-construct methods on the closed-set Atom algebra. Takes impl Into<String> so the consumer composes any &str / String / Cow<'_, str> into the typed payload without pre-coercing at its site — the .into() boundary lives at this method on the algebra, parallel to how the Sexp outer constructors (Sexp::symbol, Sexp::keyword, Sexp::string) accept the same impl Into<String> shape at the outer algebra layer.

Sibling typed-construct family on the closed-set Atom algebra — paired section-for-retraction with the soft-projection family (Self::as_symbol, Self::as_keyword, Self::as_string, Self::as_int, Self::as_float, Self::as_bool). Pre-lift the typed-construct family was missing from the algebra: consumers reached for the bare Self::Symbol(s.into()) tuple-variant constructor + .into() coercion at every site (with no impl Into ergonomy on the algebra), AND the soft-projection family had no constructor peer — section-for-retraction was uneven. Post-lift every consumer that builds an Atom from a typed payload at one site AND projects an Atom back to its typed payload at another binds to ONE method per direction on the algebra. The six Sexp outer constructors (Sexp::symbol through Sexp::boolean) route through Self::Atom(Atom::X(_)).into() ergonomy on the inner algebra is reused at the outer algebra without re-derivation.

Round-trip law binding it to the soft-projection sibling: for every s: &str, Atom::symbol(s).as_symbol() == Some(s) — every other arm projects to None. Same posture across the five sibling pairs (Atom::keyword(s).as_keyword() == Some(s), …). The kind() projection (Self::kind) similarly round-trips through the construct face: Atom::symbol(_).kind() == AtomKind::Symbol.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; every consumer that constructs an Atom of a typed kind binds to ONE typed method on the algebra rather than to the bare tuple-variant constructor + per-site .into() coercion. THEORY.md §V.1 — knowable platform; the (AtomKind variant, typed construct method) pair becomes a TYPE projection on the substrate’s Atom algebra. THEORY.md §VI.1 — generation over composition; the [Sexp; 6] outer constructors at Sexp::symbolSexp::boolean regenerate identically through Self::Atom(Atom::X(_)) composition rather than re-deriving the .into() + tuple-variant pair per outer constructor.

Frontier inspiration: Racket’s (symbol 'x) / (string s) — the typed-construct face the consumer reaches for a typed atomic value paired one-for-one with (symbol? v) / (symbol->string v) predicate/projection siblings; the substrate’s Self::symbol / Self::as_symbol pair is the Rust-typed peer on the closed-set Atom algebra, with impl Into<String> standing in for Racket’s typed-pair coerce face. MLIR’s mlir::SymbolAttr::get(ctx, name) — typed-IR attribute construction routes through ONE typed factory paired with mlir::dyn_cast<SymbolAttr>(attr) on the projection face; Atom::symbol is the substrate’s unstructured-Rust peer.

Source

pub fn keyword(s: impl Into<String>) -> Atom

Canonical Self::Keyword constructor — second of the six per-variant typed-construct methods on the closed-set Atom algebra. See Self::symbol for the algebra-level docstring.

Source

pub fn string(s: impl Into<String>) -> Atom

Canonical Self::Str constructor — third of the six per-variant typed-construct methods. The method name is string for consumer-vocabulary continuity with Self::as_string / Sexp::string / crate::error::SexpShape::String (the typed payload variant is Str for String shortening; the consumer- facing method keeps string for symmetry).

Source

pub fn int(n: i64) -> Atom

Canonical Self::Int constructor — fourth of the six per-variant typed-construct methods. The i64 is taken by value (no impl Into<…> widening) — strict typed identity at the algebra boundary, the same posture Self::as_int preserves on the soft-projection face (Atom::Int(n) projects to Some(n) only; the Sexp::as_float consumer is where Int→Float widening lives).

Source

pub fn float(n: f64) -> Atom

Canonical Self::Float constructor — fifth of the six per-variant typed-construct methods. The f64 is taken by value (no impl Into<…> widening), matching Self::int’s strict typed-identity posture at the algebra boundary.

Source

pub fn boolean(b: bool) -> Atom

Canonical Self::Bool constructor — sixth and last of the six per-variant typed-construct methods on the closed-set Atom algebra. Together with the five siblings (Self::symbol, Self::keyword, Self::string, Self::int, Self::float) the per-Atom-variant typed-construct family is complete across all six closed-set arms, and pairs section-for- retraction with the soft-projection family (Self::as_symbol, Self::as_keyword, Self::as_string, Self::as_int, Self::as_float, Self::as_bool) — every consumer that constructs an Atom from a typed payload at one site AND projects an Atom back to its typed payload at another binds to ONE method per direction on the algebra rather than to the bare tuple-variant constructor + the soft-projection method asymmetrically.

The closed-set bool payload’s Scheme-canonical #t / #f reader lexemes are dispatched at Self::from_lexeme (the typed-ENTRY classifier) — this method is the construction face the consumer composes the typed bool value into when building an Atom from already-typed Rust, parallel to how Self::int and Self::float take their typed payload by value.

Source

pub fn kind(&self) -> AtomKind

Project the atomic value into its closed-set AtomKind marker — Symbol(_) → AtomKind::Symbol, Keyword(_) → AtomKind::Keyword, Str(_) → AtomKind::Str, Int(_) → AtomKind::Int, Float(_) → AtomKind::Float, Bool(_) → AtomKind::Bool. The projection discards the payload and surfaces the typed discriminator that every per-atom-kind dispatch site (Hash cache- key bytes via AtomKind::hash_discriminator, outer-shape projection via AtomKind::sexp_shape, diagnostic label via AtomKind::label) keys on.

Soft-projection peer of Sexp::as_quote_form: where as_quote_form decomposes the four homoiconic prefix wrappers into (QuoteForm, &Sexp), kind decomposes the six atomic payloads into AtomKind alone — there is no inner-sexp body to surface, so the projection’s return type is just the marker. Sibling-arm sweep with the quote-family as_quote_form / QuoteForm algebra lifts the (Atom variant, byte-discriminator, canonical-label, SexpShape variant) quadruple from per-callsite discipline (Hash for Atom’s six byte literals AND domain::sexp_shape’s six SexpShape literals) onto ONE typed algebra the substrate’s diagnostic + cache-key surfaces both route through.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Atom variant, downstream-consumer-payload) pairing now binds at ONE typed projection site (this method composed with AtomKind’s arms) regardless of which consumer surface (cache-key Hash, diagnostic SexpShape, future LSP completion label) needs it. A regression that drifts ONE consumer’s pairing from the others cannot reach the substrate’s runtime.

Source

pub fn label(&self) -> &'static str

Project the atomic payload to its canonical &'static str diagnostic label — "symbol" for Self::Symbol, "keyword" for Self::Keyword, "string" for Self::Str, "int" for Self::Int, "float" for Self::Float, "bool" for Self::Bool. The outer-Atom peer on the Atom algebra of AtomKind::label (the marker-level label projection on the closed-set atomic-kind algebra) and crate::ast::Sexp::type_name (the outer-value label projection on the crate::ast::Sexp algebra composed through crate::ast::Sexp::shape + crate::error::SexpShape::label). Every label is byte-for-byte identical to the corresponding crate::error::SexpShape variant’s label — the AtomKind ⊂ SexpShape label-vocabulary containment established by AtomKind::label’s composition through AtomKind::sexp_shape surfaces at the outer-Atom layer through this projection.

Composition law: atom.label() == atom.kind().label() == atom.kind().sexp_shape().label() for every atom: &Atom. The body composes Self::kind (the typed projection lifting each Atom variant into its peer AtomKind marker) with AtomKind::label (the canonical &'static str projection on the closed-set atomic-payload algebra), so the six atomic-arm labels live at ONE canonical site (crate::error::SexpShape::label’s atomic arms, via AtomKind::label’s composition through AtomKind::sexp_shape) rather than at TWO (crate::error::SexpShape::label AND a parallel six-arm match on the outer Atom algebra, pre-lift). Cross-algebra agreement law: Sexp::Atom(atom.clone()).type_name() == atom.label() for every atom: Atom — the outer-crate::ast::Sexp label projection at the atomic-payload arms routes through crate::ast::Sexp::shape’s Self::Atom(a) => a.kind().sexp_shape() arm which composes with crate::error::SexpShape::label byte-for-byte with this projection’s self.kind().label() composition, so the (outer Sexp label, outer Atom label) agreement is a TYPED CONSEQUENCE of the two typed compositions rather than literal discipline at two sites.

Sibling-shape lift to Self::kind (the closed-set atomic-kind projection): where kind() carries the typed AtomKind marker on the Atom algebra, label() carries the &'static str literal the rendered diagnostic surface wants (still derived from the typed marker, but flattened through AtomKind::label for substring-grep callers, future crate::error::LispError::TypeMismatch got slots keyed on an atomic witness before the outer crate::ast::Sexp wrap, and future LSP hover / REPL completion / audit-trail metric surfaces that hold an Atom value directly rather than a wrapped crate::ast::Sexp::Atom). The &'static str lifetime is load-bearing: the composition allocates nothing at runtime (Self::kind returns a Copy value and AtomKind::label yields &'static str).

Pre-lift the (Atom variant, &'static str diagnostic label) pairing had no typed projection on the outer-Atom algebra — a consumer with a typed Atom in hand (a hand-authored Atom value at a test-harness diagnostic, a future crate::domain typed-kwarg gate that rejects on an atomic witness before the outer crate::ast::Sexp wrap, a future LSP hover surface that emits an atomic-payload identity without an enclosing crate::ast::Sexp::Atom wrap, a future audit-trail metric keyed on the observed atomic kind) wanting the canonical diagnostic label had to spell the two-step composition atom.kind().label() at every callsite, OR go through [crate::ast::Sexp::Atom(atom.clone()).type_name()] which wraps and unwraps for no runtime purpose. Post-lift the composition binds at ONE typed-algebra method on the outer Atom value- carrier — the SIXTH consumer of the outer-Atom projection surface (sibling of Self::kind, Self::to_json, Atom::to_iac_forge_sexpr (removed), Self::from_lexeme, and the six per-variant soft-projection methods Self::as_symbol / Self::as_keyword / Self::as_string / Self::as_int / Self::as_float / Self::as_bool + the composite Self::as_symbol_or_string).

Theory anchor: THEORY.md §V.1 — knowable platform; the (Atom variant, &'static str diagnostic label) pairing becomes a TYPE projection on the outer-Atom algebra rather than a per- callsite .kind().label() two-step OR a wrap-through-Sexp [crate::ast::Sexp::Atom(atom.clone()).type_name()] round-trip. A typo or swap at the outer-Atom label site is no longer a runtime label drift but a compile error against the typed composition — the AtomAtomKind ↔ label chain is rustc-enforced end-to-end. THEORY.md §II.1 invariant 2 — free middle; the outer-Atom diagnostic-label projection now binds at ONE site on the outer-Atom algebra, composing through the pre-existing marker-level label projection (AtomKind::label) rather than duplicating the six-arm match. THEORY.md §VI.1 — generation over composition; the outer-Atom label projection is the missing algebra layer between the outer Atom value-carrier and the pre-existing AtomKind marker-level label projection — the three pre-existing typed layers (AtomAtomKindcrate::error::SexpShape&'static str) become a full four-layer typed composition through ONE new named projection on the outer value-carrier.

Frontier inspiration: MLIR’s mlir::Attribute::getAbstractAttribute() .getName() typed projection composed with the attribute-kind’s typed string identity — narrowing an attribute-carrier value through its typed kind identity yields the canonical diagnostic string identity in ONE typed composition on the outer attribute algebra. Translated through the substrate’s outer-Atom value-carrier algebra, atom.kind().label() closes the (outer value, canonical diagnostic label) pairing at ONE typed projection on the value-carrier algebra composed through the marker-level diagnostic-label face. Racket’s (syntax-kind stx) composed with (kind-label kind) on the datum-kind taxonomy — the typed diagnostic label emerges from a two-hop composition on the outer datum-carrier through the typed kind identity. Atom::label is the Rust-typed peer on the closed-set outer-Atom algebra with AtomKind standing in for Racket’s datum-kind taxonomy.

Source

pub fn sexp_shape(&self) -> SexpShape

Project the atomic value into its outer-shape SexpShape variant — Symbol(_) → SexpShape::Symbol, Keyword(_) → SexpShape::Keyword, Str(_) → SexpShape::String, Int(_) → SexpShape::Int, Float(_) → SexpShape::Float, Bool(_) → SexpShape::Bool. The outer-value peer of AtomKind::sexp_shape one algebra layer down and of Sexp::shape one algebra layer up. Body composes through self.kind().sexp_shape() — routing through Self::kind (the typed 6-arm outer-value → marker projection) then AtomKind::sexp_shape (the canonical 6-of-12 atomic-payload carving of SexpShape) so the (Atom variant, SexpShape variant) pairing lives at ONE canonical site (AtomKind::sexp_shape’s six match arms in ast.rs) rather than at six byte-identical inline arms across consumers.

Same composition-through-carving-marker posture as Self::label (self.kind().label()) one vocabulary axis over on the outer-Atom algebra: Self::label closes the diagnostic-label axis, this method closes the outer-shape-projection axis, and both compose through the SAME typed marker layer (Self::kind into AtomKind) into the outer-shape’s per-axis canonical site. The two methods now paint the outer-Atom value with typed projections onto BOTH the diagnostic-label vocabulary AND the outer-shape closed-set — the pair mirrors how Sexp::type_name and Sexp::shape paint the outer-Sexp value one algebra layer up.

Composition law: atom.sexp_shape() == atom.kind().sexp_shape() for every atom: &Atom. Pinned by atom_sexp_shape_composes_through_kind_sexp_shape_for_every_variant across a representative payload sweep (including NaN via f64::to_bits round-trip on the Float arm, matching [Hash for Atom]’s posture; both empty and non-empty String/Symbol/Keyword arms; i64::{MIN, MAX} on the Int arm; both Bool arms). Sibling of atom_label_composes_through_kind_label_for_every_variant one vocabulary axis over.

Cross-algebra agreement law: for every atom: &Atom, atom.sexp_shape() == Sexp::Atom(atom.clone()).shape(). The outer-Atom shape projection routes into the SAME canonical site the outer-Sexp Sexp::shape projection lands on for every atomic-payload arm — pinned by atom_sexp_shape_agrees_with_sexp_shape_at_every_atom_arm via byte-equality on the SexpShape variant across all six atomic arms. Sibling of atom_label_agrees_with_sexp_type_name_at_every_atom_arm one vocabulary axis over.

Round-trip through the outer-shape’s soft-projection sibling: atom.sexp_shape().as_atom_kind() == Some(atom.kind()) for every atom: &Atom — the typed embed Atom → AtomKind → SexpShape inverts through the soft-projection retraction SexpShape → AtomKind exactly on the 6-of-12 atomic-payload image. Pinned by atom_sexp_shape_round_trips_through_sexp_shape_as_atom_kind.

The SexpShape return type (owned; SexpShape is not Copy because its Unknown(String) arm carries a String) is the outer-shape closed set; consumers that want the diagnostic label render string compose atom.sexp_shape().label(), and that composition IS atom.label() byte-for-byte by the composition-through-carving-marker posture the two methods share.

Theory anchor: THEORY.md §V.1 — knowable platform; the (outer Atom variant, SexpShape variant) pairing becomes a TYPE projection on the outermost atomic value-carrier algebra composed through the pre-existing marker-level projection, rather than at parallel inline match arms each future consumer of the outer-shape from an outer-Atom value has to re-derive. THEORY.md §II.1 invariant 2 — free middle; the outer-Atom outer-shape algebra now closes over THREE typed layers (outer AtomAtomKindSexpShape) with rustc-enforced consistency across each — a regression that drifts ONE layer’s shape mapping from the others cannot reach the substrate’s runtime typed-witness surface, LispError::TypeMismatch.got slot, or SexpWitness::shape projection. THEORY.md §VI.1 — generation over composition; the outer-value projection is the missing algebra layer between the outer Atom and the pre-existing marker-level shape projection — the two pre-existing typed layers become a full THREE-layer typed composition through ONE new named projection.

Frontier inspiration: MLIR’s mlir::Attribute::getType() typed projection composed with the attribute-kind’s typed outer-type identity — narrowing an attribute-carrier value through its typed kind identity yields the outer-type identity in ONE typed composition on the outer attribute algebra. Translated through the substrate’s outer-Atom value-carrier algebra, atom.kind().sexp_shape() closes the (outer value, outer-shape) pairing at ONE typed projection on the value- carrier algebra composed through the marker-level outer-shape face.

Source

pub fn to_json(&self) -> Value

Project the atomic payload to its canonical serde_json::Value rendering — the typed-algebra peer of [fmt::Display for Atom] at the JSON-projection boundary. Lifts six inline atom arms inside crate::domain::sexp_to_json’s outer match (one Sexp::Atom(Atom::<variant>(payload)) => JValue::<…>(…) arm per AtomKind variant) onto ONE typed-algebra method that every consumer routes through. Sibling-shape lift to the prior Display for Atom (the canonical-string rendering surface), Hash for Atom (the cache-key bytes surface via AtomKind::hash_discriminator), and the upcoming Atom::to_iac_forge_sexpr (the canonical-SExpr rendering surface, feature-gated iac-forge) — every per-Atom-variant projection now binds at ONE method on the closed-set algebra rather than at six inline arms inside its consumer.

Mapping (preserves the byte-identical pre-lift behavior at the sexp_to_json callsite):

Bidirectional contract anchored by tests in this module:

  • atom_to_json_projects_each_variant_to_canonical_json_value — sweeps a representative atom of each AtomKind variant and pins each variant’s canonical JValue mapping byte-for-byte against the pre-lift inline rule, so a future regression that drifts ONE arm (e.g. swaps Symbol’s mapping to a Number, or drops Keyword’s : prefix) fails loudly.
  • atom_to_json_float_nan_and_infinity_collapse_to_null — pins the JSON-structural inexpressibility branch at the atom layer directly, so a future Atom-Display-style refactor that bypasses serde_json::Number::from_f64 (e.g. tries to emit NaN as the string "NaN") surfaces at the typed-algebra boundary without requiring a Sexp wrap.
  • sexp_to_json_atom_arms_route_through_atom_to_json (in [crate::domain::tests]) — pins the lifted boundary: sexp_to_json(&Sexp::Atom(a.clone())) == Ok(a.to_json()) for every atomic payload variant. Catches a future drift where one surface’s per-variant body changes without the other.

Theory anchor: THEORY.md §VI.1 — generation over composition; the (Atom variant, canonical JValue rendering) pair lived inline at the sexp_to_json site as six byte-identical arms. The lift retires the per-site fan-out onto ONE method on the Atom algebra. THEORY.md §II.1 invariant 2 — free middle; the typed- exit JSON projection, the Display-surface rendering, the diagnostic surface, and any future canonical-form surface (e.g. Atom::to_iac_forge_sexpr) all route through ONE per-variant projection family rather than per-callsite re-derivation. THEORY.md §V.1 — knowable platform; a future seventh atomic kind (e.g. Char for #\x reader syntax) lands at one AtomKind::ALL entry plus one arm here plus one arm per sibling projection — exhaustively checked by the compiler, not by per-consumer convention.

Frontier inspiration: MLIR’s mlir::AsmPrinter::printAttribute — the typed-IR attribute printer dispatches on the closed-set AttributeKind so every printer body for a kind lives at ONE implementation site; Atom::to_json is the unstructured-Rust peer on the Atom algebra for the JSON canonical-form surface (where Display for Atom is the Lisp-canonical-form peer and From<&Sexp> for iac_forge::SExpr is the canonical-attestation- form peer). Racket’s (syntax->datum stx) then a serializer over the datum prim — to_json is the substrate’s serializer at the atomic-payload layer, with the closed-set AtomKind standing in for Racket’s datum-prim taxonomy.

Source

pub fn from_json_number(n: &Number) -> Atom

Inverse of Self::to_json restricted to the JSON Number discriminator — the ONE typed inverse projection on the closed-set Atom algebra that names the (serde_json::NumberSelf::Int / Self::Float) bifurcation. Lifts the pre-lift inline three-arm cascade inside crate::ast::Sexp::from_json’s serde_json::Value::Number(n) outer-match arm — first n.as_i64()? sink to Self::Int then n.as_f64()? sink to Self::Float then a Self::Int(0) typed floor for the structural-impossibility residual — onto ONE typed projection on the Atom algebra so the paired FORWARD (Self::to_json’s Self::Int / Self::Float arms) and INVERSE (this method) numeric-axis projections live at ONE algebra layer.

Mapping (byte-identical to the pre-lift cascade in crate::ast::Sexp::from_json):

serde_json::Number shaperesult
n.as_i64() == Some(i)Self::Int(i)
n.as_i64() == None, .as_f64() == Some(f)Self::Float(f)
n.as_i64() == None, .as_f64() == NoneSelf::Int(0) — typed floor

Every serde_json::Number today is either i64-fitting, u64-fitting (projected through f64), or f64-fitting — the Int(0) residual arm is a static-invariant statement that serde_json::Number’s closed-set discriminator excludes the “neither i64 nor f64” case in practice; the typed floor stays explicit so a future serde_json extension does NOT silently misroute through an unreachable-panic. The Self::int(0) composition in the pre-lift code equalled Self::Atom(Atom::Int(0)) via the Sexp::int sugar; post-lift the Atom algebra owns the typed floor at the atomic layer directly.

Round-trip laws (paired with Self::to_json’s numeric arms):

  • For every i: i64, Atom::from_json_number(&i.into()) == Atom::Int(i) — the Self::IntJValue::NumberSelf::Int round-trip is byte-identical.
  • For every finite non-integer-valued f: f64, Atom::from_json_number(&serde_json::Number::from_f64(f) .unwrap()) == Atom::Float(f) — the Self::FloatJValue::NumberSelf::Float round-trip is byte-identical for f64 values that don’t overlap the i64-fitting subset of serde_json::Number’s discriminator (i.e. non-integer-valued finite floats; integer-valued floats round-trip through the Self::Int arm by as_i64’s eager check).
  • Non-finite floats (f64::NAN, f64::INFINITY, f64::NEG_INFINITY) collapse to serde_json::Value::Null in Self::to_json — they NEVER produce a serde_json::Number value, so the round-trip law does not apply to them. This asymmetry is JSON’s structural inexpressibility of non-finite floats (pinned at atom_to_json_float_nan_and_infinity_collapse_to_null), not a substrate choice.

ONE consumer entrypoint the substrate binds against: the outer crate::ast::Sexp::from_json’s serde_json::Value::Number(n) arm was pre-lift a hand-rolled three-branch cascade (if let Some(i) = n.as_i64() { Self::int(i) } else if let Some(f) = n.as_f64() { Self::float(f) } else { Self::int(0) }); post-lift the outer arm collapses to Self::Atom(Atom::from_json_number(n)) — the ONE typed inverse on the Atom algebra owns the numeric-axis bifurcation, the outer arm delegates. A regression that drifts the outer arm (e.g. re-inlines the bifurcation and swaps the as_i64/as_f64 order so 42.0 sinks to Self::Float instead of Self::Int) becomes structurally unreachable — there is exactly ONE numeric decode both directions of the round-trip consume.

Sibling-lift posture: this method mirrors Self::from_lexeme on the typed-entry classification axis — that method decodes a bare-atom lexeme (&str) into the six-way Atom taxonomy; THIS method decodes a JSON Number into the two-way ( Self::Int / Self::Float) numeric subtaxonomy on the SAME algebra. Together with the seven typed-EXIT projections on Atom ([fmt::Display for Atom], Self::to_json, Atom::to_iac_forge_sexpr (removed), Self::label, Self::sexp_shape, Self::hash_discriminator, Self::bool_literal) and the two typed-ENTRY projections on Atom (Self::from_lexeme, THIS method) the algebra’s canonical-form bidirectional sweep is complete across every production-site rendering + parsing surface — every consumer’s (Atom variant, canonical rendering) OR (canonical source, Atom variant) pairing binds at ONE method per direction per surface on the closed-set algebra rather than at inline arms scattered across per-consumer sites.

Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; the (JSON Number → typed Atom numeric variant) projection IS the typed-entry gate on the JSON numeric axis. Placing the paired forward (Atom::to_json’s Self::Int / Self::Float arms) AND inverse (THIS method) on the Atom algebra closes the round-trip closure at ONE algebra layer — future numeric taxonomy extensions (e.g. u64-fitting arm for the serde-preserve-order feature’s arbitrary_precision mode, a [Self::Bigint] variant for arbitrary-precision integers, a [Self::Rational] variant for [num_rational::Rational64]) extend the algebra ONCE at Self::to_json’s match AND ONCE at this method’s cascade — both edits land on the SAME algebra rather than across the Atom module AND the Sexp module boundary. THEORY.md §V.1 — knowable platform; the numeric inverse projection becomes a NAMED primitive on the substrate’s Atom algebra rather than an inline three-arm cascade at the Sexp::from_json consumer. THEORY.md §II.1 invariant 5 — composition preserves proofs; the round-trip law Atom::from_json_number(&Atom::Int(n).to_json_as_number()) == Atom::Int(n) (pinned at atom_from_json_number_round_trips_atom_to_json_int_arm) is a coherence proof BETWEEN the paired projections on ONE algebra — a regression that drifts either side surfaces at the pin rather than as a silent Sexp ↔ JSON round-trip drift.

Frontier inspiration: MLIR’s mlir::parseAttribute(str, ctx) — the typed-IR parser inverse of printAttribute lives on the SAME Attribute algebra as its printer dual; the substrate’s Self::from_json_number is the unstructured-Rust peer on the Atom algebra for the JSON-numeric canonical-form inverse, paired with Self::to_json’s numeric arms as the closed numeric-axis round-trip. Racket’s (json->racket (racket->json v)) numeric identity — the round-trip law that a JSON-projected numeric datum recovers to its source Racket numeric primitive; THIS method’s round-trip pins are the Rust-typed peer on the Atom algebra with the closed-set numeric taxonomy (Self::Int / Self::Float) standing in for Racket’s numeric tower.

Source

pub fn from_lexeme(s: &str) -> Atom

Classify a bare reader-token lexeme into its typed Atom variant — the typed-ENTRY mirror of the three typed-EXIT projections on the Atom algebra ([fmt::Display for Atom], Self::to_json, Atom::to_iac_forge_sexpr (removed)). Lifts the five-statement classification cascade that lived inline at the reader’s private atom_from_str helper onto ONE typed-algebra method on the closed-set Atom algebra; the reader’s Token::Atom(s) arm collapses to Sexp::Atom(Atom::from_lexeme(&s)). Completes the bidirectional sweep across the four production-site per-Atom-variant projection shapes (typed-exit Display, JSON, iac-forge canonical attestation, AND now typed-entry classification) onto the algebra.

Classification rule (byte-identical to the pre-lift reader atom_from_str cascade):

  1. "#t"/"#f"Self::Bool — the Scheme bool spellings; bare true/false re-read as Self::Symbol (the CLAUDE.md “Lisp bools” warning — every :values-overlay payload depends on this for Value::Bool round-trip).
  2. :foo (leading :) → Self::Keyword — strips the : so the inverse fmt::Display rule (Keyword(s) → ":{s}") round-trips.
  3. i64::from_str succeeds → Self::Int — load-bearing ORDERING: tried BEFORE f64 so "1" classifies as Self::Int(1), NOT Self::Float(1.0). Typed-int- vs-typed-float distinction at the Display→read boundary is the dual of fmt_float’s .0-suffix discipline.
  4. f64::from_str succeeds → Self::Float.
  5. Default → Self::Symbol.

Composition laws (pinned by tests below):

  • Atom::from_lexeme(&a.to_string()) == a for every variant EXCEPT Self::Str (Display renders Str with quote marks — strings take the reader’s "-quoted tokenizer branch, NOT the bare-atom branch).
  • read(s) for every canonical bare-atom source lexeme equals vec![Sexp::Atom(Atom::from_lexeme(s))] (pinned by reader_atom_token_arm_routes_through_atom_from_lexeme_for_ every_kind in [crate::reader::tests]).

Theory anchor: THEORY.md §II.1 invariant 1 — typed entry; atom_from_str was the typed-entry gate as a free function in reader.rs, outside the typed Atom algebra. Naming it on the algebra brings the typed-entry side INTO the same closed-set match family the typed-exit projections live on, so a future seventh atomic kind (e.g. Char for #\x reader syntax) lands at ONE AtomKind::ALL entry plus ONE arm here plus ONE arm per typed-exit projection — exhaustively checked by rustc across all FOUR per-variant projection families. THEORY.md §II.1 invariant 2 — free middle; FOUR consumers (typed-entry classification, Display rendering, JSON projection, canonical- attestation-form projection) now route through ONE per-Atom-variant projection family on the closed-set algebra. THEORY.md §VI.1 — generation over composition; this lift completes the bidirectional sweep across the four production surfaces the prior runs in this series named.

Frontier inspiration: Racket’s (read-syntax …) dispatches a bare-atom lexeme through a closed-set classifier keyed on prefix + parse-as-numeric cascade; Atom::from_lexeme is the substrate’s typed-Rust peer, with AtomKind standing in for Racket’s datum-prim taxonomy. MLIR’s mlir::AsmParser::parseAttribute dispatches on the closed-set AttributeKind so every parser body for a kind lives at ONE implementation site; Atom::from_lexeme is the unstructured-Rust peer on the Atom algebra for the typed-entry classification surface.

Source

pub fn as_symbol(&self) -> Option<&str>

Soft projection onto the Self::Symbol payload — Some(&str) iff this is a Self::Symbol variant, None for every other atomic kind (Keyword, Str, Int, Float, Bool).

FIRST of the six per-variant soft-projection methods on the typed Atom algebra — the typed-EXIT soft-projection peer of the typed-EXIT canonical-form projections ([fmt::Display for Atom], Self::to_json, Atom::to_iac_forge_sexpr (removed)) and the typed-ENTRY classifier (Self::from_lexeme). Where the canonical-form trio projects the atomic payload to a rendered canonical surface (string / JSON / iac-forge SExpr) and the classifier projects a lexeme to the typed Atom, this method projects the typed Atom to its inner payload — the soft-decomposition face of the closed set, completing the algebra surface across BOTH bidirectional axes (canonical-form rendering + classification on the typed-ENTRY/ typed-EXIT axis; soft decomposition on the typed-EXIT side at the payload axis).

Sibling soft-projection peer of Sexp::as_quote_form: where as_quote_form soft-decomposes the four homoiconic prefix wrappers into Option<(QuoteForm, &Sexp)>, this method (and its five as_* siblings on Atom) soft-decompose the six atomic payloads into Option<&str> / Option<i64> / Option<f64> / Option<bool> — there is no inner-sexp body to surface, so the projection’s return type is just the payload. The Sexp::as_symbol consumer at the Sexp algebra layer composes this projection with Sexp::as_atom (the structural lift to the inner Atom) — Sexp::as_symbol(self) == self.as_atom().and_then(Atom::as_symbol) — so the per-Atom- variant soft-projection binds at ONE method on the typed algebra rather than at six inline Self::Atom(Atom::X(s)) => Some(s) arms inside the Sexp consumer.

Lifts the inline Self::Atom(Atom::Symbol(s)) => Some(s) arm at Sexp::as_symbol’s match body onto ONE typed-algebra projection the Sexp consumer routes through via the structural lift Sexp::as_atom. Sibling-shape lift to the typed-EXIT canonical-form projections (Display for Atom, Atom::to_json, Atom::to_iac_forge_sexpr) and the typed-ENTRY classifier (Atom::from_lexeme) — every per-Atom-variant projection across both the rendering surfaces AND the soft-decomposition surface now binds at ONE method on the closed-set algebra rather than at inline arms inside its consumer.

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Atom variant, downstream-consumer-payload) pairing now binds at ONE typed projection per consumer surface (six canonical-form surfaces — Display, JSON, iac-forge, plus the soft-projection FAMILY this method opens), regardless of which consumer reaches in. THEORY.md §VI.1 — generation over composition; the six inline Self::Atom(Atom::X(s)) => Some(_) arms at Sexp::as_X sites (well past the ≥2 PRIME-DIRECTIVE trigger once the structural shape is named) collapse onto the closed-set Atom algebra so a future seventh atomic kind (e.g. Char for #\x reader syntax, Bigint for arbitrary-precision integers) extends Atom::ALL + the per-variant soft-projection method ONCE and rustc enforces matching across every consumer through the closed-set match. THEORY.md §V.1 — knowable platform; the (Atom variant, payload) pairing becomes a TYPE projection on the substrate algebra rather than six inline arms at the Sexp consumer. A typo or swap at the soft-projection site is no longer a runtime drift but a compile error against the typed projection.

Frontier inspiration: Racket’s (symbol? v) / (symbol->string v) pair — the typed-predicate + typed-projection pair at the atomic-payload layer; this method (and its five as_* siblings) is the substrate’s typed soft-projection peer on the closed-set Atom algebra, with Option<&str> standing in for the predicate-AND-projection pair Racket carries as two functions. MLIR’s mlir::dyn_cast<SymbolAttribute>(attr) — the typed-IR soft-downcast onto a closed-set attribute family; Atom::as_symbol is the unstructured-Rust peer on the Atom algebra for the soft-projection face, with the closed-set AtomKind standing in for MLIR’s AttributeKind taxonomy.

Source

pub fn as_keyword(&self) -> Option<&str>

Soft projection onto the Self::Keyword payload — Some(&str) iff this is a Self::Keyword variant, None for every other atomic kind. The returned &str is the payload AFTER the : prefix has been stripped at the typed-ENTRY classifier boundary (Self::from_lexeme strips : when constructing a Keyword; this projection surfaces the bare identifier). SECOND of the six per-variant soft-projection methods on the typed Atom algebra — see Self::as_symbol for the algebra-level docstring.

Source

pub fn as_string(&self) -> Option<&str>

Soft projection onto the Self::Str payload — Some(&str) iff this is a Self::Str variant (the typed "…"-quoted string literal payload at the reader’s [crate::reader::Token::Str] branch), None for every other atomic kind. THIRD of the six per-variant soft-projection methods — named as_string at the Sexp consumer for consumer-vocabulary continuity with the pre-lift Sexp::as_string projection (the typed payload variant is Str for String shortening; the consumer-facing method keeps string for symmetry with the ExpectedKwargShape::String label and the SexpShape::String outer-shape marker).

Source

pub fn as_int(&self) -> Option<i64>

Soft projection onto the Self::Int payload — Some(i64) iff this is a Self::Int variant, None for every other atomic kind. FOURTH of the six per-variant soft-projection methods. The i64 is returned by value (the payload is Copy); contrast with Self::as_symbol / Self::as_keyword / Self::as_string which borrow the underlying String payload as &str because String is not Copy.

Strict typed identity: this method projects Atom::Int(n) to Some(n) only. The Sexp::as_float consumer at the Sexp algebra layer widens Int to Float (Atom::Int(n) → Some(n as f64)) for caller convenience at the numeric-kwarg boundary; the Atom-level projection here stays strict so the typed-identity distinction Int(1) vs Float(1.0) (the load-bearing typed identity at the Self::from_lexeme ⇄ Display round-trip boundary, dual of [fmt_float]’s .0-suffix discipline) is preserved at the algebra layer. The widening lives at the Sexp::as_float consumer (a.as_float().or_else(|| a.as_int() .map(|n| n as f64))) where the convenience is wanted, not at the algebra-level projection where the typed identity is load-bearing.

Source

pub fn as_float(&self) -> Option<f64>

Soft projection onto the Self::Float payload — Some(f64) iff this is a Self::Float variant, None for every other atomic kind. FIFTH of the six per-variant soft-projection methods.

Strict typed identity: Atom::Int(n) does NOT project through this method (it stays None). The Sexp::as_float consumer widens Int to Float at the Sexp algebra layer for caller convenience; this algebra-level projection stays strict. See Self::as_int’s docstring for the typed-identity contract.

Source

pub fn as_bool(&self) -> Option<bool>

Soft projection onto the Self::Bool payload — Some(bool) iff this is a Self::Bool variant, None for every other atomic kind. SIXTH and LAST of the six per-variant soft-projection methods on the typed Atom algebra; together with the five siblings (Self::as_symbol, Self::as_keyword, Self::as_string, Self::as_int, Self::as_float) the per-Atom-variant soft-projection family is complete across all six closed-set arms. The CLAUDE.md-pinned "#t" / "#f" Scheme bool spellings the reader’s typed-ENTRY classifier Self::from_lexeme dispatches on bind the lexeme → typed Self::Bool direction; this method binds the typed Self::Bool → payload direction at the soft-decomposition face.

Source

pub fn as_symbol_or_string(&self) -> Option<&str>

Soft projection onto the symbol-or-string union — Some(&str) iff this is a Self::Symbol variant OR a Self::Str variant, None for every other atomic kind (Keyword, Int, Float, Bool). The atomic-payload peer of Sexp::as_symbol_or_string — disjunctive composition of Self::as_symbol + Self::as_string at the typed Atom algebra rather than at the Sexp consumer layer where the union previously composed two distinct Sexp::as_atom traversals.

Sibling soft-projection peer of the six per-variant projections (Self::as_symbol, Self::as_keyword, Self::as_string, Self::as_int, Self::as_float, Self::as_bool) — this union projection completes the soft-decomposition family on the closed-set Atom algebra by naming the (Symbol ⊎ Str) union the substrate’s named-form NAME gate (crate::compile::split_name_slot via Sexp::as_symbol_or_string) keys on. Both NAME-author surfaces ((defcompiler my-name …) — bare symbol; (defcompiler "my-name" …) — quoted string) project to Some("my-name") through one method on the algebra.

Composition law binding it to Sexp::as_symbol_or_string: for every Sexp s, s.as_symbol_or_string() == s.as_atom().and_then(Atom::as_symbol_or_string) — the same structural-lift composition pattern Sexp::as_symbol / Sexp::as_keyword / Sexp::as_string / Sexp::as_int / Sexp::as_bool route through on the six per-variant axis. Lifts the self.as_symbol().or_else(|| self.as_string()) disjunctive composition at Sexp::as_symbol_or_string’s body (TWO Sexp::as_atom traversals pre-lift) onto ONE typed-algebra projection the Sexp consumer routes through via the structural lift Sexp::as_atom (ONE Sexp::as_atom traversal post-lift).

Theory anchor: THEORY.md §II.1 invariant 2 — free middle; the (Symbol ⊎ Str) union projection now binds at ONE method on the closed-set Atom algebra regardless of which consumer reaches in. THEORY.md §VI.1 — generation over composition; the disjunctive as_symbol().or_else(|| as_string()) composition at Sexp::as_symbol_or_string’s body collapses onto a SINGLE structural lift through Sexp::as_atom + the algebra-level union projection, eliminating the double-traversal redundancy the pre-lift consumer-layer composition carried. THEORY.md §V.1 — knowable platform; the (Symbol-or-Str) NAME-slot union becomes a TYPE projection on the substrate algebra rather than a disjunctive composition at every NAME-gate consumer.

Frontier inspiration: Racket’s (or/c symbol? string?) contract — a typed disjunctive predicate the consumer binds to in one place rather than re-deriving the disjunction at every callsite; Self::as_symbol_or_string is the substrate’s unstructured-Rust peer with the typed projection (Option<&str>) surfacing the underlying payload alongside the predicate face. MLIR’s mlir::dyn_cast<StringLike>(attr) — typed soft-downcast onto a closed-set attribute union; Self::as_symbol_or_string is the substrate’s Atom-algebra peer for the (Symbol ⊎ Str) union, with Option<&str> standing in for MLIR’s typed downcast result.

Trait Implementations§

Source§

impl Clone for Atom

Source§

fn clone(&self) -> Atom

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Atom

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Atom

Source§

fn deserialize<__D>( __deserializer: __D, ) -> Result<Atom, <__D as Deserializer<'de>>::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for Atom

Canonical reader-round-trippable rendering of a single atomic payload — Symbol(s) → "{s}", Keyword(s) → ":{s}", Str(s) → "{s:?}" (the debug-quoted form: \"…\" with embedded " and \ escaped), Int(n) → "{n}", Float(n) through [fmt_float] so integral values render with the .0 suffix that preserves the typed-Float-vs-typed-Int distinction at the Display→read boundary, Bool(true) → "#t", Bool(false) → "#f" (the Scheme bool spellings the reader’s typed-entry classifier Atom::from_lexeme dispatches on — true / false re-read as symbols, NOT as bools — see the CLAUDE.md “Lisp bools” warning).

This is the atomic-payload Display surface — the typed-exit-side peer of Atom::from_lexeme’s atomic-payload typed-entry surface (the FOURTH and LAST of the per-Atom-variant projection sites lifted onto the closed-set algebra, after the typed-exit Display [this impl], JSON Atom::to_json, and iac-forge canonical attestation Atom::to_iac_forge_sexpr (removed) projections — completing the bidirectional typed-entry/typed-exit sweep). Before this lift the per-variant rendering arms lived inline at the Sexp::Atom(a) => match a { … } arm of [fmt::Display for Sexp]; routing the outer arm through this impl lifts the seven inline sub-arms (the Bool variant splits into true/false to short-circuit the if-else branch) into ONE typed-algebra method the Sexp Display arm calls into via fmt::Display::fmt(a, f). Sibling closed-set lift to QuoteForm::prefix (the four homoiconic prefix wrappers) and AtomKind::label (the six diagnostic labels) — those name the quote-family and atomic-discriminator pairings at the Sexp and Atom algebras respectively; this names the atomic-payload rendering at the Atom algebra so future consumers of “render a bare atom” land on this impl directly without unwrapping through Sexp::Atom(_).to_string() and stripping the outer wrap.

Three production-site sibling shapes the substrate carries that route through a per-Atom-variant projection, all 6/7-arm inline matches pre-lift:

  • [fmt::Display for Sexp]’s atom arm — 7 sub-arms (Bool splits), produces a fmt::Formatter body. Post-lift collapses to ONE fmt::Display::fmt(a, f) delegation.
  • crate::domain::sexp_to_json’s atom arms — 6 inline arms producing serde_json::Value. Now lifted onto Atom::to_json in the sibling pattern this impl’s docstring named; the sexp_to_json site collapses to ONE Sexp::Atom(a) => a.to_json() arm.
  • crate::interop’s From<&Sexp> for SExpr (removed)’s atom arm (feature-gated iac-forge) — 6 inline arms producing iac_forge::sexpr::SExpr. Now lifted onto Atom::to_iac_forge_sexpr (removed) in the sibling pattern this impl’s docstring named; the interop site collapses to ONE Sexp::Atom(a) => a.to_iac_forge_sexpr() arm. THIRD and LAST of the three production-site atom-arm shapes lifted onto the typed Atom algebra; the sweep across the Lisp / JSON / iac-forge canonical-form surfaces is complete.

The (Atom variant, rendered prefix/suffix/body) quadruple now lives at ONE typed-algebra Display impl rather than at seven inline sub-arms inside Display for Sexp’s outer Atom arm. A regression that drifts the Bool spelling (#t/#f vs true/false) — the CLAUDE.md-pinned reader-round-trip invariant — now lands at ONE site, and the test surface pins each variant’s canonical rendering AND the round-trip identity through the reader at the Atom level directly (no Sexp wrap required to exercise the round-trip).

Bidirectional contract anchored by tests in this module:

  • atom_display_renders_each_variant_to_canonical_form — sweeps AtomKind::ALL and pins each variant’s canonical rendering byte-for-byte against the pre-lift inline literal, so a future regression that drifts ONE arm (e.g. swaps #t/#f for true/false, or strips Str’s quote marks) fails loudly.
  • sexp_atom_display_arm_routes_through_atom_display_for_every_variant — pins the lifted boundary: Sexp::Atom(a).to_string() == a.to_string() for every atomic payload variant, AND that both equal the legacy inline rendering. Catches a future drift where one surface’s per-variant body changes without the other.
  • atom_display_round_trips_through_reader_preserving_typed_identity — sweeps a representative atom of each variant, renders it via Atom::Display, parses the rendering through crate::reader::read, and pins the parsed atom equals the seed atom (modulo Str’s debug-quoted spelling — pinned separately because the reader expects unquoted source-level "foo"). Pins that the (Atom::Display, reader) pair forms a typed round-trip at the atom layer, the same invariant [fmt_float]’s .0 suffix preserves for the float-vs-int distinction at the Sexp layer.

Theory anchor: THEORY.md §VI.1 — generation over composition; the (Atom variant, canonical rendering) pair appeared inline at THREE production sites (Display for Sexp’s 7-sub-arm atom arm, sexp_to_json’s 6 atom arms, From<&Sexp> for SExpr’s 6 atom arms) — well past the ≥2 PRIME-DIRECTIVE trigger once the structural shape is named. THIS lift retires the Display-surface site by naming the typed primitive on the Atom algebra; future runs route the JSON and iac-forge sites through parallel sibling projections (Atom::to_json, Atom::to_iac_forge_sexpr) the same pattern names. THEORY.md §II.1 invariant 1 — typed entry; the substrate’s Atom::from_lexeme is the typed-entry gate at the atomic-payload boundary (lifted onto the typed Atom algebra from the reader’s pre-lift free function), and this impl is the typed-exit-side mirror — the closed-set AtomKind algebra now threads BOTH gates through ONE projection family, so a regression that drifts one side’s per-variant rendering from the other (e.g. extends Atom with a Char variant the reader accepts but the writer can’t emit) is no longer a silent two-site divergence — rustc binds both sides to the same closed-set enum. THEORY.md §II.1 invariant 2 — free middle; the typed-exit rendering, the reader, the diagnostic surface (LispError::TypeMismatch.got slot rendering an atomic witness), and any future authoring tool (LSP / REPL pretty-printer) all route through ONE per-variant rendering rather than per-callsite re-derivation.

Frontier inspiration: Racket’s (syntax->datum stx) / write pair — where syntax->datum unwraps the homoiconic surface to its atomic-payload layer and write emits the canonical S-expression rendering bound to the reader’s read inverse; Atom::Display is the substrate’s typed-algebra peer at the atomic-payload boundary, with the closed-set AtomKind standing in for Racket’s datum-prim taxonomy. MLIR’s mlir::AsmPrinter::printAttribute — the typed-IR attribute printer dispatches on the closed-set AttributeKind so every printer body for a kind lives at ONE implementation site; Atom::Display is the unstructured Rust peer for the Sexp/Atom algebra, with fmt::Display standing in for MLIR’s AsmPrinter interface.

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Hash for Atom

Source§

fn hash<H>(&self, h: &mut H)
where H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for Atom

Source§

fn eq(&self, other: &Atom) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for Atom

Source§

fn serialize<__S>( &self, __serializer: __S, ) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for Atom

Auto Trait Implementations§

§

impl Freeze for Atom

§

impl RefUnwindSafe for Atom

§

impl Send for Atom

§

impl Sync for Atom

§

impl Unpin for Atom

§

impl UnsafeUnpin for Atom

§

impl UnwindSafe for Atom

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.