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
509/// A variable declaration.
510///
511/// `<ty> [storage] <name>`
512#[derive(Debug, PartialEq, Eq, Clone)]
513#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
514pub struct VariableDeclaration {
515    /// The code location.
516    pub loc: Loc,
517    /// The type.
518    pub ty: Expression,
519    /// The optional memory location.
520    pub storage: Option<StorageLocation>,
521    /// The identifier.
522    ///
523    /// This field is `None` only if an error occurred during parsing.
524    pub name: Option<Identifier>,
525}
526
527/// A struct definition.
528///
529/// `struct <name> { <fields>;* }`
530#[derive(Debug, PartialEq, Eq, Clone)]
531#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
532pub struct StructDefinition {
533    /// The code location.
534    pub loc: Loc,
535    /// The identifier.
536    ///
537    /// This field is `None` only if an error occurred during parsing.
538    pub name: Option<Identifier>,
539    /// The list of fields.
540    pub fields: Vec<VariableDeclaration>,
541}
542
543/// A contract part.
544#[derive(Debug, PartialEq, Eq, Clone)]
545#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
546pub enum ContractPart {
547    /// A struct definition.
548    StructDefinition(Box<StructDefinition>),
549
550    /// An event definition.
551    EventDefinition(Box<EventDefinition>),
552
553    /// An enum definition.
554    EnumDefinition(Box<EnumDefinition>),
555
556    /// An error definition.
557    ErrorDefinition(Box<ErrorDefinition>),
558
559    /// A variable definition.
560    VariableDefinition(Box<VariableDefinition>),
561
562    /// A function definition.
563    FunctionDefinition(Box<FunctionDefinition>),
564
565    /// A type definition.
566    TypeDefinition(Box<TypeDefinition>),
567
568    /// A definition.
569    Annotation(Box<Annotation>),
570
571    /// A `using` directive.
572    Using(Box<Using>),
573
574    /// A stray semicolon.
575    StraySemicolon(Loc),
576}
577
578/// A pragma directive
579#[derive(Debug, PartialEq, Eq, Clone)]
580#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
581pub enum PragmaDirective {
582    /// pragma a b;
583    Identifier(Loc, Option<Identifier>, Option<Identifier>),
584    /// pragma a "b";
585    StringLiteral(Loc, Identifier, StringLiteral),
586    /// pragma version =0.5.16;
587    Version(Loc, Identifier, Vec<VersionComparator>),
588}
589
590/// A `version` list
591#[derive(Debug, PartialEq, Eq, Clone)]
592#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
593pub enum VersionComparator {
594    /// 0.8.22
595    Plain {
596        /// The code location.
597        loc: Loc,
598        /// List of versions: major, minor, patch. minor and patch are optional
599        version: Vec<String>,
600    },
601    /// =0.5.16
602    Operator {
603        /// The code location.
604        loc: Loc,
605        /// Semver comparison operator
606        op: VersionOp,
607        /// version number
608        version: Vec<String>,
609    },
610    /// foo || bar
611    Or {
612        /// The code location.
613        loc: Loc,
614        /// left part
615        left: Box<VersionComparator>,
616        /// right part
617        right: Box<VersionComparator>,
618    },
619    /// 0.7.0 - 0.8.22
620    Range {
621        /// The code location.
622        loc: Loc,
623        /// start of range
624        from: Vec<String>,
625        /// end of range
626        to: Vec<String>,
627    },
628}
629
630/// Comparison operator
631#[derive(Debug, PartialEq, Eq, Copy, Clone)]
632#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
633pub enum VersionOp {
634    /// `=`
635    Exact,
636    /// `>`
637    Greater,
638    /// `>=`
639    GreaterEq,
640    /// `<`
641    Less,
642    /// `<=`
643    LessEq,
644    /// `~`
645    Tilde,
646    /// `^`
647    Caret,
648    /// `*`
649    Wildcard,
650}
651
652/// A `using` list. See [Using].
653#[derive(Debug, PartialEq, Eq, Clone)]
654#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
655pub enum UsingList {
656    /// A single identifier path.
657    Library(IdentifierPath),
658
659    /// List of using functions.
660    ///
661    /// `{ <<identifier path> [ as <operator> ]>,* }`
662    Functions(Vec<UsingFunction>),
663
664    /// An error occurred during parsing.
665    Error,
666}
667
668/// A `using` function. See [UsingList].
669///
670/// `<path> [ as <oper> ]`
671#[derive(Debug, PartialEq, Eq, Clone)]
672#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
673pub struct UsingFunction {
674    /// The code location.
675    pub loc: Loc,
676    /// The identifier path.
677    pub path: IdentifierPath,
678    /// The optional user-defined operator.
679    pub oper: Option<UserDefinedOperator>,
680}
681
682/// A user-defined operator.
683///
684/// See also the [Solidity blog post][ref] on user-defined operators.
685///
686/// [ref]: https://blog.soliditylang.org/2023/02/22/user-defined-operators/
687#[derive(Clone, Copy, Debug, PartialEq, Eq)]
688#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
689pub enum UserDefinedOperator {
690    /// `&`
691    BitwiseAnd,
692    /// `~`
693    ///
694    BitwiseNot,
695    /// `-`
696    ///
697    /// Note that this is the same as `Subtract`, and that it is currently not being parsed.
698    Negate,
699    /// `|`
700    BitwiseOr,
701    /// `^`
702    BitwiseXor,
703    /// `+`
704    Add,
705    /// `/`
706    Divide,
707    /// `%`
708    Modulo,
709    /// `*`
710    Multiply,
711    /// `-`
712    Subtract,
713    /// `==`
714    Equal,
715    /// `>`
716    More,
717    /// `>=`
718    MoreEqual,
719    /// `<`
720    Less,
721    /// `<=`
722    LessEqual,
723    /// `!=`
724    NotEqual,
725}
726
727impl UserDefinedOperator {
728    /// Returns the number of arguments needed for this operator's operation.
729    #[inline]
730    pub const fn args(&self) -> usize {
731        match self {
732            UserDefinedOperator::BitwiseNot | UserDefinedOperator::Negate => 1,
733            _ => 2,
734        }
735    }
736
737    /// Returns whether `self` is a unary operator.
738    #[inline]
739    pub const fn is_unary(&self) -> bool {
740        matches!(self, Self::BitwiseNot | Self::Negate)
741    }
742
743    /// Returns whether `self` is a binary operator.
744    #[inline]
745    pub const fn is_binary(&self) -> bool {
746        !self.is_unary()
747    }
748
749    /// Returns whether `self` is a bitwise operator.
750    #[inline]
751    pub const fn is_bitwise(&self) -> bool {
752        matches!(
753            self,
754            Self::BitwiseAnd | Self::BitwiseOr | Self::BitwiseXor | Self::BitwiseNot
755        )
756    }
757
758    /// Returns whether `self` is an arithmetic operator.
759    #[inline]
760    pub const fn is_arithmetic(&self) -> bool {
761        matches!(
762            self,
763            Self::Add | Self::Subtract | Self::Multiply | Self::Divide | Self::Modulo
764        )
765    }
766
767    /// Returns whether this is a comparison operator.
768    #[inline]
769    pub const fn is_comparison(&self) -> bool {
770        matches!(
771            self,
772            Self::Equal
773                | Self::NotEqual
774                | Self::Less
775                | Self::LessEqual
776                | Self::More
777                | Self::MoreEqual
778        )
779    }
780}
781
782/// A `using` directive.
783///
784/// Can occur within contracts and libraries and at the file level.
785///
786/// `using <list> for <type | '*'> [global];`
787#[derive(Debug, PartialEq, Eq, Clone)]
788#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
789pub struct Using {
790    /// The code location.
791    pub loc: Loc,
792    /// The list of `using` functions or a single identifier path.
793    pub list: UsingList,
794    /// The type.
795    ///
796    /// This field is `None` if an error occurred or the specified type is `*`.
797    pub ty: Option<Expression>,
798    /// The optional `global` identifier.
799    pub global: Option<Identifier>,
800}
801
802/// The contract type.
803#[derive(Debug, PartialEq, Eq, Clone)]
804#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
805pub enum ContractTy {
806    /// `abstract contract`
807    Abstract(Loc),
808
809    /// `contract`
810    Contract(Loc),
811
812    /// `interface`
813    Interface(Loc),
814
815    /// `library`
816    Library(Loc),
817}
818
819/// A function modifier invocation (see [FunctionAttribute])
820/// or a contract inheritance specifier (see [ContractDefinition]).
821///
822/// Both have the same semantics:
823///
824/// `<name>[(<args>,*)]`
825#[derive(Debug, PartialEq, Eq, Clone)]
826#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
827pub struct Base {
828    /// The code location.
829    pub loc: Loc,
830    /// The identifier path.
831    pub name: IdentifierPath,
832    /// The optional arguments.
833    pub args: Option<Vec<Expression>>,
834}
835
836/// A contract definition.
837///
838/// `<ty> <name> [<base>,*] { <parts>,* }`
839#[derive(Debug, PartialEq, Eq, Clone)]
840#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
841pub struct ContractDefinition {
842    /// The code location.
843    pub loc: Loc,
844    /// The contract type.
845    pub ty: ContractTy,
846    /// The identifier.
847    ///
848    /// This field is `None` only if an error occurred during parsing.
849    pub name: Option<Identifier>,
850    /// The list of inheritance specifiers.
851    pub base: Vec<Base>,
852    /// The list of contract parts.
853    pub parts: Vec<ContractPart>,
854}
855
856/// An event parameter.
857///
858/// `<ty> [indexed] [name]`
859#[derive(Debug, PartialEq, Eq, Clone)]
860#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
861pub struct EventParameter {
862    /// The code location.
863    pub loc: Loc,
864    /// The type.
865    pub ty: Expression,
866    /// Whether this parameter is indexed.
867    pub indexed: bool,
868    /// The optional identifier.
869    pub name: Option<Identifier>,
870}
871
872/// An event definition.
873///
874/// `event <name>(<fields>,*) [anonymous];`
875#[derive(Debug, PartialEq, Eq, Clone)]
876#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
877pub struct EventDefinition {
878    /// The code location.
879    pub loc: Loc,
880    /// The identifier.
881    ///
882    /// This field is `None` only if an error occurred during parsing.
883    pub name: Option<Identifier>,
884    /// The list of event parameters.
885    pub fields: Vec<EventParameter>,
886    /// Whether this event is anonymous.
887    pub anonymous: bool,
888}
889
890/// An error parameter.
891///
892/// `<ty> [name]`
893#[derive(Debug, PartialEq, Eq, Clone)]
894#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
895pub struct ErrorParameter {
896    /// The code location.
897    pub loc: Loc,
898    /// The type.
899    pub ty: Expression,
900    /// The optional identifier.
901    pub name: Option<Identifier>,
902}
903
904/// An error definition.
905///
906/// `error <name> (<fields>,*);`
907#[derive(Debug, PartialEq, Eq, Clone)]
908#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
909pub struct ErrorDefinition {
910    /// The code location.
911    pub loc: Loc,
912    /// The `error` keyword.
913    pub keyword: Expression,
914    /// The identifier.
915    ///
916    /// This field is `None` only if an error occurred during parsing.
917    pub name: Option<Identifier>,
918    /// The list of error parameters.
919    pub fields: Vec<ErrorParameter>,
920}
921
922/// An enum definition.
923///
924/// `enum <name> { <values>,* }`
925#[derive(Debug, PartialEq, Eq, Clone)]
926#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
927pub struct EnumDefinition {
928    /// The code location.
929    pub loc: Loc,
930    /// The identifier.
931    ///
932    /// This field is `None` only if an error occurred during parsing.
933    pub name: Option<Identifier>,
934    /// The list of values.
935    ///
936    /// This field contains `None` only if an error occurred during parsing.
937    pub values: Vec<Option<Identifier>>,
938}
939
940/// A variable attribute.
941#[derive(Debug, PartialEq, Eq, Clone)]
942#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
943#[repr(u8)] // for cmp; order of variants is important
944pub enum VariableAttribute {
945    /// The visibility.
946    ///
947    /// Only used for storage variables.
948    Visibility(Visibility),
949
950    /// `constant`
951    Constant(Loc),
952
953    /// `immutable`
954    Immutable(Loc),
955
956    /// `ovveride(<1>,*)`
957    Override(Loc, Vec<IdentifierPath>),
958
959    /// Storage type.
960    StorageType(StorageType),
961}
962
963/// Soroban storage types.
964#[derive(Debug, PartialEq, Eq, Clone)]
965#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
966#[repr(u8)] // for cmp; order of variants is important
967pub enum StorageType {
968    /// `Temporary`
969    Temporary(Option<Loc>),
970
971    /// `persistent`
972    Persistent(Option<Loc>),
973
974    /// `Instance`
975    Instance(Option<Loc>),
976}
977
978/// A variable definition.
979///
980/// `<ty> <attrs>* <name> [= <initializer>]`
981#[derive(Debug, PartialEq, Eq, Clone)]
982#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
983pub struct VariableDefinition {
984    /// The code location.
985    pub loc: Loc,
986    /// The type.
987    pub ty: Expression,
988    /// The list of variable attributes.
989    pub attrs: Vec<VariableAttribute>,
990    /// The identifier.
991    ///
992    /// This field is `None` only if an error occurred during parsing.
993    pub name: Option<Identifier>,
994    /// The optional initializer.
995    pub initializer: Option<Expression>,
996}
997
998/// A user type definition.
999///
1000/// `type <name> is <ty>;`
1001#[derive(Debug, PartialEq, Eq, Clone)]
1002#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1003pub struct TypeDefinition {
1004    /// The code location.
1005    pub loc: Loc,
1006    /// The user-defined type name.
1007    pub name: Identifier,
1008    /// The type expression.
1009    pub ty: Expression,
1010}
1011
1012/// An annotation.
1013///
1014/// `@<id>(<value>)`
1015#[derive(Debug, PartialEq, Eq, Clone)]
1016#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1017pub struct Annotation {
1018    /// The code location.
1019    pub loc: Loc,
1020    /// The identifier.
1021    pub id: Identifier,
1022    /// The value.
1023    pub value: Option<Expression>,
1024}
1025
1026/// A string literal.
1027///
1028/// `[unicode]"<string>"`
1029#[derive(Debug, PartialEq, Eq, Clone)]
1030#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1031pub struct StringLiteral {
1032    /// The code location.
1033    pub loc: Loc,
1034    /// Whether this is a unicode string.
1035    pub unicode: bool,
1036    /// The string literal.
1037    ///
1038    /// Does not contain the quotes or the `unicode` prefix.
1039    pub string: String,
1040}
1041
1042/// A hex literal.
1043///
1044/// `hex"<literal>"`
1045#[derive(Debug, PartialEq, Eq, Clone)]
1046#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1047pub struct HexLiteral {
1048    /// The code location.
1049    pub loc: Loc,
1050    /// The hex literal.
1051    ///
1052    /// Contains the `hex` prefix.
1053    pub hex: String,
1054}
1055
1056/// A named argument.
1057///
1058/// `<name>: <expr>`
1059#[derive(Debug, PartialEq, Eq, Clone)]
1060#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1061pub struct NamedArgument {
1062    /// The code location.
1063    pub loc: Loc,
1064    /// The identifier.
1065    pub name: Identifier,
1066    /// The value.
1067    pub expr: Expression,
1068}
1069
1070/// An expression.
1071#[derive(Debug, PartialEq, Eq, Clone)]
1072#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1073pub enum Expression {
1074    /// `<1>++`
1075    PostIncrement(Loc, Box<Expression>),
1076    /// `<1>--`
1077    PostDecrement(Loc, Box<Expression>),
1078    /// `new <1>`
1079    New(Loc, Box<Expression>),
1080    /// `<1>\[ [2] \]`
1081    ArraySubscript(Loc, Box<Expression>, Option<Box<Expression>>),
1082    /// `<1>\[ [2] : [3] \]`
1083    ArraySlice(
1084        Loc,
1085        Box<Expression>,
1086        Option<Box<Expression>>,
1087        Option<Box<Expression>>,
1088    ),
1089    /// `(<1>)`
1090    Parenthesis(Loc, Box<Expression>),
1091    /// `<1>.<2>`
1092    MemberAccess(Loc, Box<Expression>, Identifier),
1093    /// `<1>(<2>,*)`
1094    FunctionCall(Loc, Box<Expression>, Vec<Expression>),
1095    /// `<1><2>` where <2> is a block.
1096    FunctionCallBlock(Loc, Box<Expression>, Box<Statement>),
1097    /// `<1>({ <2>,* })`
1098    NamedFunctionCall(Loc, Box<Expression>, Vec<NamedArgument>),
1099    /// `!<1>`
1100    Not(Loc, Box<Expression>),
1101    /// `~<1>`
1102    BitwiseNot(Loc, Box<Expression>),
1103    /// `delete <1>`
1104    Delete(Loc, Box<Expression>),
1105    /// `++<1>`
1106    PreIncrement(Loc, Box<Expression>),
1107    /// `--<1>`
1108    PreDecrement(Loc, Box<Expression>),
1109    /// `+<1>`
1110    ///
1111    /// Note that this isn't actually supported by Solidity.
1112    UnaryPlus(Loc, Box<Expression>),
1113    /// `-<1>`
1114    Negate(Loc, Box<Expression>),
1115
1116    /// `<1> ** <2>`
1117    Power(Loc, Box<Expression>, Box<Expression>),
1118    /// `<1> * <2>`
1119    Multiply(Loc, Box<Expression>, Box<Expression>),
1120    /// `<1> / <2>`
1121    Divide(Loc, Box<Expression>, Box<Expression>),
1122    /// `<1> % <2>`
1123    Modulo(Loc, Box<Expression>, Box<Expression>),
1124    /// `<1> + <2>`
1125    Add(Loc, Box<Expression>, Box<Expression>),
1126    /// `<1> - <2>`
1127    Subtract(Loc, Box<Expression>, Box<Expression>),
1128    /// `<1> << <2>`
1129    ShiftLeft(Loc, Box<Expression>, Box<Expression>),
1130    /// `<1> >> <2>`
1131    ShiftRight(Loc, Box<Expression>, Box<Expression>),
1132    /// `<1> & <2>`
1133    BitwiseAnd(Loc, Box<Expression>, Box<Expression>),
1134    /// `<1> ^ <2>`
1135    BitwiseXor(Loc, Box<Expression>, Box<Expression>),
1136    /// `<1> | <2>`
1137    BitwiseOr(Loc, Box<Expression>, Box<Expression>),
1138    /// `<1> < <2>`
1139    Less(Loc, Box<Expression>, Box<Expression>),
1140    /// `<1> > <2>`
1141    More(Loc, Box<Expression>, Box<Expression>),
1142    /// `<1> <= <2>`
1143    LessEqual(Loc, Box<Expression>, Box<Expression>),
1144    /// `<1> >= <2>`
1145    MoreEqual(Loc, Box<Expression>, Box<Expression>),
1146    /// `<1> == <2>`
1147    Equal(Loc, Box<Expression>, Box<Expression>),
1148    /// `<1> != <2>`
1149    NotEqual(Loc, Box<Expression>, Box<Expression>),
1150    /// `<1> && <2>`
1151    And(Loc, Box<Expression>, Box<Expression>),
1152    /// `<1> || <2>`
1153    Or(Loc, Box<Expression>, Box<Expression>),
1154    /// `<1> ? <2> : <3>`
1155    ///
1156    /// AKA ternary operator.
1157    ConditionalOperator(Loc, Box<Expression>, Box<Expression>, Box<Expression>),
1158    /// `<1> = <2>`
1159    Assign(Loc, Box<Expression>, Box<Expression>),
1160    /// `<1> |= <2>`
1161    AssignOr(Loc, Box<Expression>, Box<Expression>),
1162    /// `<1> &= <2>`
1163    AssignAnd(Loc, Box<Expression>, Box<Expression>),
1164    /// `<1> ^= <2>`
1165    AssignXor(Loc, Box<Expression>, Box<Expression>),
1166    /// `<1> <<= <2>`
1167    AssignShiftLeft(Loc, Box<Expression>, Box<Expression>),
1168    /// `<1> >>= <2>`
1169    AssignShiftRight(Loc, Box<Expression>, Box<Expression>),
1170    /// `<1> += <2>`
1171    AssignAdd(Loc, Box<Expression>, Box<Expression>),
1172    /// `<1> -= <2>`
1173    AssignSubtract(Loc, Box<Expression>, Box<Expression>),
1174    /// `<1> *= <2>`
1175    AssignMultiply(Loc, Box<Expression>, Box<Expression>),
1176    /// `<1> /= <2>`
1177    AssignDivide(Loc, Box<Expression>, Box<Expression>),
1178    /// `<1> %= <2>`
1179    AssignModulo(Loc, Box<Expression>, Box<Expression>),
1180
1181    /// `true` or `false`
1182    BoolLiteral(Loc, bool),
1183    /// ``
1184    NumberLiteral(Loc, String, String, Option<Identifier>),
1185    /// ``
1186    RationalNumberLiteral(Loc, String, String, String, Option<Identifier>),
1187    /// ``
1188    HexNumberLiteral(Loc, String, Option<Identifier>),
1189    /// `<1>+`. See [StringLiteral].
1190    StringLiteral(Vec<StringLiteral>),
1191    /// See [Type].
1192    Type(Loc, Type),
1193    /// `<1>+`. See [HexLiteral].
1194    HexLiteral(Vec<HexLiteral>),
1195    /// `0x[a-fA-F0-9]{40}`
1196    ///
1197    /// This [should be correctly checksummed][ref], but it currently isn't being enforced in the parser.
1198    ///
1199    /// [ref]: https://docs.soliditylang.org/en/latest/types.html#address-literals
1200    AddressLiteral(Loc, String),
1201    /// Any valid [Identifier].
1202    Variable(Identifier),
1203    /// `(<1>,*)`
1204    List(Loc, ParameterList),
1205    /// `\[ <1>.* \]`
1206    ArrayLiteral(Loc, Vec<Expression>),
1207}
1208
1209/// See `Expression::components`.
1210macro_rules! expr_components {
1211    ($s:ident) => {
1212        match $s {
1213            // (Some, None)
1214            PostDecrement(_, expr) | PostIncrement(_, expr) => (Some(expr), None),
1215
1216            // (None, Some)
1217            Not(_, expr)
1218            | BitwiseNot(_, expr)
1219            | New(_, expr)
1220            | Delete(_, expr)
1221            | UnaryPlus(_, expr)
1222            | Negate(_, expr)
1223            | PreDecrement(_, expr)
1224            | Parenthesis(_, expr)
1225            | PreIncrement(_, expr) => (None, Some(expr)),
1226
1227            // (Some, Some)
1228            Power(_, left, right)
1229            | Multiply(_, left, right)
1230            | Divide(_, left, right)
1231            | Modulo(_, left, right)
1232            | Add(_, left, right)
1233            | Subtract(_, left, right)
1234            | ShiftLeft(_, left, right)
1235            | ShiftRight(_, left, right)
1236            | BitwiseAnd(_, left, right)
1237            | BitwiseXor(_, left, right)
1238            | BitwiseOr(_, left, right)
1239            | Less(_, left, right)
1240            | More(_, left, right)
1241            | LessEqual(_, left, right)
1242            | MoreEqual(_, left, right)
1243            | Equal(_, left, right)
1244            | NotEqual(_, left, right)
1245            | And(_, left, right)
1246            | Or(_, left, right)
1247            | Assign(_, left, right)
1248            | AssignOr(_, left, right)
1249            | AssignAnd(_, left, right)
1250            | AssignXor(_, left, right)
1251            | AssignShiftLeft(_, left, right)
1252            | AssignShiftRight(_, left, right)
1253            | AssignAdd(_, left, right)
1254            | AssignSubtract(_, left, right)
1255            | AssignMultiply(_, left, right)
1256            | AssignDivide(_, left, right)
1257            | AssignModulo(_, left, right) => (Some(left), Some(right)),
1258
1259            // (None, None)
1260            MemberAccess(..)
1261            | ConditionalOperator(..)
1262            | ArraySubscript(..)
1263            | ArraySlice(..)
1264            | FunctionCall(..)
1265            | FunctionCallBlock(..)
1266            | NamedFunctionCall(..)
1267            | BoolLiteral(..)
1268            | NumberLiteral(..)
1269            | RationalNumberLiteral(..)
1270            | HexNumberLiteral(..)
1271            | StringLiteral(..)
1272            | Type(..)
1273            | HexLiteral(..)
1274            | AddressLiteral(..)
1275            | Variable(..)
1276            | List(..)
1277            | ArrayLiteral(..) => (None, None),
1278        }
1279    };
1280}
1281
1282impl Expression {
1283    /// Removes one layer of parentheses.
1284    #[inline]
1285    pub fn remove_parenthesis(&self) -> &Expression {
1286        if let Expression::Parenthesis(_, expr) = self {
1287            expr
1288        } else {
1289            self
1290        }
1291    }
1292
1293    /// Strips all parentheses recursively.
1294    pub fn strip_parentheses(&self) -> &Expression {
1295        match self {
1296            Expression::Parenthesis(_, expr) => expr.strip_parentheses(),
1297            _ => self,
1298        }
1299    }
1300
1301    /// Returns shared references to the components of this expression.
1302    ///
1303    /// `(left_component, right_component)`
1304    ///
1305    /// # Examples
1306    ///
1307    /// ```
1308    /// use solang_parser::pt::{Expression, Identifier, Loc};
1309    ///
1310    /// // `a++`
1311    /// let var = Expression::Variable(Identifier::new("a"));
1312    /// let post_increment = Expression::PostIncrement(Loc::default(), Box::new(var.clone()));
1313    /// assert_eq!(post_increment.components(), (Some(&var), None));
1314    ///
1315    /// // `++a`
1316    /// let var = Expression::Variable(Identifier::new("a"));
1317    /// let pre_increment = Expression::PreIncrement(Loc::default(), Box::new(var.clone()));
1318    /// assert_eq!(pre_increment.components(), (None, Some(&var)));
1319    ///
1320    /// // `a + b`
1321    /// let var_a = Expression::Variable(Identifier::new("a"));
1322    /// let var_b = Expression::Variable(Identifier::new("b"));
1323    /// let pre_increment = Expression::Add(Loc::default(), Box::new(var_a.clone()), Box::new(var_b.clone()));
1324    /// assert_eq!(pre_increment.components(), (Some(&var_a), Some(&var_b)));
1325    /// ```
1326    #[inline]
1327    pub fn components(&self) -> (Option<&Self>, Option<&Self>) {
1328        use Expression::*;
1329        expr_components!(self)
1330    }
1331
1332    /// Returns mutable references to the components of this expression.
1333    ///
1334    /// See also [`Expression::components`].
1335    #[inline]
1336    pub fn components_mut(&mut self) -> (Option<&mut Self>, Option<&mut Self>) {
1337        use Expression::*;
1338        expr_components!(self)
1339    }
1340
1341    /// Returns whether this expression can be split across multiple lines.
1342    #[inline]
1343    pub const fn is_unsplittable(&self) -> bool {
1344        use Expression::*;
1345        matches!(
1346            self,
1347            BoolLiteral(..)
1348                | NumberLiteral(..)
1349                | RationalNumberLiteral(..)
1350                | HexNumberLiteral(..)
1351                | StringLiteral(..)
1352                | HexLiteral(..)
1353                | AddressLiteral(..)
1354                | Variable(..)
1355        )
1356    }
1357
1358    /// Returns whether this expression has spaces around it.
1359    #[inline]
1360    pub const fn has_space_around(&self) -> bool {
1361        use Expression::*;
1362        !matches!(
1363            self,
1364            PostIncrement(..)
1365                | PreIncrement(..)
1366                | PostDecrement(..)
1367                | PreDecrement(..)
1368                | Not(..)
1369                | BitwiseNot(..)
1370                | UnaryPlus(..)
1371                | Negate(..)
1372        )
1373    }
1374
1375    /// Returns if the expression is a literal
1376    pub fn is_literal(&self) -> bool {
1377        matches!(
1378            self,
1379            Expression::AddressLiteral(..)
1380                | Expression::HexLiteral(..)
1381                | Expression::BoolLiteral(..)
1382                | Expression::NumberLiteral(..)
1383                | Expression::ArrayLiteral(..)
1384                | Expression::HexNumberLiteral(..)
1385                | Expression::RationalNumberLiteral(..)
1386                | Expression::StringLiteral(..)
1387        )
1388    }
1389}
1390
1391/// A parameter.
1392///
1393/// `<ty> [storage] <name>`
1394#[derive(Debug, PartialEq, Eq, Clone)]
1395#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1396pub struct Parameter {
1397    /// The code location.
1398    pub loc: Loc,
1399    /// An optional annotation '@annotation'.
1400    pub annotation: Option<Annotation>,
1401    /// The type.
1402    pub ty: Expression,
1403    /// The optional memory location.
1404    pub storage: Option<StorageLocation>,
1405    /// The optional identifier.
1406    pub name: Option<Identifier>,
1407}
1408
1409/// Function mutability.
1410#[derive(Debug, PartialEq, Eq, Clone)]
1411#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1412pub enum Mutability {
1413    /// `pure`
1414    Pure(Loc),
1415
1416    /// `view`
1417    View(Loc),
1418
1419    /// `constant`
1420    Constant(Loc),
1421
1422    /// `payable`
1423    Payable(Loc),
1424}
1425
1426/// Function visibility.
1427///
1428/// Deprecated for [FunctionTy] other than `Function`.
1429#[derive(Debug, PartialEq, Eq, Clone)]
1430#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1431#[repr(u8)] // for cmp; order of variants is important
1432pub enum Visibility {
1433    /// `external`
1434    External(Option<Loc>),
1435
1436    /// `public`
1437    Public(Option<Loc>),
1438
1439    /// `internal`
1440    Internal(Option<Loc>),
1441
1442    /// `private`
1443    Private(Option<Loc>),
1444}
1445
1446/// A function attribute.
1447#[derive(Debug, PartialEq, Eq, Clone)]
1448#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1449#[repr(u8)] // for cmp; order of variants is important
1450pub enum FunctionAttribute {
1451    /// Visibility attribute.
1452    Visibility(Visibility),
1453
1454    /// Mutability attribute.
1455    Mutability(Mutability),
1456
1457    /// `virtual`
1458    Virtual(Loc),
1459
1460    /// `immutable`
1461    Immutable(Loc),
1462
1463    /// `override[(<identifier path>,*)]`
1464    Override(Loc, Vec<IdentifierPath>),
1465
1466    /// A modifier or constructor invocation.
1467    BaseOrModifier(Loc, Base),
1468
1469    /// An error occurred during parsing.
1470    Error(Loc),
1471}
1472
1473/// A function's type.
1474#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1475#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1476pub enum FunctionTy {
1477    /// `constructor`
1478    Constructor,
1479
1480    /// `function`
1481    Function,
1482
1483    /// `fallback`
1484    Fallback,
1485
1486    /// `receive`
1487    Receive,
1488
1489    /// `modifier`
1490    Modifier,
1491}
1492
1493/// A function definition.
1494///
1495/// `<ty> [name](<params>,*) [attributes] [returns] [body]`
1496#[derive(Debug, PartialEq, Eq, Clone)]
1497#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1498pub struct FunctionDefinition {
1499    /// The function prototype location.
1500    pub loc_prototype: Loc,
1501    /// The code location.
1502    pub loc: Loc,
1503    /// The function type.
1504    pub ty: FunctionTy,
1505    /// The optional identifier.
1506    ///
1507    /// This can be `None` for old style fallback functions.
1508    pub name: Option<Identifier>,
1509    /// The identifier's code location.
1510    pub name_loc: Loc,
1511    /// The parameter list.
1512    pub params: ParameterList,
1513    /// The function attributes.
1514    pub attributes: Vec<FunctionAttribute>,
1515    /// The `returns` keyword's location. `Some` if this was `return`, not `returns`.
1516    pub return_not_returns: Option<Loc>,
1517    /// The return parameter list.
1518    pub returns: ParameterList,
1519    /// The function body.
1520    ///
1521    /// If `None`, the declaration ended with a semicolon.
1522    pub body: Option<Statement>,
1523}
1524
1525impl FunctionDefinition {
1526    /// Returns `true` if the function has no return parameters.
1527    #[inline]
1528    pub fn is_void(&self) -> bool {
1529        self.returns.is_empty()
1530    }
1531
1532    /// Returns `true` if the function body is empty.
1533    #[inline]
1534    pub fn is_empty(&self) -> bool {
1535        self.body.as_ref().is_none_or(Statement::is_empty)
1536    }
1537
1538    /// Sorts the function attributes.
1539    #[inline]
1540    pub fn sort_attributes(&mut self) {
1541        // we don't use unstable sort since there may be more that one `BaseOrModifier` attributes
1542        // which we want to preserve the order of
1543        self.attributes.sort();
1544    }
1545}
1546
1547/// A statement.
1548#[derive(Debug, PartialEq, Eq, Clone)]
1549#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1550#[allow(clippy::large_enum_variant, clippy::type_complexity)]
1551pub enum Statement {
1552    /// `[unchecked] { <statements>* }`
1553    Block {
1554        /// The code location.
1555        loc: Loc,
1556        /// Whether this block is `unchecked`.
1557        unchecked: bool,
1558        /// The statements.
1559        statements: Vec<Statement>,
1560    },
1561    /// `assembly [dialect] [(<flags>,*)] <block>`
1562    Assembly {
1563        /// The code location.
1564        loc: Loc,
1565        /// The assembly dialect.
1566        dialect: Option<StringLiteral>,
1567        /// The assembly flags.
1568        flags: Option<Vec<StringLiteral>>,
1569        /// The assembly block.
1570        block: YulBlock,
1571    },
1572    /// `{ <1>,* }`
1573    Args(Loc, Vec<NamedArgument>),
1574    /// `if ({1}) <2> [else <3>]`
1575    ///
1576    /// Note that the `<1>` expression does not contain the parentheses.
1577    If(Loc, Expression, Box<Statement>, Option<Box<Statement>>),
1578    /// `while ({1}) <2>`
1579    ///
1580    /// Note that the `<1>` expression does not contain the parentheses.
1581    While(Loc, Expression, Box<Statement>),
1582    /// An [Expression].
1583    Expression(Loc, Expression),
1584    /// `<1> [= <2>];`
1585    VariableDefinition(Loc, VariableDeclaration, Option<Expression>),
1586    /// `for ([1]; [2]; [3]) [4]`
1587    ///
1588    /// The `[4]` block statement is `None` when the `for` statement ends with a semicolon.
1589    For(
1590        Loc,
1591        Option<Box<Statement>>,
1592        Option<Box<Expression>>,
1593        Option<Box<Expression>>,
1594        Option<Box<Statement>>,
1595    ),
1596    /// `do <1> while ({2});`
1597    ///
1598    /// Note that the `<2>` expression does not contain the parentheses.
1599    DoWhile(Loc, Box<Statement>, Expression),
1600    /// `continue;`
1601    Continue(Loc),
1602    /// `break;`
1603    Break(Loc),
1604    /// `return [1];`
1605    Return(Loc, Option<Expression>),
1606    /// `revert [1] (<2>,*);`
1607    Revert(Loc, Option<IdentifierPath>, Vec<Expression>),
1608    /// `revert [1] ({ <2>,* });`
1609    RevertNamedArgs(Loc, Option<IdentifierPath>, Vec<NamedArgument>),
1610    /// `emit <1>;`
1611    ///
1612    /// `<1>` is `FunctionCall`.
1613    Emit(Loc, Expression),
1614    /// `try <1> [returns (<2.1>,*) <2.2>] <3>*`
1615    ///
1616    /// `<1>` is either `New(FunctionCall)` or `FunctionCall`.
1617    Try(
1618        Loc,
1619        Expression,
1620        Option<(ParameterList, Box<Statement>)>,
1621        Vec<CatchClause>,
1622    ),
1623    /// An error occurred during parsing.
1624    Error(Loc),
1625}
1626
1627impl Statement {
1628    /// Returns `true` if the block statement contains no elements.
1629    #[inline]
1630    pub fn is_empty(&self) -> bool {
1631        match self {
1632            Self::Block { statements, .. } => statements.is_empty(),
1633            Self::Assembly { block, .. } => block.is_empty(),
1634            Self::Args(_, args) => args.is_empty(),
1635            _ => false,
1636        }
1637    }
1638}
1639
1640/// A catch clause. See [Statement].
1641#[derive(Debug, PartialEq, Eq, Clone)]
1642#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1643pub enum CatchClause {
1644    /// `catch [(<1>)] <2>`
1645    Simple(Loc, Option<Parameter>, Statement),
1646
1647    /// `catch <1> (<2>) <3>`
1648    Named(Loc, Identifier, Parameter, Statement),
1649}
1650
1651/// A Yul statement.
1652#[derive(Debug, PartialEq, Eq, Clone)]
1653#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1654pub enum YulStatement {
1655    /// `<1>,+ = <2>`
1656    Assign(Loc, Vec<YulExpression>, YulExpression),
1657    /// `let <1>,+ [:= <2>]`
1658    VariableDeclaration(Loc, Vec<YulTypedIdentifier>, Option<YulExpression>),
1659    /// `if <1> <2>`
1660    If(Loc, YulExpression, YulBlock),
1661    /// A [YulFor] statement.
1662    For(YulFor),
1663    /// A [YulSwitch] statement.
1664    Switch(YulSwitch),
1665    /// `leave`
1666    Leave(Loc),
1667    /// `break`
1668    Break(Loc),
1669    /// `continue`
1670    Continue(Loc),
1671    /// A [YulBlock] statement.
1672    Block(YulBlock),
1673    /// A [YulFunctionDefinition] statement.
1674    FunctionDefinition(Box<YulFunctionDefinition>),
1675    /// A [YulFunctionCall] statement.
1676    FunctionCall(Box<YulFunctionCall>),
1677    /// An error occurred during parsing.
1678    Error(Loc),
1679}
1680
1681/// A Yul switch statement.
1682///
1683/// `switch <condition> <cases>* [default <default>]`
1684///
1685/// Enforced by the parser:
1686///
1687/// - `cases` is guaranteed to be a `Vec` of `YulSwitchOptions::Case`.
1688/// - `default` is guaranteed to be `YulSwitchOptions::Default`.
1689/// - At least one of `cases` or `default` must be non-empty/`Some` respectively.
1690#[derive(Debug, PartialEq, Eq, Clone)]
1691#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1692pub struct YulSwitch {
1693    /// The code location.
1694    pub loc: Loc,
1695    /// The switch condition.
1696    pub condition: YulExpression,
1697    /// The switch cases.
1698    pub cases: Vec<YulSwitchOptions>,
1699    /// The optional default case.
1700    pub default: Option<YulSwitchOptions>,
1701}
1702
1703/// A Yul for statement.
1704///
1705/// `for <init_block> <condition> <post_block> <execution_block>`
1706#[derive(Debug, PartialEq, Eq, Clone)]
1707#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1708pub struct YulFor {
1709    /// The code location.
1710    pub loc: Loc,
1711    /// The for statement init block.
1712    pub init_block: YulBlock,
1713    /// The for statement condition.
1714    pub condition: YulExpression,
1715    /// The for statement post block.
1716    pub post_block: YulBlock,
1717    /// The for statement execution block.
1718    pub execution_block: YulBlock,
1719}
1720
1721/// A Yul block statement.
1722///
1723/// `{ <statements>* }`
1724#[derive(Debug, PartialEq, Eq, Clone)]
1725#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1726pub struct YulBlock {
1727    /// The code location.
1728    pub loc: Loc,
1729    /// The block statements.
1730    pub statements: Vec<YulStatement>,
1731}
1732
1733impl YulBlock {
1734    /// Returns `true` if the block contains no elements.
1735    #[inline]
1736    pub fn is_empty(&self) -> bool {
1737        self.statements.is_empty()
1738    }
1739}
1740
1741/// A Yul expression.
1742#[derive(Debug, PartialEq, Eq, Clone)]
1743#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1744pub enum YulExpression {
1745    /// `<1> [: <2>]`
1746    BoolLiteral(Loc, bool, Option<Identifier>),
1747    /// `<1>[e<2>] [: <2>]`
1748    NumberLiteral(Loc, String, String, Option<Identifier>),
1749    /// `<1> [: <2>]`
1750    HexNumberLiteral(Loc, String, Option<Identifier>),
1751    /// `<0> [: <1>]`
1752    HexStringLiteral(HexLiteral, Option<Identifier>),
1753    /// `<0> [: <1>]`
1754    StringLiteral(StringLiteral, Option<Identifier>),
1755    /// Any valid [Identifier].
1756    Variable(Identifier),
1757    /// [YulFunctionCall].
1758    FunctionCall(Box<YulFunctionCall>),
1759    /// `<1>.<2>`
1760    SuffixAccess(Loc, Box<YulExpression>, Identifier),
1761}
1762
1763/// A Yul typed identifier.
1764///
1765/// `<id> [: <ty>]`
1766#[derive(Debug, PartialEq, Eq, Clone)]
1767#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1768pub struct YulTypedIdentifier {
1769    /// The code location.
1770    pub loc: Loc,
1771    /// The identifier.
1772    pub id: Identifier,
1773    /// The optional type.
1774    pub ty: Option<Identifier>,
1775}
1776
1777/// A Yul function definition.
1778///
1779/// `function <name> (<params>,*) [-> (<returns>,*)] <body>`
1780#[derive(Debug, PartialEq, Eq, Clone)]
1781#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1782pub struct YulFunctionDefinition {
1783    /// The code location.
1784    pub loc: Loc,
1785    /// The identifier.
1786    pub id: Identifier,
1787    /// The parameters.
1788    pub params: Vec<YulTypedIdentifier>,
1789    /// The return parameters.
1790    pub returns: Vec<YulTypedIdentifier>,
1791    /// The function body.
1792    pub body: YulBlock,
1793}
1794
1795impl YulFunctionDefinition {
1796    /// Returns `true` if the function has no return parameters.
1797    #[inline]
1798    pub fn is_void(&self) -> bool {
1799        self.returns.is_empty()
1800    }
1801
1802    /// Returns `true` if the function body is empty.
1803    #[inline]
1804    pub fn is_empty(&self) -> bool {
1805        self.body.is_empty()
1806    }
1807}
1808
1809/// A Yul function call.
1810///
1811/// `<id>(<arguments>,*)`
1812#[derive(Debug, PartialEq, Eq, Clone)]
1813#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1814pub struct YulFunctionCall {
1815    /// The code location.
1816    pub loc: Loc,
1817    /// The identifier.
1818    pub id: Identifier,
1819    /// The function call arguments.
1820    pub arguments: Vec<YulExpression>,
1821}
1822
1823/// A Yul switch case or default statement. See [YulSwitch].
1824#[derive(Debug, PartialEq, Eq, Clone)]
1825#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
1826pub enum YulSwitchOptions {
1827    /// `case <1> <2>`
1828    Case(Loc, YulExpression, YulBlock),
1829    /// `default <1>`
1830    Default(Loc, YulBlock),
1831}