1use solar_data_structures::{BumpExt, ThinSlice, 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 natspec;
20pub use natspec::*;
21
22mod path;
23pub use path::*;
24
25mod semver;
26pub use semver::*;
27
28mod stmt;
29pub use stmt::*;
30
31mod ty;
32pub use ty::*;
33
34pub mod yul;
35
36pub type Box<'ast, T> = &'ast mut T;
38
39pub type BoxSlice<'ast, T> = Box<'ast, ThinSlice<T>>;
41
42pub struct Arena {
44 bump: bumpalo::Bump,
45}
46
47impl Arena {
48 pub fn new() -> Self {
50 Self { bump: bumpalo::Bump::new() }
51 }
52
53 pub fn bump(&self) -> &bumpalo::Bump {
55 &self.bump
56 }
57
58 pub fn bump_mut(&mut self) -> &mut bumpalo::Bump {
60 &mut self.bump
61 }
62
63 pub fn allocated_bytes(&self) -> usize {
65 self.bump.allocated_bytes()
66 }
67
68 pub fn used_bytes(&self) -> usize {
70 self.bump.used_bytes()
71 }
72}
73
74impl Default for Arena {
75 fn default() -> Self {
76 Self::new()
77 }
78}
79
80impl std::ops::Deref for Arena {
81 type Target = bumpalo::Bump;
82
83 #[inline]
84 fn deref(&self) -> &Self::Target {
85 &self.bump
86 }
87}
88
89#[derive(Default)]
91pub struct DocComments<'ast>(BoxSlice<'ast, DocComment<'ast>>);
92
93impl<'ast> std::ops::Deref for DocComments<'ast> {
94 type Target = BoxSlice<'ast, DocComment<'ast>>;
95
96 #[inline]
97 fn deref(&self) -> &Self::Target {
98 &self.0
99 }
100}
101
102impl std::ops::DerefMut for DocComments<'_> {
103 #[inline]
104 fn deref_mut(&mut self) -> &mut Self::Target {
105 &mut self.0
106 }
107}
108
109impl<'ast> From<BoxSlice<'ast, DocComment<'ast>>> for DocComments<'ast> {
110 fn from(comments: BoxSlice<'ast, DocComment<'ast>>) -> Self {
111 Self(comments)
112 }
113}
114
115impl fmt::Debug for DocComments<'_> {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 f.write_str("DocComments")?;
118 self.0.fmt(f)
119 }
120}
121
122impl DocComments<'_> {
123 pub fn span(&self) -> Span {
125 Span::join_first_last(self.iter().map(|d| d.span))
126 }
127}
128
129pub struct SourceUnit<'ast> {
131 pub items: Box<'ast, IndexSlice<ItemId, [Item<'ast>]>>,
133}
134
135impl fmt::Debug for SourceUnit<'_> {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.write_str("SourceUnit")?;
138 self.items.fmt(f)
139 }
140}
141
142impl<'ast> SourceUnit<'ast> {
143 pub fn new(items: BoxSlice<'ast, Item<'ast>>) -> Self {
145 Self { items: IndexSlice::from_slice_mut(items) }
146 }
147
148 pub fn count_contracts(&self) -> usize {
150 self.items.iter().filter(|item| matches!(item.kind, ItemKind::Contract(_))).count()
151 }
152
153 pub fn imports(&self) -> impl Iterator<Item = (Span, &ImportDirective<'ast>)> {
155 self.items.iter().filter_map(|item| match &item.kind {
156 ItemKind::Import(import) => Some((item.span, import)),
157 _ => None,
158 })
159 }
160}
161
162newtype_index! {
163 pub struct ItemId;
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn no_drop() {
173 #[track_caller]
174 fn assert_no_drop<T>() {
175 assert!(!std::mem::needs_drop::<T>(), "{}", std::any::type_name::<T>());
176 }
177 assert_no_drop::<Type<'_>>();
178 assert_no_drop::<Expr<'_>>();
179 assert_no_drop::<Stmt<'_>>();
180 assert_no_drop::<Item<'_>>();
181 assert_no_drop::<SourceUnit<'_>>();
182 }
183
184 #[test]
186 #[cfg_attr(not(target_pointer_width = "64"), ignore = "64-bit only")]
187 #[cfg_attr(feature = "nightly", ignore = "stable only")]
188 fn sizes() {
189 use snapbox::{assert_data_eq, str};
190 #[track_caller]
191 fn assert_size<T>(size: impl snapbox::IntoData) {
192 assert_size_(std::mem::size_of::<T>(), size.into_data());
193 }
194 #[track_caller]
195 fn assert_size_(actual: usize, expected: snapbox::Data) {
196 assert_data_eq!(actual.to_string(), expected);
197 }
198
199 assert_size::<Span>(str!["8"]);
200 assert_size::<DocComments<'_>>(str!["8"]);
201
202 assert_size::<SourceUnit<'_>>(str!["16"]);
203
204 assert_size::<PragmaDirective<'_>>(str!["32"]);
205 assert_size::<ImportDirective<'_>>(str!["32"]);
206 assert_size::<UsingDirective<'_>>(str!["48"]);
207 assert_size::<ItemContract<'_>>(str!["48"]);
208 assert_size::<ItemFunction<'_>>(str!["144"]);
209 assert_size::<VariableDefinition<'_>>(str!["72"]);
210 assert_size::<ItemStruct<'_>>(str!["24"]);
211 assert_size::<ItemEnum<'_>>(str!["24"]);
212 assert_size::<ItemUdvt<'_>>(str!["40"]);
213 assert_size::<ItemError<'_>>(str!["32"]);
214 assert_size::<ItemEvent<'_>>(str!["32"]);
215 assert_size::<ItemKind<'_>>(str!["144"]);
216 assert_size::<Item<'_>>(str!["160"]);
217
218 assert_size::<FunctionHeader<'_>>(str!["112"]);
219 assert_size::<ParameterList<'_>>(str!["16"]);
220
221 assert_size::<ElementaryType>(str!["4"]);
222 assert_size::<TypeKind<'_>>(str!["16"]);
223 assert_size::<Type<'_>>(str!["24"]);
224
225 assert_size::<ExprKind<'_>>(str!["40"]);
226 assert_size::<Expr<'_>>(str!["48"]);
227
228 assert_size::<StmtKind<'_>>(str!["48"]);
229 assert_size::<Stmt<'_>>(str!["64"]);
230 assert_size::<Block<'_>>(str!["16"]);
231
232 assert_size::<yul::ExprCall<'_>>(str!["24"]);
233 assert_size::<yul::ExprKind<'_>>(str!["32"]);
234 assert_size::<yul::Expr<'_>>(str!["40"]);
235
236 assert_size::<yul::StmtKind<'_>>(str!["56"]);
237 assert_size::<yul::Stmt<'_>>(str!["72"]);
238 assert_size::<yul::Block<'_>>(str!["16"]);
239 assert_size::<yul::StmtFor<'_>>(str!["88"]);
240 }
241}