1use std::fmt::{self, Display, Formatter, Result};
4
5#[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
15pub trait CodeLocation {
17 fn loc(&self) -> Loc;
18}
19
20pub 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 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#[derive(Debug, PartialEq, Eq, Clone)]
106pub struct IdentifierPath {
107 pub loc: Loc,
109 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 DynamicBytes,
158 Mapping {
160 loc: Loc,
162 key: Box<Expression>,
164 key_name: Option<Identifier>,
166 value: Box<Expression>,
168 value_name: Option<Identifier>,
170 },
171}
172
173#[derive(Debug, PartialEq, Eq, Clone)]
175pub enum StorageLocation {
176 Memory(Loc),
178
179 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 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 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 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#[derive(Debug, PartialEq, Eq, Clone)]
251pub enum ContractTy {
252 Contract(Loc),
254
255 Interface(Loc),
257
258 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}