ola_parser/
program.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use std::fmt::{self, Display, Formatter, Result};
4
5/// file no, start offset, end offset (in bytes)
6#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
7pub enum Loc {
8    Builtin,
9    CommandLine,
10    Implicit,
11    IRgen,
12    File(usize, usize, usize),
13}
14
15/// Structs can implement this trait to easily return their loc
16pub trait CodeLocation {
17    fn loc(&self) -> Loc;
18}
19
20/// Structs should implement this trait to return an optional location
21pub trait OptionalCodeLocation {
22    fn loc_opt(&self) -> Option<Loc>;
23}
24
25impl Loc {
26    #[must_use]
27    pub fn begin_range(&self) -> Self {
28        match self {
29            Loc::File(file_no, start, _) => Loc::File(*file_no, *start, *start),
30            loc => *loc,
31        }
32    }
33
34    #[must_use]
35    pub fn end_range(&self) -> Self {
36        match self {
37            Loc::File(file_no, _, end) => Loc::File(*file_no, *end, *end),
38            loc => *loc,
39        }
40    }
41
42    pub fn file_no(&self) -> usize {
43        match self {
44            Loc::File(file_no, _, _) => *file_no,
45            _ => unreachable!(),
46        }
47    }
48
49    /// Return the file_no if the location is in a file
50    pub fn try_file_no(&self) -> Option<usize> {
51        match self {
52            Loc::File(file_no, _, _) => Some(*file_no),
53            _ => None,
54        }
55    }
56
57    pub fn start(&self) -> usize {
58        match self {
59            Loc::File(_, start, _) => *start,
60            _ => unreachable!(),
61        }
62    }
63
64    pub fn end(&self) -> usize {
65        match self {
66            Loc::File(_, _, end) => *end,
67            _ => unreachable!(),
68        }
69    }
70
71    pub fn use_end_from(&mut self, other: &Loc) {
72        match (self, other) {
73            (Loc::File(_, _, end), Loc::File(_, _, other_end)) => {
74                *end = *other_end;
75            }
76            _ => unreachable!(),
77        }
78    }
79
80    pub fn use_start_from(&mut self, other: &Loc) {
81        match (self, other) {
82            (Loc::File(_, start, _), Loc::File(_, other_start, _)) => {
83                *start = *other_start;
84            }
85            _ => unreachable!(),
86        }
87    }
88}
89
90#[derive(Debug, PartialEq, Eq, Clone)]
91pub struct Identifier {
92    pub loc: Loc,
93    pub name: String,
94}
95
96impl Display for Identifier {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        f.write_str(&self.name)
99    }
100}
101
102/// A qualified identifier.
103///
104/// `<identifiers>.*`
105#[derive(Debug, PartialEq, Eq, Clone)]
106pub struct IdentifierPath {
107    /// The code location.
108    pub loc: Loc,
109    /// The list of identifiers.
110    pub identifiers: Vec<Identifier>,
111}
112
113#[derive(Debug, PartialEq, Eq, Clone)]
114pub struct SourceUnit(pub Vec<SourceUnitPart>);
115
116#[derive(Debug, PartialEq, Eq, Clone)]
117pub enum SourceUnitPart {
118    ContractDefinition(Box<ContractDefinition>),
119    ImportDirective(Import),
120}
121
122impl SourceUnitPart {
123    pub fn loc(&self) -> &Loc {
124        match self {
125            SourceUnitPart::ContractDefinition(def) => &def.loc,
126            SourceUnitPart::ImportDirective(import) => import.loc(),
127        }
128    }
129}
130
131#[derive(Debug, PartialEq, Eq, Clone)]
132pub enum Import {
133    Plain(StringLiteral, Loc),
134    GlobalSymbol(StringLiteral, Identifier, Loc),
135}
136
137impl Import {
138    pub fn loc(&self) -> &Loc {
139        match self {
140            Import::Plain(_, loc) => loc,
141            Import::GlobalSymbol(_, _, loc) => loc,
142        }
143    }
144}
145
146pub type ParameterList = Vec<(Loc, Option<Parameter>)>;
147
148#[derive(Debug, PartialEq, Eq, Clone)]
149pub enum Type {
150    Bool,
151    Uint(u16),
152    Address,
153    String,
154    Field,
155    Hash,
156    /// `Fields`
157    DynamicBytes,
158    /// `mapping(<key> [key_name] => <value> [value_name])`
159    Mapping {
160        /// The code location.
161        loc: Loc,
162        /// The key expression.
163        key: Box<Expression>,
164        /// The optional key identifier.
165        key_name: Option<Identifier>,
166        /// The value expression.
167        value: Box<Expression>,
168        /// The optional value identifier.
169        value_name: Option<Identifier>,
170    },
171}
172
173/// Dynamic type location.
174#[derive(Debug, PartialEq, Eq, Clone)]
175pub enum StorageLocation {
176    /// `memory`
177    Memory(Loc),
178
179    /// `storage`
180    Storage(Loc),
181}
182
183impl Display for StorageLocation {
184    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
185        f.write_str(self.as_str())
186    }
187}
188impl StorageLocation {
189    /// Returns the string representation of this type.
190    pub const fn as_str(&self) -> &'static str {
191        match self {
192            Self::Memory(_) => "memory",
193            Self::Storage(_) => "storage",
194        }
195    }
196}
197
198impl CodeLocation for StorageLocation {
199    fn loc(&self) -> Loc {
200        match self {
201            Self::Memory(loc) => *loc,
202            Self::Storage(loc) => *loc,
203        }
204    }
205}
206
207#[derive(Debug, PartialEq, Eq, Clone)]
208pub struct VariableDeclaration {
209    pub loc: Loc,
210    pub ty: Expression,
211    /// The optional memory location.
212    pub storage: Option<StorageLocation>,
213    pub name: Option<Identifier>,
214}
215
216#[derive(Debug, PartialEq, Eq, Clone)]
217#[allow(clippy::vec_box)]
218pub struct StructDefinition {
219    pub loc: Loc,
220    pub name: Option<Identifier>,
221    pub fields: Vec<VariableDeclaration>,
222}
223
224#[derive(Debug, PartialEq, Eq, Clone)]
225pub enum ContractPart {
226    StructDefinition(Box<StructDefinition>),
227    EnumDefinition(Box<EnumDefinition>),
228    VariableDefinition(Box<VariableDefinition>),
229    FunctionDefinition(Box<FunctionDefinition>),
230    TypeDefinition(Box<TypeDefinition>),
231    StraySemicolon(Loc),
232}
233
234impl ContractPart {
235    // Return the location of the part. Note that this excluded the body of the
236    // function
237    pub fn loc(&self) -> &Loc {
238        match self {
239            ContractPart::StructDefinition(def) => &def.loc,
240            ContractPart::EnumDefinition(def) => &def.loc,
241            ContractPart::VariableDefinition(def) => &def.loc,
242            ContractPart::FunctionDefinition(def) => &def.loc,
243            ContractPart::TypeDefinition(def) => &def.loc,
244            ContractPart::StraySemicolon(loc) => loc,
245        }
246    }
247}
248
249/// The contract type.
250#[derive(Debug, PartialEq, Eq, Clone)]
251pub enum ContractTy {
252    /// `contract`
253    Contract(Loc),
254
255    /// `interface`
256    Interface(Loc),
257
258    /// `library`
259    Library(Loc),
260}
261
262impl fmt::Display for ContractTy {
263    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264        match self {
265            ContractTy::Contract(_) => write!(f, "contract"),
266            ContractTy::Interface(_) => write!(f, "interface"),
267            ContractTy::Library(_) => write!(f, "library"),
268        }
269    }
270}
271
272#[derive(Debug, PartialEq, Eq, Clone)]
273pub struct ContractDefinition {
274    pub loc: Loc,
275    pub ty: ContractTy,
276    pub name: Option<Identifier>,
277    pub parts: Vec<ContractPart>,
278}
279
280#[derive(Debug, PartialEq, Eq, Clone)]
281pub struct EnumDefinition {
282    pub loc: Loc,
283    pub name: Option<Identifier>,
284    pub values: Vec<Option<Identifier>>,
285}
286
287#[derive(Debug, PartialEq, Eq, Clone)]
288pub enum VariableAttribute {
289    Constant(Loc),
290    Mutable(Loc),
291}
292
293#[derive(Debug, PartialEq, Eq, Clone)]
294pub struct VariableDefinition {
295    pub loc: Loc,
296    pub ty: Expression,
297    pub attrs: Vec<VariableAttribute>,
298    pub name: Option<Identifier>,
299    pub initializer: Option<Expression>,
300}
301
302#[derive(Debug, PartialEq, Eq, Clone)]
303pub struct TypeDefinition {
304    pub loc: Loc,
305    pub name: Identifier,
306    pub ty: Expression,
307}
308
309#[derive(Debug, PartialEq, Eq, Clone)]
310pub struct StringLiteral {
311    pub loc: Loc,
312    pub string: String,
313}
314
315#[derive(Debug, PartialEq, Eq, Clone)]
316pub struct NamedArgument {
317    pub loc: Loc,
318    pub name: Identifier,
319    pub expr: Expression,
320}
321
322#[derive(Debug, PartialEq, Eq, Clone)]
323pub enum Expression {
324    Increment(Loc, Box<Expression>),
325    Decrement(Loc, Box<Expression>),
326    New(Loc, Box<Expression>),
327    ArraySubscript(Loc, Box<Expression>, Option<Box<Expression>>),
328    ArraySlice(
329        Loc,
330        Box<Expression>,
331        Option<Box<Expression>>,
332        Option<Box<Expression>>,
333    ),
334    Parenthesis(Loc, Box<Expression>),
335    MemberAccess(Loc, Box<Expression>, Identifier),
336    FunctionCall(Loc, Box<Expression>, Vec<Expression>),
337    FunctionCallBlock(Loc, Box<Expression>, Box<Statement>),
338    NamedFunctionCall(Loc, Box<Expression>, Vec<NamedArgument>),
339    Not(Loc, Box<Expression>),
340    BitwiseNot(Loc, Box<Expression>),
341    Delete(Loc, Box<Expression>),
342    Power(Loc, Box<Expression>, Box<Expression>),
343    Multiply(Loc, Box<Expression>, Box<Expression>),
344    Divide(Loc, Box<Expression>, Box<Expression>),
345    Modulo(Loc, Box<Expression>, Box<Expression>),
346    Add(Loc, Box<Expression>, Box<Expression>),
347    Subtract(Loc, Box<Expression>, Box<Expression>),
348    ShiftLeft(Loc, Box<Expression>, Box<Expression>),
349    ShiftRight(Loc, Box<Expression>, Box<Expression>),
350    BitwiseAnd(Loc, Box<Expression>, Box<Expression>),
351    BitwiseXor(Loc, Box<Expression>, Box<Expression>),
352    BitwiseOr(Loc, Box<Expression>, Box<Expression>),
353    Less(Loc, Box<Expression>, Box<Expression>),
354    More(Loc, Box<Expression>, Box<Expression>),
355    LessEqual(Loc, Box<Expression>, Box<Expression>),
356    MoreEqual(Loc, Box<Expression>, Box<Expression>),
357    Equal(Loc, Box<Expression>, Box<Expression>),
358    NotEqual(Loc, Box<Expression>, Box<Expression>),
359    And(Loc, Box<Expression>, Box<Expression>),
360    Or(Loc, Box<Expression>, Box<Expression>),
361    ConditionalOperator(Loc, Box<Expression>, Box<Expression>, Box<Expression>),
362    Assign(Loc, Box<Expression>, Box<Expression>),
363    AssignOr(Loc, Box<Expression>, Box<Expression>),
364    AssignAnd(Loc, Box<Expression>, Box<Expression>),
365    AssignXor(Loc, Box<Expression>, Box<Expression>),
366    AssignShiftLeft(Loc, Box<Expression>, Box<Expression>),
367    AssignShiftRight(Loc, Box<Expression>, Box<Expression>),
368    AssignAdd(Loc, Box<Expression>, Box<Expression>),
369    AssignSubtract(Loc, Box<Expression>, Box<Expression>),
370    AssignMultiply(Loc, Box<Expression>, Box<Expression>),
371    AssignDivide(Loc, Box<Expression>, Box<Expression>),
372    AssignModulo(Loc, Box<Expression>, Box<Expression>),
373    BoolLiteral(Loc, bool),
374    NumberLiteral(Loc, String),
375    HexNumberLiteral(Loc, String),
376    FieldsLiteral(Loc, String),
377    StringLiteral(Vec<StringLiteral>),
378    AddressLiteral(Loc, String),
379    HashLiteral(Loc, String),
380    Type(Loc, Type),
381    Variable(Identifier),
382    List(Loc, ParameterList),
383    ArrayLiteral(Loc, Vec<Expression>),
384}
385
386impl CodeLocation for Expression {
387    fn loc(&self) -> Loc {
388        match self {
389            Expression::Increment(loc, _)
390            | Expression::Decrement(loc, _)
391            | Expression::New(loc, _)
392            | Expression::Delete(loc, _)
393            | Expression::Parenthesis(loc, _)
394            | Expression::ArraySubscript(loc, ..)
395            | Expression::ArraySlice(loc, ..)
396            | Expression::MemberAccess(loc, ..)
397            | Expression::FunctionCall(loc, ..)
398            | Expression::FunctionCallBlock(loc, ..)
399            | Expression::NamedFunctionCall(loc, ..)
400            | Expression::Not(loc, _)
401            | Expression::BitwiseNot(loc, _)
402            | Expression::Power(loc, ..)
403            | Expression::Multiply(loc, ..)
404            | Expression::Divide(loc, ..)
405            | Expression::Modulo(loc, ..)
406            | Expression::Add(loc, ..)
407            | Expression::Subtract(loc, ..)
408            | Expression::ShiftLeft(loc, ..)
409            | Expression::ShiftRight(loc, ..)
410            | Expression::BitwiseAnd(loc, ..)
411            | Expression::BitwiseXor(loc, ..)
412            | Expression::BitwiseOr(loc, ..)
413            | Expression::Less(loc, ..)
414            | Expression::More(loc, ..)
415            | Expression::LessEqual(loc, ..)
416            | Expression::MoreEqual(loc, ..)
417            | Expression::Equal(loc, ..)
418            | Expression::NotEqual(loc, ..)
419            | Expression::And(loc, ..)
420            | Expression::Or(loc, ..)
421            | Expression::ConditionalOperator(loc, ..)
422            | Expression::Assign(loc, ..)
423            | Expression::AssignOr(loc, ..)
424            | Expression::AssignAnd(loc, ..)
425            | Expression::AssignXor(loc, ..)
426            | Expression::AssignShiftLeft(loc, ..)
427            | Expression::AssignShiftRight(loc, ..)
428            | Expression::AssignAdd(loc, ..)
429            | Expression::AssignSubtract(loc, ..)
430            | Expression::AssignMultiply(loc, ..)
431            | Expression::AssignDivide(loc, ..)
432            | Expression::AssignModulo(loc, ..)
433            | Expression::BoolLiteral(loc, _)
434            | Expression::NumberLiteral(loc, ..)
435            | Expression::HexNumberLiteral(loc, _)
436            | Expression::FieldsLiteral(loc, _)
437            | Expression::ArrayLiteral(loc, _)
438            | Expression::List(loc, _)
439            | Expression::Type(loc, _)
440            | Expression::Variable(Identifier { loc, .. }) => *loc,
441            Expression::StringLiteral(v) => v[0].loc,
442            Expression::AddressLiteral(loc, _) => *loc,
443            Expression::HashLiteral(loc, _) => *loc,
444        }
445    }
446}
447
448impl Display for Expression {
449    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450        match self {
451            Expression::Variable(id) => write!(f, "{}", id.name),
452            Expression::MemberAccess(_, e, id) => write!(f, "{}.{}", e, id.name),
453            _ => unimplemented!(),
454        }
455    }
456}
457
458impl Expression {
459    #[inline]
460    pub fn remove_parenthesis(&self) -> &Expression {
461        if let Expression::Parenthesis(_, expr) = self {
462            expr
463        } else {
464            self
465        }
466    }
467}
468
469#[derive(Debug, PartialEq, Eq, Clone)]
470pub struct Parameter {
471    pub loc: Loc,
472    pub ty: Expression,
473    pub name: Option<Identifier>,
474}
475
476#[derive(Debug, PartialEq, Eq, Clone)]
477pub struct FunctionDefinition {
478    pub loc: Loc,
479    pub name: Option<Identifier>,
480    pub name_loc: Loc,
481    pub params: ParameterList,
482    pub returns: ParameterList,
483    pub body: Option<Statement>,
484}
485
486#[derive(Debug, PartialEq, Eq, Clone)]
487#[allow(clippy::large_enum_variant, clippy::type_complexity)]
488pub enum Statement {
489    Block {
490        loc: Loc,
491
492        statements: Vec<Statement>,
493    },
494    Args(Loc, Vec<NamedArgument>),
495    If(Loc, Expression, Box<Statement>, Option<Box<Statement>>),
496    While(Loc, Expression, Box<Statement>),
497    Expression(Loc, Expression),
498    VariableDefinition(Loc, VariableDeclaration, Option<Expression>),
499    For(
500        Loc,
501        Option<Box<Statement>>,
502        Option<Box<Expression>>,
503        Option<Box<Expression>>,
504        Option<Box<Statement>>,
505    ),
506    DoWhile(Loc, Box<Statement>, Expression),
507    Continue(Loc),
508    Break(Loc),
509    Error(Loc),
510    Return(Loc, Option<Expression>),
511}
512
513impl CodeLocation for Statement {
514    fn loc(&self) -> Loc {
515        match self {
516            Statement::Block { loc, .. }
517            | Statement::Args(loc, ..)
518            | Statement::If(loc, ..)
519            | Statement::While(loc, ..)
520            | Statement::Expression(loc, ..)
521            | Statement::VariableDefinition(loc, ..)
522            | Statement::For(loc, ..)
523            | Statement::Continue(loc)
524            | Statement::DoWhile(loc, ..)
525            | Statement::Break(loc)
526            | Statement::Error(loc)
527            | Statement::Return(loc, ..) => *loc,
528        }
529    }
530}