use crate::{kw, variable::VariableDefinition, SolIdent, Spanned};
use proc_macro2::Span;
use std::fmt;
use syn::{
parse::{Parse, ParseStream},
Attribute, Result, Token,
};
mod contract;
pub use contract::{ContractKind, Inheritance, ItemContract};
mod r#enum;
pub use r#enum::{ItemEnum, Variant};
mod error;
pub use error::ItemError;
mod event;
pub use event::{EventParameter, ItemEvent};
mod function;
pub use function::{FunctionBody, FunctionKind, ItemFunction, Returns};
mod import;
pub use import::{
ImportAlias, ImportAliases, ImportDirective, ImportGlob, ImportPath, ImportPlain,
};
mod pragma;
pub use pragma::{PragmaDirective, PragmaTokens};
mod r#struct;
pub use r#struct::ItemStruct;
mod udt;
pub use udt::ItemUdt;
mod using;
pub use using::{UserDefinableOperator, UsingDirective, UsingList, UsingListItem, UsingType};
#[derive(Clone)]
pub enum Item {
Contract(ItemContract),
Enum(ItemEnum),
Error(ItemError),
Event(ItemEvent),
Function(ItemFunction),
Import(ImportDirective),
Pragma(PragmaDirective),
Struct(ItemStruct),
Udt(ItemUdt),
Using(UsingDirective),
Variable(VariableDefinition),
}
impl fmt::Display for Item {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Contract(item) => item.fmt(f),
Self::Enum(item) => item.fmt(f),
Self::Error(item) => item.fmt(f),
Self::Event(item) => item.fmt(f),
Self::Function(item) => item.fmt(f),
Self::Import(item) => item.fmt(f),
Self::Pragma(item) => item.fmt(f),
Self::Struct(item) => item.fmt(f),
Self::Udt(item) => item.fmt(f),
Self::Using(item) => item.fmt(f),
Self::Variable(item) => item.fmt(f),
}
}
}
impl fmt::Debug for Item {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Item::")?;
match self {
Self::Contract(item) => item.fmt(f),
Self::Enum(item) => item.fmt(f),
Self::Error(item) => item.fmt(f),
Self::Event(item) => item.fmt(f),
Self::Function(item) => item.fmt(f),
Self::Import(item) => item.fmt(f),
Self::Pragma(item) => item.fmt(f),
Self::Struct(item) => item.fmt(f),
Self::Udt(item) => item.fmt(f),
Self::Using(item) => item.fmt(f),
Self::Variable(item) => item.fmt(f),
}
}
}
impl Parse for Item {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let mut attrs = input.call(Attribute::parse_outer)?;
let lookahead = input.lookahead1();
let mut item = if FunctionKind::peek(&lookahead) {
input.parse().map(Self::Function)
} else if lookahead.peek(Token![struct]) {
input.parse().map(Self::Struct)
} else if lookahead.peek(kw::event) {
input.parse().map(Self::Event)
} else if lookahead.peek(kw::error) {
input.parse().map(Self::Error)
} else if ContractKind::peek(&lookahead) {
input.parse().map(Self::Contract)
} else if lookahead.peek(Token![enum]) {
input.parse().map(Self::Enum)
} else if lookahead.peek(Token![type]) {
input.parse().map(Self::Udt)
} else if lookahead.peek(kw::pragma) {
input.parse().map(Self::Pragma)
} else if lookahead.peek(kw::import) {
input.parse().map(Self::Import)
} else if lookahead.peek(kw::using) {
input.parse().map(Self::Using)
} else if crate::Type::peek(&lookahead) {
input.parse().map(Self::Variable)
} else {
Err(lookahead.error())
}?;
attrs.extend(item.replace_attrs(Vec::new()));
item.replace_attrs(attrs);
Ok(item)
}
}
impl Spanned for Item {
fn span(&self) -> Span {
match self {
Self::Contract(contract) => contract.span(),
Self::Enum(enumm) => enumm.span(),
Self::Error(error) => error.span(),
Self::Event(event) => event.span(),
Self::Function(function) => function.span(),
Self::Import(import) => import.span(),
Self::Pragma(pragma) => pragma.span(),
Self::Struct(strukt) => strukt.span(),
Self::Udt(udt) => udt.span(),
Self::Using(using) => using.span(),
Self::Variable(variable) => variable.span(),
}
}
fn set_span(&mut self, span: Span) {
match self {
Self::Contract(contract) => contract.set_span(span),
Self::Enum(enumm) => enumm.set_span(span),
Self::Error(error) => error.set_span(span),
Self::Event(event) => event.set_span(span),
Self::Function(function) => function.set_span(span),
Self::Import(import) => import.set_span(span),
Self::Pragma(pragma) => pragma.set_span(span),
Self::Struct(strukt) => strukt.set_span(span),
Self::Udt(udt) => udt.set_span(span),
Self::Using(using) => using.set_span(span),
Self::Variable(variable) => variable.set_span(span),
}
}
}
impl Item {
pub fn name(&self) -> Option<&SolIdent> {
match self {
Self::Contract(ItemContract { name, .. })
| Self::Enum(ItemEnum { name, .. })
| Self::Error(ItemError { name, .. })
| Self::Event(ItemEvent { name, .. })
| Self::Function(ItemFunction { name: Some(name), .. })
| Self::Struct(ItemStruct { name, .. })
| Self::Udt(ItemUdt { name, .. }) => Some(name),
_ => None,
}
}
pub fn attrs(&self) -> Option<&Vec<Attribute>> {
match self {
Self::Contract(ItemContract { attrs, .. })
| Self::Function(ItemFunction { attrs, .. })
| Self::Enum(ItemEnum { attrs, .. })
| Self::Error(ItemError { attrs, .. })
| Self::Event(ItemEvent { attrs, .. })
| Self::Struct(ItemStruct { attrs, .. })
| Self::Udt(ItemUdt { attrs, .. })
| Self::Variable(VariableDefinition { attrs, .. }) => Some(attrs),
Self::Import(_) | Self::Pragma(_) | Self::Using(_) => None,
}
}
pub fn attrs_mut(&mut self) -> Option<&mut Vec<Attribute>> {
match self {
Self::Contract(ItemContract { attrs, .. })
| Self::Function(ItemFunction { attrs, .. })
| Self::Enum(ItemEnum { attrs, .. })
| Self::Error(ItemError { attrs, .. })
| Self::Event(ItemEvent { attrs, .. })
| Self::Struct(ItemStruct { attrs, .. })
| Self::Udt(ItemUdt { attrs, .. })
| Self::Variable(VariableDefinition { attrs, .. }) => Some(attrs),
Self::Import(_) | Self::Pragma(_) | Self::Using(_) => None,
}
}
fn replace_attrs(&mut self, src: Vec<Attribute>) -> Vec<Attribute> {
if let Some(attrs) = self.attrs_mut() {
std::mem::replace(attrs, src)
} else {
Vec::new()
}
}
}