solang_parser/helpers/
loc.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use crate::lexer::LexicalError;
4use crate::pt::{self, Loc};
5use std::sync::Arc;
6use std::{borrow::Cow, rc::Rc};
7
8/// Returns the optional code location.
9pub trait OptionalCodeLocation {
10    /// Returns the optional code location of `self`.
11    fn loc_opt(&self) -> Option<Loc>;
12}
13
14impl<T: CodeLocation> OptionalCodeLocation for Option<T> {
15    fn loc_opt(&self) -> Option<Loc> {
16        self.as_ref().map(CodeLocation::loc)
17    }
18}
19
20impl OptionalCodeLocation for pt::Visibility {
21    fn loc_opt(&self) -> Option<Loc> {
22        match self {
23            Self::Internal(l, ..)
24            | Self::External(l, ..)
25            | Self::Private(l, ..)
26            | Self::Public(l, ..) => *l,
27        }
28    }
29}
30
31impl OptionalCodeLocation for pt::StorageType {
32    fn loc_opt(&self) -> Option<Loc> {
33        match self {
34            Self::Persistent(l) | Self::Temporary(l) | Self::Instance(l) => *l,
35        }
36    }
37}
38
39impl OptionalCodeLocation for pt::SourceUnit {
40    #[inline]
41    fn loc_opt(&self) -> Option<Loc> {
42        self.0.loc_opt()
43    }
44}
45
46impl<T: CodeLocation> OptionalCodeLocation for [T] {
47    // TODO: Merge first with last span?
48    fn loc_opt(&self) -> Option<Loc> {
49        self.first().map(CodeLocation::loc)
50    }
51}
52
53impl<T: CodeLocation> OptionalCodeLocation for Vec<T> {
54    fn loc_opt(&self) -> Option<Loc> {
55        (**self).loc_opt()
56    }
57}
58
59impl<T: ?Sized + OptionalCodeLocation> OptionalCodeLocation for &T {
60    fn loc_opt(&self) -> Option<Loc> {
61        (**self).loc_opt()
62    }
63}
64
65impl<T: ?Sized + OptionalCodeLocation> OptionalCodeLocation for &mut T {
66    fn loc_opt(&self) -> Option<Loc> {
67        (**self).loc_opt()
68    }
69}
70
71impl<T: ?Sized + ToOwned + OptionalCodeLocation> OptionalCodeLocation for Cow<'_, T> {
72    fn loc_opt(&self) -> Option<Loc> {
73        (**self).loc_opt()
74    }
75}
76
77impl<T: ?Sized + OptionalCodeLocation> OptionalCodeLocation for Box<T> {
78    fn loc_opt(&self) -> Option<Loc> {
79        (**self).loc_opt()
80    }
81}
82
83impl<T: ?Sized + OptionalCodeLocation> OptionalCodeLocation for Rc<T> {
84    fn loc_opt(&self) -> Option<Loc> {
85        (**self).loc_opt()
86    }
87}
88
89impl<T: ?Sized + OptionalCodeLocation> OptionalCodeLocation for Arc<T> {
90    fn loc_opt(&self) -> Option<Loc> {
91        (**self).loc_opt()
92    }
93}
94
95// would be: `impl<T: CodeLocation> OptionalCodeLocation for T { ... }`
96// but then we wouldn't have the correct implementation for `Box<T>` and the other smart pointers
97macro_rules! impl_optional_for_pt {
98    ($($t:ty),+ $(,)?) => {
99        $(
100            impl OptionalCodeLocation for $t {
101                #[inline]
102                fn loc_opt(&self) -> Option<Loc> {
103                    Some(<$t as CodeLocation>::loc(self))
104                }
105            }
106        )+
107    };
108}
109
110impl_optional_for_pt!(
111    // structs
112    pt::Annotation,
113    pt::Base,
114    pt::ContractDefinition,
115    pt::EnumDefinition,
116    pt::ErrorDefinition,
117    pt::ErrorParameter,
118    pt::EventDefinition,
119    pt::EventParameter,
120    pt::FunctionDefinition,
121    pt::HexLiteral,
122    pt::Identifier,
123    pt::IdentifierPath,
124    pt::NamedArgument,
125    pt::Parameter,
126    pt::StringLiteral,
127    pt::StructDefinition,
128    pt::TypeDefinition,
129    pt::Using,
130    pt::UsingFunction,
131    pt::VariableDeclaration,
132    pt::VariableDefinition,
133    pt::YulBlock,
134    pt::YulFor,
135    pt::YulFunctionCall,
136    pt::YulFunctionDefinition,
137    pt::YulSwitch,
138    pt::YulTypedIdentifier,
139    // enums
140    pt::CatchClause,
141    pt::Comment,
142    pt::ContractPart,
143    pt::ContractTy,
144    pt::Expression,
145    pt::FunctionAttribute,
146    pt::Import,
147    pt::Loc,
148    pt::Mutability,
149    pt::SourceUnitPart,
150    pt::Statement,
151    pt::StorageLocation,
152    pt::UsingList,
153    pt::VariableAttribute,
154    pt::YulExpression,
155    pt::YulStatement,
156    pt::YulSwitchOptions,
157    // other
158    LexicalError,
159);
160
161/// Returns the code location.
162pub trait CodeLocation {
163    /// Returns the code location of `self`.
164    fn loc(&self) -> Loc;
165}
166
167impl CodeLocation for Loc {
168    #[inline]
169    fn loc(&self) -> Loc {
170        *self
171    }
172}
173
174impl<T: ?Sized + CodeLocation> CodeLocation for &T {
175    fn loc(&self) -> Loc {
176        (**self).loc()
177    }
178}
179
180impl<T: ?Sized + CodeLocation> CodeLocation for &mut T {
181    fn loc(&self) -> Loc {
182        (**self).loc()
183    }
184}
185
186impl<T: ?Sized + ToOwned + CodeLocation> CodeLocation for Cow<'_, T> {
187    fn loc(&self) -> Loc {
188        (**self).loc()
189    }
190}
191
192impl<T: ?Sized + CodeLocation> CodeLocation for Box<T> {
193    fn loc(&self) -> Loc {
194        (**self).loc()
195    }
196}
197
198impl<T: ?Sized + CodeLocation> CodeLocation for Rc<T> {
199    fn loc(&self) -> Loc {
200        (**self).loc()
201    }
202}
203
204impl<T: ?Sized + CodeLocation> CodeLocation for Arc<T> {
205    fn loc(&self) -> Loc {
206        (**self).loc()
207    }
208}
209
210macro_rules! impl_for_structs {
211    ($($t:ty),+ $(,)?) => {
212        $(
213            impl CodeLocation for $t {
214                #[inline]
215                fn loc(&self) -> Loc {
216                    self.loc
217                }
218            }
219        )+
220    };
221}
222
223// all structs except for SourceUnit
224impl_for_structs!(
225    pt::Annotation,
226    pt::Base,
227    pt::ContractDefinition,
228    pt::EnumDefinition,
229    pt::ErrorDefinition,
230    pt::ErrorParameter,
231    pt::EventDefinition,
232    pt::EventParameter,
233    pt::FunctionDefinition,
234    pt::HexLiteral,
235    pt::Identifier,
236    pt::IdentifierPath,
237    pt::NamedArgument,
238    pt::Parameter,
239    pt::StringLiteral,
240    pt::StructDefinition,
241    pt::TypeDefinition,
242    pt::Using,
243    pt::UsingFunction,
244    pt::VariableDeclaration,
245    pt::VariableDefinition,
246    pt::YulBlock,
247    pt::YulFor,
248    pt::YulFunctionCall,
249    pt::YulFunctionDefinition,
250    pt::YulSwitch,
251    pt::YulTypedIdentifier,
252);
253
254macro_rules! impl_for_enums {
255    ($(
256        $t:ty: match $s:ident {
257            $($m:tt)*
258        }
259    )+) => {
260        $(
261            impl CodeLocation for $t {
262                fn loc(&$s) -> Loc {
263                    match *$s {
264                        $($m)*
265                    }
266                }
267            }
268        )+
269    };
270}
271
272// all enums except for Type, UserDefinedOperator and FunctionTy
273impl_for_enums! {
274    pt::CatchClause: match self {
275        Self::Simple(l, ..)
276        | Self::Named(l, ..) => l,
277    }
278
279    pt::Comment: match self {
280        Self::Line(l, ..)
281        | Self::Block(l, ..)
282        | Self::DocLine(l, ..)
283        | Self::DocBlock(l, ..) => l,
284    }
285
286    pt::ContractPart: match self {
287        Self::StructDefinition(ref l, ..) => l.loc(),
288        Self::EventDefinition(ref l, ..) => l.loc(),
289        Self::EnumDefinition(ref l, ..) => l.loc(),
290        Self::ErrorDefinition(ref l, ..) => l.loc(),
291        Self::VariableDefinition(ref l, ..) => l.loc(),
292        Self::FunctionDefinition(ref l, ..) => l.loc(),
293        Self::TypeDefinition(ref l, ..) => l.loc(),
294        Self::Annotation(ref l, ..) => l.loc(),
295        Self::Using(ref l, ..) => l.loc(),
296        Self::StraySemicolon(l, ..) => l,
297    }
298
299    pt::ContractTy: match self {
300        Self::Abstract(l, ..)
301        | Self::Contract(l, ..)
302        | Self::Library(l, ..)
303        | Self::Interface(l, ..) => l,
304    }
305
306    pt::Expression: match self {
307        // literals have at least one item
308        Self::StringLiteral(ref l, ..) => l.loc_opt().unwrap(),
309        Self::HexLiteral(ref l, ..) => l.loc_opt().unwrap(),
310        Self::Variable(ref l, ..) => l.loc(),
311        Self::PostIncrement(l, ..)
312        | Self::PostDecrement(l, ..)
313        | Self::New(l, ..)
314        | Self::Parenthesis(l, ..)
315        | Self::ArraySubscript(l, ..)
316        | Self::ArraySlice(l, ..)
317        | Self::MemberAccess(l, ..)
318        | Self::FunctionCall(l, ..)
319        | Self::FunctionCallBlock(l, ..)
320        | Self::NamedFunctionCall(l, ..)
321        | Self::Not(l, ..)
322        | Self::BitwiseNot(l, ..)
323        | Self::Delete(l, ..)
324        | Self::PreIncrement(l, ..)
325        | Self::PreDecrement(l, ..)
326        | Self::UnaryPlus(l, ..)
327        | Self::Negate(l, ..)
328        | Self::Power(l, ..)
329        | Self::Multiply(l, ..)
330        | Self::Divide(l, ..)
331        | Self::Modulo(l, ..)
332        | Self::Add(l, ..)
333        | Self::Subtract(l, ..)
334        | Self::ShiftLeft(l, ..)
335        | Self::ShiftRight(l, ..)
336        | Self::BitwiseAnd(l, ..)
337        | Self::BitwiseXor(l, ..)
338        | Self::BitwiseOr(l, ..)
339        | Self::Less(l, ..)
340        | Self::More(l, ..)
341        | Self::LessEqual(l, ..)
342        | Self::MoreEqual(l, ..)
343        | Self::Equal(l, ..)
344        | Self::NotEqual(l, ..)
345        | Self::And(l, ..)
346        | Self::Or(l, ..)
347        | Self::ConditionalOperator(l, ..)
348        | Self::Assign(l, ..)
349        | Self::AssignOr(l, ..)
350        | Self::AssignAnd(l, ..)
351        | Self::AssignXor(l, ..)
352        | Self::AssignShiftLeft(l, ..)
353        | Self::AssignShiftRight(l, ..)
354        | Self::AssignAdd(l, ..)
355        | Self::AssignSubtract(l, ..)
356        | Self::AssignMultiply(l, ..)
357        | Self::AssignDivide(l, ..)
358        | Self::AssignModulo(l, ..)
359        | Self::BoolLiteral(l, ..)
360        | Self::NumberLiteral(l, ..)
361        | Self::RationalNumberLiteral(l, ..)
362        | Self::HexNumberLiteral(l, ..)
363        | Self::ArrayLiteral(l, ..)
364        | Self::List(l, ..)
365        | Self::Type(l, ..)
366        | Self::AddressLiteral(l, ..) => l,
367    }
368
369    pt::FunctionAttribute: match self {
370        Self::Mutability(ref l) => l.loc(),
371        Self::Visibility(ref l) => l.loc_opt().unwrap_or_default(),
372        Self::Virtual(l, ..)
373        | Self::Immutable(l, ..)
374        | Self::Override(l, ..,)
375        | Self::BaseOrModifier(l, ..)
376        | Self::Error(l, ..) => l,
377    }
378
379    pt::Import: match self {
380        Self::GlobalSymbol(.., l)
381        | Self::Plain(.., l)
382        | Self::Rename(.., l) => l,
383    }
384
385    pt::Mutability: match self {
386        Self::Constant(l, ..)
387        | Self::Payable(l, ..)
388        | Self::Pure(l, ..)
389        | Self::View(l, ..) => l,
390    }
391
392    pt::SourceUnitPart: match self {
393        Self::ImportDirective(ref l, ..) => l.loc(),
394        Self::ContractDefinition(ref l, ..) => l.loc(),
395        Self::EnumDefinition(ref l, ..) => l.loc(),
396        Self::StructDefinition(ref l, ..) => l.loc(),
397        Self::EventDefinition(ref l, ..) => l.loc(),
398        Self::ErrorDefinition(ref l, ..) => l.loc(),
399        Self::FunctionDefinition(ref l, ..) => l.loc(),
400        Self::VariableDefinition(ref l, ..) => l.loc(),
401        Self::TypeDefinition(ref l, ..) => l.loc(),
402        Self::Annotation(ref l, ..) => l.loc(),
403        Self::Using(ref l, ..) => l.loc(),
404        Self::PragmaDirective(ref l, ..) => l.loc(),
405        Self::StraySemicolon(l, ..) => l,
406    }
407
408    pt::Statement: match self {
409        Self::Block { loc: l, .. }
410        | Self::Assembly { loc: l, .. }
411        | Self::Args(l, ..)
412        | Self::If(l, ..)
413        | Self::While(l, ..)
414        | Self::Expression(l, ..)
415        | Self::VariableDefinition(l, ..)
416        | Self::For(l, ..)
417        | Self::DoWhile(l, ..)
418        | Self::Continue(l, ..)
419        | Self::Break(l, ..)
420        | Self::Return(l, ..)
421        | Self::Revert(l, ..)
422        | Self::RevertNamedArgs(l, ..)
423        | Self::Emit(l, ..)
424        | Self::Try(l, ..)
425        | Self::Error(l, ..) => l,
426    }
427
428    pt::StorageLocation: match self {
429        Self::Calldata(l, ..)
430        | Self::Memory(l, ..)
431        | Self::Storage(l, ..) => l,
432    }
433
434    pt::UsingList: match self {
435        Self::Library(ref l, ..) => l.loc(),
436        Self::Functions(ref l, ..) => l.loc_opt().unwrap_or_default(),
437        Self::Error => panic!("an error occurred"),
438    }
439
440    pt::VariableAttribute: match self {
441        Self::Visibility(ref l, ..) => l.loc_opt().unwrap_or_default(),
442        Self::StorageType(ref l, ..) => l.loc_opt().unwrap_or_default(),
443        Self::Constant(l, ..)
444        | Self::Immutable(l, ..)
445        | Self::Override(l, ..) => l,
446    }
447
448    pt::YulExpression: match self {
449        Self::HexStringLiteral(ref l, ..) => l.loc(),
450        Self::StringLiteral(ref l, ..) => l.loc(),
451        Self::Variable(ref l, ..) => l.loc(),
452        Self::FunctionCall(ref l, ..) => l.loc(),
453        Self::BoolLiteral(l, ..)
454        | Self::NumberLiteral(l, ..)
455        | Self::HexNumberLiteral(l, ..)
456        | Self::SuffixAccess(l, ..) => l,
457    }
458
459    pt::YulStatement: match self {
460        Self::Block(ref l, ..) => l.loc(),
461        Self::FunctionDefinition(ref l, ..) => l.loc(),
462        Self::FunctionCall(ref l, ..) => l.loc(),
463        Self::For(ref l, ..) => l.loc(),
464        Self::Switch(ref l, ..) => l.loc(),
465        Self::Assign(l, ..)
466        | Self::VariableDeclaration(l, ..)
467        | Self::If(l, ..)
468        | Self::Leave(l, ..)
469        | Self::Break(l, ..)
470        | Self::Continue(l, ..)
471        | Self::Error(l, ..) => l,
472    }
473
474    pt::YulSwitchOptions: match self {
475        Self::Case(l, ..)
476        | Self::Default(l, ..) => l,
477    }
478
479    pt::PragmaDirective: match self {
480        Self::Identifier(l, ..)
481        | Self::StringLiteral(l, ..)
482        | Self::Version(l, ..) => l,
483    }
484
485    // other
486    LexicalError: match self {
487        Self::EndOfFileInComment(l)
488        | Self::EndOfFileInString(l)
489        | Self::EndofFileInHex(l)
490        | Self::MissingNumber(l)
491        | Self::InvalidCharacterInHexLiteral(l, _)
492        | Self::UnrecognisedToken(l, _)
493        | Self::ExpectedFrom(l, _)
494        | Self::MissingExponent(l) => l,
495    }
496}