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    /// Only transient.
1000    StorageLocation(StorageLocation),
1001}
1002
1003/// Soroban storage types.
1004#[derive(Debug, PartialEq, Eq, Clone)]
1005#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1006#[repr(u8)] // for cmp; order of variants is important
1007pub enum StorageType {
1008    /// `Temporary`
1009    Temporary(Option<Loc>),
1010
1011    /// `persistent`
1012    Persistent(Option<Loc>),
1013
1014    /// `Instance`
1015    Instance(Option<Loc>),
1016}
1017
1018/// A variable definition.
1019///
1020/// `<ty> <attrs>* <name> [= <initializer>]`
1021#[derive(Debug, PartialEq, Eq, Clone)]
1022#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1023pub struct VariableDefinition {
1024    /// The code location.
1025    pub loc: Loc,
1026    /// The type.
1027    pub ty: Expression,
1028    /// The list of variable attributes.
1029    pub attrs: Vec<VariableAttribute>,
1030    /// The identifier.
1031    ///
1032    /// This field is `None` only if an error occurred during parsing.
1033    pub name: Option<Identifier>,
1034    /// The optional initializer.
1035    pub initializer: Option<Expression>,
1036}
1037
1038/// A user type definition.
1039///
1040/// `type <name> is <ty>;`
1041#[derive(Debug, PartialEq, Eq, Clone)]
1042#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1043pub struct TypeDefinition {
1044    /// The code location.
1045    pub loc: Loc,
1046    /// The user-defined type name.
1047    pub name: Identifier,
1048    /// The type expression.
1049    pub ty: Expression,
1050}
1051
1052/// An annotation.
1053///
1054/// `@<id>(<value>)`
1055#[derive(Debug, PartialEq, Eq, Clone)]
1056#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1057pub struct Annotation {
1058    /// The code location.
1059    pub loc: Loc,
1060    /// The identifier.
1061    pub id: Identifier,
1062    /// The value.
1063    pub value: Option<Expression>,
1064}
1065
1066/// A string literal.
1067///
1068/// `[unicode]"<string>"`
1069#[derive(Debug, PartialEq, Eq, Clone)]
1070#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1071pub struct StringLiteral {
1072    /// The code location.
1073    pub loc: Loc,
1074    /// Whether this is a unicode string.
1075    pub unicode: bool,
1076    /// The string literal.
1077    ///
1078    /// Does not contain the quotes or the `unicode` prefix.
1079    pub string: String,
1080}
1081
1082/// A hex literal.
1083///
1084/// `hex"<literal>"`
1085#[derive(Debug, PartialEq, Eq, Clone)]
1086#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1087pub struct HexLiteral {
1088    /// The code location.
1089    pub loc: Loc,
1090    /// The hex literal.
1091    ///
1092    /// Contains the `hex` prefix.
1093    pub hex: String,
1094}
1095
1096/// A named argument.
1097///
1098/// `<name>: <expr>`
1099#[derive(Debug, PartialEq, Eq, Clone)]
1100#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1101pub struct NamedArgument {
1102    /// The code location.
1103    pub loc: Loc,
1104    /// The identifier.
1105    pub name: Identifier,
1106    /// The value.
1107    pub expr: Expression,
1108}
1109
1110/// An expression.
1111#[derive(Debug, PartialEq, Eq, Clone)]
1112#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1113pub enum Expression {
1114    /// `<1>++`
1115    PostIncrement(Loc, Box<Expression>),
1116    /// `<1>--`
1117    PostDecrement(Loc, Box<Expression>),
1118    /// `new <1>`
1119    New(Loc, Box<Expression>),
1120    /// `<1>\[ [2] \]`
1121    ArraySubscript(Loc, Box<Expression>, Option<Box<Expression>>),
1122    /// `<1>\[ [2] : [3] \]`
1123    ArraySlice(
1124        Loc,
1125        Box<Expression>,
1126        Option<Box<Expression>>,
1127        Option<Box<Expression>>,
1128    ),
1129    /// `(<1>)`
1130    Parenthesis(Loc, Box<Expression>),
1131    /// `<1>.<2>`
1132    MemberAccess(Loc, Box<Expression>, Identifier),
1133    /// `<1>(<2>,*)`
1134    FunctionCall(Loc, Box<Expression>, Vec<Expression>),
1135    /// `<1><2>` where <2> is a block.
1136    FunctionCallBlock(Loc, Box<Expression>, Box<Statement>),
1137    /// `<1>({ <2>,* })`
1138    NamedFunctionCall(Loc, Box<Expression>, Vec<NamedArgument>),
1139    /// `!<1>`
1140    Not(Loc, Box<Expression>),
1141    /// `~<1>`
1142    BitwiseNot(Loc, Box<Expression>),
1143    /// `delete <1>`
1144    Delete(Loc, Box<Expression>),
1145    /// `++<1>`
1146    PreIncrement(Loc, Box<Expression>),
1147    /// `--<1>`
1148    PreDecrement(Loc, Box<Expression>),
1149    /// `+<1>`
1150    ///
1151    /// Note that this isn't actually supported by Solidity.
1152    UnaryPlus(Loc, Box<Expression>),
1153    /// `-<1>`
1154    Negate(Loc, Box<Expression>),
1155
1156    /// `<1> ** <2>`
1157    Power(Loc, Box<Expression>, Box<Expression>),
1158    /// `<1> * <2>`
1159    Multiply(Loc, Box<Expression>, Box<Expression>),
1160    /// `<1> / <2>`
1161    Divide(Loc, Box<Expression>, Box<Expression>),
1162    /// `<1> % <2>`
1163    Modulo(Loc, Box<Expression>, Box<Expression>),
1164    /// `<1> + <2>`
1165    Add(Loc, Box<Expression>, Box<Expression>),
1166    /// `<1> - <2>`
1167    Subtract(Loc, Box<Expression>, Box<Expression>),
1168    /// `<1> << <2>`
1169    ShiftLeft(Loc, Box<Expression>, Box<Expression>),
1170    /// `<1> >> <2>`
1171    ShiftRight(Loc, Box<Expression>, Box<Expression>),
1172    /// `<1> & <2>`
1173    BitwiseAnd(Loc, Box<Expression>, Box<Expression>),
1174    /// `<1> ^ <2>`
1175    BitwiseXor(Loc, Box<Expression>, Box<Expression>),
1176    /// `<1> | <2>`
1177    BitwiseOr(Loc, Box<Expression>, Box<Expression>),
1178    /// `<1> < <2>`
1179    Less(Loc, Box<Expression>, Box<Expression>),
1180    /// `<1> > <2>`
1181    More(Loc, Box<Expression>, Box<Expression>),
1182    /// `<1> <= <2>`
1183    LessEqual(Loc, Box<Expression>, Box<Expression>),
1184    /// `<1> >= <2>`
1185    MoreEqual(Loc, Box<Expression>, Box<Expression>),
1186    /// `<1> == <2>`
1187    Equal(Loc, Box<Expression>, Box<Expression>),
1188    /// `<1> != <2>`
1189    NotEqual(Loc, Box<Expression>, Box<Expression>),
1190    /// `<1> && <2>`
1191    And(Loc, Box<Expression>, Box<Expression>),
1192    /// `<1> || <2>`
1193    Or(Loc, Box<Expression>, Box<Expression>),
1194    /// `<1> ? <2> : <3>`
1195    ///
1196    /// AKA ternary operator.
1197    ConditionalOperator(Loc, Box<Expression>, Box<Expression>, Box<Expression>),
1198    /// `<1> = <2>`
1199    Assign(Loc, Box<Expression>, Box<Expression>),
1200    /// `<1> |= <2>`
1201    AssignOr(Loc, Box<Expression>, Box<Expression>),
1202    /// `<1> &= <2>`
1203    AssignAnd(Loc, Box<Expression>, Box<Expression>),
1204    /// `<1> ^= <2>`
1205    AssignXor(Loc, Box<Expression>, Box<Expression>),
1206    /// `<1> <<= <2>`
1207    AssignShiftLeft(Loc, Box<Expression>, Box<Expression>),
1208    /// `<1> >>= <2>`
1209    AssignShiftRight(Loc, Box<Expression>, Box<Expression>),
1210    /// `<1> += <2>`
1211    AssignAdd(Loc, Box<Expression>, Box<Expression>),
1212    /// `<1> -= <2>`
1213    AssignSubtract(Loc, Box<Expression>, Box<Expression>),
1214    /// `<1> *= <2>`
1215    AssignMultiply(Loc, Box<Expression>, Box<Expression>),
1216    /// `<1> /= <2>`
1217    AssignDivide(Loc, Box<Expression>, Box<Expression>),
1218    /// `<1> %= <2>`
1219    AssignModulo(Loc, Box<Expression>, Box<Expression>),
1220
1221    /// `true` or `false`
1222    BoolLiteral(Loc, bool),
1223    /// ``
1224    NumberLiteral(Loc, String, String, Option<Identifier>),
1225    /// ``
1226    RationalNumberLiteral(Loc, String, String, String, Option<Identifier>),
1227    /// ``
1228    HexNumberLiteral(Loc, String, Option<Identifier>),
1229    /// `<1>+`. See [StringLiteral].
1230    StringLiteral(Vec<StringLiteral>),
1231    /// See [Type].
1232    Type(Loc, Type),
1233    /// `<1>+`. See [HexLiteral].
1234    HexLiteral(Vec<HexLiteral>),
1235    /// `0x[a-fA-F0-9]{40}`
1236    ///
1237    /// This [should be correctly checksummed][ref], but it currently isn't being enforced in the parser.
1238    ///
1239    /// [ref]: https://docs.soliditylang.org/en/latest/types.html#address-literals
1240    AddressLiteral(Loc, String),
1241    /// Any valid [Identifier].
1242    Variable(Identifier),
1243    /// `(<1>,*)`
1244    List(Loc, ParameterList),
1245    /// `\[ <1>.* \]`
1246    ArrayLiteral(Loc, Vec<Expression>),
1247}
1248
1249/// See `Expression::components`.
1250macro_rules! expr_components {
1251    ($s:ident) => {
1252        match $s {
1253            // (Some, None)
1254            PostDecrement(_, expr) | PostIncrement(_, expr) => (Some(expr), None),
1255
1256            // (None, Some)
1257            Not(_, expr)
1258            | BitwiseNot(_, expr)
1259            | New(_, expr)
1260            | Delete(_, expr)
1261            | UnaryPlus(_, expr)
1262            | Negate(_, expr)
1263            | PreDecrement(_, expr)
1264            | Parenthesis(_, expr)
1265            | PreIncrement(_, expr) => (None, Some(expr)),
1266
1267            // (Some, Some)
1268            Power(_, left, right)
1269            | Multiply(_, left, right)
1270            | Divide(_, left, right)
1271            | Modulo(_, left, right)
1272            | Add(_, left, right)
1273            | Subtract(_, left, right)
1274            | ShiftLeft(_, left, right)
1275            | ShiftRight(_, left, right)
1276            | BitwiseAnd(_, left, right)
1277            | BitwiseXor(_, left, right)
1278            | BitwiseOr(_, left, right)
1279            | Less(_, left, right)
1280            | More(_, left, right)
1281            | LessEqual(_, left, right)
1282            | MoreEqual(_, left, right)
1283            | Equal(_, left, right)
1284            | NotEqual(_, left, right)
1285            | And(_, left, right)
1286            | Or(_, left, right)
1287            | Assign(_, left, right)
1288            | AssignOr(_, left, right)
1289            | AssignAnd(_, left, right)
1290            | AssignXor(_, left, right)
1291            | AssignShiftLeft(_, left, right)
1292            | AssignShiftRight(_, left, right)
1293            | AssignAdd(_, left, right)
1294            | AssignSubtract(_, left, right)
1295            | AssignMultiply(_, left, right)
1296            | AssignDivide(_, left, right)
1297            | AssignModulo(_, left, right) => (Some(left), Some(right)),
1298
1299            // (None, None)
1300            MemberAccess(..)
1301            | ConditionalOperator(..)
1302            | ArraySubscript(..)
1303            | ArraySlice(..)
1304            | FunctionCall(..)
1305            | FunctionCallBlock(..)
1306            | NamedFunctionCall(..)
1307            | BoolLiteral(..)
1308            | NumberLiteral(..)
1309            | RationalNumberLiteral(..)
1310            | HexNumberLiteral(..)
1311            | StringLiteral(..)
1312            | Type(..)
1313            | HexLiteral(..)
1314            | AddressLiteral(..)
1315            | Variable(..)
1316            | List(..)
1317            | ArrayLiteral(..) => (None, None),
1318        }
1319    };
1320}
1321
1322impl Expression {
1323    /// Removes one layer of parentheses.
1324    #[inline]
1325    pub fn remove_parenthesis(&self) -> &Expression {
1326        if let Expression::Parenthesis(_, expr) = self {
1327            expr
1328        } else {
1329            self
1330        }
1331    }
1332
1333    /// Strips all parentheses recursively.
1334    pub fn strip_parentheses(&self) -> &Expression {
1335        match self {
1336            Expression::Parenthesis(_, expr) => expr.strip_parentheses(),
1337            _ => self,
1338        }
1339    }
1340
1341    /// Returns shared references to the components of this expression.
1342    ///
1343    /// `(left_component, right_component)`
1344    ///
1345    /// # Examples
1346    ///
1347    /// ```
1348    /// use solang_parser::pt::{Expression, Identifier, Loc};
1349    ///
1350    /// // `a++`
1351    /// let var = Expression::Variable(Identifier::new("a"));
1352    /// let post_increment = Expression::PostIncrement(Loc::default(), Box::new(var.clone()));
1353    /// assert_eq!(post_increment.components(), (Some(&var), None));
1354    ///
1355    /// // `++a`
1356    /// let var = Expression::Variable(Identifier::new("a"));
1357    /// let pre_increment = Expression::PreIncrement(Loc::default(), Box::new(var.clone()));
1358    /// assert_eq!(pre_increment.components(), (None, Some(&var)));
1359    ///
1360    /// // `a + b`
1361    /// let var_a = Expression::Variable(Identifier::new("a"));
1362    /// let var_b = Expression::Variable(Identifier::new("b"));
1363    /// let pre_increment = Expression::Add(Loc::default(), Box::new(var_a.clone()), Box::new(var_b.clone()));
1364    /// assert_eq!(pre_increment.components(), (Some(&var_a), Some(&var_b)));
1365    /// ```
1366    #[inline]
1367    pub fn components(&self) -> (Option<&Self>, Option<&Self>) {
1368        use Expression::*;
1369        expr_components!(self)
1370    }
1371
1372    /// Returns mutable references to the components of this expression.
1373    ///
1374    /// See also [`Expression::components`].
1375    #[inline]
1376    pub fn components_mut(&mut self) -> (Option<&mut Self>, Option<&mut Self>) {
1377        use Expression::*;
1378        expr_components!(self)
1379    }
1380
1381    /// Returns whether this expression can be split across multiple lines.
1382    #[inline]
1383    pub const fn is_unsplittable(&self) -> bool {
1384        use Expression::*;
1385        matches!(
1386            self,
1387            BoolLiteral(..)
1388                | NumberLiteral(..)
1389                | RationalNumberLiteral(..)
1390                | HexNumberLiteral(..)
1391                | StringLiteral(..)
1392                | HexLiteral(..)
1393                | AddressLiteral(..)
1394                | Variable(..)
1395        )
1396    }
1397
1398    /// Returns whether this expression has spaces around it.
1399    #[inline]
1400    pub const fn has_space_around(&self) -> bool {
1401        use Expression::*;
1402        !matches!(
1403            self,
1404            PostIncrement(..)
1405                | PreIncrement(..)
1406                | PostDecrement(..)
1407                | PreDecrement(..)
1408                | Not(..)
1409                | BitwiseNot(..)
1410                | UnaryPlus(..)
1411                | Negate(..)
1412        )
1413    }
1414
1415    /// Returns if the expression is a literal
1416    pub fn is_literal(&self) -> bool {
1417        matches!(
1418            self,
1419            Expression::AddressLiteral(..)
1420                | Expression::HexLiteral(..)
1421                | Expression::BoolLiteral(..)
1422                | Expression::NumberLiteral(..)
1423                | Expression::ArrayLiteral(..)
1424                | Expression::HexNumberLiteral(..)
1425                | Expression::RationalNumberLiteral(..)
1426                | Expression::StringLiteral(..)
1427        )
1428    }
1429}
1430
1431/// A parameter.
1432///
1433/// `<ty> [storage] <name>`
1434#[derive(Debug, PartialEq, Eq, Clone)]
1435#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1436pub struct Parameter {
1437    /// The code location.
1438    pub loc: Loc,
1439    /// An optional annotation '@annotation'.
1440    pub annotation: Option<Annotation>,
1441    /// The type.
1442    pub ty: Expression,
1443    /// The optional memory location.
1444    pub storage: Option<StorageLocation>,
1445    /// The optional identifier.
1446    pub name: Option<Identifier>,
1447}
1448
1449/// Function mutability.
1450#[derive(Debug, PartialEq, Eq, Clone)]
1451#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1452pub enum Mutability {
1453    /// `pure`
1454    Pure(Loc),
1455
1456    /// `view`
1457    View(Loc),
1458
1459    /// `constant`
1460    Constant(Loc),
1461
1462    /// `payable`
1463    Payable(Loc),
1464}
1465
1466/// Function visibility.
1467///
1468/// Deprecated for [FunctionTy] other than `Function`.
1469#[derive(Debug, PartialEq, Eq, Clone)]
1470#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1471#[repr(u8)] // for cmp; order of variants is important
1472pub enum Visibility {
1473    /// `external`
1474    External(Option<Loc>),
1475
1476    /// `public`
1477    Public(Option<Loc>),
1478
1479    /// `internal`
1480    Internal(Option<Loc>),
1481
1482    /// `private`
1483    Private(Option<Loc>),
1484}
1485
1486/// A function attribute.
1487#[derive(Debug, PartialEq, Eq, Clone)]
1488#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1489#[repr(u8)] // for cmp; order of variants is important
1490pub enum FunctionAttribute {
1491    /// Visibility attribute.
1492    Visibility(Visibility),
1493
1494    /// Mutability attribute.
1495    Mutability(Mutability),
1496
1497    /// `virtual`
1498    Virtual(Loc),
1499
1500    /// `immutable`
1501    Immutable(Loc),
1502
1503    /// `override[(<identifier path>,*)]`
1504    Override(Loc, Vec<IdentifierPath>),
1505
1506    /// A modifier or constructor invocation.
1507    BaseOrModifier(Loc, Base),
1508
1509    /// An error occurred during parsing.
1510    Error(Loc),
1511}
1512
1513/// A function's type.
1514#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1515#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1516pub enum FunctionTy {
1517    /// `constructor`
1518    Constructor,
1519
1520    /// `function`
1521    Function,
1522
1523    /// `fallback`
1524    Fallback,
1525
1526    /// `receive`
1527    Receive,
1528
1529    /// `modifier`
1530    Modifier,
1531}
1532
1533/// A function definition.
1534///
1535/// `<ty> [name](<params>,*) [attributes] [returns] [body]`
1536#[derive(Debug, PartialEq, Eq, Clone)]
1537#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1538pub struct FunctionDefinition {
1539    /// The function prototype location.
1540    pub loc_prototype: Loc,
1541    /// The code location.
1542    pub loc: Loc,
1543    /// The function type.
1544    pub ty: FunctionTy,
1545    /// The optional identifier.
1546    ///
1547    /// This can be `None` for old style fallback functions.
1548    pub name: Option<Identifier>,
1549    /// The identifier's code location.
1550    pub name_loc: Loc,
1551    /// The parameter list.
1552    pub params: ParameterList,
1553    /// The function attributes.
1554    pub attributes: Vec<FunctionAttribute>,
1555    /// The `returns` keyword's location. `Some` if this was `return`, not `returns`.
1556    pub return_not_returns: Option<Loc>,
1557    /// The return parameter list.
1558    pub returns: ParameterList,
1559    /// The function body.
1560    ///
1561    /// If `None`, the declaration ended with a semicolon.
1562    pub body: Option<Statement>,
1563}
1564
1565impl FunctionDefinition {
1566    /// Returns `true` if the function has no return parameters.
1567    #[inline]
1568    pub fn is_void(&self) -> bool {
1569        self.returns.is_empty()
1570    }
1571
1572    /// Returns `true` if the function body is empty.
1573    #[inline]
1574    pub fn is_empty(&self) -> bool {
1575        self.body.as_ref().is_none_or(Statement::is_empty)
1576    }
1577
1578    /// Sorts the function attributes.
1579    #[inline]
1580    pub fn sort_attributes(&mut self) {
1581        // we don't use unstable sort since there may be more that one `BaseOrModifier` attributes
1582        // which we want to preserve the order of
1583        self.attributes.sort();
1584    }
1585}
1586
1587/// A statement.
1588#[derive(Debug, PartialEq, Eq, Clone)]
1589#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1590#[allow(clippy::large_enum_variant, clippy::type_complexity)]
1591pub enum Statement {
1592    /// `[unchecked] { <statements>* }`
1593    Block {
1594        /// The code location.
1595        loc: Loc,
1596        /// Whether this block is `unchecked`.
1597        unchecked: bool,
1598        /// The statements.
1599        statements: Vec<Statement>,
1600    },
1601    /// `assembly [dialect] [(<flags>,*)] <block>`
1602    Assembly {
1603        /// The code location.
1604        loc: Loc,
1605        /// The assembly dialect.
1606        dialect: Option<StringLiteral>,
1607        /// The assembly flags.
1608        flags: Option<Vec<StringLiteral>>,
1609        /// The assembly block.
1610        block: YulBlock,
1611    },
1612    /// `{ <1>,* }`
1613    Args(Loc, Vec<NamedArgument>),
1614    /// `if ({1}) <2> [else <3>]`
1615    ///
1616    /// Note that the `<1>` expression does not contain the parentheses.
1617    If(Loc, Expression, Box<Statement>, Option<Box<Statement>>),
1618    /// `while ({1}) <2>`
1619    ///
1620    /// Note that the `<1>` expression does not contain the parentheses.
1621    While(Loc, Expression, Box<Statement>),
1622    /// An [Expression].
1623    Expression(Loc, Expression),
1624    /// `<1> [= <2>];`
1625    VariableDefinition(Loc, VariableDeclaration, Option<Expression>),
1626    /// `for ([1]; [2]; [3]) [4]`
1627    ///
1628    /// The `[4]` block statement is `None` when the `for` statement ends with a semicolon.
1629    For(
1630        Loc,
1631        Option<Box<Statement>>,
1632        Option<Box<Expression>>,
1633        Option<Box<Expression>>,
1634        Option<Box<Statement>>,
1635    ),
1636    /// `do <1> while ({2});`
1637    ///
1638    /// Note that the `<2>` expression does not contain the parentheses.
1639    DoWhile(Loc, Box<Statement>, Expression),
1640    /// `continue;`
1641    Continue(Loc),
1642    /// `break;`
1643    Break(Loc),
1644    /// `return [1];`
1645    Return(Loc, Option<Expression>),
1646    /// `revert [1] (<2>,*);`
1647    Revert(Loc, Option<IdentifierPath>, Vec<Expression>),
1648    /// `revert [1] ({ <2>,* });`
1649    RevertNamedArgs(Loc, Option<IdentifierPath>, Vec<NamedArgument>),
1650    /// `emit <1>;`
1651    ///
1652    /// `<1>` is `FunctionCall`.
1653    Emit(Loc, Expression),
1654    /// `try <1> [returns (<2.1>,*) <2.2>] <3>*`
1655    ///
1656    /// `<1>` is either `New(FunctionCall)` or `FunctionCall`.
1657    Try(
1658        Loc,
1659        Expression,
1660        Option<(ParameterList, Box<Statement>)>,
1661        Vec<CatchClause>,
1662    ),
1663    /// An error occurred during parsing.
1664    Error(Loc),
1665}
1666
1667impl Statement {
1668    /// Returns `true` if the block statement contains no elements.
1669    #[inline]
1670    pub fn is_empty(&self) -> bool {
1671        match self {
1672            Self::Block { statements, .. } => statements.is_empty(),
1673            Self::Assembly { block, .. } => block.is_empty(),
1674            Self::Args(_, args) => args.is_empty(),
1675            _ => false,
1676        }
1677    }
1678}
1679
1680/// A catch clause. See [Statement].
1681#[derive(Debug, PartialEq, Eq, Clone)]
1682#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1683pub enum CatchClause {
1684    /// `catch [(<1>)] <2>`
1685    Simple(Loc, Option<Parameter>, Statement),
1686
1687    /// `catch <1> (<2>) <3>`
1688    Named(Loc, Identifier, Parameter, Statement),
1689}
1690
1691/// A Yul statement.
1692#[derive(Debug, PartialEq, Eq, Clone)]
1693#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1694pub enum YulStatement {
1695    /// `<1>,+ = <2>`
1696    Assign(Loc, Vec<YulExpression>, YulExpression),
1697    /// `let <1>,+ [:= <2>]`
1698    VariableDeclaration(Loc, Vec<YulTypedIdentifier>, Option<YulExpression>),
1699    /// `if <1> <2>`
1700    If(Loc, YulExpression, YulBlock),
1701    /// A [YulFor] statement.
1702    For(YulFor),
1703    /// A [YulSwitch] statement.
1704    Switch(YulSwitch),
1705    /// `leave`
1706    Leave(Loc),
1707    /// `break`
1708    Break(Loc),
1709    /// `continue`
1710    Continue(Loc),
1711    /// A [YulBlock] statement.
1712    Block(YulBlock),
1713    /// A [YulFunctionDefinition] statement.
1714    FunctionDefinition(Box<YulFunctionDefinition>),
1715    /// A [YulFunctionCall] statement.
1716    FunctionCall(Box<YulFunctionCall>),
1717    /// An error occurred during parsing.
1718    Error(Loc),
1719}
1720
1721/// A Yul switch statement.
1722///
1723/// `switch <condition> <cases>* [default <default>]`
1724///
1725/// Enforced by the parser:
1726///
1727/// - `cases` is guaranteed to be a `Vec` of `YulSwitchOptions::Case`.
1728/// - `default` is guaranteed to be `YulSwitchOptions::Default`.
1729/// - At least one of `cases` or `default` must be non-empty/`Some` respectively.
1730#[derive(Debug, PartialEq, Eq, Clone)]
1731#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1732pub struct YulSwitch {
1733    /// The code location.
1734    pub loc: Loc,
1735    /// The switch condition.
1736    pub condition: YulExpression,
1737    /// The switch cases.
1738    pub cases: Vec<YulSwitchOptions>,
1739    /// The optional default case.
1740    pub default: Option<YulSwitchOptions>,
1741}
1742
1743/// A Yul for statement.
1744///
1745/// `for <init_block> <condition> <post_block> <execution_block>`
1746#[derive(Debug, PartialEq, Eq, Clone)]
1747#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1748pub struct YulFor {
1749    /// The code location.
1750    pub loc: Loc,
1751    /// The for statement init block.
1752    pub init_block: YulBlock,
1753    /// The for statement condition.
1754    pub condition: YulExpression,
1755    /// The for statement post block.
1756    pub post_block: YulBlock,
1757    /// The for statement execution block.
1758    pub execution_block: YulBlock,
1759}
1760
1761/// A Yul block statement.
1762///
1763/// `{ <statements>* }`
1764#[derive(Debug, PartialEq, Eq, Clone)]
1765#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1766pub struct YulBlock {
1767    /// The code location.
1768    pub loc: Loc,
1769    /// The block statements.
1770    pub statements: Vec<YulStatement>,
1771}
1772
1773impl YulBlock {
1774    /// Returns `true` if the block contains no elements.
1775    #[inline]
1776    pub fn is_empty(&self) -> bool {
1777        self.statements.is_empty()
1778    }
1779}
1780
1781/// A Yul expression.
1782#[derive(Debug, PartialEq, Eq, Clone)]
1783#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1784pub enum YulExpression {
1785    /// `<1> [: <2>]`
1786    BoolLiteral(Loc, bool, Option<Identifier>),
1787    /// `<1>[e<2>] [: <2>]`
1788    NumberLiteral(Loc, String, String, Option<Identifier>),
1789    /// `<1> [: <2>]`
1790    HexNumberLiteral(Loc, String, Option<Identifier>),
1791    /// `<0> [: <1>]`
1792    HexStringLiteral(HexLiteral, Option<Identifier>),
1793    /// `<0> [: <1>]`
1794    StringLiteral(StringLiteral, Option<Identifier>),
1795    /// Any valid [Identifier].
1796    Variable(Identifier),
1797    /// [YulFunctionCall].
1798    FunctionCall(Box<YulFunctionCall>),
1799    /// `<1>.<2>`
1800    SuffixAccess(Loc, Box<YulExpression>, Identifier),
1801}
1802
1803/// A Yul typed identifier.
1804///
1805/// `<id> [: <ty>]`
1806#[derive(Debug, PartialEq, Eq, Clone)]
1807#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1808pub struct YulTypedIdentifier {
1809    /// The code location.
1810    pub loc: Loc,
1811    /// The identifier.
1812    pub id: Identifier,
1813    /// The optional type.
1814    pub ty: Option<Identifier>,
1815}
1816
1817/// A Yul function definition.
1818///
1819/// `function <name> (<params>,*) [-> (<returns>,*)] <body>`
1820#[derive(Debug, PartialEq, Eq, Clone)]
1821#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1822pub struct YulFunctionDefinition {
1823    /// The code location.
1824    pub loc: Loc,
1825    /// The identifier.
1826    pub id: Identifier,
1827    /// The parameters.
1828    pub params: Vec<YulTypedIdentifier>,
1829    /// The return parameters.
1830    pub returns: Vec<YulTypedIdentifier>,
1831    /// The function body.
1832    pub body: YulBlock,
1833}
1834
1835impl YulFunctionDefinition {
1836    /// Returns `true` if the function has no return parameters.
1837    #[inline]
1838    pub fn is_void(&self) -> bool {
1839        self.returns.is_empty()
1840    }
1841
1842    /// Returns `true` if the function body is empty.
1843    #[inline]
1844    pub fn is_empty(&self) -> bool {
1845        self.body.is_empty()
1846    }
1847}
1848
1849/// A Yul function call.
1850///
1851/// `<id>(<arguments>,*)`
1852#[derive(Debug, PartialEq, Eq, Clone)]
1853#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1854pub struct YulFunctionCall {
1855    /// The code location.
1856    pub loc: Loc,
1857    /// The identifier.
1858    pub id: Identifier,
1859    /// The function call arguments.
1860    pub arguments: Vec<YulExpression>,
1861}
1862
1863/// A Yul switch case or default statement. See [YulSwitch].
1864#[derive(Debug, PartialEq, Eq, Clone)]
1865#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1866pub enum YulSwitchOptions {
1867    /// `case <1> <2>`
1868    Case(Loc, YulExpression, YulBlock),
1869    /// `default <1>`
1870    Default(Loc, YulBlock),
1871}