Skip to main content

rucc_ast/
ast.rs

1//! The arenas, and everything that hangs off them.
2//!
3//! Design: `spec/03-architecture.md` section 3.3 and `spec/06-lexer-and-parser.md` section 6.2.
4//!
5//! One [`Ast`] per translation unit owns every node in it. Nothing is boxed and nothing is
6//! individually freed: the tree is a set of flat vectors, a reference between nodes is a
7//! four-byte index, and the whole thing is dropped in one go when the unit is finished. That
8//! removes the allocator from the parser's hot path, removes the destructor storm at the end,
9//! and makes the tree `Send` without any effort.
10//!
11//! Spans are out of line, in a vector parallel to each arena. Almost nothing that walks the
12//! tree reads a span, and keeping eight bytes of source position out of the node makes the
13//! arrays that are walked half again as dense.
14//!
15//! # Reading and building
16//!
17//! Reading is indexing: `ast[id]` gives a node and `&ast[list]` gives a slice. Building is one
18//! method per table, which is also what keeps the span vectors in step with the arenas they
19//! belong to.
20//!
21//! There are twenty-eight tables, and the accessors for them are generated by two small macros
22//! at the bottom of this file rather than written twenty-eight times. This is the only place in
23//! the compiler that does that, and the reason is that the alternative is two hundred lines of
24//! copy-paste in which indexing the wrong vector would compile, run, and give the wrong answer.
25
26use std::fmt;
27use std::ops::Index;
28
29use rucc_base::{Idx, IdxRange, Symbol};
30use rucc_diag::Span;
31use rucc_lex::{CharConstant, FloatConstant, IntConstant, StringLiteral};
32
33use crate::asm::{Asm, AsmId, AsmOperand};
34use crate::attr::{AttrArg, Attribute};
35use crate::decl::{
36    Decl, DeclId, Declarator, DeclaratorId, Derived, Enumerator, InitDeclarator, Member, Param,
37    TypeName, TypeNameId,
38};
39use crate::expr::{Expr, ExprId, GenericAssoc};
40use crate::init::{Designator, Init, InitId, InitItem};
41use crate::spec::{DeclSpecs, DeclSpecsId};
42use crate::stmt::{Stmt, StmtId};
43
44/// An integer constant, in the constant table.
45pub type IntId = Idx<IntConstant>;
46/// A floating constant, in the constant table.
47pub type FloatId = Idx<FloatConstant>;
48/// A character constant, in the constant table.
49pub type CharId = Idx<CharConstant>;
50/// A string literal, in the constant table.
51pub type StrId = Idx<StringLiteral>;
52
53/// The table of references to expressions, which is what a call's arguments are a run of.
54#[derive(Debug)]
55pub struct ExprRef;
56/// The table of references to statements, which is what a compound statement is a run of.
57#[derive(Debug)]
58pub struct StmtRef;
59/// The table of references to declarations.
60#[derive(Debug)]
61pub struct DeclRef;
62/// The table of references to string literals, which is what an `asm` clobber list is a run of.
63#[derive(Debug)]
64pub struct StrRef;
65
66/// A run of expressions.
67pub type ExprList = IdxRange<ExprRef>;
68/// A run of statements.
69pub type StmtList = IdxRange<StmtRef>;
70/// A run of declarations.
71pub type DeclList = IdxRange<DeclRef>;
72/// A run of string literals.
73pub type StrList = IdxRange<StrRef>;
74/// A run of identifiers.
75pub type SymbolList = IdxRange<Symbol>;
76/// A run of attributes.
77pub type AttrList = IdxRange<Attribute>;
78/// A run of attribute arguments.
79pub type AttrArgList = IdxRange<AttrArg>;
80/// A run of declarator derivations.
81pub type DerivedList = IdxRange<Derived>;
82/// A run of function parameters.
83pub type ParamList = IdxRange<Param>;
84/// A run of struct or union members.
85pub type MemberList = IdxRange<Member>;
86/// A run of enumerators.
87pub type EnumeratorList = IdxRange<Enumerator>;
88/// A run of init-declarators.
89pub type InitDeclaratorList = IdxRange<InitDeclarator>;
90/// A run of braced initializer elements.
91pub type InitItemList = IdxRange<InitItem>;
92/// A run of designators.
93pub type DesignatorList = IdxRange<Designator>;
94/// A run of `_Generic` associations.
95pub type GenericList = IdxRange<GenericAssoc>;
96/// A run of assembly operands.
97pub type AsmOperandList = IdxRange<AsmOperand>;
98
99/// Every node of one translation unit.
100#[derive(Default)]
101pub struct Ast {
102    exprs: Vec<Expr>,
103    expr_spans: Vec<Span>,
104    stmts: Vec<Stmt>,
105    stmt_spans: Vec<Span>,
106    decls: Vec<Decl>,
107    decl_spans: Vec<Span>,
108
109    declarators: Vec<Declarator>,
110    type_names: Vec<TypeName>,
111    specs: Vec<DeclSpecs>,
112    inits: Vec<Init>,
113    asms: Vec<Asm>,
114
115    ints: Vec<IntConstant>,
116    floats: Vec<FloatConstant>,
117    chars: Vec<CharConstant>,
118    strings: Vec<StringLiteral>,
119
120    expr_refs: Vec<ExprId>,
121    stmt_refs: Vec<StmtId>,
122    decl_refs: Vec<DeclId>,
123    str_refs: Vec<StrId>,
124    symbols: Vec<Symbol>,
125    attrs: Vec<Attribute>,
126    attr_args: Vec<AttrArg>,
127    derived: Vec<Derived>,
128    params: Vec<Param>,
129    members: Vec<Member>,
130    enumerators: Vec<Enumerator>,
131    init_declarators: Vec<InitDeclarator>,
132    init_items: Vec<InitItem>,
133    designators: Vec<Designator>,
134    generics: Vec<GenericAssoc>,
135    asm_operands: Vec<AsmOperand>,
136
137    top_level: Vec<DeclId>,
138}
139
140impl Ast {
141    /// An empty tree.
142    #[must_use]
143    pub fn new() -> Ast {
144        Ast::default()
145    }
146
147    /// The declarations of the translation unit, in source order.
148    #[must_use]
149    pub fn top_level(&self) -> &[DeclId] {
150        &self.top_level
151    }
152
153    /// Adds a declaration at file scope.
154    pub fn add_top_level(&mut self, decl: DeclId) {
155        self.top_level.push(decl);
156    }
157
158    /// Adds an expression, with the source it came from.
159    ///
160    /// # Panics
161    ///
162    /// Panics if the arena would exceed four billion nodes, which is not a translation unit
163    /// this compiler intends to accept.
164    pub fn expr(&mut self, expr: Expr, span: Span) -> ExprId {
165        let id = Idx::from_usize(self.exprs.len());
166        self.exprs.push(expr);
167        self.expr_spans.push(span);
168        id
169    }
170
171    /// Adds a statement, with the source it came from.
172    ///
173    /// # Panics
174    ///
175    /// Panics if the arena would exceed four billion nodes.
176    pub fn stmt(&mut self, stmt: Stmt, span: Span) -> StmtId {
177        let id = Idx::from_usize(self.stmts.len());
178        self.stmts.push(stmt);
179        self.stmt_spans.push(span);
180        id
181    }
182
183    /// Adds a declaration, with the source it came from.
184    ///
185    /// # Panics
186    ///
187    /// Panics if the arena would exceed four billion nodes.
188    pub fn decl(&mut self, decl: Decl, span: Span) -> DeclId {
189        let id = Idx::from_usize(self.decls.len());
190        self.decls.push(decl);
191        self.decl_spans.push(span);
192        id
193    }
194
195    /// The source an expression came from.
196    #[must_use]
197    pub fn expr_span(&self, id: ExprId) -> Span {
198        self.expr_spans[id.index()]
199    }
200
201    /// The source a statement came from.
202    #[must_use]
203    pub fn stmt_span(&self, id: StmtId) -> Span {
204        self.stmt_spans[id.index()]
205    }
206
207    /// The source a declaration came from.
208    #[must_use]
209    pub fn decl_span(&self, id: DeclId) -> Span {
210        self.decl_spans[id.index()]
211    }
212
213    /// How many expressions, statements and declarations the tree holds.
214    ///
215    /// The three numbers the size of a translation unit is usually quoted in, and what the
216    /// `--emit=ast` header prints.
217    #[must_use]
218    pub fn counts(&self) -> Counts {
219        Counts { exprs: self.exprs.len(), stmts: self.stmts.len(), decls: self.decls.len() }
220    }
221
222    /// Whether nothing has been parsed into this tree.
223    #[must_use]
224    pub fn is_empty(&self) -> bool {
225        self.exprs.is_empty() && self.stmts.is_empty() && self.decls.is_empty()
226    }
227}
228
229/// How many nodes of each kind a tree holds.
230#[derive(Debug, Clone, Copy, PartialEq, Eq)]
231pub struct Counts {
232    /// Expressions.
233    pub exprs: usize,
234    /// Statements.
235    pub stmts: usize,
236    /// Declarations.
237    pub decls: usize,
238}
239
240impl fmt::Debug for Ast {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        // Printing a translation unit as a `{:?}` is never what anyone wanted from the tree,
243        // and there is a printer for the case where they did. This reports the shape.
244        let counts = self.counts();
245        f.debug_struct("Ast")
246            .field("exprs", &counts.exprs)
247            .field("stmts", &counts.stmts)
248            .field("decls", &counts.decls)
249            .field("top_level", &self.top_level.len())
250            .finish()
251    }
252}
253
254/// Generates the read side of a table that holds one item per index.
255macro_rules! node_table {
256    ($id:ty => $item:ty, $field:ident) => {
257        impl Index<$id> for Ast {
258            type Output = $item;
259
260            #[inline]
261            fn index(&self, id: $id) -> &$item {
262                &self.$field[id.index()]
263            }
264        }
265    };
266}
267
268/// Generates both sides of a table that is read in runs: the builder that appends a run and
269/// returns the range covering it, and the indexing that gives the run back.
270macro_rules! list_table {
271    (
272        $(#[$doc:meta])*
273        $add:ident, $list:ty => $item:ty, $field:ident
274    ) => {
275        impl Ast {
276            $(#[$doc])*
277            ///
278            /// # Panics
279            ///
280            /// Panics if the table would exceed four billion entries.
281            pub fn $add(&mut self, items: &[$item]) -> $list {
282                let start = Idx::from_usize(self.$field.len());
283                self.$field.extend_from_slice(items);
284                let end = Idx::from_usize(self.$field.len());
285                IdxRange::new(start, end)
286            }
287        }
288
289        impl Index<$list> for Ast {
290            type Output = [$item];
291
292            #[inline]
293            fn index(&self, list: $list) -> &[$item] {
294                &self.$field[list.as_usize_range()]
295            }
296        }
297    };
298}
299
300/// Generates both sides of a side table whose items are added one at a time.
301macro_rules! side_table {
302    (
303        $(#[$doc:meta])*
304        $add:ident, $id:ty => $item:ty, $field:ident
305    ) => {
306        impl Ast {
307            $(#[$doc])*
308            ///
309            /// # Panics
310            ///
311            /// Panics if the table would exceed four billion entries.
312            pub fn $add(&mut self, item: $item) -> $id {
313                let id = Idx::from_usize(self.$field.len());
314                self.$field.push(item);
315                id
316            }
317        }
318
319        node_table!($id => $item, $field);
320    };
321}
322
323node_table!(ExprId => Expr, exprs);
324node_table!(StmtId => Stmt, stmts);
325node_table!(DeclId => Decl, decls);
326
327side_table! {
328    /// Adds a declarator.
329    add_declarator, DeclaratorId => Declarator, declarators
330}
331side_table! {
332    /// Adds a type name.
333    add_type_name, TypeNameId => TypeName, type_names
334}
335side_table! {
336    /// Adds a set of declaration specifiers.
337    add_specs, DeclSpecsId => DeclSpecs, specs
338}
339side_table! {
340    /// Adds an initializer.
341    add_init, InitId => Init, inits
342}
343side_table! {
344    /// Adds an assembly statement.
345    add_asm, AsmId => Asm, asms
346}
347side_table! {
348    /// Adds an integer constant.
349    add_int, IntId => IntConstant, ints
350}
351side_table! {
352    /// Adds a floating constant.
353    add_float, FloatId => FloatConstant, floats
354}
355side_table! {
356    /// Adds a character constant.
357    add_char, CharId => CharConstant, chars
358}
359side_table! {
360    /// Adds a string literal.
361    add_string, StrId => StringLiteral, strings
362}
363
364list_table! {
365    /// Adds a run of expressions, such as the arguments of a call.
366    add_expr_list, ExprList => ExprId, expr_refs
367}
368list_table! {
369    /// Adds a run of statements, such as the body of a compound statement.
370    add_stmt_list, StmtList => StmtId, stmt_refs
371}
372list_table! {
373    /// Adds a run of declarations, such as the parameter declarations of an old-style
374    /// function definition.
375    add_decl_list, DeclList => DeclId, decl_refs
376}
377list_table! {
378    /// Adds a run of string literals, such as an `asm` clobber list.
379    add_str_list, StrList => StrId, str_refs
380}
381list_table! {
382    /// Adds a run of identifiers, such as the labels of an `asm goto`.
383    add_symbol_list, SymbolList => Symbol, symbols
384}
385list_table! {
386    /// Adds a run of attributes.
387    add_attr_list, AttrList => Attribute, attrs
388}
389list_table! {
390    /// Adds a run of attribute arguments.
391    add_attr_args, AttrArgList => AttrArg, attr_args
392}
393list_table! {
394    /// Adds a run of declarator derivations, from the name outward.
395    add_derived_list, DerivedList => Derived, derived
396}
397list_table! {
398    /// Adds a run of function parameters.
399    add_param_list, ParamList => Param, params
400}
401list_table! {
402    /// Adds a run of struct or union members.
403    add_member_list, MemberList => Member, members
404}
405list_table! {
406    /// Adds a run of enumerators.
407    add_enumerator_list, EnumeratorList => Enumerator, enumerators
408}
409list_table! {
410    /// Adds a run of init-declarators.
411    add_init_declarator_list, InitDeclaratorList => InitDeclarator, init_declarators
412}
413list_table! {
414    /// Adds a run of braced initializer elements.
415    add_init_item_list, InitItemList => InitItem, init_items
416}
417list_table! {
418    /// Adds a run of designators.
419    add_designator_list, DesignatorList => Designator, designators
420}
421list_table! {
422    /// Adds a run of `_Generic` associations.
423    add_generic_list, GenericList => GenericAssoc, generics
424}
425list_table! {
426    /// Adds a run of assembly operands.
427    add_asm_operand_list, AsmOperandList => AsmOperand, asm_operands
428}
429
430#[cfg(test)]
431mod tests {
432    use super::*;
433    use crate::expr::BinaryOp;
434
435    fn span(lo: u32, hi: u32) -> Span {
436        Span::new(lo, hi)
437    }
438
439    #[test]
440    fn a_new_tree_is_empty() {
441        let ast = Ast::new();
442        assert!(ast.is_empty());
443        assert!(ast.top_level().is_empty());
444        assert_eq!(ast.counts(), Counts { exprs: 0, stmts: 0, decls: 0 });
445    }
446
447    #[test]
448    fn nodes_come_back_by_index_and_spans_stay_beside_them() {
449        let mut ast = Ast::new();
450        let one = ast.expr(Expr::Nullptr, span(0, 7));
451        let two = ast.expr(Expr::Bool(true), span(10, 14));
452        let sum = ast.expr(Expr::Binary { op: BinaryOp::Add, lhs: one, rhs: two }, span(0, 14));
453
454        assert_eq!(ast[one], Expr::Nullptr);
455        assert_eq!(ast[two], Expr::Bool(true));
456        assert_eq!(ast[sum], Expr::Binary { op: BinaryOp::Add, lhs: one, rhs: two });
457        assert_eq!(ast.expr_span(one), span(0, 7));
458        assert_eq!(ast.expr_span(sum), span(0, 14));
459        assert_eq!(ast.counts().exprs, 3);
460        assert!(!ast.is_empty());
461    }
462
463    #[test]
464    fn a_run_comes_back_in_the_order_it_went_in() {
465        let mut ast = Ast::new();
466        let a = ast.expr(Expr::Nullptr, span(0, 1));
467        let b = ast.expr(Expr::Bool(false), span(2, 3));
468        let c = ast.expr(Expr::Bool(true), span(4, 5));
469        let first = ast.add_expr_list(&[a, b]);
470        let second = ast.add_expr_list(&[c]);
471
472        assert_eq!(ast[first], [a, b]);
473        assert_eq!(ast[second], [c]);
474        assert_eq!(first.len(), 2);
475    }
476
477    #[test]
478    fn an_empty_run_is_valid_before_anything_is_in_the_table() {
479        let ast = Ast::new();
480        assert!(ast[AttrList::EMPTY].is_empty());
481        assert!(ast[DerivedList::EMPTY].is_empty());
482        assert!(ast[ExprList::EMPTY].is_empty());
483    }
484
485    #[test]
486    fn the_three_arenas_are_numbered_independently() {
487        let mut ast = Ast::new();
488        let e = ast.expr(Expr::Nullptr, span(0, 1));
489        let s = ast.stmt(Stmt::Empty, span(0, 1));
490        let d = ast.decl(Decl::Error, span(0, 1));
491        assert_eq!(e.raw(), 0);
492        assert_eq!(s.raw(), 0);
493        assert_eq!(d.raw(), 0);
494        assert_eq!(ast[s], Stmt::Empty);
495        assert_eq!(ast[d], Decl::Error);
496        assert_eq!(ast.stmt_span(s), span(0, 1));
497        assert_eq!(ast.decl_span(d), span(0, 1));
498    }
499
500    #[test]
501    fn debug_reports_the_shape_rather_than_the_tree() {
502        let mut ast = Ast::new();
503        let d = ast.decl(Decl::Error, span(0, 1));
504        ast.add_top_level(d);
505        let text = format!("{ast:?}");
506        assert!(text.starts_with("Ast {"), "{text}");
507        assert!(text.contains("decls: 1"), "{text}");
508        assert!(text.contains("top_level: 1"), "{text}");
509    }
510}