1use solar_data_structures::{BumpExt, index::IndexSlice, newtype_index};
4use std::fmt;
5
6pub use crate::token::CommentKind;
7pub use either::{self, Either};
8pub use solar_interface::{Ident, Span, Spanned, Symbol};
9
10mod expr;
11pub use expr::*;
12
13mod item;
14pub use item::*;
15
16mod lit;
17pub use lit::*;
18
19mod path;
20pub use path::*;
21
22mod semver;
23pub use semver::*;
24
25mod stmt;
26pub use stmt::*;
27
28mod ty;
29pub use ty::*;
30
31pub mod yul;
32
33pub type Box<'ast, T> = &'ast mut T;
34
35pub struct Arena {
37 bump: bumpalo::Bump,
38}
39
40impl Arena {
41 pub fn new() -> Self {
43 Self { bump: bumpalo::Bump::new() }
44 }
45
46 pub fn bump(&self) -> &bumpalo::Bump {
48 &self.bump
49 }
50
51 pub fn bump_mut(&mut self) -> &mut bumpalo::Bump {
53 &mut self.bump
54 }
55
56 pub fn allocated_bytes(&self) -> usize {
58 self.bump.allocated_bytes()
59 }
60
61 pub fn used_bytes(&self) -> usize {
63 self.bump.used_bytes()
64 }
65}
66
67impl Default for Arena {
68 fn default() -> Self {
69 Self::new()
70 }
71}
72
73impl std::ops::Deref for Arena {
74 type Target = bumpalo::Bump;
75
76 #[inline]
77 fn deref(&self) -> &Self::Target {
78 &self.bump
79 }
80}
81
82#[derive(Default)]
84pub struct DocComments<'ast>(pub Box<'ast, [DocComment]>);
85
86impl<'ast> std::ops::Deref for DocComments<'ast> {
87 type Target = Box<'ast, [DocComment]>;
88
89 #[inline]
90 fn deref(&self) -> &Self::Target {
91 &self.0
92 }
93}
94
95impl std::ops::DerefMut for DocComments<'_> {
96 #[inline]
97 fn deref_mut(&mut self) -> &mut Self::Target {
98 &mut self.0
99 }
100}
101
102impl<'ast> From<Box<'ast, [DocComment]>> for DocComments<'ast> {
103 fn from(comments: Box<'ast, [DocComment]>) -> Self {
104 Self(comments)
105 }
106}
107
108impl fmt::Debug for DocComments<'_> {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 f.write_str("DocComments")?;
111 self.0.fmt(f)
112 }
113}
114
115impl DocComments<'_> {
116 pub fn span(&self) -> Span {
118 Span::join_first_last(self.iter().map(|d| d.span))
119 }
120}
121
122#[derive(Clone, Copy, Debug)]
124pub struct DocComment {
125 pub kind: CommentKind,
127 pub span: Span,
129 pub symbol: Symbol,
132}
133
134pub struct SourceUnit<'ast> {
136 pub items: Box<'ast, IndexSlice<ItemId, [Item<'ast>]>>,
138}
139
140impl fmt::Debug for SourceUnit<'_> {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 f.write_str("SourceUnit")?;
143 self.items.fmt(f)
144 }
145}
146
147impl<'ast> SourceUnit<'ast> {
148 pub fn new(items: Box<'ast, [Item<'ast>]>) -> Self {
150 Self { items: IndexSlice::from_slice_mut(items) }
151 }
152
153 pub fn count_contracts(&self) -> usize {
155 self.items.iter().filter(|item| matches!(item.kind, ItemKind::Contract(_))).count()
156 }
157
158 pub fn imports(&self) -> impl Iterator<Item = (Span, &ImportDirective<'ast>)> {
160 self.items.iter().filter_map(|item| match &item.kind {
161 ItemKind::Import(import) => Some((item.span, import)),
162 _ => None,
163 })
164 }
165}
166
167newtype_index! {
168 pub struct ItemId;
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn no_drop() {
178 #[track_caller]
179 fn assert_no_drop<T>() {
180 assert!(!std::mem::needs_drop::<T>(), "{}", std::any::type_name::<T>());
181 }
182 assert_no_drop::<Type<'_>>();
183 assert_no_drop::<Expr<'_>>();
184 assert_no_drop::<Stmt<'_>>();
185 assert_no_drop::<Item<'_>>();
186 assert_no_drop::<SourceUnit<'_>>();
187 }
188}