foundry_solang_parser/
pt.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Solidity parse tree data structures.
4//!
5//! See also the [Solidity documentation][sol].
6//!
7//! [sol]: https://docs.soliditylang.org/en/latest/grammar.html
8
9// backwards compatibility re-export
10#[doc(hidden)]
11pub use crate::helpers::{CodeLocation, OptionalCodeLocation};
12
13#[cfg(feature = "pt-serde")]
14use serde::{Deserialize, Serialize};
15
16/// A code location.
17#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
19pub enum Loc {
20    /// Builtin
21    Builtin,
22    /// Command line
23    CommandLine,
24    /// Implicit
25    Implicit,
26    /// Codegen
27    Codegen,
28    /// The file number, start offset and end offset in bytes of the source file.
29    File(usize, usize, usize),
30}
31
32impl Default for Loc {
33    fn default() -> Self {
34        Self::File(0, 0, 0)
35    }
36}
37
38#[inline(never)]
39#[cold]
40#[track_caller]
41fn not_a_file() -> ! {
42    panic!("location is not a file")
43}
44
45impl Loc {
46    /// Returns this location's beginning range.
47    #[inline]
48    pub fn begin_range(&self) -> Self {
49        match self {
50            Loc::File(file_no, start, _) => Loc::File(*file_no, *start, *start),
51            loc => *loc,
52        }
53    }
54
55    /// Returns this location's end range.
56    #[inline]
57    pub fn end_range(&self) -> Self {
58        match self {
59            Loc::File(file_no, _, end) => Loc::File(*file_no, *end, *end),
60            loc => *loc,
61        }
62    }
63
64    /// Returns this location's file number.
65    ///
66    /// # Panics
67    ///
68    /// If this location is not a file.
69    #[track_caller]
70    #[inline]
71    pub fn file_no(&self) -> usize {
72        match self {
73            Loc::File(file_no, _, _) => *file_no,
74            _ => not_a_file(),
75        }
76    }
77
78    /// Returns this location's file number if it is a file, otherwise `None`.
79    #[inline]
80    pub fn try_file_no(&self) -> Option<usize> {
81        match self {
82            Loc::File(file_no, _, _) => Some(*file_no),
83            _ => None,
84        }
85    }
86
87    /// Returns this location's start.
88    ///
89    /// # Panics
90    ///
91    /// If this location is not a file.
92    #[track_caller]
93    #[inline]
94    pub fn start(&self) -> usize {
95        match self {
96            Loc::File(_, start, _) => *start,
97            _ => not_a_file(),
98        }
99    }
100
101    /// Returns this location's end.
102    ///
103    /// # Panics
104    ///
105    /// If this location is not a file.
106    #[track_caller]
107    #[inline]
108    pub fn end(&self) -> usize {
109        match self {
110            Loc::File(_, _, end) => *end,
111            _ => not_a_file(),
112        }
113    }
114
115    /// Returns this location's end.
116    /// The returned endpoint is not part of the range.
117    /// This is used when a half-open range is needed.
118    ///
119    /// # Panics
120    ///
121    /// If this location is not a file.
122    #[track_caller]
123    #[inline]
124    pub fn exclusive_end(&self) -> usize {
125        self.end() + 1
126    }
127
128    /// Replaces this location's start with `other`'s.
129    ///
130    /// # Panics
131    ///
132    /// If this location is not a file.
133    #[track_caller]
134    #[inline]
135    pub fn use_start_from(&mut self, other: &Loc) {
136        match (self, other) {
137            (Loc::File(_, start, _), Loc::File(_, other_start, _)) => {
138                *start = *other_start;
139            }
140            _ => not_a_file(),
141        }
142    }
143
144    /// Replaces this location's end with `other`'s.
145    ///
146    /// # Panics
147    ///
148    /// If this location is not a file.
149    #[track_caller]
150    #[inline]
151    pub fn use_end_from(&mut self, other: &Loc) {
152        match (self, other) {
153            (Loc::File(_, _, end), Loc::File(_, _, other_end)) => {
154                *end = *other_end;
155            }
156            _ => not_a_file(),
157        }
158    }
159
160    /// See [`Loc::use_start_from`].
161    ///
162    /// # Panics
163    ///
164    /// If this location is not a file.
165    #[track_caller]
166    #[inline]
167    pub fn with_start_from(mut self, other: &Self) -> Self {
168        self.use_start_from(other);
169        self
170    }
171
172    /// See [`Loc::use_end_from`].
173    ///
174    /// # Panics
175    ///
176    /// If this location is not a file.
177    #[track_caller]
178    #[inline]
179    pub fn with_end_from(mut self, other: &Self) -> Self {
180        self.use_end_from(other);
181        self
182    }
183
184    /// Creates a new `Loc::File` by replacing `start`.
185    ///
186    /// # Panics
187    ///
188    /// If this location is not a file.
189    #[track_caller]
190    #[inline]
191    pub fn with_start(self, start: usize) -> Self {
192        match self {
193            Self::File(no, _, end) => Self::File(no, start, end),
194            _ => not_a_file(),
195        }
196    }
197
198    /// Creates a new `Loc::File` by replacing `end`.
199    ///
200    /// # Panics
201    ///
202    /// If this location is not a file.
203    #[track_caller]
204    #[inline]
205    pub fn with_end(self, end: usize) -> Self {
206        match self {
207            Self::File(no, start, _) => Self::File(no, start, end),
208            _ => not_a_file(),
209        }
210    }
211
212    /// Returns this location's range.
213    ///
214    /// # Panics
215    ///
216    /// If this location is not a file.
217    #[track_caller]
218    #[inline]
219    pub fn range(self) -> std::ops::Range<usize> {
220        match self {
221            Self::File(_, start, end) => start..end,
222            _ => not_a_file(),
223        }
224    }
225
226    /// Performs the union of two locations
227    pub fn union(&mut self, other: &Self) {
228        match (self, other) {
229            (Self::File(r_file, r_start, r_end), Self::File(l_file, l_start, l_end)) => {
230                assert_eq!(r_file, l_file, "cannot perform union in different files");
231                *r_start = std::cmp::min(*r_start, *l_start);
232                *r_end = std::cmp::max(*r_end, *l_end);
233            }
234
235            _ => unimplemented!("cannot perform union in non File Loc"),
236        }
237    }
238}
239
240/// An identifier.
241///
242/// `<name>`
243#[derive(Debug, PartialEq, Eq, Clone)]
244#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
245pub struct Identifier {
246    /// The code location.
247    pub loc: Loc,
248    /// The identifier string.
249    pub name: String,
250}
251
252impl Identifier {
253    /// Creates a new identifier.
254    pub fn new(s: impl Into<String>) -> Self {
255        Self {
256            loc: Loc::default(),
257            name: s.into(),
258        }
259    }
260}
261
262/// A qualified identifier.
263///
264/// `<identifiers>.*`
265#[derive(Debug, PartialEq, Eq, Clone)]
266#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
267pub struct IdentifierPath {
268    /// The code location.
269    pub loc: Loc,
270    /// The list of identifiers.
271    pub identifiers: Vec<Identifier>,
272}
273
274/// A comment or [doc comment][natspec].
275///
276/// [natspec]: https://docs.soliditylang.org/en/latest/natspec-format.html
277#[derive(Debug, PartialEq, Eq, Clone)]
278#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
279pub enum Comment {
280    /// A line comment.
281    ///
282    /// `// line comment`
283    Line(Loc, String),
284
285    /// A block doc comment.
286    ///
287    /// ` /* block comment */ `
288    Block(Loc, String),
289
290    /// A line doc comment.
291    ///
292    /// `/// line doc comment`
293    DocLine(Loc, String),
294
295    /// A block doc comment.
296    ///
297    /// ```text
298    /// /**
299    ///  * block doc comment
300    ///  */
301    /// ```
302    DocBlock(Loc, String),
303}
304
305impl Comment {
306    /// Returns the comment's value.
307    #[inline]
308    pub const fn value(&self) -> &String {
309        match self {
310            Self::Line(_, s) | Self::Block(_, s) | Self::DocLine(_, s) | Self::DocBlock(_, s) => s,
311        }
312    }
313
314    /// Returns whether this is a doc comment.
315    #[inline]
316    pub const fn is_doc(&self) -> bool {
317        matches!(self, Self::DocLine(..) | Self::DocBlock(..))
318    }
319
320    /// Returns whether this is a line comment.
321    #[inline]
322    pub const fn is_line(&self) -> bool {
323        matches!(self, Self::Line(..) | Self::DocLine(..))
324    }
325
326    /// Returns whether this is a block comment.
327    #[inline]
328    pub const fn is_block(&self) -> bool {
329        !self.is_line()
330    }
331}
332
333/// The source unit of the parse tree.
334///
335/// Contains all of the parse tree's parts in a vector.
336#[derive(Debug, PartialEq, Eq, Clone)]
337#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
338pub struct SourceUnit(pub Vec<SourceUnitPart>);
339
340/// A parse tree part.
341#[derive(Debug, PartialEq, Eq, Clone)]
342#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
343pub enum SourceUnitPart {
344    /// A pragma directive.
345    ///
346    /// `pragma <1> <2>;`
347    ///
348    /// `1` and `2` are `None` only if an error occurred during parsing.
349    PragmaDirective(Box<PragmaDirective>),
350
351    /// An import directive.
352    ImportDirective(Import),
353
354    /// A contract definition.
355    ContractDefinition(Box<ContractDefinition>),
356
357    /// An enum definition.
358    EnumDefinition(Box<EnumDefinition>),
359
360    /// A struct definition.
361    StructDefinition(Box<StructDefinition>),
362
363    /// An event definition.
364    EventDefinition(Box<EventDefinition>),
365
366    /// An error definition.
367    ErrorDefinition(Box<ErrorDefinition>),
368
369    /// A function definition.
370    FunctionDefinition(Box<FunctionDefinition>),
371
372    /// A variable definition.
373    VariableDefinition(Box<VariableDefinition>),
374
375    /// A type definition.
376    TypeDefinition(Box<TypeDefinition>),
377
378    /// An annotation.
379    Annotation(Box<Annotation>),
380
381    /// A `using` directive.
382    Using(Box<Using>),
383
384    /// A stray semicolon.
385    StraySemicolon(Loc),
386}
387
388/// An import statement.
389#[derive(Debug, PartialEq, Eq, Clone)]
390#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
391pub enum Import {
392    /// `import <0>;`
393    Plain(ImportPath, Loc),
394
395    /// `import * as <1> from <0>;`
396    ///
397    /// or
398    ///
399    /// `import <0> as <1>;`
400    GlobalSymbol(ImportPath, Identifier, Loc),
401
402    /// `import { <<1.0> [as <1.1>]>,* } from <0>;`
403    Rename(ImportPath, Vec<(Identifier, Option<Identifier>)>, Loc),
404}
405
406/// An import statement.
407#[derive(Debug, PartialEq, Eq, Clone)]
408#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
409pub enum ImportPath {
410    /// "foo.sol"
411    Filename(StringLiteral),
412    /// std.stub (experimental Solidity feature)
413    Path(IdentifierPath),
414}
415
416impl Import {
417    /// Returns the import string.
418    #[inline]
419    pub const fn literal(&self) -> Option<&StringLiteral> {
420        match self {
421            Self::Plain(ImportPath::Filename(literal), _)
422            | Self::GlobalSymbol(ImportPath::Filename(literal), _, _)
423            | Self::Rename(ImportPath::Filename(literal), _, _) => Some(literal),
424            _ => None,
425        }
426    }
427}
428
429/// Type alias for a list of function parameters.
430pub type ParameterList = Vec<(Loc, Option<Parameter>)>;
431
432/// A type.
433#[derive(Debug, PartialEq, Eq, Clone)]
434#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
435pub enum Type {
436    /// `address`
437    Address,
438
439    /// `address payable`
440    AddressPayable,
441
442    /// `payable`
443    ///
444    /// Only used as a cast.
445    Payable,
446
447    /// `bool`
448    Bool,
449
450    /// `string`
451    String,
452
453    /// `int<n>`
454    Int(u16),
455
456    /// `uint<n>`
457    Uint(u16),
458
459    /// `bytes<n>`
460    Bytes(u8),
461
462    /// `fixed`
463    Rational,
464
465    /// `bytes`
466    DynamicBytes,
467
468    /// `mapping(<key> [key_name] => <value> [value_name])`
469    Mapping {
470        /// The code location.
471        loc: Loc,
472        /// The key expression.
473        ///
474        /// This is only allowed to be an elementary type or a user defined type.
475        key: Box<Expression>,
476        /// The optional key identifier.
477        key_name: Option<Identifier>,
478        /// The value expression.
479        value: Box<Expression>,
480        /// The optional value identifier.
481        value_name: Option<Identifier>,
482    },
483
484    /// `function (<params>) <attributes> [returns]`
485    Function {
486        /// The list of parameters.
487        params: ParameterList,
488        /// The list of attributes.
489        attributes: Vec<FunctionAttribute>,
490        /// The optional list of return parameters.
491        returns: Option<(ParameterList, Vec<FunctionAttribute>)>,
492    },
493}
494
495/// Dynamic type location.
496#[derive(Debug, PartialEq, Eq, Clone)]
497#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
498pub enum StorageLocation {
499    /// `memory`
500    Memory(Loc),
501
502    /// `storage`
503    Storage(Loc),
504
505    /// `calldata`
506    Calldata(Loc),
507
508    /// `transient`
509    Transient(Loc),
510}
511
512/// A variable declaration.
513///
514/// `<ty> [storage] <name>`
515#[derive(Debug, PartialEq, Eq, Clone)]
516#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
517pub struct VariableDeclaration {
518    /// The code location.
519    pub loc: Loc,
520    /// The type.
521    pub ty: Expression,
522    /// The optional memory location.
523    pub storage: Option<StorageLocation>,
524    /// The identifier.
525    ///
526    /// This field is `None` only if an error occurred during parsing.
527    pub name: Option<Identifier>,
528}
529
530/// A struct definition.
531///
532/// `struct <name> { <fields>;* }`
533#[derive(Debug, PartialEq, Eq, Clone)]
534#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
535pub struct StructDefinition {
536    /// The code location.
537    pub loc: Loc,
538    /// The identifier.
539    ///
540    /// This field is `None` only if an error occurred during parsing.
541    pub name: Option<Identifier>,
542    /// The list of fields.
543    pub fields: Vec<VariableDeclaration>,
544}
545
546/// A contract part.
547#[derive(Debug, PartialEq, Eq, Clone)]
548#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
549pub enum ContractPart {
550    /// A struct definition.
551    StructDefinition(Box<StructDefinition>),
552
553    /// An event definition.
554    EventDefinition(Box<EventDefinition>),
555
556    /// An enum definition.
557    EnumDefinition(Box<EnumDefinition>),
558
559    /// An error definition.
560    ErrorDefinition(Box<ErrorDefinition>),
561
562    /// A variable definition.
563    VariableDefinition(Box<VariableDefinition>),
564
565    /// A function definition.
566    FunctionDefinition(Box<FunctionDefinition>),
567
568    /// A type definition.
569    TypeDefinition(Box<TypeDefinition>),
570
571    /// A definition.
572    Annotation(Box<Annotation>),
573
574    /// A `using` directive.
575    Using(Box<Using>),
576
577    /// A stray semicolon.
578    StraySemicolon(Loc),
579}
580
581/// A pragma directive
582#[derive(Debug, PartialEq, Eq, Clone)]
583#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
584pub enum PragmaDirective {
585    /// pragma a b;
586    Identifier(Loc, Option<Identifier>, Option<Identifier>),
587    /// pragma a "b";
588    StringLiteral(Loc, Identifier, StringLiteral),
589    /// pragma version =0.5.16;
590    Version(Loc, Identifier, Vec<VersionComparator>),
591}
592
593/// A `version` list
594#[derive(Debug, PartialEq, Eq, Clone)]
595#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
596pub enum VersionComparator {
597    /// 0.8.22
598    Plain {
599        /// The code location.
600        loc: Loc,
601        /// List of versions: major, minor, patch. minor and patch are optional
602        version: Vec<String>,
603    },
604    /// =0.5.16
605    Operator {
606        /// The code location.
607        loc: Loc,
608        /// Semver comparison operator
609        op: VersionOp,
610        /// version number
611        version: Vec<String>,
612    },
613    /// foo || bar
614    Or {
615        /// The code location.
616        loc: Loc,
617        /// left part
618        left: Box<VersionComparator>,
619        /// right part
620        right: Box<VersionComparator>,
621    },
622    /// 0.7.0 - 0.8.22
623    Range {
624        /// The code location.
625        loc: Loc,
626        /// start of range
627        from: Vec<String>,
628        /// end of range
629        to: Vec<String>,
630    },
631}
632
633/// Comparison operator
634#[derive(Debug, PartialEq, Eq, Copy, Clone)]
635#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
636pub enum VersionOp {
637    /// `=`
638    Exact,
639    /// `>`
640    Greater,
641    /// `>=`
642    GreaterEq,
643    /// `<`
644    Less,
645    /// `<=`
646    LessEq,
647    /// `~`
648    Tilde,
649    /// `^`
650    Caret,
651    /// `*`
652    Wildcard,
653}
654
655/// A `using` list. See [Using].
656#[derive(Debug, PartialEq, Eq, Clone)]
657#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
658pub enum UsingList {
659    /// A single identifier path.
660    Library(IdentifierPath),
661
662    /// List of using functions.
663    ///
664    /// `{ <<identifier path> [ as <operator> ]>,* }`
665    Functions(Vec<UsingFunction>),
666
667    /// An error occurred during parsing.
668    Error,
669}
670
671/// A `using` function. See [UsingList].
672///
673/// `<path> [ as <oper> ]`
674#[derive(Debug, PartialEq, Eq, Clone)]
675#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
676pub struct UsingFunction {
677    /// The code location.
678    pub loc: Loc,
679    /// The identifier path.
680    pub path: IdentifierPath,
681    /// The optional user-defined operator.
682    pub oper: Option<UserDefinedOperator>,
683}
684
685/// A user-defined operator.
686///
687/// See also the [Solidity blog post][ref] on user-defined operators.
688///
689/// [ref]: https://blog.soliditylang.org/2023/02/22/user-defined-operators/
690#[derive(Clone, Copy, Debug, PartialEq, Eq)]
691#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
692pub enum UserDefinedOperator {
693    /// `&`
694    BitwiseAnd,
695    /// `~`
696    ///
697    BitwiseNot,
698    /// `-`
699    ///
700    /// Note that this is the same as `Subtract`, and that it is currently not being parsed.
701    Negate,
702    /// `|`
703    BitwiseOr,
704    /// `^`
705    BitwiseXor,
706    /// `+`
707    Add,
708    /// `/`
709    Divide,
710    /// `%`
711    Modulo,
712    /// `*`
713    Multiply,
714    /// `-`
715    Subtract,
716    /// `==`
717    Equal,
718    /// `>`
719    More,
720    /// `>=`
721    MoreEqual,
722    /// `<`
723    Less,
724    /// `<=`
725    LessEqual,
726    /// `!=`
727    NotEqual,
728}
729
730impl UserDefinedOperator {
731    /// Returns the number of arguments needed for this operator's operation.
732    #[inline]
733    pub const fn args(&self) -> usize {
734        match self {
735            UserDefinedOperator::BitwiseNot | UserDefinedOperator::Negate => 1,
736            _ => 2,
737        }
738    }
739
740    /// Returns whether `self` is a unary operator.
741    #[inline]
742    pub const fn is_unary(&self) -> bool {
743        matches!(self, Self::BitwiseNot | Self::Negate)
744    }
745
746    /// Returns whether `self` is a binary operator.
747    #[inline]
748    pub const fn is_binary(&self) -> bool {
749        !self.is_unary()
750    }
751
752    /// Returns whether `self` is a bitwise operator.
753    #[inline]
754    pub const fn is_bitwise(&self) -> bool {
755        matches!(
756            self,
757            Self::BitwiseAnd | Self::BitwiseOr | Self::BitwiseXor | Self::BitwiseNot
758        )
759    }
760
761    /// Returns whether `self` is an arithmetic operator.
762    #[inline]
763    pub const fn is_arithmetic(&self) -> bool {
764        matches!(
765            self,
766            Self::Add | Self::Subtract | Self::Multiply | Self::Divide | Self::Modulo
767        )
768    }
769
770    /// Returns whether this is a comparison operator.
771    #[inline]
772    pub const fn is_comparison(&self) -> bool {
773        matches!(
774            self,
775            Self::Equal
776                | Self::NotEqual
777                | Self::Less
778                | Self::LessEqual
779                | Self::More
780                | Self::MoreEqual
781        )
782    }
783}
784
785/// A `using` directive.
786///
787/// Can occur within contracts and libraries and at the file level.
788///
789/// `using <list> for <type | '*'> [global];`
790#[derive(Debug, PartialEq, Eq, Clone)]
791#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
792pub struct Using {
793    /// The code location.
794    pub loc: Loc,
795    /// The list of `using` functions or a single identifier path.
796    pub list: UsingList,
797    /// The type.
798    ///
799    /// This field is `None` if an error occurred or the specified type is `*`.
800    pub ty: Option<Expression>,
801    /// The optional `global` identifier.
802    pub global: Option<Identifier>,
803}
804
805/// The contract type.
806#[derive(Debug, PartialEq, Eq, Clone)]
807#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
808pub enum ContractTy {
809    /// `abstract contract`
810    Abstract(Loc),
811
812    /// `contract`
813    Contract(Loc),
814
815    /// `interface`
816    Interface(Loc),
817
818    /// `library`
819    Library(Loc),
820}
821
822/// A function modifier invocation (see [FunctionAttribute])
823/// or a contract inheritance specifier (see [ContractDefinition]).
824///
825/// Both have the same semantics:
826///
827/// `<name>[(<args>,*)]`
828#[derive(Debug, PartialEq, Eq, Clone)]
829#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
830pub struct Base {
831    /// The code location.
832    pub loc: Loc,
833    /// The identifier path.
834    pub name: IdentifierPath,
835    /// The optional arguments.
836    pub args: Option<Vec<Expression>>,
837}
838
839/// A contract definition.
840///
841/// `<ty> <name> [<base>,*] { <parts>,* }`
842#[derive(Debug, PartialEq, Eq, Clone)]
843#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
844pub struct ContractDefinition {
845    /// The code location.
846    pub loc: Loc,
847    /// The contract type.
848    pub ty: ContractTy,
849    /// The identifier.
850    ///
851    /// This field is `None` only if an error occurred during parsing.
852    pub name: Option<Identifier>,
853    /// The list of inheritance specifiers.
854    pub base: Vec<Base>,
855    /// The layout specifier.
856    pub layout: Option<Box<Expression>>,
857    /// The list of contract parts.
858    pub parts: Vec<ContractPart>,
859}
860
861impl ContractDefinition {
862    pub(crate) fn new(
863        loc: Loc,
864        ty: ContractTy,
865        name: Option<Identifier>,
866        attrs: Vec<ContractAttribute>,
867        parts: Vec<ContractPart>,
868    ) -> Self {
869        let mut base = Vec::new();
870        let mut layout = None;
871        for attr in attrs {
872            match attr {
873                ContractAttribute::Bases(b) => base.extend(b),
874                ContractAttribute::Layout(l) => layout = Some(l),
875            }
876        }
877        Self {
878            loc,
879            ty,
880            name,
881            base,
882            layout: layout.map(Box::new),
883            parts,
884        }
885    }
886}
887
888pub(crate) enum ContractAttribute {
889    Bases(Vec<Base>),
890    Layout(Expression),
891}
892
893/// An event parameter.
894///
895/// `<ty> [indexed] [name]`
896#[derive(Debug, PartialEq, Eq, Clone)]
897#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
898pub struct EventParameter {
899    /// The code location.
900    pub loc: Loc,
901    /// The type.
902    pub ty: Expression,
903    /// Whether this parameter is indexed.
904    pub indexed: bool,
905    /// The optional identifier.
906    pub name: Option<Identifier>,
907}
908
909/// An event definition.
910///
911/// `event <name>(<fields>,*) [anonymous];`
912#[derive(Debug, PartialEq, Eq, Clone)]
913#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
914pub struct EventDefinition {
915    /// The code location.
916    pub loc: Loc,
917    /// The identifier.
918    ///
919    /// This field is `None` only if an error occurred during parsing.
920    pub name: Option<Identifier>,
921    /// The list of event parameters.
922    pub fields: Vec<EventParameter>,
923    /// Whether this event is anonymous.
924    pub anonymous: bool,
925}
926
927/// An error parameter.
928///
929/// `<ty> [name]`
930#[derive(Debug, PartialEq, Eq, Clone)]
931#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
932pub struct ErrorParameter {
933    /// The code location.
934    pub loc: Loc,
935    /// The type.
936    pub ty: Expression,
937    /// The optional identifier.
938    pub name: Option<Identifier>,
939}
940
941/// An error definition.
942///
943/// `error <name> (<fields>,*);`
944#[derive(Debug, PartialEq, Eq, Clone)]
945#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
946pub struct ErrorDefinition {
947    /// The code location.
948    pub loc: Loc,
949    /// The `error` keyword.
950    pub keyword: Expression,
951    /// The identifier.
952    ///
953    /// This field is `None` only if an error occurred during parsing.
954    pub name: Option<Identifier>,
955    /// The list of error parameters.
956    pub fields: Vec<ErrorParameter>,
957}
958
959/// An enum definition.
960///
961/// `enum <name> { <values>,* }`
962#[derive(Debug, PartialEq, Eq, Clone)]
963#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
964pub struct EnumDefinition {
965    /// The code location.
966    pub loc: Loc,
967    /// The identifier.
968    ///
969    /// This field is `None` only if an error occurred during parsing.
970    pub name: Option<Identifier>,
971    /// The list of values.
972    ///
973    /// This field contains `None` only if an error occurred during parsing.
974    pub values: Vec<Option<Identifier>>,
975}
976
977/// A variable attribute.
978#[derive(Debug, PartialEq, Eq, Clone)]
979#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
980#[repr(u8)] // for cmp; order of variants is important
981pub enum VariableAttribute {
982    /// The visibility.
983    ///
984    /// Only used for storage variables.
985    Visibility(Visibility),
986
987    /// `constant`
988    Constant(Loc),
989
990    /// `immutable`
991    Immutable(Loc),
992
993    /// `ovveride(<1>,*)`
994    Override(Loc, Vec<IdentifierPath>),
995
996    /// Storage type.
997    StorageType(StorageType),
998}
999
1000/// Soroban storage types.
1001#[derive(Debug, PartialEq, Eq, Clone)]
1002#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1003#[repr(u8)] // for cmp; order of variants is important
1004pub enum StorageType {
1005    /// `Temporary`
1006    Temporary(Option<Loc>),
1007
1008    /// `persistent`
1009    Persistent(Option<Loc>),
1010
1011    /// `Instance`
1012    Instance(Option<Loc>),
1013}
1014
1015/// A variable definition.
1016///
1017/// `<ty> <attrs>* <name> [= <initializer>]`
1018#[derive(Debug, PartialEq, Eq, Clone)]
1019#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1020pub struct VariableDefinition {
1021    /// The code location.
1022    pub loc: Loc,
1023    /// The type.
1024    pub ty: Expression,
1025    /// The list of variable attributes.
1026    pub attrs: Vec<VariableAttribute>,
1027    /// The identifier.
1028    ///
1029    /// This field is `None` only if an error occurred during parsing.
1030    pub name: Option<Identifier>,
1031    /// The optional initializer.
1032    pub initializer: Option<Expression>,
1033}
1034
1035/// A user type definition.
1036///
1037/// `type <name> is <ty>;`
1038#[derive(Debug, PartialEq, Eq, Clone)]
1039#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1040pub struct TypeDefinition {
1041    /// The code location.
1042    pub loc: Loc,
1043    /// The user-defined type name.
1044    pub name: Identifier,
1045    /// The type expression.
1046    pub ty: Expression,
1047}
1048
1049/// An annotation.
1050///
1051/// `@<id>(<value>)`
1052#[derive(Debug, PartialEq, Eq, Clone)]
1053#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1054pub struct Annotation {
1055    /// The code location.
1056    pub loc: Loc,
1057    /// The identifier.
1058    pub id: Identifier,
1059    /// The value.
1060    pub value: Option<Expression>,
1061}
1062
1063/// A string literal.
1064///
1065/// `[unicode]"<string>"`
1066#[derive(Debug, PartialEq, Eq, Clone)]
1067#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1068pub struct StringLiteral {
1069    /// The code location.
1070    pub loc: Loc,
1071    /// Whether this is a unicode string.
1072    pub unicode: bool,
1073    /// The string literal.
1074    ///
1075    /// Does not contain the quotes or the `unicode` prefix.
1076    pub string: String,
1077}
1078
1079/// A hex literal.
1080///
1081/// `hex"<literal>"`
1082#[derive(Debug, PartialEq, Eq, Clone)]
1083#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1084pub struct HexLiteral {
1085    /// The code location.
1086    pub loc: Loc,
1087    /// The hex literal.
1088    ///
1089    /// Contains the `hex` prefix.
1090    pub hex: String,
1091}
1092
1093/// A named argument.
1094///
1095/// `<name>: <expr>`
1096#[derive(Debug, PartialEq, Eq, Clone)]
1097#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1098pub struct NamedArgument {
1099    /// The code location.
1100    pub loc: Loc,
1101    /// The identifier.
1102    pub name: Identifier,
1103    /// The value.
1104    pub expr: Expression,
1105}
1106
1107/// An expression.
1108#[derive(Debug, PartialEq, Eq, Clone)]
1109#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1110pub enum Expression {
1111    /// `<1>++`
1112    PostIncrement(Loc, Box<Expression>),
1113    /// `<1>--`
1114    PostDecrement(Loc, Box<Expression>),
1115    /// `new <1>`
1116    New(Loc, Box<Expression>),
1117    /// `<1>\[ [2] \]`
1118    ArraySubscript(Loc, Box<Expression>, Option<Box<Expression>>),
1119    /// `<1>\[ [2] : [3] \]`
1120    ArraySlice(
1121        Loc,
1122        Box<Expression>,
1123        Option<Box<Expression>>,
1124        Option<Box<Expression>>,
1125    ),
1126    /// `(<1>)`
1127    Parenthesis(Loc, Box<Expression>),
1128    /// `<1>.<2>`
1129    MemberAccess(Loc, Box<Expression>, Identifier),
1130    /// `<1>(<2>,*)`
1131    FunctionCall(Loc, Box<Expression>, Vec<Expression>),
1132    /// `<1><2>` where <2> is a block.
1133    FunctionCallBlock(Loc, Box<Expression>, Box<Statement>),
1134    /// `<1>({ <2>,* })`
1135    NamedFunctionCall(Loc, Box<Expression>, Vec<NamedArgument>),
1136    /// `!<1>`
1137    Not(Loc, Box<Expression>),
1138    /// `~<1>`
1139    BitwiseNot(Loc, Box<Expression>),
1140    /// `delete <1>`
1141    Delete(Loc, Box<Expression>),
1142    /// `++<1>`
1143    PreIncrement(Loc, Box<Expression>),
1144    /// `--<1>`
1145    PreDecrement(Loc, Box<Expression>),
1146    /// `+<1>`
1147    ///
1148    /// Note that this isn't actually supported by Solidity.
1149    UnaryPlus(Loc, Box<Expression>),
1150    /// `-<1>`
1151    Negate(Loc, Box<Expression>),
1152
1153    /// `<1> ** <2>`
1154    Power(Loc, Box<Expression>, Box<Expression>),
1155    /// `<1> * <2>`
1156    Multiply(Loc, Box<Expression>, Box<Expression>),
1157    /// `<1> / <2>`
1158    Divide(Loc, Box<Expression>, Box<Expression>),
1159    /// `<1> % <2>`
1160    Modulo(Loc, Box<Expression>, Box<Expression>),
1161    /// `<1> + <2>`
1162    Add(Loc, Box<Expression>, Box<Expression>),
1163    /// `<1> - <2>`
1164    Subtract(Loc, Box<Expression>, Box<Expression>),
1165    /// `<1> << <2>`
1166    ShiftLeft(Loc, Box<Expression>, Box<Expression>),
1167    /// `<1> >> <2>`
1168    ShiftRight(Loc, Box<Expression>, Box<Expression>),
1169    /// `<1> & <2>`
1170    BitwiseAnd(Loc, Box<Expression>, Box<Expression>),
1171    /// `<1> ^ <2>`
1172    BitwiseXor(Loc, Box<Expression>, Box<Expression>),
1173    /// `<1> | <2>`
1174    BitwiseOr(Loc, Box<Expression>, Box<Expression>),
1175    /// `<1> < <2>`
1176    Less(Loc, Box<Expression>, Box<Expression>),
1177    /// `<1> > <2>`
1178    More(Loc, Box<Expression>, Box<Expression>),
1179    /// `<1> <= <2>`
1180    LessEqual(Loc, Box<Expression>, Box<Expression>),
1181    /// `<1> >= <2>`
1182    MoreEqual(Loc, Box<Expression>, Box<Expression>),
1183    /// `<1> == <2>`
1184    Equal(Loc, Box<Expression>, Box<Expression>),
1185    /// `<1> != <2>`
1186    NotEqual(Loc, Box<Expression>, Box<Expression>),
1187    /// `<1> && <2>`
1188    And(Loc, Box<Expression>, Box<Expression>),
1189    /// `<1> || <2>`
1190    Or(Loc, Box<Expression>, Box<Expression>),
1191    /// `<1> ? <2> : <3>`
1192    ///
1193    /// AKA ternary operator.
1194    ConditionalOperator(Loc, Box<Expression>, Box<Expression>, Box<Expression>),
1195    /// `<1> = <2>`
1196    Assign(Loc, Box<Expression>, Box<Expression>),
1197    /// `<1> |= <2>`
1198    AssignOr(Loc, Box<Expression>, Box<Expression>),
1199    /// `<1> &= <2>`
1200    AssignAnd(Loc, Box<Expression>, Box<Expression>),
1201    /// `<1> ^= <2>`
1202    AssignXor(Loc, Box<Expression>, Box<Expression>),
1203    /// `<1> <<= <2>`
1204    AssignShiftLeft(Loc, Box<Expression>, Box<Expression>),
1205    /// `<1> >>= <2>`
1206    AssignShiftRight(Loc, Box<Expression>, Box<Expression>),
1207    /// `<1> += <2>`
1208    AssignAdd(Loc, Box<Expression>, Box<Expression>),
1209    /// `<1> -= <2>`
1210    AssignSubtract(Loc, Box<Expression>, Box<Expression>),
1211    /// `<1> *= <2>`
1212    AssignMultiply(Loc, Box<Expression>, Box<Expression>),
1213    /// `<1> /= <2>`
1214    AssignDivide(Loc, Box<Expression>, Box<Expression>),
1215    /// `<1> %= <2>`
1216    AssignModulo(Loc, Box<Expression>, Box<Expression>),
1217
1218    /// `true` or `false`
1219    BoolLiteral(Loc, bool),
1220    /// ``
1221    NumberLiteral(Loc, String, String, Option<Identifier>),
1222    /// ``
1223    RationalNumberLiteral(Loc, String, String, String, Option<Identifier>),
1224    /// ``
1225    HexNumberLiteral(Loc, String, Option<Identifier>),
1226    /// `<1>+`. See [StringLiteral].
1227    StringLiteral(Vec<StringLiteral>),
1228    /// See [Type].
1229    Type(Loc, Type),
1230    /// `<1>+`. See [HexLiteral].
1231    HexLiteral(Vec<HexLiteral>),
1232    /// `0x[a-fA-F0-9]{40}`
1233    ///
1234    /// This [should be correctly checksummed][ref], but it currently isn't being enforced in the parser.
1235    ///
1236    /// [ref]: https://docs.soliditylang.org/en/latest/types.html#address-literals
1237    AddressLiteral(Loc, String),
1238    /// Any valid [Identifier].
1239    Variable(Identifier),
1240    /// `(<1>,*)`
1241    List(Loc, ParameterList),
1242    /// `\[ <1>.* \]`
1243    ArrayLiteral(Loc, Vec<Expression>),
1244}
1245
1246/// See `Expression::components`.
1247macro_rules! expr_components {
1248    ($s:ident) => {
1249        match $s {
1250            // (Some, None)
1251            PostDecrement(_, expr) | PostIncrement(_, expr) => (Some(expr), None),
1252
1253            // (None, Some)
1254            Not(_, expr)
1255            | BitwiseNot(_, expr)
1256            | New(_, expr)
1257            | Delete(_, expr)
1258            | UnaryPlus(_, expr)
1259            | Negate(_, expr)
1260            | PreDecrement(_, expr)
1261            | Parenthesis(_, expr)
1262            | PreIncrement(_, expr) => (None, Some(expr)),
1263
1264            // (Some, Some)
1265            Power(_, left, right)
1266            | Multiply(_, left, right)
1267            | Divide(_, left, right)
1268            | Modulo(_, left, right)
1269            | Add(_, left, right)
1270            | Subtract(_, left, right)
1271            | ShiftLeft(_, left, right)
1272            | ShiftRight(_, left, right)
1273            | BitwiseAnd(_, left, right)
1274            | BitwiseXor(_, left, right)
1275            | BitwiseOr(_, left, right)
1276            | Less(_, left, right)
1277            | More(_, left, right)
1278            | LessEqual(_, left, right)
1279            | MoreEqual(_, left, right)
1280            | Equal(_, left, right)
1281            | NotEqual(_, left, right)
1282            | And(_, left, right)
1283            | Or(_, left, right)
1284            | Assign(_, left, right)
1285            | AssignOr(_, left, right)
1286            | AssignAnd(_, left, right)
1287            | AssignXor(_, left, right)
1288            | AssignShiftLeft(_, left, right)
1289            | AssignShiftRight(_, left, right)
1290            | AssignAdd(_, left, right)
1291            | AssignSubtract(_, left, right)
1292            | AssignMultiply(_, left, right)
1293            | AssignDivide(_, left, right)
1294            | AssignModulo(_, left, right) => (Some(left), Some(right)),
1295
1296            // (None, None)
1297            MemberAccess(..)
1298            | ConditionalOperator(..)
1299            | ArraySubscript(..)
1300            | ArraySlice(..)
1301            | FunctionCall(..)
1302            | FunctionCallBlock(..)
1303            | NamedFunctionCall(..)
1304            | BoolLiteral(..)
1305            | NumberLiteral(..)
1306            | RationalNumberLiteral(..)
1307            | HexNumberLiteral(..)
1308            | StringLiteral(..)
1309            | Type(..)
1310            | HexLiteral(..)
1311            | AddressLiteral(..)
1312            | Variable(..)
1313            | List(..)
1314            | ArrayLiteral(..) => (None, None),
1315        }
1316    };
1317}
1318
1319impl Expression {
1320    /// Removes one layer of parentheses.
1321    #[inline]
1322    pub fn remove_parenthesis(&self) -> &Expression {
1323        if let Expression::Parenthesis(_, expr) = self {
1324            expr
1325        } else {
1326            self
1327        }
1328    }
1329
1330    /// Strips all parentheses recursively.
1331    pub fn strip_parentheses(&self) -> &Expression {
1332        match self {
1333            Expression::Parenthesis(_, expr) => expr.strip_parentheses(),
1334            _ => self,
1335        }
1336    }
1337
1338    /// Returns shared references to the components of this expression.
1339    ///
1340    /// `(left_component, right_component)`
1341    ///
1342    /// # Examples
1343    ///
1344    /// ```
1345    /// use solang_parser::pt::{Expression, Identifier, Loc};
1346    ///
1347    /// // `a++`
1348    /// let var = Expression::Variable(Identifier::new("a"));
1349    /// let post_increment = Expression::PostIncrement(Loc::default(), Box::new(var.clone()));
1350    /// assert_eq!(post_increment.components(), (Some(&var), None));
1351    ///
1352    /// // `++a`
1353    /// let var = Expression::Variable(Identifier::new("a"));
1354    /// let pre_increment = Expression::PreIncrement(Loc::default(), Box::new(var.clone()));
1355    /// assert_eq!(pre_increment.components(), (None, Some(&var)));
1356    ///
1357    /// // `a + b`
1358    /// let var_a = Expression::Variable(Identifier::new("a"));
1359    /// let var_b = Expression::Variable(Identifier::new("b"));
1360    /// let pre_increment = Expression::Add(Loc::default(), Box::new(var_a.clone()), Box::new(var_b.clone()));
1361    /// assert_eq!(pre_increment.components(), (Some(&var_a), Some(&var_b)));
1362    /// ```
1363    #[inline]
1364    pub fn components(&self) -> (Option<&Self>, Option<&Self>) {
1365        use Expression::*;
1366        expr_components!(self)
1367    }
1368
1369    /// Returns mutable references to the components of this expression.
1370    ///
1371    /// See also [`Expression::components`].
1372    #[inline]
1373    pub fn components_mut(&mut self) -> (Option<&mut Self>, Option<&mut Self>) {
1374        use Expression::*;
1375        expr_components!(self)
1376    }
1377
1378    /// Returns whether this expression can be split across multiple lines.
1379    #[inline]
1380    pub const fn is_unsplittable(&self) -> bool {
1381        use Expression::*;
1382        matches!(
1383            self,
1384            BoolLiteral(..)
1385                | NumberLiteral(..)
1386                | RationalNumberLiteral(..)
1387                | HexNumberLiteral(..)
1388                | StringLiteral(..)
1389                | HexLiteral(..)
1390                | AddressLiteral(..)
1391                | Variable(..)
1392        )
1393    }
1394
1395    /// Returns whether this expression has spaces around it.
1396    #[inline]
1397    pub const fn has_space_around(&self) -> bool {
1398        use Expression::*;
1399        !matches!(
1400            self,
1401            PostIncrement(..)
1402                | PreIncrement(..)
1403                | PostDecrement(..)
1404                | PreDecrement(..)
1405                | Not(..)
1406                | BitwiseNot(..)
1407                | UnaryPlus(..)
1408                | Negate(..)
1409        )
1410    }
1411
1412    /// Returns if the expression is a literal
1413    pub fn is_literal(&self) -> bool {
1414        matches!(
1415            self,
1416            Expression::AddressLiteral(..)
1417                | Expression::HexLiteral(..)
1418                | Expression::BoolLiteral(..)
1419                | Expression::NumberLiteral(..)
1420                | Expression::ArrayLiteral(..)
1421                | Expression::HexNumberLiteral(..)
1422                | Expression::RationalNumberLiteral(..)
1423                | Expression::StringLiteral(..)
1424        )
1425    }
1426}
1427
1428/// A parameter.
1429///
1430/// `<ty> [storage] <name>`
1431#[derive(Debug, PartialEq, Eq, Clone)]
1432#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1433pub struct Parameter {
1434    /// The code location.
1435    pub loc: Loc,
1436    /// An optional annotation '@annotation'.
1437    pub annotation: Option<Annotation>,
1438    /// The type.
1439    pub ty: Expression,
1440    /// The optional memory location.
1441    pub storage: Option<StorageLocation>,
1442    /// The optional identifier.
1443    pub name: Option<Identifier>,
1444}
1445
1446/// Function mutability.
1447#[derive(Debug, PartialEq, Eq, Clone)]
1448#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1449pub enum Mutability {
1450    /// `pure`
1451    Pure(Loc),
1452
1453    /// `view`
1454    View(Loc),
1455
1456    /// `constant`
1457    Constant(Loc),
1458
1459    /// `payable`
1460    Payable(Loc),
1461}
1462
1463/// Function visibility.
1464///
1465/// Deprecated for [FunctionTy] other than `Function`.
1466#[derive(Debug, PartialEq, Eq, Clone)]
1467#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1468#[repr(u8)] // for cmp; order of variants is important
1469pub enum Visibility {
1470    /// `external`
1471    External(Option<Loc>),
1472
1473    /// `public`
1474    Public(Option<Loc>),
1475
1476    /// `internal`
1477    Internal(Option<Loc>),
1478
1479    /// `private`
1480    Private(Option<Loc>),
1481}
1482
1483/// A function attribute.
1484#[derive(Debug, PartialEq, Eq, Clone)]
1485#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1486#[repr(u8)] // for cmp; order of variants is important
1487pub enum FunctionAttribute {
1488    /// Visibility attribute.
1489    Visibility(Visibility),
1490
1491    /// Mutability attribute.
1492    Mutability(Mutability),
1493
1494    /// `virtual`
1495    Virtual(Loc),
1496
1497    /// `immutable`
1498    Immutable(Loc),
1499
1500    /// `override[(<identifier path>,*)]`
1501    Override(Loc, Vec<IdentifierPath>),
1502
1503    /// A modifier or constructor invocation.
1504    BaseOrModifier(Loc, Base),
1505
1506    /// An error occurred during parsing.
1507    Error(Loc),
1508}
1509
1510/// A function's type.
1511#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1512#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1513pub enum FunctionTy {
1514    /// `constructor`
1515    Constructor,
1516
1517    /// `function`
1518    Function,
1519
1520    /// `fallback`
1521    Fallback,
1522
1523    /// `receive`
1524    Receive,
1525
1526    /// `modifier`
1527    Modifier,
1528}
1529
1530/// A function definition.
1531///
1532/// `<ty> [name](<params>,*) [attributes] [returns] [body]`
1533#[derive(Debug, PartialEq, Eq, Clone)]
1534#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1535pub struct FunctionDefinition {
1536    /// The function prototype location.
1537    pub loc_prototype: Loc,
1538    /// The code location.
1539    pub loc: Loc,
1540    /// The function type.
1541    pub ty: FunctionTy,
1542    /// The optional identifier.
1543    ///
1544    /// This can be `None` for old style fallback functions.
1545    pub name: Option<Identifier>,
1546    /// The identifier's code location.
1547    pub name_loc: Loc,
1548    /// The parameter list.
1549    pub params: ParameterList,
1550    /// The function attributes.
1551    pub attributes: Vec<FunctionAttribute>,
1552    /// The `returns` keyword's location. `Some` if this was `return`, not `returns`.
1553    pub return_not_returns: Option<Loc>,
1554    /// The return parameter list.
1555    pub returns: ParameterList,
1556    /// The function body.
1557    ///
1558    /// If `None`, the declaration ended with a semicolon.
1559    pub body: Option<Statement>,
1560}
1561
1562impl FunctionDefinition {
1563    /// Returns `true` if the function has no return parameters.
1564    #[inline]
1565    pub fn is_void(&self) -> bool {
1566        self.returns.is_empty()
1567    }
1568
1569    /// Returns `true` if the function body is empty.
1570    #[inline]
1571    pub fn is_empty(&self) -> bool {
1572        self.body.as_ref().is_none_or(Statement::is_empty)
1573    }
1574
1575    /// Sorts the function attributes.
1576    #[inline]
1577    pub fn sort_attributes(&mut self) {
1578        // we don't use unstable sort since there may be more that one `BaseOrModifier` attributes
1579        // which we want to preserve the order of
1580        self.attributes.sort();
1581    }
1582}
1583
1584/// A statement.
1585#[derive(Debug, PartialEq, Eq, Clone)]
1586#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1587#[allow(clippy::large_enum_variant, clippy::type_complexity)]
1588pub enum Statement {
1589    /// `[unchecked] { <statements>* }`
1590    Block {
1591        /// The code location.
1592        loc: Loc,
1593        /// Whether this block is `unchecked`.
1594        unchecked: bool,
1595        /// The statements.
1596        statements: Vec<Statement>,
1597    },
1598    /// `assembly [dialect] [(<flags>,*)] <block>`
1599    Assembly {
1600        /// The code location.
1601        loc: Loc,
1602        /// The assembly dialect.
1603        dialect: Option<StringLiteral>,
1604        /// The assembly flags.
1605        flags: Option<Vec<StringLiteral>>,
1606        /// The assembly block.
1607        block: YulBlock,
1608    },
1609    /// `{ <1>,* }`
1610    Args(Loc, Vec<NamedArgument>),
1611    /// `if ({1}) <2> [else <3>]`
1612    ///
1613    /// Note that the `<1>` expression does not contain the parentheses.
1614    If(Loc, Expression, Box<Statement>, Option<Box<Statement>>),
1615    /// `while ({1}) <2>`
1616    ///
1617    /// Note that the `<1>` expression does not contain the parentheses.
1618    While(Loc, Expression, Box<Statement>),
1619    /// An [Expression].
1620    Expression(Loc, Expression),
1621    /// `<1> [= <2>];`
1622    VariableDefinition(Loc, VariableDeclaration, Option<Expression>),
1623    /// `for ([1]; [2]; [3]) [4]`
1624    ///
1625    /// The `[4]` block statement is `None` when the `for` statement ends with a semicolon.
1626    For(
1627        Loc,
1628        Option<Box<Statement>>,
1629        Option<Box<Expression>>,
1630        Option<Box<Expression>>,
1631        Option<Box<Statement>>,
1632    ),
1633    /// `do <1> while ({2});`
1634    ///
1635    /// Note that the `<2>` expression does not contain the parentheses.
1636    DoWhile(Loc, Box<Statement>, Expression),
1637    /// `continue;`
1638    Continue(Loc),
1639    /// `break;`
1640    Break(Loc),
1641    /// `return [1];`
1642    Return(Loc, Option<Expression>),
1643    /// `revert [1] (<2>,*);`
1644    Revert(Loc, Option<IdentifierPath>, Vec<Expression>),
1645    /// `revert [1] ({ <2>,* });`
1646    RevertNamedArgs(Loc, Option<IdentifierPath>, Vec<NamedArgument>),
1647    /// `emit <1>;`
1648    ///
1649    /// `<1>` is `FunctionCall`.
1650    Emit(Loc, Expression),
1651    /// `try <1> [returns (<2.1>,*) <2.2>] <3>*`
1652    ///
1653    /// `<1>` is either `New(FunctionCall)` or `FunctionCall`.
1654    Try(
1655        Loc,
1656        Expression,
1657        Option<(ParameterList, Box<Statement>)>,
1658        Vec<CatchClause>,
1659    ),
1660    /// An error occurred during parsing.
1661    Error(Loc),
1662}
1663
1664impl Statement {
1665    /// Returns `true` if the block statement contains no elements.
1666    #[inline]
1667    pub fn is_empty(&self) -> bool {
1668        match self {
1669            Self::Block { statements, .. } => statements.is_empty(),
1670            Self::Assembly { block, .. } => block.is_empty(),
1671            Self::Args(_, args) => args.is_empty(),
1672            _ => false,
1673        }
1674    }
1675}
1676
1677/// A catch clause. See [Statement].
1678#[derive(Debug, PartialEq, Eq, Clone)]
1679#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1680pub enum CatchClause {
1681    /// `catch [(<1>)] <2>`
1682    Simple(Loc, Option<Parameter>, Statement),
1683
1684    /// `catch <1> (<2>) <3>`
1685    Named(Loc, Identifier, Parameter, Statement),
1686}
1687
1688/// A Yul statement.
1689#[derive(Debug, PartialEq, Eq, Clone)]
1690#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1691pub enum YulStatement {
1692    /// `<1>,+ = <2>`
1693    Assign(Loc, Vec<YulExpression>, YulExpression),
1694    /// `let <1>,+ [:= <2>]`
1695    VariableDeclaration(Loc, Vec<YulTypedIdentifier>, Option<YulExpression>),
1696    /// `if <1> <2>`
1697    If(Loc, YulExpression, YulBlock),
1698    /// A [YulFor] statement.
1699    For(YulFor),
1700    /// A [YulSwitch] statement.
1701    Switch(YulSwitch),
1702    /// `leave`
1703    Leave(Loc),
1704    /// `break`
1705    Break(Loc),
1706    /// `continue`
1707    Continue(Loc),
1708    /// A [YulBlock] statement.
1709    Block(YulBlock),
1710    /// A [YulFunctionDefinition] statement.
1711    FunctionDefinition(Box<YulFunctionDefinition>),
1712    /// A [YulFunctionCall] statement.
1713    FunctionCall(Box<YulFunctionCall>),
1714    /// An error occurred during parsing.
1715    Error(Loc),
1716}
1717
1718/// A Yul switch statement.
1719///
1720/// `switch <condition> <cases>* [default <default>]`
1721///
1722/// Enforced by the parser:
1723///
1724/// - `cases` is guaranteed to be a `Vec` of `YulSwitchOptions::Case`.
1725/// - `default` is guaranteed to be `YulSwitchOptions::Default`.
1726/// - At least one of `cases` or `default` must be non-empty/`Some` respectively.
1727#[derive(Debug, PartialEq, Eq, Clone)]
1728#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1729pub struct YulSwitch {
1730    /// The code location.
1731    pub loc: Loc,
1732    /// The switch condition.
1733    pub condition: YulExpression,
1734    /// The switch cases.
1735    pub cases: Vec<YulSwitchOptions>,
1736    /// The optional default case.
1737    pub default: Option<YulSwitchOptions>,
1738}
1739
1740/// A Yul for statement.
1741///
1742/// `for <init_block> <condition> <post_block> <execution_block>`
1743#[derive(Debug, PartialEq, Eq, Clone)]
1744#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1745pub struct YulFor {
1746    /// The code location.
1747    pub loc: Loc,
1748    /// The for statement init block.
1749    pub init_block: YulBlock,
1750    /// The for statement condition.
1751    pub condition: YulExpression,
1752    /// The for statement post block.
1753    pub post_block: YulBlock,
1754    /// The for statement execution block.
1755    pub execution_block: YulBlock,
1756}
1757
1758/// A Yul block statement.
1759///
1760/// `{ <statements>* }`
1761#[derive(Debug, PartialEq, Eq, Clone)]
1762#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1763pub struct YulBlock {
1764    /// The code location.
1765    pub loc: Loc,
1766    /// The block statements.
1767    pub statements: Vec<YulStatement>,
1768}
1769
1770impl YulBlock {
1771    /// Returns `true` if the block contains no elements.
1772    #[inline]
1773    pub fn is_empty(&self) -> bool {
1774        self.statements.is_empty()
1775    }
1776}
1777
1778/// A Yul expression.
1779#[derive(Debug, PartialEq, Eq, Clone)]
1780#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1781pub enum YulExpression {
1782    /// `<1> [: <2>]`
1783    BoolLiteral(Loc, bool, Option<Identifier>),
1784    /// `<1>[e<2>] [: <2>]`
1785    NumberLiteral(Loc, String, String, Option<Identifier>),
1786    /// `<1> [: <2>]`
1787    HexNumberLiteral(Loc, String, Option<Identifier>),
1788    /// `<0> [: <1>]`
1789    HexStringLiteral(HexLiteral, Option<Identifier>),
1790    /// `<0> [: <1>]`
1791    StringLiteral(StringLiteral, Option<Identifier>),
1792    /// Any valid [Identifier].
1793    Variable(Identifier),
1794    /// [YulFunctionCall].
1795    FunctionCall(Box<YulFunctionCall>),
1796    /// `<1>.<2>`
1797    SuffixAccess(Loc, Box<YulExpression>, Identifier),
1798}
1799
1800/// A Yul typed identifier.
1801///
1802/// `<id> [: <ty>]`
1803#[derive(Debug, PartialEq, Eq, Clone)]
1804#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1805pub struct YulTypedIdentifier {
1806    /// The code location.
1807    pub loc: Loc,
1808    /// The identifier.
1809    pub id: Identifier,
1810    /// The optional type.
1811    pub ty: Option<Identifier>,
1812}
1813
1814/// A Yul function definition.
1815///
1816/// `function <name> (<params>,*) [-> (<returns>,*)] <body>`
1817#[derive(Debug, PartialEq, Eq, Clone)]
1818#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1819pub struct YulFunctionDefinition {
1820    /// The code location.
1821    pub loc: Loc,
1822    /// The identifier.
1823    pub id: Identifier,
1824    /// The parameters.
1825    pub params: Vec<YulTypedIdentifier>,
1826    /// The return parameters.
1827    pub returns: Vec<YulTypedIdentifier>,
1828    /// The function body.
1829    pub body: YulBlock,
1830}
1831
1832impl YulFunctionDefinition {
1833    /// Returns `true` if the function has no return parameters.
1834    #[inline]
1835    pub fn is_void(&self) -> bool {
1836        self.returns.is_empty()
1837    }
1838
1839    /// Returns `true` if the function body is empty.
1840    #[inline]
1841    pub fn is_empty(&self) -> bool {
1842        self.body.is_empty()
1843    }
1844}
1845
1846/// A Yul function call.
1847///
1848/// `<id>(<arguments>,*)`
1849#[derive(Debug, PartialEq, Eq, Clone)]
1850#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1851pub struct YulFunctionCall {
1852    /// The code location.
1853    pub loc: Loc,
1854    /// The identifier.
1855    pub id: Identifier,
1856    /// The function call arguments.
1857    pub arguments: Vec<YulExpression>,
1858}
1859
1860/// A Yul switch case or default statement. See [YulSwitch].
1861#[derive(Debug, PartialEq, Eq, Clone)]
1862#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1863pub enum YulSwitchOptions {
1864    /// `case <1> <2>`
1865    Case(Loc, YulExpression, YulBlock),
1866    /// `default <1>`
1867    Default(Loc, YulBlock),
1868}