1use 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
44pub type IntId = Idx<IntConstant>;
46pub type FloatId = Idx<FloatConstant>;
48pub type CharId = Idx<CharConstant>;
50pub type StrId = Idx<StringLiteral>;
52
53#[derive(Debug)]
55pub struct ExprRef;
56#[derive(Debug)]
58pub struct StmtRef;
59#[derive(Debug)]
61pub struct DeclRef;
62#[derive(Debug)]
64pub struct StrRef;
65
66pub type ExprList = IdxRange<ExprRef>;
68pub type StmtList = IdxRange<StmtRef>;
70pub type DeclList = IdxRange<DeclRef>;
72pub type StrList = IdxRange<StrRef>;
74pub type SymbolList = IdxRange<Symbol>;
76pub type AttrList = IdxRange<Attribute>;
78pub type AttrArgList = IdxRange<AttrArg>;
80pub type DerivedList = IdxRange<Derived>;
82pub type ParamList = IdxRange<Param>;
84pub type MemberList = IdxRange<Member>;
86pub type EnumeratorList = IdxRange<Enumerator>;
88pub type InitDeclaratorList = IdxRange<InitDeclarator>;
90pub type InitItemList = IdxRange<InitItem>;
92pub type DesignatorList = IdxRange<Designator>;
94pub type GenericList = IdxRange<GenericAssoc>;
96pub type AsmOperandList = IdxRange<AsmOperand>;
98
99#[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 #[must_use]
143 pub fn new() -> Ast {
144 Ast::default()
145 }
146
147 #[must_use]
149 pub fn top_level(&self) -> &[DeclId] {
150 &self.top_level
151 }
152
153 pub fn add_top_level(&mut self, decl: DeclId) {
155 self.top_level.push(decl);
156 }
157
158 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 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 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 #[must_use]
197 pub fn expr_span(&self, id: ExprId) -> Span {
198 self.expr_spans[id.index()]
199 }
200
201 #[must_use]
203 pub fn stmt_span(&self, id: StmtId) -> Span {
204 self.stmt_spans[id.index()]
205 }
206
207 #[must_use]
209 pub fn decl_span(&self, id: DeclId) -> Span {
210 self.decl_spans[id.index()]
211 }
212
213 #[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 #[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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
231pub struct Counts {
232 pub exprs: usize,
234 pub stmts: usize,
236 pub decls: usize,
238}
239
240impl fmt::Debug for Ast {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 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
254macro_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
268macro_rules! list_table {
271 (
272 $(#[$doc:meta])*
273 $add:ident, $list:ty => $item:ty, $field:ident
274 ) => {
275 impl Ast {
276 $(#[$doc])*
277 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
300macro_rules! side_table {
302 (
303 $(#[$doc:meta])*
304 $add:ident, $id:ty => $item:ty, $field:ident
305 ) => {
306 impl Ast {
307 $(#[$doc])*
308 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 add_declarator, DeclaratorId => Declarator, declarators
330}
331side_table! {
332 add_type_name, TypeNameId => TypeName, type_names
334}
335side_table! {
336 add_specs, DeclSpecsId => DeclSpecs, specs
338}
339side_table! {
340 add_init, InitId => Init, inits
342}
343side_table! {
344 add_asm, AsmId => Asm, asms
346}
347side_table! {
348 add_int, IntId => IntConstant, ints
350}
351side_table! {
352 add_float, FloatId => FloatConstant, floats
354}
355side_table! {
356 add_char, CharId => CharConstant, chars
358}
359side_table! {
360 add_string, StrId => StringLiteral, strings
362}
363
364list_table! {
365 add_expr_list, ExprList => ExprId, expr_refs
367}
368list_table! {
369 add_stmt_list, StmtList => StmtId, stmt_refs
371}
372list_table! {
373 add_decl_list, DeclList => DeclId, decl_refs
376}
377list_table! {
378 add_str_list, StrList => StrId, str_refs
380}
381list_table! {
382 add_symbol_list, SymbolList => Symbol, symbols
384}
385list_table! {
386 add_attr_list, AttrList => Attribute, attrs
388}
389list_table! {
390 add_attr_args, AttrArgList => AttrArg, attr_args
392}
393list_table! {
394 add_derived_list, DerivedList => Derived, derived
396}
397list_table! {
398 add_param_list, ParamList => Param, params
400}
401list_table! {
402 add_member_list, MemberList => Member, members
404}
405list_table! {
406 add_enumerator_list, EnumeratorList => Enumerator, enumerators
408}
409list_table! {
410 add_init_declarator_list, InitDeclaratorList => InitDeclarator, init_declarators
412}
413list_table! {
414 add_init_item_list, InitItemList => InitItem, init_items
416}
417list_table! {
418 add_designator_list, DesignatorList => Designator, designators
420}
421list_table! {
422 add_generic_list, GenericList => GenericAssoc, generics
424}
425list_table! {
426 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}