solar_ast/ast/
mod.rs

1//! Solidity AST.
2
3use solar_data_structures::{index::IndexSlice, newtype_index, BumpExt};
4use std::fmt;
5
6pub use crate::token::CommentKind;
7pub use solar_interface::{Ident, Span, Symbol};
8
9mod expr;
10pub use expr::*;
11
12mod item;
13pub use item::*;
14
15mod lit;
16pub use lit::*;
17
18mod path;
19pub use path::*;
20
21mod semver;
22pub use semver::*;
23
24mod stmt;
25pub use stmt::*;
26
27mod ty;
28pub use ty::*;
29
30pub mod yul;
31
32pub type Box<'ast, T> = &'ast mut T;
33
34/// AST arena allocator.
35pub struct Arena {
36    pub bump: bumpalo::Bump,
37    pub literals: typed_arena::Arena<Lit>,
38}
39
40impl Arena {
41    /// Creates a new AST arena.
42    pub fn new() -> Self {
43        Self { bump: bumpalo::Bump::new(), literals: typed_arena::Arena::new() }
44    }
45
46    pub fn allocated_bytes(&self) -> usize {
47        self.bump.allocated_bytes()
48            + (self.literals.len() + self.literals.uninitialized_array().len())
49                * std::mem::size_of::<Lit>()
50    }
51
52    pub fn used_bytes(&self) -> usize {
53        self.bump.used_bytes() + self.literals.len() * std::mem::size_of::<Lit>()
54    }
55}
56
57impl Default for Arena {
58    fn default() -> Self {
59        Self::new()
60    }
61}
62
63impl std::ops::Deref for Arena {
64    type Target = bumpalo::Bump;
65
66    #[inline]
67    fn deref(&self) -> &Self::Target {
68        &self.bump
69    }
70}
71
72/// A list of doc-comments.
73#[derive(Default)]
74pub struct DocComments<'ast>(pub Box<'ast, [DocComment]>);
75
76impl<'ast> std::ops::Deref for DocComments<'ast> {
77    type Target = Box<'ast, [DocComment]>;
78
79    #[inline]
80    fn deref(&self) -> &Self::Target {
81        &self.0
82    }
83}
84
85impl std::ops::DerefMut for DocComments<'_> {
86    #[inline]
87    fn deref_mut(&mut self) -> &mut Self::Target {
88        &mut self.0
89    }
90}
91
92impl<'ast> From<Box<'ast, [DocComment]>> for DocComments<'ast> {
93    fn from(comments: Box<'ast, [DocComment]>) -> Self {
94        Self(comments)
95    }
96}
97
98impl fmt::Debug for DocComments<'_> {
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100        f.write_str("DocComments ")?;
101        self.0.fmt(f)
102    }
103}
104
105impl DocComments<'_> {
106    /// Returns the span containing all doc-comments.
107    pub fn span(&self) -> Span {
108        Span::join_first_last(self.iter().map(|d| d.span))
109    }
110}
111
112/// A single doc-comment: `/// foo`, `/** bar */`.
113#[derive(Clone, Copy, Debug)]
114pub struct DocComment {
115    /// The comment kind.
116    pub kind: CommentKind,
117    /// The comment's span including its "quotes" (`//`, `/**`).
118    pub span: Span,
119    /// The comment's contents excluding its "quotes" (`//`, `/**`)
120    /// similarly to symbols in string literal tokens.
121    pub symbol: Symbol,
122}
123
124/// A Solidity source file.
125pub struct SourceUnit<'ast> {
126    /// The source unit's items.
127    pub items: Box<'ast, IndexSlice<ItemId, [Item<'ast>]>>,
128}
129
130impl fmt::Debug for SourceUnit<'_> {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        f.write_str("SourceUnit ")?;
133        self.items.fmt(f)
134    }
135}
136
137impl<'ast> SourceUnit<'ast> {
138    /// Creates a new source unit from the given items.
139    pub fn new(items: Box<'ast, [Item<'ast>]>) -> Self {
140        Self { items: IndexSlice::from_slice_mut(items) }
141    }
142}
143
144newtype_index! {
145    /// A [source unit item](Item) ID. Only used in [`SourceUnit`].
146    pub struct ItemId;
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152
153    #[test]
154    fn no_drop() {
155        #[track_caller]
156        fn assert_no_drop<T>() {
157            assert!(!std::mem::needs_drop::<T>(), "{}", std::any::type_name::<T>());
158        }
159        assert_no_drop::<Type<'_>>();
160        assert_no_drop::<Expr<'_>>();
161        assert_no_drop::<Stmt<'_>>();
162        assert_no_drop::<Item<'_>>();
163        assert_no_drop::<SourceUnit<'_>>();
164    }
165}