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