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 to_op(self) -> Either<UnOpKind, BinOpKind> {
360 match self {
361 Self::BitAnd => Either::Right(BinOpKind::BitAnd),
362 Self::BitNot => Either::Left(UnOpKind::BitNot),
363 Self::BitOr => Either::Right(BinOpKind::BitOr),
364 Self::BitXor => Either::Right(BinOpKind::BitXor),
365 Self::Add => Either::Right(BinOpKind::Add),
366 Self::Div => Either::Right(BinOpKind::Div),
367 Self::Rem => Either::Right(BinOpKind::Rem),
368 Self::Mul => Either::Right(BinOpKind::Mul),
369 Self::Sub => Either::Right(BinOpKind::Sub),
370 Self::Eq => Either::Right(BinOpKind::Eq),
371 Self::Ge => Either::Right(BinOpKind::Ge),
372 Self::Gt => Either::Right(BinOpKind::Gt),
373 Self::Le => Either::Right(BinOpKind::Le),
374 Self::Lt => Either::Right(BinOpKind::Lt),
375 Self::Ne => Either::Right(BinOpKind::Ne),
376 }
377 }
378
379 pub const fn to_str(self) -> &'static str {
381 match self.to_op() {
382 Either::Left(unop) => unop.to_str(),
383 Either::Right(binop) => binop.to_str(),
384 }
385 }
386}
387
388#[derive(Debug)]
393pub struct ItemContract<'ast> {
394 pub kind: ContractKind,
395 pub name: Ident,
396 pub layout: Option<StorageLayoutSpecifier<'ast>>,
397 pub bases: BoxSlice<'ast, Modifier<'ast>>,
398 pub body: BoxSlice<'ast, Item<'ast>>,
399}
400
401#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIs)]
403pub enum ContractKind {
404 Contract,
406 AbstractContract,
408 Interface,
410 Library,
412}
413
414impl fmt::Display for ContractKind {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 f.write_str(self.to_str())
417 }
418}
419
420impl ContractKind {
421 pub const fn to_str(self) -> &'static str {
423 match self {
424 Self::Contract => "contract",
425 Self::AbstractContract => "abstract contract",
426 Self::Interface => "interface",
427 Self::Library => "library",
428 }
429 }
430}
431
432#[derive(Debug)]
436pub struct StorageLayoutSpecifier<'ast> {
437 pub span: Span,
438 pub slot: Box<'ast, Expr<'ast>>,
439}
440
441#[derive(Debug)]
446pub struct ItemFunction<'ast> {
447 pub kind: FunctionKind,
449 pub header: FunctionHeader<'ast>,
451 pub body: Option<Block<'ast>>,
453 pub body_span: Span,
455}
456
457impl ItemFunction<'_> {
458 pub fn is_implemented(&self) -> bool {
460 self.body.is_some()
461 }
462}
463
464#[derive(Debug, Default)]
466pub struct FunctionHeader<'ast> {
467 pub span: Span,
469
470 pub name: Option<Ident>,
473
474 pub parameters: ParameterList<'ast>,
476
477 pub visibility: Option<Spanned<Visibility>>,
479
480 pub state_mutability: Option<Spanned<StateMutability>>,
482
483 pub modifiers: BoxSlice<'ast, Modifier<'ast>>,
485
486 pub virtual_: Option<Span>,
488
489 pub override_: Option<Override<'ast>>,
491
492 pub returns: Option<ParameterList<'ast>>,
496}
497
498impl<'ast> FunctionHeader<'ast> {
499 pub fn visibility(&self) -> Option<Visibility> {
500 self.visibility.map(Spanned::into_inner)
501 }
502
503 pub fn state_mutability(&self) -> StateMutability {
504 self.state_mutability.map(Spanned::into_inner).unwrap_or(StateMutability::NonPayable)
505 }
506
507 pub fn virtual_(&self) -> bool {
508 self.virtual_.is_some()
509 }
510
511 pub fn returns(&self) -> &[VariableDefinition<'ast>] {
512 self.returns.as_ref().map(|pl| &pl.vars[..]).unwrap_or(&[])
513 }
514}
515
516#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIs)]
518pub enum FunctionKind {
519 Constructor,
521 Function,
523 Fallback,
525 Receive,
527 Modifier,
529}
530
531impl fmt::Display for FunctionKind {
532 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533 f.write_str(self.to_str())
534 }
535}
536
537impl FunctionKind {
538 pub const fn to_str(self) -> &'static str {
540 match self {
541 Self::Constructor => "constructor",
542 Self::Function => "function",
543 Self::Fallback => "fallback",
544 Self::Receive => "receive",
545 Self::Modifier => "modifier",
546 }
547 }
548
549 pub fn allowed_in_global(&self) -> bool {
551 self.is_ordinary()
552 }
553
554 pub fn is_ordinary(&self) -> bool {
556 matches!(self, Self::Function)
557 }
558}
559
560#[derive(Debug)]
565pub struct Modifier<'ast> {
566 pub name: AstPath<'ast>,
567 pub arguments: CallArgs<'ast>,
568}
569
570impl Modifier<'_> {
571 pub fn span(&self) -> Span {
573 self.name.span().to(self.arguments.span)
574 }
575}
576
577#[derive(Debug)]
579pub struct Override<'ast> {
580 pub span: Span,
581 pub paths: BoxSlice<'ast, AstPath<'ast>>,
582}
583
584#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
586pub enum DataLocation {
587 Storage,
589 Transient,
591 Memory,
593 Calldata,
595}
596
597impl fmt::Display for DataLocation {
598 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
599 f.write_str(self.to_str())
600 }
601}
602
603impl DataLocation {
604 pub const fn to_str(self) -> &'static str {
606 match self {
607 Self::Storage => "storage",
608 Self::Transient => "transient",
609 Self::Memory => "memory",
610 Self::Calldata => "calldata",
611 }
612 }
613
614 pub const fn opt_to_str(this: Option<Self>) -> &'static str {
616 match this {
617 Some(location) => location.to_str(),
618 None => "none",
619 }
620 }
621}
622
623#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, EnumIs, PartialOrd, Ord)]
625pub enum StateMutability {
626 Pure,
628 View,
630 Payable,
632 #[default]
634 NonPayable,
635}
636
637impl fmt::Display for StateMutability {
638 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
639 f.write_str(self.to_str())
640 }
641}
642
643impl StateMutability {
644 pub const fn to_str(self) -> &'static str {
646 match self {
647 Self::Pure => "pure",
648 Self::View => "view",
649 Self::Payable => "payable",
650 Self::NonPayable => "nonpayable",
651 }
652 }
653}
654
655#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
657pub enum Visibility {
658 Private,
660 Internal,
662 Public,
664 External,
666}
667
668impl fmt::Display for Visibility {
669 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
670 self.to_str().fmt(f)
671 }
672}
673
674impl Visibility {
675 pub const fn to_str(self) -> &'static str {
677 match self {
678 Self::Private => "private",
679 Self::Internal => "internal",
680 Self::Public => "public",
681 Self::External => "external",
682 }
683 }
684}
685
686#[derive(Debug)]
690pub struct VariableDefinition<'ast> {
691 pub span: Span,
692 pub ty: Type<'ast>,
693 pub visibility: Option<Visibility>,
694 pub mutability: Option<VarMut>,
695 pub data_location: Option<DataLocation>,
696 pub override_: Option<Override<'ast>>,
697 pub indexed: bool,
698 pub name: Option<Ident>,
699 pub initializer: Option<Box<'ast, Expr<'ast>>>,
700}
701
702#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
704pub enum VarMut {
705 Immutable,
707 Constant,
709}
710
711impl fmt::Display for VarMut {
712 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
713 f.write_str(self.to_str())
714 }
715}
716
717impl VarMut {
718 pub const fn to_str(self) -> &'static str {
720 match self {
721 Self::Immutable => "immutable",
722 Self::Constant => "constant",
723 }
724 }
725
726 pub const fn is_immutable(self) -> bool {
728 matches!(self, Self::Immutable)
729 }
730
731 pub const fn is_constant(self) -> bool {
733 matches!(self, Self::Constant)
734 }
735}
736
737#[derive(Debug)]
741pub struct ItemStruct<'ast> {
742 pub name: Ident,
743 pub fields: BoxSlice<'ast, VariableDefinition<'ast>>,
744}
745
746#[derive(Debug)]
750pub struct ItemEnum<'ast> {
751 pub name: Ident,
752 pub variants: BoxSlice<'ast, Ident>,
753}
754
755#[derive(Debug)]
759pub struct ItemUdvt<'ast> {
760 pub name: Ident,
761 pub ty: Type<'ast>,
762}
763
764#[derive(Debug)]
768pub struct ItemError<'ast> {
769 pub name: Ident,
770 pub parameters: ParameterList<'ast>,
771}
772
773#[derive(Debug)]
778pub struct ItemEvent<'ast> {
779 pub name: Ident,
780 pub parameters: ParameterList<'ast>,
781 pub anonymous: bool,
782}