use solar_data_structures::{BumpExt, ThinSlice, index::IndexSlice, newtype_index};
use std::fmt;
pub use crate::token::CommentKind;
pub use either::{self, Either};
pub use solar_interface::{Ident, Span, Spanned, Symbol};
mod expr;
pub use expr::*;
mod item;
pub use item::*;
mod lit;
pub use lit::*;
mod natspec;
pub use natspec::*;
mod path;
pub use path::*;
mod semver;
pub use semver::*;
mod stmt;
pub use stmt::*;
mod ty;
pub use ty::*;
pub mod yul;
pub type Box<'ast, T> = &'ast mut T;
pub type BoxSlice<'ast, T> = Box<'ast, ThinSlice<T>>;
pub struct Arena {
bump: bumpalo::Bump,
}
impl Arena {
pub fn new() -> Self {
Self { bump: bumpalo::Bump::new() }
}
pub fn bump(&self) -> &bumpalo::Bump {
&self.bump
}
pub fn bump_mut(&mut self) -> &mut bumpalo::Bump {
&mut self.bump
}
pub fn allocated_bytes(&self) -> usize {
self.bump.allocated_bytes()
}
pub fn used_bytes(&self) -> usize {
self.bump.used_bytes()
}
}
impl Default for Arena {
fn default() -> Self {
Self::new()
}
}
impl std::ops::Deref for Arena {
type Target = bumpalo::Bump;
#[inline]
fn deref(&self) -> &Self::Target {
&self.bump
}
}
#[derive(Default)]
pub struct DocComments<'ast>(BoxSlice<'ast, DocComment<'ast>>);
impl<'ast> std::ops::Deref for DocComments<'ast> {
type Target = BoxSlice<'ast, DocComment<'ast>>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for DocComments<'_> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'ast> From<BoxSlice<'ast, DocComment<'ast>>> for DocComments<'ast> {
fn from(comments: BoxSlice<'ast, DocComment<'ast>>) -> Self {
Self(comments)
}
}
impl fmt::Debug for DocComments<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("DocComments")?;
self.0.fmt(f)
}
}
impl DocComments<'_> {
pub fn span(&self) -> Span {
Span::join_first_last(self.iter().map(|d| d.span))
}
}
pub struct SourceUnit<'ast> {
pub items: Box<'ast, IndexSlice<ItemId, [Item<'ast>]>>,
}
impl fmt::Debug for SourceUnit<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("SourceUnit")?;
self.items.fmt(f)
}
}
impl<'ast> SourceUnit<'ast> {
pub fn new(items: BoxSlice<'ast, Item<'ast>>) -> Self {
Self { items: IndexSlice::from_slice_mut(items) }
}
pub fn count_contracts(&self) -> usize {
self.items.iter().filter(|item| matches!(item.kind, ItemKind::Contract(_))).count()
}
pub fn imports(&self) -> impl Iterator<Item = (Span, &ImportDirective<'ast>)> {
self.items.iter().filter_map(|item| match &item.kind {
ItemKind::Import(import) => Some((item.span, import)),
_ => None,
})
}
}
newtype_index! {
pub struct ItemId;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_drop() {
#[track_caller]
fn assert_no_drop<T>() {
assert!(!std::mem::needs_drop::<T>(), "{}", std::any::type_name::<T>());
}
assert_no_drop::<Type<'_>>();
assert_no_drop::<Expr<'_>>();
assert_no_drop::<Stmt<'_>>();
assert_no_drop::<Item<'_>>();
assert_no_drop::<SourceUnit<'_>>();
}
#[test]
#[cfg_attr(not(target_pointer_width = "64"), ignore = "64-bit only")]
#[cfg_attr(feature = "nightly", ignore = "stable only")]
fn sizes() {
use snapbox::{assert_data_eq, str};
#[track_caller]
fn assert_size<T>(size: impl snapbox::IntoData) {
assert_size_(std::mem::size_of::<T>(), size.into_data());
}
#[track_caller]
fn assert_size_(actual: usize, expected: snapbox::Data) {
assert_data_eq!(actual.to_string(), expected);
}
assert_size::<Span>(str!["8"]);
assert_size::<DocComments<'_>>(str!["8"]);
assert_size::<SourceUnit<'_>>(str!["16"]);
assert_size::<PragmaDirective<'_>>(str!["32"]);
assert_size::<ImportDirective<'_>>(str!["32"]);
assert_size::<UsingDirective<'_>>(str!["48"]);
assert_size::<ItemContract<'_>>(str!["48"]);
assert_size::<ItemFunction<'_>>(str!["144"]);
assert_size::<VariableDefinition<'_>>(str!["72"]);
assert_size::<ItemStruct<'_>>(str!["24"]);
assert_size::<ItemEnum<'_>>(str!["24"]);
assert_size::<ItemUdvt<'_>>(str!["40"]);
assert_size::<ItemError<'_>>(str!["32"]);
assert_size::<ItemEvent<'_>>(str!["32"]);
assert_size::<ItemKind<'_>>(str!["144"]);
assert_size::<Item<'_>>(str!["160"]);
assert_size::<FunctionHeader<'_>>(str!["112"]);
assert_size::<ParameterList<'_>>(str!["16"]);
assert_size::<ElementaryType>(str!["4"]);
assert_size::<TypeKind<'_>>(str!["16"]);
assert_size::<Type<'_>>(str!["24"]);
assert_size::<ExprKind<'_>>(str!["40"]);
assert_size::<Expr<'_>>(str!["48"]);
assert_size::<StmtKind<'_>>(str!["48"]);
assert_size::<Stmt<'_>>(str!["64"]);
assert_size::<Block<'_>>(str!["16"]);
assert_size::<yul::ExprCall<'_>>(str!["24"]);
assert_size::<yul::ExprKind<'_>>(str!["32"]);
assert_size::<yul::Expr<'_>>(str!["40"]);
assert_size::<yul::StmtKind<'_>>(str!["56"]);
assert_size::<yul::Stmt<'_>>(str!["72"]);
assert_size::<yul::Block<'_>>(str!["16"]);
assert_size::<yul::StmtFor<'_>>(str!["88"]);
}
}