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
26impl FormKind {
27    /// Heap bytes owned by this node and all children.
28    pub fn heap_size(&self) -> usize {
29        match self {
30            // Inline scalars — no heap.
31            FormKind::Nil
32            | FormKind::Bool(_)
33            | FormKind::Int(_)
34            | FormKind::Float(_)
35            | FormKind::Char(_)
36            | FormKind::Symbolic(_) => 0,
37
38            // String payloads.
39            FormKind::BigInt(s)
40            | FormKind::BigDecimal(s)
41            | FormKind::Ratio(s)
42            | FormKind::Str(s)
43            | FormKind::Regex(s)
44            | FormKind::Symbol(s)
45            | FormKind::Keyword(s)
46            | FormKind::AutoKeyword(s)
47            | FormKind::AutoSymbol(s) => s.capacity(),
48
49            // Vec<Form> — Vec overhead + recursive children.
50            FormKind::List(v)
51            | FormKind::Vector(v)
52            | FormKind::Map(v)
53            | FormKind::Set(v)
54            | FormKind::AnonFn(v) => vec_heap_size(v),
55
56            // Box<Form> — one Form on heap.
57            FormKind::Quote(f)
58            | FormKind::SyntaxQuote(f)
59            | FormKind::Unquote(f)
60            | FormKind::UnquoteSplice(f)
61            | FormKind::Deref(f)
62            | FormKind::Var(f) => mem::size_of::<Form>() + f.heap_size(),
63
64            // Two Box<Form>.
65            FormKind::Meta(a, b) => mem::size_of::<Form>() * 2 + a.heap_size() + b.heap_size(),
66
67            // String + Box<Form>.
68            FormKind::TaggedLiteral(s, f) => s.capacity() + mem::size_of::<Form>() + f.heap_size(),
69
70            FormKind::ReaderCond { clauses, .. } => vec_heap_size(clauses),
71        }
72    }
73}
74
75impl PartialEq for Form {
76    fn eq(&self, other: &Self) -> bool {
77        self.kind == other.kind
78    }
79}
80
81/// The payload of a `Form` node.
82#[derive(Debug, Clone, PartialEq)]
83pub enum FormKind {
84    // ── Atoms ─────────────────────────────────────────────────────────────────
85    Nil,
86    Bool(bool),
87    Int(i64),
88    BigInt(String),
89    Float(f64), // NaN != NaN per IEEE 754 — acceptable for AST equality
90    BigDecimal(String),
91    Ratio(String),
92    Char(char),
93    Str(String),
94    Regex(String),
95    /// `##Inf` → `INFINITY`, `##-Inf` → `NEG_INFINITY`, `##NaN` → `NAN`
96    Symbolic(f64),
97
98    // ── Identifiers ───────────────────────────────────────────────────────────
99    Symbol(String),
100    Keyword(String),
101    /// `::kw` / `::alias/kw` - the namespace is resolved against the reading
102    /// namespace by the evaluator, not by the reader.
103    AutoKeyword(String),
104    /// A symbol whose namespace is auto-resolved the same way. There is no
105    /// surface syntax for one; the reader produces it for a bare symbol key in
106    /// an auto-resolved namespaced map (`#::{a 1}`, `#::alias{a 1}`).
107    AutoSymbol(String),
108
109    // ── Collections ───────────────────────────────────────────────────────────
110    List(Vec<Form>),
111    Vector(Vec<Form>),
112    /// Flat key/value pairs; length is always even.
113    Map(Vec<Form>),
114    Set(Vec<Form>),
115
116    // ── Wrapping reader macros ────────────────────────────────────────────────
117    Quote(Box<Form>),
118    SyntaxQuote(Box<Form>),
119    Unquote(Box<Form>),
120    UnquoteSplice(Box<Form>),
121    Deref(Box<Form>),
122    /// `#'symbol`
123    Var(Box<Form>),
124    /// `^meta-form annotated-form` — raw meta form kept as-is; evaluator
125    /// expands shorthand (`:kw` → `{:kw true}`, `Sym` → `{:tag Sym}`).
126    Meta(Box<Form>, Box<Form>),
127
128    // ── Dispatch forms ────────────────────────────────────────────────────────
129    /// `#(…)` anonymous function literal
130    AnonFn(Vec<Form>),
131    /// `#tag form` tagged literal
132    TaggedLiteral(String, Box<Form>),
133
134    // ── Reader conditionals ───────────────────────────────────────────────────
135    /// All branches are kept; the evaluator filters by `:rust`.
136    /// `clauses` is flat: `[keyword, form, keyword, form, …]`.
137    ReaderCond {
138        splicing: bool,
139        clauses: Vec<Form>,
140    },
141}
142
143fn vec_heap_size(forms: &[Form]) -> usize {
144    mem::size_of_val(forms) + forms.iter().map(|f| f.heap_size()).sum::<usize>()
145}