pub struct Node {
pub kind: NodeKind,
pub span: Span,
pub leading: Vec<Trivia>,
pub trailing: Vec<Trivia>,
pub after: Vec<Trivia>,
}Expand description
A parsed Lisp node with span + attached trivia.
Fields§
§kind: NodeKind§span: Span§leading: Vec<Trivia>Comments / blank lines immediately before this node.
trailing: Vec<Trivia>For a compound node: trivia sitting between its last child and its
closing delimiter, with no child to attach to. Emitted INSIDE the
form, before the ).
Note this slot is overloaded relative to its original meaning
(“trailing on the same line”); sequence() claimed it for the
dangling case. That is why Self::after exists rather than this
being reused again.
after: Vec<Trivia>Trivia that follows this node at its own level — OUTSIDE any delimiter it owns.
The distinction from Self::trailing is load-bearing, not
pedantry: (define x 1) ; why and (define x 1 ; why\n) are
different documents, and a single slot cannot represent both. With
only the two original slots the top-level case had nowhere to go
and was DISCARDED at EOF — measurably: one mass-format destroyed 44
trailing comments in pleme-io/actions alone.
Implementations§
Source§impl Node
impl Node
pub fn new(kind: NodeKind, span: Span) -> Self
Sourcepub fn to_tatara_sexp(&self) -> Sexp
pub fn to_tatara_sexp(&self) -> Sexp
Drop all spans + trivia, lowering into the plain tatara_lisp::Sexp
used by the compile pipeline.
Route the D4-dialect compound-body lowering through the lifted
NodeKind::as_seq_body Option<&[Node]> accessor rather than
the raw four-arm NodeKind::List(items) => Sexp::List(…) | NodeKind::Map(items) | NodeKind::Vector(items) => Sexp::List(…)
open-coded per-arm dispatch — sibling in shape to the peer
crate::visit::walk, caixa-fmt::Printer::emit,
caixa-fmt::render_node_inline, caixa-fmt::emit_header_operand,
caixa-fmt::is_atom, and caixa-teia::node_to_value compound-body
sites that all key off the same substrate-canonical accessor. The
three D4-dialect compound arms produce IDENTICAL Sexp::List
bodies (only the brace-ness is dropped — see the historical note
below), so the pre-lift shape was two match arms restating the
same Sexp::List(items.iter().map(Node::to_tatara_sexp).collect())
body; the lift folds both onto one dispatch that gates on the
substrate-primitive compound-body-carrying arm-set.
tatara_lisp::Sexp has no Map/Vector variant yet — adding them is
a LANGUAGE change, sequenced as Phase 2 of
theory/TATARA-LISP-CONSOLIDATION.md D4 and gated on its own
differential run over the 1,123-file corpus (correction C4). Until
that lands, all three compound arms lower to a plain list: the
elements survive in order, only the brace-ness is dropped. That is
strictly closer to intent than the pre-D4 behaviour, where the
delimiters lowered as literal { / } SYMBOLS inside the list.
This projection is used only by the round-trip equivalence tests,
which stay honest because formatting re-emits the delimiters and
re-parsing recovers the node.
Sourcepub fn head_symbol(&self) -> Option<&str>
pub fn head_symbol(&self) -> Option<&str>
Head symbol for a list node like (defX ...). Returns None unless this
is a List whose first element is a Symbol.
Routes the head-slot symbol-name projection through the lifted
NodeKind::as_symbol Option<&str> accessor rather than the
raw let NodeKind::Symbol(s) = &items.first()?.kind else …
open-coded per-arm pattern-match — sibling in shape to the
caixa-fmt special_head_arity / head_symbol_is_command,
caixa-lint check_paired_kwargs / check_aplicacao_timeout /
check_git_pin / check_consistent_quote, and caixa-teia
is_ref_form sites (all converged in this run) that partition
on the outer-NodeKind Symbol arm through the same substrate-
canonical accessor.