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