1use super::{
2 AstPath, BinOpKind, Block, Box, CallArgs, DocComments, Expr, SemverReq, StrLit, Type, UnOpKind,
3};
4use crate::{BoxSlice, token::Token};
5use either::Either;
6use solar_interface::{Ident, Span, Spanned, Symbol};
7use std::{
8 fmt,
9 ops::{Deref, DerefMut},
10};
11use strum::EnumIs;
12
13#[derive(Debug, Default)]
17pub struct ParameterList<'ast> {
18 pub span: Span,
19 pub vars: BoxSlice<'ast, VariableDefinition<'ast>>,
20}
21
22impl<'ast> Deref for ParameterList<'ast> {
23 type Target = BoxSlice<'ast, VariableDefinition<'ast>>;
24
25 fn deref(&self) -> &Self::Target {
26 &self.vars
27 }
28}
29
30impl<'ast> DerefMut for ParameterList<'ast> {
31 fn deref_mut(&mut self) -> &mut Self::Target {
32 &mut self.vars
33 }
34}
35
36#[derive(Debug)]
38pub struct Item<'ast> {
39 pub docs: DocComments<'ast>,
40 pub span: Span,
41 pub kind: ItemKind<'ast>,
43}
44
45impl Item<'_> {
46 pub fn name(&self) -> Option<Ident> {
48 self.kind.name()
49 }
50
51 pub fn description(&self) -> &'static str {
53 self.kind.description()
54 }
55
56 pub fn is_allowed_in_contract(&self) -> bool {
58 self.kind.is_allowed_in_contract()
59 }
60}
61
62pub enum ItemKind<'ast> {
66 Pragma(PragmaDirective<'ast>),
68
69 Import(ImportDirective<'ast>),
71
72 Using(UsingDirective<'ast>),
74
75 Contract(ItemContract<'ast>),
78
79 Function(ItemFunction<'ast>),
82
83 Variable(VariableDefinition<'ast>),
85
86 Struct(ItemStruct<'ast>),
88
89 Enum(ItemEnum<'ast>),
91
92 Udvt(ItemUdvt<'ast>),
94
95 Error(ItemError<'ast>),
97
98 Event(ItemEvent<'ast>),
101}
102
103impl fmt::Debug for ItemKind<'_> {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.write_str("ItemKind::")?;
106 match self {
107 ItemKind::Pragma(item) => item.fmt(f),
108 ItemKind::Import(item) => item.fmt(f),
109 ItemKind::Using(item) => item.fmt(f),
110 ItemKind::Contract(item) => item.fmt(f),
111 ItemKind::Function(item) => item.fmt(f),
112 ItemKind::Variable(item) => item.fmt(f),
113 ItemKind::Struct(item) => item.fmt(f),
114 ItemKind::Enum(item) => item.fmt(f),
115 ItemKind::Udvt(item) => item.fmt(f),
116 ItemKind::Error(item) => item.fmt(f),
117 ItemKind::Event(item) => item.fmt(f),
118 }
119 }
120}
121
122impl ItemKind<'_> {
123 pub fn name(&self) -> Option<Ident> {
125 match self {
126 Self::Pragma(_) | Self::Import(_) | Self::Using(_) => None,
127 Self::Contract(item) => Some(item.name),
128 Self::Function(item) => item.header.name,
129 Self::Variable(item) => item.name,
130 Self::Struct(item) => Some(item.name),
131 Self::Enum(item) => Some(item.name),
132 Self::Udvt(item) => Some(item.name),
133 Self::Error(item) => Some(item.name),
134 Self::Event(item) => Some(item.name),
135 }
136 }
137
138 pub fn description(&self) -> &'static str {
140 match self {
141 Self::Pragma(_) => "pragma directive",
142 Self::Import(_) => "import directive",
143 Self::Using(_) => "using directive",
144 Self::Contract(_) => "contract definition",
145 Self::Function(_) => "function definition",
146 Self::Variable(_) => "variable definition",
147 Self::Struct(_) => "struct definition",
148 Self::Enum(_) => "enum definition",
149 Self::Udvt(_) => "user-defined value type definition",
150 Self::Error(_) => "error definition",
151 Self::Event(_) => "event definition",
152 }
153 }
154
155 pub fn is_allowed_in_contract(&self) -> bool {
157 match self {
158 Self::Pragma(_) => false,
159 Self::Import(_) => false,
160 Self::Using(_) => true,
161 Self::Contract(_) => false,
162 Self::Function(_) => true,
163 Self::Variable(_) => true,
164 Self::Struct(_) => true,
165 Self::Enum(_) => true,
166 Self::Udvt(_) => true,
167 Self::Error(_) => true,
168 Self::Event(_) => true,
169 }
170 }
171}
172
173#[derive(Debug)]
175pub struct PragmaDirective<'ast> {
176 pub tokens: PragmaTokens<'ast>,
178}
179
180#[derive(Debug)]
182pub enum PragmaTokens<'ast> {
183 Version(Ident, SemverReq<'ast>),
187 Custom(IdentOrStrLit, Option<IdentOrStrLit>),
189 Verbatim(BoxSlice<'ast, Token>),
191}
192
193impl PragmaTokens<'_> {
194 pub fn as_name_and_value(&self) -> Option<(&IdentOrStrLit, Option<&IdentOrStrLit>)> {
209 match self {
210 Self::Custom(name, value) => Some((name, value.as_ref())),
211 _ => None,
212 }
213 }
214}
215
216#[derive(Clone, Debug)]
225pub enum IdentOrStrLit {
226 Ident(Ident),
228 StrLit(StrLit),
230}
231
232impl IdentOrStrLit {
233 pub fn value(&self) -> Symbol {
235 match self {
236 Self::Ident(ident) => ident.name,
237 Self::StrLit(str_lit) => str_lit.value,
238 }
239 }
240
241 pub fn as_str(&self) -> &str {
243 match self {
244 Self::Ident(ident) => ident.as_str(),
245 Self::StrLit(str_lit) => str_lit.value.as_str(),
246 }
247 }
248
249 pub fn span(&self) -> Span {
251 match self {
252 Self::Ident(ident) => ident.span,
253 Self::StrLit(str_lit) => str_lit.span,
254 }
255 }
256}
257
258#[derive(Debug)]
262pub struct ImportDirective<'ast> {
263 pub path: StrLit,
267 pub items: ImportItems<'ast>,
268}
269
270impl ImportDirective<'_> {
271 pub fn source_alias(&self) -> Option<Ident> {
273 self.items.source_alias()
274 }
275}
276
277#[derive(Debug)]
279pub enum ImportItems<'ast> {
280 Plain(Option<Ident>),
282 Aliases(BoxSlice<'ast, (Ident, Option<Ident>)>),
284 Glob(Ident),
286}
287
288impl ImportItems<'_> {
289 pub fn source_alias(&self) -> Option<Ident> {
291 match *self {
292 ImportItems::Plain(ident) => ident,
293 ImportItems::Aliases(_) => None,
294 ImportItems::Glob(ident) => Some(ident),
295 }
296 }
297}
298
299#[derive(Debug)]
303pub struct UsingDirective<'ast> {
304 pub list: UsingList<'ast>,
306 pub ty: Option<Type<'ast>>,
308 pub global: bool,
309}
310
311#[derive(Debug)]
313pub enum UsingList<'ast> {
314 Single(AstPath<'ast>),
316 Multiple(BoxSlice<'ast, (AstPath<'ast>, Option<UserDefinableOperator>)>),
318}
319
320#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
324pub enum UserDefinableOperator {
325 BitAnd,
327 BitNot,
329 BitOr,
331 BitXor,
333 Add,
335 Div,
337 Rem,
339 Mul,
341 Sub,
343 Eq,
345 Ge,
347 Gt,
349 Le,
351 Lt,
353 Ne,
355}
356
357impl UserDefinableOperator {
358 pub const fn from_unop(op: UnOpKind) -> Option<Self> {
360 Some(match op {
361 UnOpKind::Neg => Self::Sub,
362 UnOpKind::BitNot => Self::BitNot,
363 UnOpKind::PreInc
364 | UnOpKind::PreDec
365 | UnOpKind::Not
366 | UnOpKind::PostInc
367 | UnOpKind::PostDec => {
368 return None;
369 }
370 })
371 }
372
373 pub const fn from_binop(op: BinOpKind) -> Option<Self> {
375 Some(match op {
376 BinOpKind::BitAnd => Self::BitAnd,
377 BinOpKind::BitOr => Self::BitOr,
378 BinOpKind::BitXor => Self::BitXor,
379 BinOpKind::Add => Self::Add,
380 BinOpKind::Div => Self::Div,
381 BinOpKind::Rem => Self::Rem,
382 BinOpKind::Mul => Self::Mul,
383 BinOpKind::Sub => Self::Sub,
384 BinOpKind::Eq => Self::Eq,
385 BinOpKind::Ge => Self::Ge,
386 BinOpKind::Gt => Self::Gt,
387 BinOpKind::Le => Self::Le,
388 BinOpKind::Lt => Self::Lt,
389 BinOpKind::Ne => Self::Ne,
390 BinOpKind::Or
391 | BinOpKind::And
392 | BinOpKind::Shr
393 | BinOpKind::Shl
394 | BinOpKind::Sar
395 | BinOpKind::Pow => {
396 return None;
397 }
398 })
399 }
400
401 pub const fn to_op(self) -> Either<UnOpKind, BinOpKind> {
403 match self {
404 Self::BitAnd => Either::Right(BinOpKind::BitAnd),
405 Self::BitNot => Either::Left(UnOpKind::BitNot),
406 Self::BitOr => Either::Right(BinOpKind::BitOr),
407 Self::BitXor => Either::Right(BinOpKind::BitXor),
408 Self::Add => Either::Right(BinOpKind::Add),
409 Self::Div => Either::Right(BinOpKind::Div),
410 Self::Rem => Either::Right(BinOpKind::Rem),
411 Self::Mul => Either::Right(BinOpKind::Mul),
412 Self::Sub => Either::Right(BinOpKind::Sub),
413 Self::Eq => Either::Right(BinOpKind::Eq),
414 Self::Ge => Either::Right(BinOpKind::Ge),
415 Self::Gt => Either::Right(BinOpKind::Gt),
416 Self::Le => Either::Right(BinOpKind::Le),
417 Self::Lt => Either::Right(BinOpKind::Lt),
418 Self::Ne => Either::Right(BinOpKind::Ne),
419 }
420 }
421
422 pub const fn to_str(self) -> &'static str {
424 match self.to_op() {
425 Either::Left(unop) => unop.to_str(),
426 Either::Right(binop) => binop.to_str(),
427 }
428 }
429}
430
431#[derive(Debug)]
436pub struct ItemContract<'ast> {
437 pub kind: ContractKind,
438 pub name: Ident,
439 pub layout: Option<StorageLayoutSpecifier<'ast>>,
440 pub bases: BoxSlice<'ast, Modifier<'ast>>,
441 pub body: BoxSlice<'ast, Item<'ast>>,
442}
443
444#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIs)]
446pub enum ContractKind {
447 Contract,
449 AbstractContract,
451 Interface,
453 Library,
455}
456
457impl fmt::Display for ContractKind {
458 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
459 f.write_str(self.to_str())
460 }
461}
462
463impl ContractKind {
464 pub const fn to_str(self) -> &'static str {
466 match self {
467 Self::Contract => "contract",
468 Self::AbstractContract => "abstract contract",
469 Self::Interface => "interface",
470 Self::Library => "library",
471 }
472 }
473}
474
475#[derive(Debug)]
479pub struct StorageLayoutSpecifier<'ast> {
480 pub span: Span,
481 pub slot: Box<'ast, Expr<'ast>>,
482}
483
484#[derive(Debug)]
489pub struct ItemFunction<'ast> {
490 pub kind: FunctionKind,
492 pub header: FunctionHeader<'ast>,
494 pub body: Option<Block<'ast>>,
496 pub body_span: Span,
498}
499
500impl ItemFunction<'_> {
501 pub fn is_implemented(&self) -> bool {
503 self.body.is_some()
504 }
505}
506
507#[derive(Debug, Default)]
509pub struct FunctionHeader<'ast> {
510 pub span: Span,
512
513 pub name: Option<Ident>,
516
517 pub parameters: ParameterList<'ast>,
519
520 pub visibility: Option<Spanned<Visibility>>,
522
523 pub state_mutability: Option<Spanned<StateMutability>>,
525
526 pub modifiers: BoxSlice<'ast, Modifier<'ast>>,
528
529 pub virtual_: Option<Span>,
531
532 pub override_: Option<Override<'ast>>,
534
535 pub returns: Option<ParameterList<'ast>>,
539}
540
541impl<'ast> FunctionHeader<'ast> {
542 pub fn visibility(&self) -> Option<Visibility> {
543 self.visibility.map(Spanned::into_inner)
544 }
545
546 pub fn state_mutability(&self) -> StateMutability {
547 self.state_mutability.map(Spanned::into_inner).unwrap_or(StateMutability::NonPayable)
548 }
549
550 pub fn virtual_(&self) -> bool {
551 self.virtual_.is_some()
552 }
553
554 pub fn returns(&self) -> &[VariableDefinition<'ast>] {
555 self.returns.as_ref().map(|pl| &pl.vars[..]).unwrap_or(&[])
556 }
557}
558
559#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIs)]
561pub enum FunctionKind {
562 Constructor,
564 Function,
566 Fallback,
568 Receive,
570 Modifier,
572}
573
574impl fmt::Display for FunctionKind {
575 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
576 f.write_str(self.to_str())
577 }
578}
579
580impl FunctionKind {
581 pub const fn to_str(self) -> &'static str {
583 match self {
584 Self::Constructor => "constructor",
585 Self::Function => "function",
586 Self::Fallback => "fallback",
587 Self::Receive => "receive",
588 Self::Modifier => "modifier",
589 }
590 }
591
592 pub fn allowed_in_global(&self) -> bool {
594 self.is_ordinary()
595 }
596
597 pub fn is_ordinary(&self) -> bool {
599 matches!(self, Self::Function)
600 }
601}
602
603#[derive(Debug)]
608pub struct Modifier<'ast> {
609 pub name: AstPath<'ast>,
610 pub arguments: CallArgs<'ast>,
611}
612
613impl Modifier<'_> {
614 pub fn span(&self) -> Span {
616 self.name.span().to(self.arguments.span)
617 }
618}
619
620#[derive(Debug)]
622pub struct Override<'ast> {
623 pub span: Span,
624 pub paths: BoxSlice<'ast, AstPath<'ast>>,
625}
626
627#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIs)]
629pub enum DataLocation {
630 Storage,
632 Transient,
634 Memory,
636 Calldata,
638}
639
640impl fmt::Display for DataLocation {
641 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
642 f.write_str(self.to_str())
643 }
644}
645
646impl DataLocation {
647 pub const fn to_str(self) -> &'static str {
649 match self {
650 Self::Storage => "storage",
651 Self::Transient => "transient",
652 Self::Memory => "memory",
653 Self::Calldata => "calldata",
654 }
655 }
656
657 pub const fn opt_to_str(this: Option<Self>) -> &'static str {
659 match this {
660 Some(location) => location.to_str(),
661 None => "none",
662 }
663 }
664}
665
666#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, EnumIs, PartialOrd, Ord)]
668pub enum StateMutability {
669 Pure,
671 View,
673 Payable,
675 #[default]
677 NonPayable,
678}
679
680impl fmt::Display for StateMutability {
681 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
682 f.write_str(self.to_str())
683 }
684}
685
686impl StateMutability {
687 pub const fn to_str(self) -> &'static str {
689 match self {
690 Self::Pure => "pure",
691 Self::View => "view",
692 Self::Payable => "payable",
693 Self::NonPayable => "nonpayable",
694 }
695 }
696}
697
698#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
700pub enum Visibility {
701 Private,
703 Internal,
705 Public,
707 External,
709}
710
711impl fmt::Display for Visibility {
712 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
713 self.to_str().fmt(f)
714 }
715}
716
717impl Visibility {
718 pub const fn to_str(self) -> &'static str {
720 match self {
721 Self::Private => "private",
722 Self::Internal => "internal",
723 Self::Public => "public",
724 Self::External => "external",
725 }
726 }
727}
728
729#[derive(Debug)]
733pub struct VariableDefinition<'ast> {
734 pub span: Span,
735 pub ty: Type<'ast>,
736 pub visibility: Option<Visibility>,
737 pub mutability: Option<VarMut>,
738 pub data_location: Option<DataLocation>,
739 pub override_: Option<Override<'ast>>,
740 pub indexed: bool,
741 pub name: Option<Ident>,
742 pub initializer: Option<Box<'ast, Expr<'ast>>>,
743}
744
745#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
747pub enum VarMut {
748 Immutable,
750 Constant,
752}
753
754impl fmt::Display for VarMut {
755 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
756 f.write_str(self.to_str())
757 }
758}
759
760impl VarMut {
761 pub const fn to_str(self) -> &'static str {
763 match self {
764 Self::Immutable => "immutable",
765 Self::Constant => "constant",
766 }
767 }
768
769 pub const fn is_immutable(self) -> bool {
771 matches!(self, Self::Immutable)
772 }
773
774 pub const fn is_constant(self) -> bool {
776 matches!(self, Self::Constant)
777 }
778}
779
780#[derive(Debug)]
784pub struct ItemStruct<'ast> {
785 pub name: Ident,
786 pub fields: BoxSlice<'ast, VariableDefinition<'ast>>,
787}
788
789#[derive(Debug)]
793pub struct ItemEnum<'ast> {
794 pub name: Ident,
795 pub variants: BoxSlice<'ast, Ident>,
796}
797
798#[derive(Debug)]
802pub struct ItemUdvt<'ast> {
803 pub name: Ident,
804 pub ty: Type<'ast>,
805}
806
807#[derive(Debug)]
811pub struct ItemError<'ast> {
812 pub name: Ident,
813 pub parameters: ParameterList<'ast>,
814}
815
816#[derive(Debug)]
821pub struct ItemEvent<'ast> {
822 pub name: Ident,
823 pub parameters: ParameterList<'ast>,
824 pub anonymous: bool,
825}