Skip to main content

cljrs_reader/
form.rs

1use std::mem;
2
3use cljrs_types::span::Span;
4
5/// A parsed Clojure form with its source location.
6///
7/// `PartialEq` ignores spans so test assertions can compare forms without
8/// constructing exact span values.
9#[derive(Debug, Clone)]
10pub struct Form {
11    pub kind: FormKind,
12    pub span: Span,
13}
14
15impl Form {
16    pub fn new(kind: FormKind, span: Span) -> Self {
17        Self { kind, span }
18    }
19
20    /// Total heap bytes owned by this form tree (excluding the `Form` itself).
21    pub fn heap_size(&self) -> usize {
22        mem::size_of::<FormKind>() + self.kind.heap_size()
23    }
24
25    /// The annotated form with every `^meta` wrapper removed.
26    ///
27    /// Returns `self` when the form carries no metadata. Stacked metadata
28    /// (`^:a ^:b x`) is peeled down to the innermost form.
29    pub fn unmeta(&self) -> &Form {
30        let mut form = self;
31        while let FormKind::Meta(_, inner) = &form.kind {
32            form = inner;
33        }
34        form
35    }
36
37    /// The `^meta` forms attached to this form, outermost first, together with
38    /// the annotated form itself.
39    pub fn peel_meta(&self) -> (Vec<&Form>, &Form) {
40        let mut metas = Vec::new();
41        let mut form = self;
42        while let FormKind::Meta(meta, inner) = &form.kind {
43            metas.push(meta.as_ref());
44            form = inner;
45        }
46        (metas, form)
47    }
48
49    // ── Structural views ──────────────────────────────────────────────────────
50    //
51    // Every accessor below reports the shape of [`Form::unmeta`], so an
52    // annotated form has the same structural shape as the form it annotates.
53
54    /// The symbol name, if this form is a symbol.
55    pub fn as_symbol(&self) -> Option<&str> {
56        match &self.unmeta().kind {
57            FormKind::Symbol(s) => Some(s),
58            _ => None,
59        }
60    }
61
62    /// The keyword name (without the leading `:`), if this form is a keyword.
63    pub fn as_keyword(&self) -> Option<&str> {
64        match &self.unmeta().kind {
65            FormKind::Keyword(k) => Some(k),
66            _ => None,
67        }
68    }
69
70    /// The string contents, if this form is a string literal.
71    pub fn as_string(&self) -> Option<&str> {
72        match &self.unmeta().kind {
73            FormKind::Str(s) => Some(s),
74            _ => None,
75        }
76    }
77
78    /// The elements, if this form is a list.
79    pub fn as_list(&self) -> Option<&[Form]> {
80        match &self.unmeta().kind {
81            FormKind::List(v) => Some(v),
82            _ => None,
83        }
84    }
85
86    /// The elements, if this form is a vector.
87    pub fn as_vector(&self) -> Option<&[Form]> {
88        match &self.unmeta().kind {
89            FormKind::Vector(v) => Some(v),
90            _ => None,
91        }
92    }
93
94    /// The flat key/value pairs, if this form is a map literal.
95    pub fn as_map(&self) -> Option<&[Form]> {
96        match &self.unmeta().kind {
97            FormKind::Map(v) => Some(v),
98            _ => None,
99        }
100    }
101}
102
103impl FormKind {
104    /// Heap bytes owned by this node and all children.
105    pub fn heap_size(&self) -> usize {
106        match self {
107            // Inline scalars — no heap.
108            FormKind::Nil
109            | FormKind::Bool(_)
110            | FormKind::Int(_)
111            | FormKind::Float(_)
112            | FormKind::Char(_)
113            | FormKind::Symbolic(_) => 0,
114
115            // String payloads.
116            FormKind::BigInt(s)
117            | FormKind::BigDecimal(s)
118            | FormKind::Ratio(s)
119            | FormKind::Str(s)
120            | FormKind::Regex(s)
121            | FormKind::Symbol(s)
122            | FormKind::Keyword(s)
123            | FormKind::AutoKeyword(s)
124            | FormKind::AutoSymbol(s) => s.capacity(),
125
126            // Vec<Form> — Vec overhead + recursive children.
127            FormKind::List(v)
128            | FormKind::Vector(v)
129            | FormKind::Map(v)
130            | FormKind::Set(v)
131            | FormKind::AnonFn(v) => vec_heap_size(v),
132
133            // Box<Form> — one Form on heap.
134            FormKind::Quote(f)
135            | FormKind::SyntaxQuote(f)
136            | FormKind::Unquote(f)
137            | FormKind::UnquoteSplice(f)
138            | FormKind::Deref(f)
139            | FormKind::Var(f) => mem::size_of::<Form>() + f.heap_size(),
140
141            // Two Box<Form>.
142            FormKind::Meta(a, b) => mem::size_of::<Form>() * 2 + a.heap_size() + b.heap_size(),
143
144            // String + Box<Form>.
145            FormKind::TaggedLiteral(s, f) => s.capacity() + mem::size_of::<Form>() + f.heap_size(),
146
147            FormKind::ReaderCond { clauses, .. } => vec_heap_size(clauses),
148        }
149    }
150}
151
152impl PartialEq for Form {
153    fn eq(&self, other: &Self) -> bool {
154        self.kind == other.kind
155    }
156}
157
158/// The payload of a `Form` node.
159#[derive(Debug, Clone, PartialEq)]
160pub enum FormKind {
161    // ── Atoms ─────────────────────────────────────────────────────────────────
162    Nil,
163    Bool(bool),
164    Int(i64),
165    BigInt(String),
166    Float(f64), // NaN != NaN per IEEE 754 — acceptable for AST equality
167    BigDecimal(String),
168    Ratio(String),
169    Char(char),
170    Str(String),
171    Regex(String),
172    /// `##Inf` → `INFINITY`, `##-Inf` → `NEG_INFINITY`, `##NaN` → `NAN`
173    Symbolic(f64),
174
175    // ── Identifiers ───────────────────────────────────────────────────────────
176    Symbol(String),
177    Keyword(String),
178    /// `::kw` / `::alias/kw` - the namespace is resolved against the reading
179    /// namespace by the evaluator, not by the reader.
180    AutoKeyword(String),
181    /// A symbol whose namespace is auto-resolved the same way. There is no
182    /// surface syntax for one; the reader produces it for a bare symbol key in
183    /// an auto-resolved namespaced map (`#::{a 1}`, `#::alias{a 1}`).
184    AutoSymbol(String),
185
186    // ── Collections ───────────────────────────────────────────────────────────
187    List(Vec<Form>),
188    Vector(Vec<Form>),
189    /// Flat key/value pairs; length is always even.
190    Map(Vec<Form>),
191    Set(Vec<Form>),
192
193    // ── Wrapping reader macros ────────────────────────────────────────────────
194    Quote(Box<Form>),
195    SyntaxQuote(Box<Form>),
196    Unquote(Box<Form>),
197    UnquoteSplice(Box<Form>),
198    Deref(Box<Form>),
199    /// `#'symbol`
200    Var(Box<Form>),
201    /// `^meta-form annotated-form` — raw meta form kept as-is; evaluator
202    /// expands shorthand (`:kw` → `{:kw true}`, `Sym` → `{:tag Sym}`).
203    Meta(Box<Form>, Box<Form>),
204
205    // ── Dispatch forms ────────────────────────────────────────────────────────
206    /// `#(…)` anonymous function literal
207    AnonFn(Vec<Form>),
208    /// `#tag form` tagged literal
209    TaggedLiteral(String, Box<Form>),
210
211    // ── Reader conditionals ───────────────────────────────────────────────────
212    /// All branches are kept; the evaluator filters by `:rust`.
213    /// `clauses` is flat: `[keyword, form, keyword, form, …]`.
214    ReaderCond {
215        splicing: bool,
216        clauses: Vec<Form>,
217    },
218}
219
220fn vec_heap_size(forms: &[Form]) -> usize {
221    mem::size_of_val(forms) + forms.iter().map(|f| f.heap_size()).sum::<usize>()
222}