1use crate::pt::{self, StorageType};
8use std::{
9 borrow::Cow,
10 fmt::{Display, Formatter, Result, Write},
11};
12
13macro_rules! write_opt {
14 ($f:expr, $opt:expr $(,)?) => {
16 if let Some(t) = $opt {
17 Display::fmt(t, $f)?;
18 }
19 };
20
21 ($f:expr, $sep:literal, $opt:expr $(,)?) => {
23 if let Some(t) = $opt {
24 Display::fmt(&$sep, $f)?;
25 Display::fmt(t, $f)?;
26 }
27 };
28
29 ($f:expr, $opt:expr, $sep:literal $(,)?) => {
31 if let Some(t) = $opt {
32 Display::fmt(t, $f)?;
33 Display::fmt(&$sep, $f)?;
34 }
35 };
36
37 ($f:expr, $sep1:literal, $opt:expr, $sep2:literal $(,)?) => {
39 if let Some(t) = $opt {
40 Display::fmt(&$sep1, $f)?;
41 Display::fmt(t, $f)?;
42 Display::fmt(&$sep2, $f)?;
43 }
44 };
45}
46
47impl Display for pt::Annotation {
49 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
50 f.write_char('@')?;
51 self.id.fmt(f)?;
52 if let Some(value) = &self.value {
53 f.write_char('(')?;
54 value.fmt(f)?;
55 f.write_char(')')?;
56 }
57
58 Ok(())
59 }
60}
61
62impl Display for pt::Base {
63 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
64 self.name.fmt(f)?;
65 if let Some(args) = &self.args {
66 f.write_char('(')?;
67 write_separated(args, f, ", ")?;
68 f.write_char(')')?;
69 }
70 Ok(())
71 }
72}
73
74impl Display for pt::ContractDefinition {
75 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
76 self.ty.fmt(f)?;
77 f.write_char(' ')?;
78
79 write_opt!(f, &self.name, ' ');
80
81 if !self.base.is_empty() {
82 write_separated(&self.base, f, " ")?;
83 f.write_char(' ')?;
84 }
85
86 f.write_char('{')?;
87 write_separated(&self.parts, f, " ")?;
88 f.write_char('}')
89 }
90}
91
92impl Display for pt::EnumDefinition {
93 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
94 f.write_str("enum ")?;
95 write_opt!(f, &self.name, ' ');
96
97 f.write_char('{')?;
98 write_separated_iter(self.values.iter().flatten(), f, ", ")?;
99 f.write_char('}')
100 }
101}
102
103impl Display for pt::ErrorDefinition {
104 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
105 self.keyword.fmt(f)?;
106 write_opt!(f, ' ', &self.name);
107
108 f.write_char('(')?;
109 write_separated(&self.fields, f, ", ")?;
110 f.write_str(");")
111 }
112}
113
114impl Display for pt::ErrorParameter {
115 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
116 self.ty.fmt(f)?;
117 write_opt!(f, ' ', &self.name);
118 Ok(())
119 }
120}
121
122impl Display for pt::EventDefinition {
123 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
124 f.write_str("event")?;
125 write_opt!(f, ' ', &self.name);
126
127 f.write_char('(')?;
128 write_separated(&self.fields, f, ", ")?;
129 f.write_char(')')?;
130
131 if self.anonymous {
132 f.write_str(" anonymous")?;
133 }
134 f.write_char(';')
135 }
136}
137
138impl Display for pt::EventParameter {
139 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
140 self.ty.fmt(f)?;
141 if self.indexed {
142 f.write_str(" indexed")?;
143 }
144 write_opt!(f, ' ', &self.name);
145 Ok(())
146 }
147}
148
149impl Display for pt::FunctionDefinition {
150 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
151 self.ty.fmt(f)?;
152 write_opt!(f, ' ', &self.name);
153
154 f.write_char('(')?;
155 fmt_parameter_list(&self.params, f)?;
156 f.write_char(')')?;
157
158 if !self.attributes.is_empty() {
159 f.write_char(' ')?;
160 write_separated(&self.attributes, f, " ")?;
161 }
162
163 if !self.returns.is_empty() {
164 f.write_str(" returns (")?;
165 fmt_parameter_list(&self.returns, f)?;
166 f.write_char(')')?;
167 }
168
169 if let Some(body) = &self.body {
170 f.write_char(' ')?;
171 body.fmt(f)
172 } else {
173 f.write_char(';')
174 }
175 }
176}
177
178impl Display for pt::HexLiteral {
179 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
180 f.write_str(&self.hex)
181 }
182}
183
184impl Display for pt::Identifier {
185 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
186 f.write_str(&self.name)
187 }
188}
189
190impl Display for pt::IdentifierPath {
191 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
192 write_separated(&self.identifiers, f, ".")
193 }
194}
195
196impl Display for pt::NamedArgument {
197 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
198 self.name.fmt(f)?;
199 f.write_str(": ")?;
200 self.expr.fmt(f)
201 }
202}
203
204impl Display for pt::Parameter {
205 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
206 write_opt!(f, &self.annotation, ' ');
207 self.ty.fmt(f)?;
208 write_opt!(f, ' ', &self.storage);
209 write_opt!(f, ' ', &self.name);
210 Ok(())
211 }
212}
213
214impl Display for pt::SourceUnit {
215 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
216 write_separated(&self.0, f, "\n")
217 }
218}
219
220impl Display for pt::StringLiteral {
221 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
222 if self.unicode {
223 f.write_str("unicode")?;
224 }
225 f.write_char('"')?;
226 f.write_str(&self.string)?;
227 f.write_char('"')
228 }
229}
230
231impl Display for pt::StructDefinition {
232 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
233 f.write_str("struct ")?;
234 write_opt!(f, &self.name, ' ');
235
236 f.write_char('{')?;
237 write_separated(&self.fields, f, "; ")?;
238 if !self.fields.is_empty() {
239 f.write_char(';')?;
240 }
241 f.write_char('}')
242 }
243}
244
245impl Display for pt::TypeDefinition {
246 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
247 f.write_str("type ")?;
248 self.name.fmt(f)?;
249 f.write_str(" is ")?;
250 self.ty.fmt(f)?;
251 f.write_char(';')
252 }
253}
254
255impl Display for pt::Using {
256 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
257 f.write_str("using ")?;
258
259 self.list.fmt(f)?;
260
261 f.write_str(" for ")?;
262
263 match &self.ty {
264 Some(ty) => Display::fmt(ty, f),
265 None => f.write_str("*"),
266 }?;
267
268 write_opt!(f, ' ', &self.global);
269 f.write_char(';')
270 }
271}
272
273impl Display for pt::UsingFunction {
274 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
275 self.path.fmt(f)?;
276 write_opt!(f, " as ", &self.oper);
277 Ok(())
278 }
279}
280
281impl Display for pt::VariableDeclaration {
282 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
283 self.ty.fmt(f)?;
284 write_opt!(f, ' ', &self.storage);
285 write_opt!(f, ' ', &self.name);
286 Ok(())
287 }
288}
289
290impl Display for pt::VariableDefinition {
291 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
292 self.ty.fmt(f)?;
293 if !self.attrs.is_empty() {
294 f.write_char(' ')?;
295 write_separated(&self.attrs, f, " ")?;
296 }
297 write_opt!(f, ' ', &self.name);
298 write_opt!(f, " = ", &self.initializer);
299 f.write_char(';')
300 }
301}
302
303impl Display for pt::YulBlock {
304 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
305 f.write_char('{')?;
306 write_separated(&self.statements, f, " ")?;
307 f.write_char('}')
308 }
309}
310
311impl Display for pt::YulFor {
312 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
313 f.write_str("for ")?;
314 self.init_block.fmt(f)?;
315 f.write_char(' ')?;
316 self.condition.fmt(f)?;
317 f.write_char(' ')?;
318 self.post_block.fmt(f)?;
319 f.write_char(' ')?;
320 self.execution_block.fmt(f)
321 }
322}
323
324impl Display for pt::YulFunctionCall {
325 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
326 self.id.fmt(f)?;
327 f.write_char('(')?;
328 write_separated(&self.arguments, f, ", ")?;
329 f.write_char(')')
330 }
331}
332
333impl Display for pt::YulFunctionDefinition {
334 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
335 f.write_str("function ")?;
336 self.id.fmt(f)?;
337 f.write_char('(')?;
338 write_separated(&self.params, f, ", ")?;
339 f.write_str(") ")?;
340
341 if !self.returns.is_empty() {
342 f.write_str("-> (")?;
343 write_separated(&self.returns, f, ", ")?;
344 f.write_str(") ")?;
345 }
346
347 self.body.fmt(f)
348 }
349}
350
351impl Display for pt::YulSwitch {
352 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
353 f.write_str("switch ")?;
354 self.condition.fmt(f)?;
355 if !self.cases.is_empty() {
356 f.write_char(' ')?;
357 write_separated(&self.cases, f, " ")?;
358 }
359 write_opt!(f, " ", &self.default);
360 Ok(())
361 }
362}
363
364impl Display for pt::YulTypedIdentifier {
365 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
366 self.id.fmt(f)?;
367 write_opt!(f, ": ", &self.ty);
368 Ok(())
369 }
370}
371
372impl Display for pt::CatchClause {
374 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
375 match self {
376 Self::Simple(_, param, block) => {
377 f.write_str("catch ")?;
378 write_opt!(f, '(', param, ") ");
379 block.fmt(f)
380 }
381 Self::Named(_, ident, param, block) => {
382 f.write_str("catch ")?;
383 ident.fmt(f)?;
384 f.write_char('(')?;
385 param.fmt(f)?;
386 f.write_str(") ")?;
387 block.fmt(f)
388 }
389 }
390 }
391}
392
393impl Display for pt::Comment {
394 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
395 f.write_str(self.value())
396 }
397}
398
399impl Display for pt::ContractPart {
400 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
401 match self {
402 Self::StructDefinition(inner) => inner.fmt(f),
403 Self::EventDefinition(inner) => inner.fmt(f),
404 Self::EnumDefinition(inner) => inner.fmt(f),
405 Self::ErrorDefinition(inner) => inner.fmt(f),
406 Self::VariableDefinition(inner) => inner.fmt(f),
407 Self::FunctionDefinition(inner) => inner.fmt(f),
408 Self::TypeDefinition(inner) => inner.fmt(f),
409 Self::Annotation(inner) => inner.fmt(f),
410 Self::Using(inner) => inner.fmt(f),
411 Self::StraySemicolon(_) => f.write_char(';'),
412 }
413 }
414}
415
416impl Display for pt::ContractTy {
417 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
418 f.write_str(self.as_str())
419 }
420}
421impl pt::ContractTy {
422 pub const fn as_str(&self) -> &'static str {
424 match self {
425 Self::Abstract(..) => "abstract contract",
426 Self::Contract(..) => "contract",
427 Self::Interface(..) => "interface",
428 Self::Library(..) => "library",
429 }
430 }
431}
432
433impl Display for pt::Expression {
434 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
435 match self {
436 Self::New(_, expr) => {
437 f.write_str("new ")?;
438 expr.fmt(f)
439 }
440 Self::Delete(_, expr) => {
441 f.write_str("delete ")?;
442 expr.fmt(f)
443 }
444
445 Self::Type(_, ty) => ty.fmt(f),
446
447 Self::Variable(ident) => ident.fmt(f),
448
449 Self::ArrayLiteral(_, exprs) => {
450 f.write_char('[')?;
451 write_separated(exprs, f, ", ")?;
452 f.write_char(']')
453 }
454 Self::ArraySubscript(_, expr1, expr2) => {
455 expr1.fmt(f)?;
456 f.write_char('[')?;
457 write_opt!(f, expr2);
458 f.write_char(']')
459 }
460 Self::ArraySlice(_, arr, l, r) => {
461 arr.fmt(f)?;
462 f.write_char('[')?;
463 write_opt!(f, l);
464 f.write_char(':')?;
465 write_opt!(f, r);
466 f.write_char(']')
467 }
468
469 Self::MemberAccess(_, expr, ident) => {
470 expr.fmt(f)?;
471 f.write_char('.')?;
472 ident.fmt(f)
473 }
474
475 Self::Parenthesis(_, expr) => {
476 f.write_char('(')?;
477 expr.fmt(f)?;
478 f.write_char(')')
479 }
480 Self::List(_, list) => {
481 f.write_char('(')?;
482 fmt_parameter_list(list, f)?;
483 f.write_char(')')
484 }
485
486 Self::AddressLiteral(_, lit) => f.write_str(lit),
487 Self::StringLiteral(vals) => write_separated(vals, f, " "),
488 Self::HexLiteral(vals) => write_separated(vals, f, " "),
489 Self::BoolLiteral(_, bool) => {
490 let s = if *bool { "true" } else { "false" };
491 f.write_str(s)
492 }
493 Self::HexNumberLiteral(_, val, unit) => {
494 f.write_str(val)?;
497 write_opt!(f, ' ', unit);
498 Ok(())
499 }
500 Self::NumberLiteral(_, val, exp, unit) => {
501 let val = rm_underscores(val);
502 f.write_str(&val)?;
503 if !exp.is_empty() {
504 f.write_char('e')?;
505 let exp = rm_underscores(exp);
506 f.write_str(&exp)?;
507 }
508 write_opt!(f, ' ', unit);
509 Ok(())
510 }
511 Self::RationalNumberLiteral(_, val, fraction, exp, unit) => {
512 let val = rm_underscores(val);
513 f.write_str(&val)?;
514
515 let mut fraction = fraction.trim_end_matches('0');
516 if fraction.is_empty() {
517 fraction = "0"
518 }
519 f.write_char('.')?;
520 f.write_str(fraction)?;
521
522 if !exp.is_empty() {
523 f.write_char('e')?;
524 let exp = rm_underscores(exp);
525 f.write_str(&exp)?;
526 }
527 write_opt!(f, ' ', unit);
528 Ok(())
529 }
530
531 Self::FunctionCall(_, expr, exprs) => {
532 expr.fmt(f)?;
533 f.write_char('(')?;
534 write_separated(exprs, f, ", ")?;
535 f.write_char(')')
536 }
537 Self::FunctionCallBlock(_, expr, block) => {
538 expr.fmt(f)?;
539 block.fmt(f)
540 }
541 Self::NamedFunctionCall(_, expr, args) => {
542 expr.fmt(f)?;
543 f.write_str("({")?;
544 write_separated(args, f, ", ")?;
545 f.write_str("})")
546 }
547
548 Self::ConditionalOperator(_, cond, l, r) => {
549 cond.fmt(f)?;
550 f.write_str(" ? ")?;
551 l.fmt(f)?;
552 f.write_str(" : ")?;
553 r.fmt(f)
554 }
555
556 Self::PreIncrement(..)
557 | Self::PostIncrement(..)
558 | Self::PreDecrement(..)
559 | Self::PostDecrement(..)
560 | Self::Not(..)
561 | Self::BitwiseNot(..)
562 | Self::UnaryPlus(..)
563 | Self::Add(..)
564 | Self::Negate(..)
565 | Self::Subtract(..)
566 | Self::Power(..)
567 | Self::Multiply(..)
568 | Self::Divide(..)
569 | Self::Modulo(..)
570 | Self::ShiftLeft(..)
571 | Self::ShiftRight(..)
572 | Self::BitwiseAnd(..)
573 | Self::BitwiseXor(..)
574 | Self::BitwiseOr(..)
575 | Self::Less(..)
576 | Self::More(..)
577 | Self::LessEqual(..)
578 | Self::MoreEqual(..)
579 | Self::And(..)
580 | Self::Or(..)
581 | Self::Equal(..)
582 | Self::NotEqual(..)
583 | Self::Assign(..)
584 | Self::AssignOr(..)
585 | Self::AssignAnd(..)
586 | Self::AssignXor(..)
587 | Self::AssignShiftLeft(..)
588 | Self::AssignShiftRight(..)
589 | Self::AssignAdd(..)
590 | Self::AssignSubtract(..)
591 | Self::AssignMultiply(..)
592 | Self::AssignDivide(..)
593 | Self::AssignModulo(..) => {
594 let (left, right) = self.components();
595 let has_spaces = self.has_space_around();
596
597 if let Some(left) = left {
598 left.fmt(f)?;
599 if has_spaces {
600 f.write_char(' ')?;
601 }
602 }
603
604 let operator = self.operator().unwrap();
605 f.write_str(operator)?;
606
607 if let Some(right) = right {
608 if has_spaces {
609 f.write_char(' ')?;
610 }
611 right.fmt(f)?;
612 }
613
614 Ok(())
615 }
616 }
617 }
618}
619impl pt::Expression {
620 #[inline]
622 pub const fn operator(&self) -> Option<&'static str> {
623 use pt::Expression::*;
624 let operator = match self {
625 New(..) => "new",
626 Delete(..) => "delete",
627
628 PreIncrement(..) | PostIncrement(..) => "++",
629 PreDecrement(..) | PostDecrement(..) => "--",
630
631 Not(..) => "!",
632 BitwiseNot(..) => "~",
633 UnaryPlus(..) | Add(..) => "+",
634 Negate(..) | Subtract(..) => "-",
635 Power(..) => "**",
636 Multiply(..) => "*",
637 Divide(..) => "/",
638 Modulo(..) => "%",
639 ShiftLeft(..) => "<<",
640 ShiftRight(..) => ">>",
641 BitwiseAnd(..) => "&",
642 BitwiseXor(..) => "^",
643 BitwiseOr(..) => "|",
644
645 Less(..) => "<",
646 More(..) => ">",
647 LessEqual(..) => "<=",
648 MoreEqual(..) => ">=",
649 And(..) => "&&",
650 Or(..) => "||",
651 Equal(..) => "==",
652 NotEqual(..) => "!=",
653
654 Assign(..) => "=",
655 AssignOr(..) => "|=",
656 AssignAnd(..) => "&=",
657 AssignXor(..) => "^=",
658 AssignShiftLeft(..) => "<<=",
659 AssignShiftRight(..) => ">>=",
660 AssignAdd(..) => "+=",
661 AssignSubtract(..) => "-=",
662 AssignMultiply(..) => "*=",
663 AssignDivide(..) => "/=",
664 AssignModulo(..) => "%=",
665
666 MemberAccess(..)
667 | ArraySubscript(..)
668 | ArraySlice(..)
669 | FunctionCall(..)
670 | FunctionCallBlock(..)
671 | NamedFunctionCall(..)
672 | ConditionalOperator(..)
673 | BoolLiteral(..)
674 | NumberLiteral(..)
675 | RationalNumberLiteral(..)
676 | HexNumberLiteral(..)
677 | StringLiteral(..)
678 | Type(..)
679 | HexLiteral(..)
680 | AddressLiteral(..)
681 | Variable(..)
682 | List(..)
683 | ArrayLiteral(..)
684 | Parenthesis(..) => return None,
685 };
686 Some(operator)
687 }
688}
689
690impl Display for pt::FunctionAttribute {
691 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
692 match self {
693 Self::Mutability(mutability) => mutability.fmt(f),
694 Self::Visibility(visibility) => visibility.fmt(f),
695 Self::Virtual(_) => f.write_str("virtual"),
696 Self::Immutable(_) => f.write_str("immutable"),
697 Self::Override(_, idents) => {
698 f.write_str("override")?;
699 if !idents.is_empty() {
700 f.write_char('(')?;
701 write_separated(idents, f, ", ")?;
702 f.write_char(')')?;
703 }
704 Ok(())
705 }
706 Self::BaseOrModifier(_, base) => base.fmt(f),
707 Self::Error(_) => Ok(()),
708 }
709 }
710}
711
712impl Display for pt::FunctionTy {
713 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
714 f.write_str(self.as_str())
715 }
716}
717impl pt::FunctionTy {
718 pub const fn as_str(&self) -> &'static str {
720 match self {
721 Self::Constructor => "constructor",
722 Self::Function => "function",
723 Self::Fallback => "fallback",
724 Self::Receive => "receive",
725 Self::Modifier => "modifier",
726 }
727 }
728}
729
730impl Display for pt::Import {
731 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
732 match self {
733 Self::Plain(lit, _) => {
734 f.write_str("import ")?;
735 lit.fmt(f)?;
736 f.write_char(';')
737 }
738 Self::GlobalSymbol(lit, ident, _) => {
739 f.write_str("import ")?;
740 lit.fmt(f)?;
741 f.write_str(" as ")?;
742 ident.fmt(f)?;
743 f.write_char(';')
744 }
745 Self::Rename(lit, idents, _) => {
746 f.write_str("import {")?;
747
748 let mut idents = idents.iter();
750 if let Some((ident, as_ident)) = idents.next() {
751 ident.fmt(f)?;
752 write_opt!(f, " as ", as_ident);
753 for (ident, as_ident) in idents {
754 f.write_str(", ")?;
755 ident.fmt(f)?;
756 write_opt!(f, " as ", as_ident);
757 }
758 }
759 f.write_str("} from ")?;
760 lit.fmt(f)?;
761 f.write_char(';')
762 }
763 }
764 }
765}
766
767impl Display for pt::ImportPath {
768 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
769 match self {
770 Self::Filename(lit) => lit.fmt(f),
771 Self::Path(path) => path.fmt(f),
772 }
773 }
774}
775
776impl Display for pt::Mutability {
777 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
778 f.write_str(self.as_str())
779 }
780}
781impl pt::Mutability {
782 pub const fn as_str(&self) -> &'static str {
784 match self {
785 Self::Pure(_) => "pure",
786 Self::Constant(_) | Self::View(_) => "view",
787 Self::Payable(_) => "payable",
788 }
789 }
790}
791
792impl Display for pt::SourceUnitPart {
793 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
794 match self {
795 Self::ImportDirective(inner) => inner.fmt(f),
796 Self::ContractDefinition(inner) => inner.fmt(f),
797 Self::EnumDefinition(inner) => inner.fmt(f),
798 Self::StructDefinition(inner) => inner.fmt(f),
799 Self::EventDefinition(inner) => inner.fmt(f),
800 Self::ErrorDefinition(inner) => inner.fmt(f),
801 Self::FunctionDefinition(inner) => inner.fmt(f),
802 Self::VariableDefinition(inner) => inner.fmt(f),
803 Self::TypeDefinition(inner) => inner.fmt(f),
804 Self::Annotation(inner) => inner.fmt(f),
805 Self::Using(inner) => inner.fmt(f),
806 Self::PragmaDirective(inner) => inner.fmt(f),
807 Self::StraySemicolon(_) => f.write_char(';'),
808 }
809 }
810}
811
812impl Display for pt::PragmaDirective {
813 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
814 match self {
815 Self::Identifier(_, ident, val) => {
816 f.write_str("pragma")?;
817 write_opt!(f, ' ', ident);
818 write_opt!(f, ' ', val);
819 f.write_char(';')
820 }
821 Self::StringLiteral(_, ident, lit) => {
822 f.write_str("pragma ")?;
823 ident.fmt(f)?;
824 f.write_char(' ')?;
825 lit.fmt(f)?;
826 f.write_char(';')
827 }
828 Self::Version(_, ident, versions) => {
829 f.write_str("pragma ")?;
830 ident.fmt(f)?;
831 f.write_char(' ')?;
832 write_separated(versions, f, " ")?;
833 f.write_char(';')
834 }
835 }
836 }
837}
838
839impl Display for pt::VersionComparator {
840 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
841 match self {
842 Self::Plain { version, .. } => write_separated(version, f, "."),
843 Self::Operator { op, version, .. } => {
844 op.fmt(f)?;
845 write_separated(version, f, ".")
846 }
847 Self::Range { from, to, .. } => {
848 write_separated(from, f, ".")?;
849 f.write_str(" - ")?;
850 write_separated(to, f, ".")
851 }
852 Self::Or { left, right, .. } => {
853 left.fmt(f)?;
854 f.write_str(" || ")?;
855 right.fmt(f)
856 }
857 }
858 }
859}
860
861impl Display for pt::VersionOp {
862 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
863 f.write_str(self.as_str())
864 }
865}
866
867impl pt::VersionOp {
868 pub const fn as_str(&self) -> &'static str {
870 match self {
871 Self::Exact => "=",
872 Self::Greater => ">",
873 Self::GreaterEq => ">=",
874 Self::Less => "<",
875 Self::LessEq => "<=",
876 Self::Tilde => "~",
877 Self::Caret => "^",
878 Self::Wildcard => "*",
879 }
880 }
881}
882
883impl Display for pt::Statement {
884 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
885 match self {
886 Self::Block {
887 unchecked,
888 statements,
889 ..
890 } => {
891 if *unchecked {
892 f.write_str("unchecked ")?;
893 }
894
895 f.write_char('{')?;
896 write_separated(statements, f, " ")?;
897 f.write_char('}')
898 }
899 Self::Assembly {
900 dialect,
901 flags,
902 block,
903 ..
904 } => {
905 f.write_str("assembly ")?;
906 write_opt!(f, dialect, ' ');
907 if let Some(flags) = flags {
908 if !flags.is_empty() {
909 f.write_char('(')?;
910 write_separated(flags, f, ", ")?;
911 f.write_str(") ")?;
912 }
913 }
914 block.fmt(f)
915 }
916 Self::Args(_, args) => {
917 f.write_char('{')?;
918 write_separated(args, f, ", ")?;
919 f.write_char('}')
920 }
921 Self::If(_, cond, block, end_block) => {
922 f.write_str("if (")?;
923 cond.fmt(f)?;
924 f.write_str(") ")?;
925 block.fmt(f)?;
926 write_opt!(f, " else ", end_block);
927 Ok(())
928 }
929 Self::While(_, cond, block) => {
930 f.write_str("while (")?;
931 cond.fmt(f)?;
932 f.write_str(") ")?;
933 block.fmt(f)
934 }
935 Self::Expression(_, expr) => {
936 expr.fmt(f)?;
937 f.write_char(';')
938 }
939 Self::VariableDefinition(_, var, expr) => {
940 var.fmt(f)?;
941 write_opt!(f, " = ", expr);
942 f.write_char(';')
943 }
944 Self::For(_, init, cond, expr, block) => {
945 f.write_str("for (")?;
946 match init.as_deref() {
948 Some(var @ pt::Statement::VariableDefinition(..)) => var.fmt(f),
949 Some(stmt) => {
950 stmt.fmt(f)?;
951 f.write_char(';')
952 }
953 None => f.write_char(';'),
954 }?;
955 write_opt!(f, ' ', cond);
956 f.write_char(';')?;
957 write_opt!(f, ' ', expr);
958 f.write_str(") ")?;
959 if let Some(block) = block {
960 block.fmt(f)
961 } else {
962 f.write_char(';')
963 }
964 }
965 Self::DoWhile(_, block, cond) => {
966 f.write_str("do ")?;
967 block.fmt(f)?;
968 f.write_str(" while (")?;
969 cond.fmt(f)?;
970 f.write_str(");")
971 }
972 Self::Continue(_) => f.write_str("continue;"),
973 Self::Break(_) => f.write_str("break;"),
974 Self::Return(_, expr) => {
975 f.write_str("return")?;
976 write_opt!(f, ' ', expr);
977 f.write_char(';')
978 }
979 Self::Revert(_, ident, exprs) => {
980 f.write_str("revert")?;
981 write_opt!(f, ' ', ident);
982 f.write_char('(')?;
983 write_separated(exprs, f, ", ")?;
984 f.write_str(");")
985 }
986 Self::RevertNamedArgs(_, ident, args) => {
987 f.write_str("revert")?;
988 write_opt!(f, ' ', ident);
989 f.write_char('(')?;
990 if !args.is_empty() {
991 f.write_char('{')?;
992 write_separated(args, f, ", ")?;
993 f.write_char('}')?;
994 }
995 f.write_str(");")
996 }
997 Self::Emit(_, expr) => {
998 f.write_str("emit ")?;
999 expr.fmt(f)?;
1000 f.write_char(';')
1001 }
1002 Self::Try(_, expr, returns, catch) => {
1003 f.write_str("try ")?;
1004 expr.fmt(f)?;
1005
1006 if let Some((list, stmt)) = returns {
1007 f.write_str(" returns (")?;
1008 fmt_parameter_list(list, f)?;
1009 f.write_str(") ")?;
1010 stmt.fmt(f)?;
1011 }
1012
1013 if !catch.is_empty() {
1014 f.write_char(' ')?;
1015 write_separated(catch, f, " ")?;
1016 }
1017 Ok(())
1018 }
1019 Self::Error(_) => Ok(()),
1020 }
1021 }
1022}
1023
1024impl Display for pt::StorageLocation {
1025 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1026 f.write_str(self.as_str())
1027 }
1028}
1029impl pt::StorageLocation {
1030 pub const fn as_str(&self) -> &'static str {
1032 match self {
1033 Self::Memory(_) => "memory",
1034 Self::Storage(_) => "storage",
1035 Self::Calldata(_) => "calldata",
1036 }
1037 }
1038}
1039
1040impl Display for pt::Type {
1041 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1042 match self {
1043 Self::Address => f.write_str("address"),
1044 Self::AddressPayable => f.write_str("address payable"),
1045 Self::Payable => f.write_str("payable"),
1046 Self::Bool => f.write_str("bool"),
1047 Self::String => f.write_str("string"),
1048 Self::Rational => f.write_str("fixed"),
1049 Self::DynamicBytes => f.write_str("bytes"),
1050 Self::Bytes(n) => {
1051 f.write_str("bytes")?;
1052 n.fmt(f)
1053 }
1054 Self::Int(n) => {
1055 f.write_str("int")?;
1056 n.fmt(f)
1057 }
1058 Self::Uint(n) => {
1059 f.write_str("uint")?;
1060 n.fmt(f)
1061 }
1062 Self::Mapping {
1063 key,
1064 key_name,
1065 value,
1066 value_name,
1067 ..
1068 } => {
1069 f.write_str("mapping(")?;
1070
1071 key.fmt(f)?;
1072 write_opt!(f, ' ', key_name);
1073
1074 f.write_str(" => ")?;
1075
1076 value.fmt(f)?;
1077 write_opt!(f, ' ', value_name);
1078
1079 f.write_char(')')
1080 }
1081 Self::Function {
1082 params,
1083 attributes,
1084 returns,
1085 } => {
1086 f.write_str("function (")?;
1087 fmt_parameter_list(params, f)?;
1088 f.write_char(')')?;
1089
1090 if !attributes.is_empty() {
1091 f.write_char(' ')?;
1092 write_separated(attributes, f, " ")?;
1093 }
1094
1095 if let Some((returns, attrs)) = returns {
1096 if !attrs.is_empty() {
1097 f.write_char(' ')?;
1098 write_separated(attrs, f, " ")?;
1099 }
1100
1101 if !returns.is_empty() {
1102 f.write_str(" returns (")?;
1103 fmt_parameter_list(returns, f)?;
1104 f.write_char(')')?;
1105 }
1106 }
1107 Ok(())
1108 }
1109 }
1110 }
1111}
1112
1113impl Display for pt::UserDefinedOperator {
1114 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1115 f.write_str(self.as_str())
1116 }
1117}
1118
1119impl pt::UserDefinedOperator {
1120 pub const fn as_str(&self) -> &'static str {
1122 match self {
1123 Self::BitwiseAnd => "&",
1124 Self::BitwiseNot => "~",
1125 Self::Negate => "-",
1126 Self::BitwiseOr => "|",
1127 Self::BitwiseXor => "^",
1128 Self::Add => "+",
1129 Self::Divide => "/",
1130 Self::Modulo => "%",
1131 Self::Multiply => "*",
1132 Self::Subtract => "-",
1133 Self::Equal => "==",
1134 Self::More => ">",
1135 Self::MoreEqual => ">=",
1136 Self::Less => "<",
1137 Self::LessEqual => "<=",
1138 Self::NotEqual => "!=",
1139 }
1140 }
1141}
1142
1143impl Display for pt::UsingList {
1144 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1145 match self {
1146 Self::Library(ident) => ident.fmt(f),
1147 Self::Functions(list) => {
1148 f.write_char('{')?;
1149 write_separated(list, f, ", ")?;
1150 f.write_char('}')
1151 }
1152 Self::Error => Ok(()),
1153 }
1154 }
1155}
1156
1157impl Display for pt::VariableAttribute {
1158 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1159 match self {
1160 Self::Visibility(vis) => vis.fmt(f),
1161 Self::Constant(_) => f.write_str("constant"),
1162 Self::Immutable(_) => f.write_str("immutable"),
1163 Self::Override(_, idents) => {
1164 f.write_str("override")?;
1165 if !idents.is_empty() {
1166 f.write_char('(')?;
1167 write_separated(idents, f, ", ")?;
1168 f.write_char(')')?;
1169 }
1170 Ok(())
1171 }
1172 Self::StorageType(storage) => match storage {
1173 StorageType::Instance(_) => f.write_str("instance"),
1174 StorageType::Temporary(_) => f.write_str("temporary"),
1175 StorageType::Persistent(_) => f.write_str("persistent"),
1176 },
1177 }
1178 }
1179}
1180
1181impl Display for pt::Visibility {
1182 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1183 f.write_str(self.as_str())
1184 }
1185}
1186impl pt::Visibility {
1187 pub const fn as_str(&self) -> &'static str {
1189 match self {
1190 Self::Public(_) => "public",
1191 Self::Internal(_) => "internal",
1192 Self::Private(_) => "private",
1193 Self::External(_) => "external",
1194 }
1195 }
1196}
1197
1198impl Display for pt::YulExpression {
1199 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1200 match self {
1201 Self::BoolLiteral(_, value, ident) => {
1202 let value = if *value { "true" } else { "false" };
1203 f.write_str(value)?;
1204 write_opt!(f, ": ", ident);
1205 Ok(())
1206 }
1207 Self::NumberLiteral(_, value, exponent, ident) => {
1208 f.write_str(value)?;
1209 if !exponent.is_empty() {
1210 f.write_char('e')?;
1211 f.write_str(exponent)?;
1212 }
1213 write_opt!(f, ": ", ident);
1214 Ok(())
1215 }
1216 Self::HexNumberLiteral(_, value, ident) => {
1217 f.write_str(value)?;
1218 write_opt!(f, ": ", ident);
1219 Ok(())
1220 }
1221 Self::HexStringLiteral(value, ident) => {
1222 value.fmt(f)?;
1223 write_opt!(f, ": ", ident);
1224 Ok(())
1225 }
1226 Self::StringLiteral(value, ident) => {
1227 value.fmt(f)?;
1228 write_opt!(f, ": ", ident);
1229 Ok(())
1230 }
1231 Self::Variable(ident) => ident.fmt(f),
1232 Self::FunctionCall(call) => call.fmt(f),
1233 Self::SuffixAccess(_, l, r) => {
1234 l.fmt(f)?;
1235 f.write_char('.')?;
1236 r.fmt(f)
1237 }
1238 }
1239 }
1240}
1241
1242impl Display for pt::YulStatement {
1243 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1244 match self {
1245 Self::Block(inner) => inner.fmt(f),
1246 Self::FunctionDefinition(inner) => inner.fmt(f),
1247 Self::FunctionCall(inner) => inner.fmt(f),
1248 Self::For(inner) => inner.fmt(f),
1249 Self::Switch(inner) => inner.fmt(f),
1250
1251 Self::Assign(_, exprs, eq_expr) => {
1252 write_separated(exprs, f, ", ")?;
1253 f.write_str(" := ")?;
1254 eq_expr.fmt(f)
1255 }
1256 Self::VariableDeclaration(_, vars, eq_expr) => {
1257 f.write_str("let")?;
1258 if !vars.is_empty() {
1259 f.write_char(' ')?;
1260 write_separated(vars, f, ", ")?;
1261 }
1262 write_opt!(f, " := ", eq_expr);
1263 Ok(())
1264 }
1265
1266 Self::If(_, expr, block) => {
1267 f.write_str("if ")?;
1268 expr.fmt(f)?;
1269 f.write_char(' ')?;
1270 block.fmt(f)
1271 }
1272
1273 Self::Leave(_) => f.write_str("leave"),
1274 Self::Break(_) => f.write_str("break"),
1275 Self::Continue(_) => f.write_str("continue"),
1276
1277 Self::Error(_) => Ok(()),
1278 }
1279 }
1280}
1281
1282impl Display for pt::YulSwitchOptions {
1283 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1284 match self {
1285 Self::Case(_, expr, block) => {
1286 f.write_str("case ")?;
1287 expr.fmt(f)?;
1288 f.write_str(" ")?;
1289 block.fmt(f)
1290 }
1291 Self::Default(_, block) => {
1292 f.write_str("default ")?;
1293 block.fmt(f)
1294 }
1295 }
1296 }
1297}
1298
1299#[inline]
1304fn fmt_parameter_list(list: &pt::ParameterList, f: &mut Formatter<'_>) -> Result {
1305 let iter = list.iter().flat_map(|(_, param)| param);
1306 write_separated_iter(iter, f, ", ")
1307}
1308
1309#[inline]
1310fn write_separated<T: Display>(slice: &[T], f: &mut Formatter<'_>, sep: &str) -> Result {
1311 write_separated_iter(slice.iter(), f, sep)
1312}
1313
1314fn write_separated_iter<T, I>(mut iter: I, f: &mut Formatter<'_>, sep: &str) -> Result
1315where
1316 I: Iterator<Item = T>,
1317 T: Display,
1318{
1319 if let Some(first) = iter.next() {
1320 first.fmt(f)?;
1321 for item in iter {
1322 f.write_str(sep)?;
1323 item.fmt(f)?;
1324 }
1325 }
1326 Ok(())
1327}
1328
1329fn rm_underscores(s: &str) -> Cow<'_, str> {
1330 if s.is_empty() {
1331 Cow::Borrowed("0")
1332 } else if s.contains('_') {
1333 let mut s = s.to_string();
1334 s.retain(|c| c != '_');
1335 Cow::Owned(s)
1336 } else {
1337 Cow::Borrowed(s)
1338 }
1339}
1340
1341#[cfg(test)]
1342mod tests {
1343 use super::*;
1344 use crate::pt::{Annotation, Loc};
1345
1346 macro_rules! struct_tests {
1347 ($(pt::$t:ident { $( $f:ident: $e:expr ),* $(,)? } => $expected:expr),* $(,)?) => {
1348 $(
1349 assert_eq_display(
1350 pt::$t {
1351 loc: loc!(),
1352 $( $f: $e, )*
1353 },
1354 $expected,
1355 );
1356 )*
1357 };
1358 }
1359
1360 macro_rules! enum_tests {
1361 ($(
1362 $t:ty: {
1363 $($p:expr => $expected:expr,)+
1364 }
1365 )+) => {
1366 $(
1367 $(
1368 assert_eq_display($p, $expected);
1369 )+
1370 )+
1371 };
1372 }
1373
1374 macro_rules! expr {
1376 (this) => {
1377 pt::Expression::This(loc!())
1378 };
1379
1380 ($i:ident) => {
1381 pt::Expression::Variable(id(stringify!($i)))
1382 };
1383
1384 ($l:literal) => {
1385 pt::Expression::Variable(id(stringify!($l)))
1386 };
1387
1388 (++ $($t:tt)+) => {
1389 pt::Expression::PreIncrement(loc!(), Box::new(expr!($($t)+)))
1390 };
1391
1392 ($($t:tt)+ ++) => {
1393 pt::Expression::PostIncrement(loc!(), Box::new(expr!($($t)+)))
1394 };
1395 }
1396 macro_rules! yexpr {
1397 ($i:ident) => {
1398 pt::YulExpression::Variable(id(stringify!($i)))
1399 };
1400 ($l:literal) => {
1401 pt::YulExpression::Variable(id(stringify!($l)))
1402 };
1403 }
1404
1405 macro_rules! ty {
1407 (uint256) => {
1408 pt::Type::Uint(256)
1409 };
1410 (string) => {
1411 pt::Type::String
1412 };
1413 (bytes) => {
1414 pt::Type::DynamicBytes
1415 };
1416 (address) => {
1417 pt::Type::Address
1418 };
1419 }
1420 macro_rules! expr_ty {
1421 ($($t:tt)+) => {
1422 pt::Expression::Type(loc!(), ty!($($t)+))
1423 };
1424 }
1425
1426 macro_rules! lit {
1428 (unicode $($l:literal)+) => {
1430 pt::StringLiteral {
1431 loc: loc!(),
1432 unicode: true,
1433 string: concat!( $($l),+ ).to_string(),
1434 }
1435 };
1436
1437 (hex $($l:literal)+) => {
1438 pt::HexLiteral {
1439 loc: loc!(),
1440 hex: concat!( "hex\"", $($l),+ , "\"" ).to_string(),
1441 }
1442 };
1443
1444 ($($l:literal)+) => {
1445 pt::StringLiteral {
1446 loc: loc!(),
1447 unicode: false,
1448 string: concat!( $($l),+ ).to_string(),
1449 }
1450 };
1451 }
1452
1453 macro_rules! version {
1455 ($($l:literal),+) => {
1456 <[_]>::into_vec(Box::new([ $( $l.into() ),+ ]))
1457 }
1458 }
1459
1460 macro_rules! plain_version {
1461 ($($l:literal),+) => {
1462 pt::VersionComparator::Plain {
1463 loc: loc!(),
1464 version: <[_]>::into_vec(Box::new([ $( $l.into() ),+ ])),
1465 }
1466 };
1467 }
1468
1469 macro_rules! op_version {
1470 ($op:expr, $($l:literal),+) => {
1471 pt::VersionComparator::Operator {
1472 loc: loc!(),
1473 op: $op,
1474 version: <[_]>::into_vec(Box::new([ $( $l.into() ),+ ])),
1475 }
1476 };
1477 }
1478
1479 macro_rules! range_version {
1480 ($from:expr, $to:expr) => {
1481 pt::VersionComparator::Range {
1482 loc: loc!(),
1483 from: $from,
1484 to: $to,
1485 }
1486 };
1487 }
1488
1489 macro_rules! or_version {
1490 ($left:expr, $right:expr) => {
1491 pt::VersionComparator::Or {
1492 loc: loc!(),
1493 left: $left.into(),
1494 right: $right.into(),
1495 }
1496 };
1497 }
1498
1499 macro_rules! stmt {
1501 ( {} ) => {
1502 pt::Statement::Block {
1503 loc: loc!(),
1504 unchecked: false,
1505 statements: vec![],
1506 }
1507 };
1508
1509 ( unchecked { $($t:tt)* } ) => {
1510 pt::Statement::Block {
1511 loc: loc!(),
1512 unchecked: true,
1513 statements: vec![stmt!($(t)*)],
1514 }
1515 };
1516 ( { $($t:tt)* } ) => {
1517 pt::Statement::Block {
1518 loc: loc!(),
1519 unchecked: false,
1520 statements: vec![stmt!($(t)*)],
1521 }
1522 };
1523 }
1524
1525 macro_rules! idp {
1527 ($($e:expr),* $(,)?) => {
1528 pt::IdentifierPath {
1529 loc: loc!(),
1530 identifiers: vec![$(id($e)),*],
1531 }
1532 };
1533 }
1534
1535 macro_rules! loc {
1536 () => {
1537 pt::Loc::File(0, 0, 0)
1538 };
1539 }
1540
1541 macro_rules! param {
1543 ($i:ident) => {
1544 pt::Parameter {
1545 loc: loc!(),
1546 ty: expr_ty!($i),
1547 storage: None,
1548 name: None,
1549 annotation: None,
1550 }
1551 };
1552
1553 ($i:ident $n:ident) => {
1554 pt::Parameter {
1555 loc: loc!(),
1556 ty: expr_ty!($i),
1557 storage: None,
1558 name: Some(id(stringify!($n))),
1559 annotation: None,
1560 }
1561 };
1562
1563 ($i:ident $s:ident $n:ident) => {
1564 pt::Parameter {
1565 loc: loc!(),
1566 ty: expr_ty!($i),
1567 storage: Some(storage!($s)),
1568 name: Some(id(stringify!($n))),
1569 annotation: None,
1570 }
1571 };
1572 }
1573
1574 macro_rules! storage {
1575 (memory) => {
1576 pt::StorageLocation::Memory(loc!())
1577 };
1578 (storage) => {
1579 pt::StorageLocation::Storage(loc!())
1580 };
1581 (calldata) => {
1582 pt::StorageLocation::Calldata(loc!())
1583 };
1584 }
1585
1586 fn id(s: &str) -> pt::Identifier {
1588 pt::Identifier {
1589 loc: loc!(),
1590 name: s.to_string(),
1591 }
1592 }
1593
1594 macro_rules! yid {
1595 ($i:ident) => {
1596 pt::YulTypedIdentifier {
1597 loc: loc!(),
1598 id: id(stringify!($i)),
1599 ty: None,
1600 }
1601 };
1602
1603 ($i:ident : $t:ident) => {
1604 pt::YulTypedIdentifier {
1605 loc: loc!(),
1606 id: id(stringify!($i)),
1607 ty: Some(id(stringify!($t))),
1608 }
1609 };
1610 }
1611
1612 fn var(s: &str) -> Box<pt::Expression> {
1613 Box::new(pt::Expression::Variable(id(s)))
1614 }
1615
1616 fn yul_block() -> pt::YulBlock {
1617 pt::YulBlock {
1618 loc: loc!(),
1619 statements: vec![],
1620 }
1621 }
1622
1623 fn assert_eq_display<T: Display + std::fmt::Debug>(item: T, expected: &str) {
1624 let ty = std::any::type_name::<T>();
1625 let actual = item.to_string();
1626 assert_eq!(actual, expected, "\"{ty}\": {item:?}");
1627 }
1631
1632 #[test]
1633 fn display_structs_simple() {
1634 struct_tests![
1635 pt::Annotation {
1636 id: id("name"),
1637 value: Some(expr!(value)),
1638 } => "@name(value)",
1639
1640 pt::Base {
1641 name: idp!("id", "path"),
1642 args: None,
1643 } => "id.path",
1644 pt::Base {
1645 name: idp!("id", "path"),
1646 args: Some(vec![expr!(value)]),
1647 } => "id.path(value)",
1648 pt::Base {
1649 name: idp!("id", "path"),
1650 args: Some(vec![expr!(value1), expr!(value2)]),
1651 } => "id.path(value1, value2)",
1652
1653 pt::ErrorParameter {
1654 ty: expr_ty!(uint256),
1655 name: None,
1656 } => "uint256",
1657 pt::ErrorParameter {
1658 ty: expr_ty!(uint256),
1659 name: Some(id("name")),
1660 } => "uint256 name",
1661
1662 pt::EventParameter {
1663 ty: expr_ty!(uint256),
1664 indexed: false,
1665 name: None,
1666 } => "uint256",
1667 pt::EventParameter {
1668 ty: expr_ty!(uint256),
1669 indexed: true,
1670 name: None,
1671 } => "uint256 indexed",
1672 pt::EventParameter {
1673 ty: expr_ty!(uint256),
1674 indexed: false,
1675 name: Some(id("name")),
1676 } => "uint256 name",
1677 pt::EventParameter {
1678 ty: expr_ty!(uint256),
1679 indexed: true,
1680 name: Some(id("name")),
1681 } => "uint256 indexed name",
1682
1683 pt::HexLiteral {
1684 hex: "hex\"1234\"".into(),
1685 } => "hex\"1234\"",
1686 pt::HexLiteral {
1687 hex: "hex\"455318975130845\"".into(),
1688 } => "hex\"455318975130845\"",
1689
1690 pt::Identifier {
1691 name: "name".to_string(),
1692 } => "name",
1693
1694 pt::IdentifierPath {
1695 identifiers: vec![id("id")],
1696 } => "id",
1697 pt::IdentifierPath {
1698 identifiers: vec![id("id"), id("path")],
1699 } => "id.path",
1700 pt::IdentifierPath {
1701 identifiers: vec![id("long"), id("id"), id("path")],
1702 } => "long.id.path",
1703
1704 pt::NamedArgument {
1705 name: id("name"),
1706 expr: expr!(expr),
1707 } => "name: expr",
1708
1709 pt::Parameter {
1710 ty: expr_ty!(uint256),
1711 storage: None,
1712 name: None,
1713 annotation: None,
1714 } => "uint256",
1715 pt::Parameter {
1716 ty: expr_ty!(uint256),
1717 storage: None,
1718 name: Some(id("name")),
1719 annotation: None,
1720 } => "uint256 name",
1721 pt::Parameter {
1722 ty: expr_ty!(uint256),
1723 storage: Some(pt::StorageLocation::Calldata(Default::default())),
1724 name: Some(id("name")),
1725 annotation: None,
1726 } => "uint256 calldata name",
1727 pt::Parameter {
1728 ty: expr_ty!(uint256),
1729 storage: Some(pt::StorageLocation::Calldata(Default::default())),
1730 name: None,
1731 annotation: None,
1732 } => "uint256 calldata",
1733 pt::Parameter {
1734 ty: expr_ty!(bytes),
1735 storage: None,
1736 name: Some(id("my_seed")),
1737 annotation: Some(Annotation {
1738 loc: Loc::Builtin,
1739 id: id("name"),
1740 value: None,
1741 }),
1742 } => "@name bytes my_seed",
1743
1744 pt::StringLiteral {
1745 unicode: false,
1746 string: "string".into(),
1747 } => "\"string\"",
1748 pt::StringLiteral {
1749 unicode: true,
1750 string: "string".into(),
1751 } => "unicode\"string\"",
1752
1753 pt::UsingFunction {
1754 path: idp!["id", "path"],
1755 oper: None,
1756 } => "id.path",
1757 pt::UsingFunction {
1758 path: idp!["id", "path"],
1759 oper: Some(pt::UserDefinedOperator::Add),
1760 } => "id.path as +",
1761
1762 pt::VariableDeclaration {
1763 ty: expr_ty!(uint256),
1764 storage: None,
1765 name: None,
1766 } => "uint256",
1767 pt::VariableDeclaration {
1768 ty: expr_ty!(uint256),
1769 storage: None,
1770 name: Some(id("name")),
1771 } => "uint256 name",
1772 pt::VariableDeclaration {
1773 ty: expr_ty!(uint256),
1774 storage: Some(pt::StorageLocation::Calldata(Default::default())),
1775 name: Some(id("name")),
1776 } => "uint256 calldata name",
1777 pt::VariableDeclaration {
1778 ty: expr_ty!(uint256),
1779 storage: Some(pt::StorageLocation::Calldata(Default::default())),
1780 name: None,
1781 } => "uint256 calldata",
1782
1783 pt::VariableDefinition {
1784 ty: expr_ty!(uint256),
1785 attrs: vec![],
1786 name: None,
1787 initializer: None,
1788 } => "uint256;",
1789 pt::VariableDefinition {
1790 ty: expr_ty!(uint256),
1791 attrs: vec![],
1792 name: Some(id("name")),
1793 initializer: None,
1794 } => "uint256 name;",
1795 pt::VariableDefinition {
1796 ty: expr_ty!(uint256),
1797 attrs: vec![],
1798 name: Some(id("name")),
1799 initializer: Some(expr!(value)),
1800 } => "uint256 name = value;",
1801 pt::VariableDefinition {
1802 ty: expr_ty!(uint256),
1803 attrs: vec![pt::VariableAttribute::Constant(loc!())],
1804 name: Some(id("name")),
1805 initializer: Some(expr!(value)),
1806 } => "uint256 constant name = value;",
1807 pt::VariableDefinition {
1808 ty: expr_ty!(uint256),
1809 attrs: vec![
1810 pt::VariableAttribute::Visibility(pt::Visibility::Public(None)),
1811 pt::VariableAttribute::Constant(loc!())
1812 ],
1813 name: Some(id("name")),
1814 initializer: Some(expr!(value)),
1815 } => "uint256 public constant name = value;",
1816
1817 pt::YulTypedIdentifier {
1818 id: id("name"),
1819 ty: None,
1820 } => "name",
1821 pt::YulTypedIdentifier {
1822 id: id("name"),
1823 ty: Some(id("uint256")),
1824 } => "name: uint256",
1825 ];
1826 }
1827
1828 #[test]
1829 fn display_structs_complex() {
1830 struct_tests![
1831 pt::ContractDefinition {
1832 ty: pt::ContractTy::Contract(loc!()),
1833 name: Some(id("name")),
1834 base: vec![],
1835 parts: vec![],
1836 } => "contract name {}",
1837 pt::ContractDefinition {
1838 ty: pt::ContractTy::Contract(loc!()),
1839 name: Some(id("name")),
1840 base: vec![pt::Base {
1841 loc: loc!(),
1842 name: idp!("base"),
1843 args: None
1844 }],
1845 parts: vec![],
1846 } => "contract name base {}",
1847 pt::ContractDefinition {
1848 ty: pt::ContractTy::Contract(loc!()),
1849 name: Some(id("name")),
1850 base: vec![pt::Base {
1851 loc: loc!(),
1852 name: idp!("base"),
1853 args: Some(vec![])
1854 }],
1855 parts: vec![],
1856 } => "contract name base() {}",
1857 pt::ContractDefinition {
1858 ty: pt::ContractTy::Contract(loc!()),
1859 name: Some(id("name")),
1860 base: vec![pt::Base {
1861 loc: loc!(),
1862 name: idp!("base"),
1863 args: Some(vec![expr!(expr)])
1864 }],
1865 parts: vec![],
1866 } => "contract name base(expr) {}",
1867 pt::ContractDefinition {
1868 ty: pt::ContractTy::Contract(loc!()),
1869 name: Some(id("name")),
1870 base: vec![
1871 pt::Base {
1872 loc: loc!(),
1873 name: idp!("base1"),
1874 args: None
1875 },
1876 pt::Base {
1877 loc: loc!(),
1878 name: idp!("base2"),
1879 args: None
1880 },
1881 ],
1882 parts: vec![],
1883 } => "contract name base1 base2 {}",
1884
1885 pt::EnumDefinition {
1886 name: Some(id("name")),
1887 values: vec![]
1888 } => "enum name {}",
1889 pt::EnumDefinition {
1890 name: Some(id("name")),
1891 values: vec![Some(id("variant"))]
1892 } => "enum name {variant}",
1893 pt::EnumDefinition {
1894 name: Some(id("name")),
1895 values: vec![
1896 Some(id("variant1")),
1897 Some(id("variant2")),
1898 ]
1899 } => "enum name {variant1, variant2}",
1900
1901 pt::ErrorDefinition {
1902 keyword: expr!(error),
1903 name: Some(id("name")),
1904 fields: vec![],
1905 } => "error name();",
1906 pt::ErrorDefinition {
1907 keyword: expr!(error),
1908 name: Some(id("name")),
1909 fields: vec![pt::ErrorParameter {
1910 loc: loc!(),
1911 ty: expr_ty!(uint256),
1912 name: None,
1913 }],
1914 } => "error name(uint256);",
1915
1916 pt::EventDefinition {
1917 name: Some(id("name")),
1918 fields: vec![],
1919 anonymous: false,
1920 } => "event name();",
1921 pt::EventDefinition {
1922 name: Some(id("name")),
1923 fields: vec![pt::EventParameter {
1924 loc: loc!(),
1925 ty: expr_ty!(uint256),
1926 indexed: false,
1927 name: None,
1928 }],
1929 anonymous: false,
1930 } => "event name(uint256);",
1931 pt::EventDefinition {
1932 name: Some(id("name")),
1933 fields: vec![pt::EventParameter {
1934 loc: loc!(),
1935 ty: expr_ty!(uint256),
1936 indexed: true,
1937 name: None,
1938 }],
1939 anonymous: false,
1940 } => "event name(uint256 indexed);",
1941 pt::EventDefinition {
1942 name: Some(id("name")),
1943 fields: vec![],
1944 anonymous: true,
1945 } => "event name() anonymous;",
1946
1947 pt::FunctionDefinition {
1948 loc_prototype: loc!(),
1949 ty: pt::FunctionTy::Function,
1950 name: Some(id("name")),
1951 name_loc: loc!(),
1952 params: vec![],
1953 attributes: vec![],
1954 return_not_returns: None,
1955 returns: vec![],
1956 body: None,
1957 } => "function name();",
1958 pt::FunctionDefinition {
1959 loc_prototype: loc!(),
1960 ty: pt::FunctionTy::Function,
1961 name: Some(id("name")),
1962 name_loc: loc!(),
1963 params: vec![],
1964 attributes: vec![],
1965 return_not_returns: None,
1966 returns: vec![],
1967 body: Some(stmt!({})),
1968 } => "function name() {}",
1969 pt::FunctionDefinition {
1970 loc_prototype: loc!(),
1971 ty: pt::FunctionTy::Function,
1972 name: Some(id("name")),
1973 name_loc: loc!(),
1974 params: vec![],
1975 attributes: vec![],
1976 return_not_returns: None,
1977 returns: vec![(loc!(), Some(param!(uint256)))],
1978 body: Some(stmt!({})),
1979 } => "function name() returns (uint256) {}",
1980 pt::FunctionDefinition {
1981 loc_prototype: loc!(),
1982 ty: pt::FunctionTy::Function,
1983 name: Some(id("name")),
1984 name_loc: loc!(),
1985 params: vec![],
1986 attributes: vec![pt::FunctionAttribute::Virtual(loc!())],
1987 return_not_returns: None,
1988 returns: vec![(loc!(), Some(param!(uint256)))],
1989 body: Some(stmt!({})),
1990 } => "function name() virtual returns (uint256) {}",
1991
1992 pt::StructDefinition {
1993 name: Some(id("name")),
1994 fields: vec![],
1995 } => "struct name {}",
1996 pt::StructDefinition {
1997 name: Some(id("name")),
1998 fields: vec![pt::VariableDeclaration {
1999 loc: loc!(),
2000 ty: expr_ty!(uint256),
2001 storage: None,
2002 name: Some(id("a")),
2003 }],
2004 } => "struct name {uint256 a;}",
2005 pt::StructDefinition {
2006 name: Some(id("name")),
2007 fields: vec![
2008 pt::VariableDeclaration {
2009 loc: loc!(),
2010 ty: expr_ty!(uint256),
2011 storage: None,
2012 name: Some(id("a")),
2013 },
2014 pt::VariableDeclaration {
2015 loc: loc!(),
2016 ty: expr_ty!(uint256),
2017 storage: None,
2018 name: Some(id("b")),
2019 }
2020 ],
2021 } => "struct name {uint256 a; uint256 b;}",
2022
2023 pt::TypeDefinition {
2024 name: id("MyType"),
2025 ty: expr_ty!(uint256),
2026 } => "type MyType is uint256;",
2027
2028 pt::Using {
2029 list: pt::UsingList::Library(idp!["id", "path"]),
2030 ty: None,
2031 global: None,
2032 } => "using id.path for *;",
2033 pt::Using {
2034 list: pt::UsingList::Library(idp!["id", "path"]),
2035 ty: Some(expr_ty!(uint256)),
2036 global: None,
2037 } => "using id.path for uint256;",
2038 pt::Using {
2039 list: pt::UsingList::Library(idp!["id", "path"]),
2040 ty: Some(expr_ty!(uint256)),
2041 global: Some(id("global")),
2042 } => "using id.path for uint256 global;",
2043 pt::Using {
2044 list: pt::UsingList::Functions(vec![]),
2045 ty: None,
2046 global: None,
2047 } => "using {} for *;",
2048 pt::Using {
2049 list: pt::UsingList::Functions(vec![
2050 pt::UsingFunction {
2051 loc: loc!(),
2052 path: idp!("id", "path"),
2053 oper: None,
2054 }
2055 ]),
2056 ty: None,
2057 global: None,
2058 } => "using {id.path} for *;",
2059 pt::Using {
2060 list: pt::UsingList::Functions(vec![
2061 pt::UsingFunction {
2062 loc: loc!(),
2063 path: idp!("id", "path"),
2064 oper: Some(pt::UserDefinedOperator::Add),
2065 }
2066 ]),
2067 ty: Some(expr_ty!(uint256)),
2068 global: None,
2069 } => "using {id.path as +} for uint256;",
2070 pt::Using {
2071 list: pt::UsingList::Functions(vec![
2072 pt::UsingFunction {
2073 loc: loc!(),
2074 path: idp!("id", "path1"),
2075 oper: None,
2076 },
2077 pt::UsingFunction {
2078 loc: loc!(),
2079 path: idp!("id", "path2"),
2080 oper: None,
2081 }
2082 ]),
2083 ty: Some(expr_ty!(uint256)),
2084 global: Some(id("global")),
2085 } => "using {id.path1, id.path2} for uint256 global;",
2086
2087 pt::YulBlock {
2088 statements: vec![]
2089 } => "{}",
2090
2091 pt::YulFor {
2092 init_block: yul_block(),
2093 condition: yexpr!(cond),
2094 post_block: yul_block(),
2095 execution_block: yul_block(),
2096 } => "for {} cond {} {}",
2097
2098 pt::YulFunctionCall {
2099 id: id("name"),
2100 arguments: vec![],
2101 } => "name()",
2102 pt::YulFunctionCall {
2103 id: id("name"),
2104 arguments: vec![yexpr!(arg)],
2105 } => "name(arg)",
2106 pt::YulFunctionCall {
2107 id: id("name"),
2108 arguments: vec![yexpr!(arg1), yexpr!(arg2)],
2109 } => "name(arg1, arg2)",
2110
2111 pt::YulFunctionDefinition {
2112 id: id("name"),
2113 params: vec![],
2114 returns: vec![],
2115 body: yul_block(),
2116 } => "function name() {}",
2117 pt::YulFunctionDefinition {
2118 id: id("name"),
2119 params: vec![yid!(param1: a), yid!(param2: b)],
2120 returns: vec![],
2121 body: yul_block(),
2122 } => "function name(param1: a, param2: b) {}",
2123 pt::YulFunctionDefinition {
2124 id: id("name"),
2125 params: vec![yid!(param1: a), yid!(param2: b)],
2126 returns: vec![yid!(ret1: c), yid!(ret2: d)],
2127 body: yul_block(),
2128 } => "function name(param1: a, param2: b) -> (ret1: c, ret2: d) {}",
2129
2130 pt::YulSwitch {
2131 condition: yexpr!(cond),
2132 cases: vec![pt::YulSwitchOptions::Case(loc!(), yexpr!(expr), yul_block())],
2133 default: None,
2134 } => "switch cond case expr {}",
2135 pt::YulSwitch {
2136 condition: yexpr!(cond),
2137 cases: vec![
2138 pt::YulSwitchOptions::Case(loc!(), yexpr!(0), yul_block()),
2139 pt::YulSwitchOptions::Case(loc!(), yexpr!(1), yul_block()),
2140 ],
2141 default: None,
2142 } => "switch cond case 0 {} case 1 {}",
2143 pt::YulSwitch {
2144 condition: yexpr!(cond),
2145 cases: vec![pt::YulSwitchOptions::Case(loc!(), yexpr!(0), yul_block())],
2146 default: Some(pt::YulSwitchOptions::Default(loc!(), yul_block())),
2147 } => "switch cond case 0 {} default {}",
2148 ];
2149 }
2150
2151 #[test]
2152 fn display_enums() {
2153 enum_tests![
2154 pt::CatchClause: {
2156 pt::CatchClause::Named(loc!(), id("Error"), param!(string memory reason), stmt!({}))
2157 => "catch Error(string memory reason) {}",
2158 pt::CatchClause::Named(loc!(), id("Panic"), param!(uint256 errorCode), stmt!({}))
2159 => "catch Panic(uint256 errorCode) {}",
2160
2161 pt::CatchClause::Simple(loc!(), None, stmt!({})) => "catch {}",
2162 pt::CatchClause::Simple(loc!(), Some(param!(uint256)), stmt!({}))
2163 => "catch (uint256) {}",
2164 pt::CatchClause::Simple(loc!(), Some(param!(bytes memory data)), stmt!({}))
2165 => "catch (bytes memory data) {}",
2166 }
2167
2168 pt::Comment: {
2169 pt::Comment::Line(loc!(), "// line".into()) => "// line",
2170 pt::Comment::Block(loc!(), "/* \nblock\n*/".into()) => "/* \nblock\n*/",
2171 pt::Comment::DocLine(loc!(), "/// doc line".into()) => "/// doc line",
2172 pt::Comment::DocBlock(loc!(), "/**\n * doc block\n */".into()) => "/**\n * doc block\n */",
2173 }
2174
2175 pt::ContractPart: {
2177 pt::ContractPart::StraySemicolon(loc!()) => ";",
2178 }
2179
2180 pt::ContractTy: {
2181 pt::ContractTy::Abstract(loc!()) => "abstract contract",
2182 pt::ContractTy::Contract(loc!()) => "contract",
2183 pt::ContractTy::Interface(loc!()) => "interface",
2184 pt::ContractTy::Library(loc!()) => "library",
2185 }
2186
2187 pt::Expression: {
2188 pt::Expression::New(loc!(), Box::new(expr_ty!(uint256))) => "new uint256",
2189 pt::Expression::Delete(loc!(), Box::new(expr_ty!(uint256))) => "delete uint256",
2190
2191 pt::Expression::Type(loc!(), ty!(uint256)) => "uint256",
2192 pt::Expression::Variable(id("myVar")) => "myVar",
2193
2194 pt::Expression::ArrayLiteral(loc!(), vec![expr!(1), expr!(2)]) => "[1, 2]",
2195
2196 pt::Expression::ArraySubscript(loc!(), Box::new(expr!(arr)), None) => "arr[]",
2197 pt::Expression::ArraySubscript(loc!(), Box::new(expr!(arr)), Some(Box::new(expr!(0)))) => "arr[0]",
2198 pt::Expression::ArraySlice(loc!(), Box::new(expr!(arr)), None, None) => "arr[:]",
2199 pt::Expression::ArraySlice(loc!(), Box::new(expr!(arr)), Some(Box::new(expr!(left))), None)
2200 => "arr[left:]",
2201 pt::Expression::ArraySlice(loc!(), Box::new(expr!(arr)), None, Some(Box::new(expr!(right))))
2202 => "arr[:right]",
2203 pt::Expression::ArraySlice(loc!(), Box::new(expr!(arr)), Some(Box::new(expr!(left))), Some(Box::new(expr!(right))))
2204 => "arr[left:right]",
2205
2206 pt::Expression::MemberAccess(loc!(), Box::new(expr!(struct)), id("access")) => "struct.access",
2207
2208 pt::Expression::Parenthesis(loc!(), Box::new(expr!(var))) => "(var)",
2209 pt::Expression::List(loc!(), vec![]) => "()",
2210 pt::Expression::List(loc!(), vec![(loc!(), Some(param!(address)))])
2211 => "(address)",
2212 pt::Expression::List(loc!(), vec![(loc!(), Some(param!(address))), (loc!(), Some(param!(uint256)))])
2213 => "(address, uint256)",
2214
2215 pt::Expression::AddressLiteral(loc!(), "0x1234".into()) => "0x1234",
2216 pt::Expression::StringLiteral(vec![lit!(unicode "¹²³")]) => "unicode\"¹²³\"",
2217 pt::Expression::HexLiteral(vec![lit!(hex "00112233")]) => "hex\"00112233\"",
2218 pt::Expression::BoolLiteral(loc!(), true) => "true",
2219 pt::Expression::BoolLiteral(loc!(), false) => "false",
2220
2221 pt::Expression::HexNumberLiteral(loc!(), "0x1234".into(), None) => "0x1234",
2222 pt::Expression::HexNumberLiteral(loc!(), "0x1234".into(), Some(id("gwei"))) => "0x1234 gwei",
2223 pt::Expression::NumberLiteral(loc!(), "_123_4_".into(), "".into(), None)
2224 => "1234",
2225 pt::Expression::NumberLiteral(loc!(), "_1_234_".into(), "_2".into(), None)
2226 => "1234e2",
2227 pt::Expression::NumberLiteral(loc!(), "_1_23_4".into(), "".into(), Some(id("gwei")))
2228 => "1234 gwei",
2229 pt::Expression::NumberLiteral(loc!(), "1_23_4_".into(), "2_".into(), Some(id("gwei")))
2230 => "1234e2 gwei",
2231 pt::Expression::RationalNumberLiteral(loc!(), "1_23_4_".into(), "".into(), "".into(), None)
2232 => "1234.0",
2233 pt::Expression::RationalNumberLiteral(loc!(), "_1_23_4".into(), "0".into(), "_2".into(), None)
2234 => "1234.0e2",
2235 pt::Expression::RationalNumberLiteral(loc!(), "_1_234_".into(), "09".into(), "".into(), Some(id("gwei")))
2236 => "1234.09 gwei",
2237 pt::Expression::RationalNumberLiteral(loc!(), "_123_4_".into(), "90".into(), "2_".into(), Some(id("gwei")))
2238 => "1234.9e2 gwei",
2239
2240 pt::Expression::FunctionCall(loc!(), Box::new(expr!(func)), vec![]) => "func()",
2241 pt::Expression::FunctionCall(loc!(), Box::new(expr!(func)), vec![expr!(arg)])
2242 => "func(arg)",
2243 pt::Expression::FunctionCall(loc!(), Box::new(expr!(func)), vec![expr!(arg1), expr!(arg2)])
2244 => "func(arg1, arg2)",
2245 pt::Expression::FunctionCallBlock(loc!(), Box::new(expr!(func)), Box::new(stmt!({})))
2246 => "func{}",
2247 pt::Expression::NamedFunctionCall(loc!(), Box::new(expr!(func)), vec![])
2248 => "func({})",
2249 pt::Expression::NamedFunctionCall(loc!(), Box::new(expr!(func)), vec![pt::NamedArgument {
2250 loc: loc!(),
2251 name: id("arg"),
2252 expr: expr!(value),
2253 }]) => "func({arg: value})",
2254 pt::Expression::NamedFunctionCall(loc!(), Box::new(expr!(func)), vec![
2255 pt::NamedArgument {
2256 loc: loc!(),
2257 name: id("arg1"),
2258 expr: expr!(value1),
2259 },
2260 pt::NamedArgument {
2261 loc: loc!(),
2262 name: id("arg2"),
2263 expr: expr!(value2),
2264 }
2265 ]) => "func({arg1: value1, arg2: value2})",
2266
2267 pt::Expression::PreIncrement(loc!(), var("a")) => "++a",
2268 pt::Expression::PostIncrement(loc!(), var("a")) => "a++",
2269 pt::Expression::PreDecrement(loc!(), var("a")) => "--a",
2270 pt::Expression::PostDecrement(loc!(), var("a")) => "a--",
2271 pt::Expression::Not(loc!(), var("a")) => "!a",
2272 pt::Expression::BitwiseNot(loc!(), var("a")) => "~a",
2273 pt::Expression::UnaryPlus(loc!(), var("a")) => "+a",
2274 pt::Expression::Negate(loc!(), var("a")) => "-a",
2275
2276 pt::Expression::Add(loc!(), var("a"), var("b")) => "a + b",
2277 pt::Expression::Subtract(loc!(), var("a"), var("b")) => "a - b",
2278 pt::Expression::Power(loc!(), var("a"), var("b")) => "a ** b",
2279 pt::Expression::Multiply(loc!(), var("a"), var("b")) => "a * b",
2280 pt::Expression::Divide(loc!(), var("a"), var("b")) => "a / b",
2281 pt::Expression::Modulo(loc!(), var("a"), var("b")) => "a % b",
2282 pt::Expression::ShiftLeft(loc!(), var("a"), var("b")) => "a << b",
2283 pt::Expression::ShiftRight(loc!(), var("a"), var("b")) => "a >> b",
2284 pt::Expression::BitwiseAnd(loc!(), var("a"), var("b")) => "a & b",
2285 pt::Expression::BitwiseXor(loc!(), var("a"), var("b")) => "a ^ b",
2286 pt::Expression::BitwiseOr(loc!(), var("a"), var("b")) => "a | b",
2287 pt::Expression::Less(loc!(), var("a"), var("b")) => "a < b",
2288 pt::Expression::More(loc!(), var("a"), var("b")) => "a > b",
2289 pt::Expression::LessEqual(loc!(), var("a"), var("b")) => "a <= b",
2290 pt::Expression::MoreEqual(loc!(), var("a"), var("b")) => "a >= b",
2291 pt::Expression::And(loc!(), var("a"), var("b")) => "a && b",
2292 pt::Expression::Or(loc!(), var("a"), var("b")) => "a || b",
2293 pt::Expression::Equal(loc!(), var("a"), var("b")) => "a == b",
2294 pt::Expression::NotEqual(loc!(), var("a"), var("b")) => "a != b",
2295
2296 pt::Expression::Assign(loc!(), var("a"), var("b")) => "a = b",
2297 pt::Expression::AssignOr(loc!(), var("a"), var("b")) => "a |= b",
2298 pt::Expression::AssignAnd(loc!(), var("a"), var("b")) => "a &= b",
2299 pt::Expression::AssignXor(loc!(), var("a"), var("b")) => "a ^= b",
2300 pt::Expression::AssignShiftLeft(loc!(), var("a"), var("b")) => "a <<= b",
2301 pt::Expression::AssignShiftRight(loc!(), var("a"), var("b")) => "a >>= b",
2302 pt::Expression::AssignAdd(loc!(), var("a"), var("b")) => "a += b",
2303 pt::Expression::AssignSubtract(loc!(), var("a"), var("b")) => "a -= b",
2304 pt::Expression::AssignMultiply(loc!(), var("a"), var("b")) => "a *= b",
2305 pt::Expression::AssignDivide(loc!(), var("a"), var("b")) => "a /= b",
2306 pt::Expression::AssignModulo(loc!(), var("a"), var("b")) => "a %= b",
2307 }
2308
2309 pt::FunctionAttribute: {
2310 pt::FunctionAttribute::Virtual(loc!()) => "virtual",
2311 pt::FunctionAttribute::Immutable(loc!()) => "immutable",
2312
2313 pt::FunctionAttribute::Override(loc!(), vec![]) => "override",
2314 pt::FunctionAttribute::Override(loc!(), vec![idp!["a", "b"]]) => "override(a.b)",
2315 pt::FunctionAttribute::Override(loc!(), vec![idp!["a", "b"], idp!["c", "d"]])
2316 => "override(a.b, c.d)",
2317 }
2318
2319 pt::FunctionTy: {
2320 pt::FunctionTy::Constructor => "constructor",
2321 pt::FunctionTy::Function => "function",
2322 pt::FunctionTy::Fallback => "fallback",
2323 pt::FunctionTy::Receive => "receive",
2324 pt::FunctionTy::Modifier => "modifier",
2325 }
2326
2327 pt::Import: {
2328 pt::Import::Plain(pt::ImportPath::Filename(lit!("path/to/import")), loc!()) => "import \"path/to/import\";",
2329
2330 pt::Import::GlobalSymbol(pt::ImportPath::Filename(lit!("path-to-import")), id("ImportedContract"), loc!())
2331 => "import \"path-to-import\" as ImportedContract;",
2332
2333 pt::Import::Rename(pt::ImportPath::Filename(lit!("import\\to\\path")), vec![], loc!())
2334 => "import {} from \"import\\to\\path\";",
2335 pt::Import::Rename(pt::ImportPath::Filename(lit!("import\\to\\path")), vec![(id("A"), None), (id("B"), Some(id("C")))], loc!())
2336 => "import {A, B as C} from \"import\\to\\path\";",
2337
2338 pt::Import::Plain(pt::ImportPath::Path(idp!("std", "stub")), loc!()) => "import std.stub;",
2339
2340 pt::Import::GlobalSymbol(pt::ImportPath::Path(idp!("a", "b", "c")), id("ImportedContract"), loc!())
2341 => "import a.b.c as ImportedContract;",
2342
2343 pt::Import::Rename(pt::ImportPath::Path(idp!("std", "stub")), vec![], loc!())
2344 => "import {} from std.stub;",
2345 pt::Import::Rename(pt::ImportPath::Path(idp!("std", "stub")), vec![(id("A"), None), (id("B"), Some(id("C")))], loc!())
2346 => "import {A, B as C} from std.stub;",
2347 }
2348
2349 pt::Mutability: {
2350 pt::Mutability::Pure(loc!()) => "pure",
2351 pt::Mutability::View(loc!()) => "view",
2352 pt::Mutability::Constant(loc!()) => "view",
2353 pt::Mutability::Payable(loc!()) => "payable",
2354 }
2355
2356 pt::SourceUnitPart: {
2357 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Identifier(loc!(), None, None).into()) => "pragma;",
2360 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Identifier(loc!(), Some(id("solidity")), None).into())
2361 => "pragma solidity;",
2362 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::StringLiteral(loc!(), id("abi"), lit!("v2")).into())
2363 => "pragma abi \"v2\";",
2364 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Version(loc!(), id("solidity"), vec![plain_version!("0", "8", "0")]).into())
2365 => "pragma solidity 0.8.0;",
2366 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Version(loc!(), id("solidity"), vec![
2367 op_version!(pt::VersionOp::Exact, "0", "5", "16"),
2368 op_version!(pt::VersionOp::GreaterEq, "0", "5"),
2369 op_version!(pt::VersionOp::Greater, "0"),
2370 op_version!(pt::VersionOp::Less, "1"),
2371 op_version!(pt::VersionOp::LessEq, "1"),
2372 op_version!(pt::VersionOp::Caret, "0", "5", "16"),
2373 op_version!(pt::VersionOp::Wildcard, "5", "5")]
2374 ).into())
2375 => "pragma solidity =0.5.16 >=0.5 >0 <1 <=1 ^0.5.16 *5.5;",
2376 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Version(loc!(), id("solidity"), vec![or_version!(plain_version!("0"), op_version!(pt::VersionOp::Caret, "1", "0"))]).into())
2377 => "pragma solidity 0 || ^1.0;",
2378 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Version(loc!(), id("solidity"), vec![range_version!(version!["0"], version!["1", "0"])]).into())
2379 => "pragma solidity 0 - 1.0;",
2380 pt::SourceUnitPart::StraySemicolon(loc!()) => ";",
2381 }
2382
2383 pt::Statement: {
2384 pt::Statement::Assembly {
2385 loc: loc!(),
2386 dialect: None,
2387 flags: None,
2388 block: yul_block(),
2389 } => "assembly {}",
2390 pt::Statement::Assembly {
2391 loc: loc!(),
2392 dialect: None,
2393 flags: Some(vec![lit!("memory-safe")]),
2394 block: yul_block(),
2395 } => "assembly (\"memory-safe\") {}",
2396 pt::Statement::Assembly {
2397 loc: loc!(),
2398 dialect: None,
2399 flags: Some(vec![lit!("memory-safe"), lit!("second-flag")]),
2400 block: yul_block(),
2401 } => "assembly (\"memory-safe\", \"second-flag\") {}",
2402
2403 pt::Statement::Args(loc!(), vec![]) => "{}",
2404 pt::Statement::Args(loc!(), vec![
2405 pt::NamedArgument {
2406 loc: loc!(),
2407 name: id("name"),
2408 expr: expr!(value),
2409 },
2410 ]) => "{name: value}",
2411 pt::Statement::Args(loc!(), vec![
2412 pt::NamedArgument {
2413 loc: loc!(),
2414 name: id("name1"),
2415 expr: expr!(value1),
2416 },
2417 pt::NamedArgument {
2418 loc: loc!(),
2419 name: id("name2"),
2420 expr: expr!(value2),
2421 },
2422 ]) => "{name1: value1, name2: value2}",
2423
2424 pt::Statement::If(loc!(), expr!(true), Box::new(stmt!({})), None) => "if (true) {}",
2425 pt::Statement::If(loc!(), expr!(true), Box::new(stmt!({})), Some(Box::new(stmt!({}))))
2426 => "if (true) {} else {}",
2427
2428 pt::Statement::While(loc!(), expr!(true), Box::new(stmt!({}))) => "while (true) {}",
2429
2430 pt::Statement::Expression(loc!(), expr!(true)) => "true;",
2431
2432 pt::Statement::VariableDefinition(loc!(), pt::VariableDeclaration {
2433 loc: loc!(),
2434 ty: expr_ty!(uint256),
2435 storage: None,
2436 name: Some(id("a")),
2437 }, None) => "uint256 a;",
2438 pt::Statement::VariableDefinition(loc!(), pt::VariableDeclaration {
2439 loc: loc!(),
2440 ty: expr_ty!(uint256),
2441 storage: None,
2442 name: Some(id("a")),
2443 }, Some(expr!(0))) => "uint256 a = 0;",
2444
2445 pt::Statement::For(loc!(), None, None, None, Some(Box::new(stmt!({}))))
2446 => "for (;;) {}",
2447 pt::Statement::For(loc!(), Some(Box::new(pt::Statement::VariableDefinition(
2448 loc!(),
2449 pt::VariableDeclaration {
2450 loc: loc!(),
2451 ty: expr_ty!(uint256),
2452 storage: None,
2453 name: Some(id("a")),
2454 },
2455 None
2456 ))), None, None, Some(Box::new(stmt!({}))))
2457 => "for (uint256 a;;) {}",
2458 pt::Statement::For(loc!(), None, Some(Box::new(expr!(true))), None, Some(Box::new(stmt!({}))))
2459 => "for (; true;) {}",
2460 pt::Statement::For(
2461 loc!(),
2462 None,
2463 Some(Box::new(expr!(true))),
2464 Some(Box::new(expr!(++i))),
2465 Some(Box::new(stmt!({})))
2466 ) => "for (; true; ++i) {}",
2467
2468 pt::Statement::DoWhile(loc!(), Box::new(stmt!({})), expr!(true))
2469 => "do {} while (true);",
2470
2471 pt::Statement::Continue(loc!()) => "continue;",
2472 pt::Statement::Break(loc!()) => "break;",
2473
2474 pt::Statement::Return(loc!(), None) => "return;",
2475 pt::Statement::Return(loc!(), Some(expr!(true))) => "return true;",
2476
2477 pt::Statement::Revert(loc!(), None, vec![]) => "revert();",
2478 pt::Statement::Revert(loc!(), None, vec![expr!("error")])
2479 => "revert(\"error\");",
2480 pt::Statement::Revert(loc!(), Some(idp!("my", "error")), vec![expr!("error")])
2481 => "revert my.error(\"error\");",
2482
2483 pt::Statement::RevertNamedArgs(loc!(), None, vec![]) => "revert();",
2484 pt::Statement::RevertNamedArgs(loc!(), None, vec![pt::NamedArgument {
2485 loc: loc!(),
2486 name: id("name"),
2487 expr: expr!(value),
2488 }]) => "revert({name: value});",
2489 pt::Statement::RevertNamedArgs(loc!(), Some(idp!("my", "error")), vec![pt::NamedArgument {
2490 loc: loc!(),
2491 name: id("name"),
2492 expr: expr!(value),
2493 }]) => "revert my.error({name: value});",
2494
2495 pt::Statement::Emit(loc!(), expr!(true)) => "emit true;",
2496
2497 pt::Statement::Try(loc!(), expr!(true), None, vec![]) => "try true",
2498 pt::Statement::Try(loc!(), expr!(true), None, vec![pt::CatchClause::Simple(loc!(), None, stmt!({}))])
2499 => "try true catch {}",
2500 pt::Statement::Try(loc!(), expr!(true), Some((vec![], Box::new(stmt!({})))), vec![])
2501 => "try true returns () {}",
2502 pt::Statement::Try(
2503 loc!(),
2504 expr!(true),
2505 Some((vec![], Box::new(stmt!({})))),
2506 vec![pt::CatchClause::Simple(loc!(), None, stmt!({}))]
2507 ) => "try true returns () {} catch {}",
2508 pt::Statement::Try(
2509 loc!(),
2510 expr!(true),
2511 Some((vec![(loc!(), Some(param!(uint256 a)))], Box::new(stmt!({})))),
2512 vec![pt::CatchClause::Simple(loc!(), None, stmt!({}))]
2513 ) => "try true returns (uint256 a) {} catch {}",
2514 }
2515
2516 pt::StorageLocation: {
2517 pt::StorageLocation::Memory(loc!()) => "memory",
2518 pt::StorageLocation::Storage(loc!()) => "storage",
2519 pt::StorageLocation::Calldata(loc!()) => "calldata",
2520 }
2521
2522 pt::Type: {
2523 pt::Type::Address => "address",
2524 pt::Type::AddressPayable => "address payable",
2525 pt::Type::Payable => "payable",
2526 pt::Type::Bool => "bool",
2527 pt::Type::String => "string",
2528 pt::Type::Int(256) => "int256",
2529 pt::Type::Uint(256) => "uint256",
2530 pt::Type::Bytes(32) => "bytes32",
2531 pt::Type::Rational => "fixed",
2532 pt::Type::DynamicBytes => "bytes",
2533
2534 pt::Type::Mapping {
2535 loc: loc!(),
2536 key: Box::new(expr_ty!(uint256)),
2537 key_name: None,
2538 value: Box::new(expr_ty!(uint256)),
2539 value_name: None,
2540 } => "mapping(uint256 => uint256)",
2541 pt::Type::Mapping {
2542 loc: loc!(),
2543 key: Box::new(expr_ty!(uint256)),
2544 key_name: Some(id("key")),
2545 value: Box::new(expr_ty!(uint256)),
2546 value_name: None,
2547 } => "mapping(uint256 key => uint256)",
2548 pt::Type::Mapping {
2549 loc: loc!(),
2550 key: Box::new(expr_ty!(uint256)),
2551 key_name: Some(id("key")),
2552 value: Box::new(expr_ty!(uint256)),
2553 value_name: Some(id("value")),
2554 } => "mapping(uint256 key => uint256 value)",
2555
2556 pt::Type::Function {
2557 params: vec![],
2558 attributes: vec![],
2559 returns: None
2560 } => "function ()",
2561 pt::Type::Function {
2562 params: vec![(loc!(), Some(param!(uint256)))],
2563 attributes: vec![],
2564 returns: None
2565 } => "function (uint256)",
2566 pt::Type::Function {
2567 params: vec![(loc!(), Some(param!(uint256))), (loc!(), Some(param!(address)))],
2568 attributes: vec![],
2569 returns: None
2570 } => "function (uint256, address)",
2571 pt::Type::Function {
2572 params: vec![(loc!(), Some(param!(uint256)))],
2573 attributes: vec![pt::FunctionAttribute::Virtual(loc!())],
2574 returns: None
2575 } => "function (uint256) virtual",
2576 pt::Type::Function {
2577 params: vec![(loc!(), Some(param!(uint256)))],
2578 attributes: vec![pt::FunctionAttribute::Virtual(loc!()), pt::FunctionAttribute::Override(loc!(), vec![])],
2579 returns: None
2580 } => "function (uint256) virtual override",
2581 pt::Type::Function {
2582 params: vec![(loc!(), Some(param!(uint256)))],
2583 attributes: vec![pt::FunctionAttribute::Virtual(loc!()), pt::FunctionAttribute::Override(loc!(), vec![idp!["a", "b"]])],
2584 returns: None
2585 } => "function (uint256) virtual override(a.b)",
2586 pt::Type::Function {
2587 params: vec![(loc!(), Some(param!(uint256)))],
2588 attributes: vec![],
2589 returns: Some((vec![], vec![])),
2590 } => "function (uint256)",
2591 pt::Type::Function {
2592 params: vec![(loc!(), Some(param!(uint256)))],
2593 attributes: vec![],
2594 returns: Some((vec![(loc!(), Some(param!(uint256)))], vec![])),
2595 } => "function (uint256) returns (uint256)",
2596 pt::Type::Function {
2597 params: vec![(loc!(), Some(param!(uint256)))],
2598 attributes: vec![],
2599 returns: Some((vec![(loc!(), Some(param!(uint256))), (loc!(), Some(param!(address)))], vec![])),
2600 } => "function (uint256) returns (uint256, address)",
2601 }
2602
2603 pt::UserDefinedOperator: {
2604 pt::UserDefinedOperator::BitwiseAnd => "&",
2605 pt::UserDefinedOperator::BitwiseNot => "~",
2606 pt::UserDefinedOperator::Negate => "-",
2607 pt::UserDefinedOperator::BitwiseOr => "|",
2608 pt::UserDefinedOperator::BitwiseXor => "^",
2609 pt::UserDefinedOperator::Add => "+",
2610 pt::UserDefinedOperator::Divide => "/",
2611 pt::UserDefinedOperator::Modulo => "%",
2612 pt::UserDefinedOperator::Multiply => "*",
2613 pt::UserDefinedOperator::Subtract => "-",
2614 pt::UserDefinedOperator::Equal => "==",
2615 pt::UserDefinedOperator::More => ">",
2616 pt::UserDefinedOperator::MoreEqual => ">=",
2617 pt::UserDefinedOperator::Less => "<",
2618 pt::UserDefinedOperator::LessEqual => "<=",
2619 pt::UserDefinedOperator::NotEqual => "!=",
2620 }
2621
2622 pt::UsingList: {
2623 pt::UsingList::Library(idp!("id", "path")) => "id.path",
2624
2625 pt::UsingList::Functions(vec![]) => "{}",
2626 pt::UsingList::Functions(vec![
2627 pt::UsingFunction {
2628 loc: loc!(),
2629 path: idp!["id", "path"],
2630 oper: None,
2631 },
2632 pt::UsingFunction {
2633 loc: loc!(),
2634 path: idp!["id", "path"],
2635 oper: Some(pt::UserDefinedOperator::Add),
2636 }]) => "{id.path, id.path as +}",
2637 }
2638
2639 pt::VariableAttribute: {
2640 pt::VariableAttribute::Constant(loc!()) => "constant",
2641 pt::VariableAttribute::Immutable(loc!()) => "immutable",
2642
2643 pt::VariableAttribute::Override(loc!(), vec![]) => "override",
2644 pt::VariableAttribute::Override(loc!(), vec![idp!["a", "b"]]) => "override(a.b)",
2645 pt::VariableAttribute::Override(loc!(), vec![idp!["a", "b"], idp!["c", "d"]])
2646 => "override(a.b, c.d)",
2647 }
2648
2649 pt::Visibility: {
2650 pt::Visibility::Public(Some(loc!())) => "public",
2651 pt::Visibility::Internal(Some(loc!())) => "internal",
2652 pt::Visibility::Private(Some(loc!())) => "private",
2653 pt::Visibility::External(Some(loc!())) => "external",
2654 }
2655
2656 pt::YulExpression: {
2657 pt::YulExpression::BoolLiteral(loc!(), false, None) => "false",
2658 pt::YulExpression::BoolLiteral(loc!(), true, None) => "true",
2659 pt::YulExpression::BoolLiteral(loc!(), false, Some(id("name"))) => "false: name",
2660 pt::YulExpression::BoolLiteral(loc!(), true, Some(id("name"))) => "true: name",
2661
2662 pt::YulExpression::NumberLiteral(loc!(), "1234".into(), "".into(), None) => "1234",
2663 pt::YulExpression::NumberLiteral(loc!(), "1234".into(), "9".into(), None) => "1234e9",
2664 pt::YulExpression::NumberLiteral(loc!(), "1234".into(), "".into(), Some(id("name"))) => "1234: name",
2665 pt::YulExpression::NumberLiteral(loc!(), "1234".into(), "9".into(), Some(id("name"))) => "1234e9: name",
2666
2667 pt::YulExpression::HexNumberLiteral(loc!(), "0x1234".into(), None) => "0x1234",
2668 pt::YulExpression::HexNumberLiteral(loc!(), "0x1234".into(), Some(id("name"))) => "0x1234: name",
2669
2670 pt::YulExpression::HexStringLiteral(lit!(hex "1234"), None) => "hex\"1234\"",
2671 pt::YulExpression::HexStringLiteral(lit!(hex "1234"), Some(id("name"))) => "hex\"1234\": name",
2672
2673 pt::YulExpression::StringLiteral(lit!("1234"), None) => "\"1234\"",
2674 pt::YulExpression::StringLiteral(lit!("1234"), Some(id("name"))) => "\"1234\": name",
2675
2676 pt::YulExpression::Variable(id("name")) => "name",
2677
2678 pt::YulExpression::FunctionCall(Box::new(pt::YulFunctionCall {
2679 loc: loc!(),
2680 id: id("name"),
2681 arguments: vec![],
2682 })) => "name()",
2683
2684 pt::YulExpression::SuffixAccess(loc!(), Box::new(yexpr!(struct)), id("access"))
2685 => "struct.access",
2686 }
2687
2688 pt::YulStatement: {
2689 pt::YulStatement::Assign(loc!(), vec![yexpr!(var)], yexpr!(eq))
2692 => "var := eq",
2693 pt::YulStatement::Assign(loc!(), vec![yexpr!(a), yexpr!(b)], yexpr!(eq))
2694 => "a, b := eq",
2695
2696 pt::YulStatement::VariableDeclaration(loc!(), vec![yid!(var)], None)
2697 => "let var",
2698 pt::YulStatement::VariableDeclaration(loc!(), vec![yid!(a), yid!(b)], None)
2699 => "let a, b",
2700 pt::YulStatement::VariableDeclaration(loc!(), vec![yid!(var)], Some(yexpr!(eq)))
2701 => "let var := eq",
2702 pt::YulStatement::VariableDeclaration(loc!(), vec![yid!(a), yid!(b)], Some(yexpr!(eq)))
2703 => "let a, b := eq",
2704
2705 pt::YulStatement::If(loc!(), yexpr!(expr), yul_block()) => "if expr {}",
2706
2707 pt::YulStatement::Leave(loc!()) => "leave",
2708 pt::YulStatement::Break(loc!()) => "break",
2709 pt::YulStatement::Continue(loc!()) => "continue",
2710 }
2711
2712 pt::YulSwitchOptions: {
2713 pt::YulSwitchOptions::Case(loc!(), yexpr!(expr), yul_block()) => "case expr {}",
2714 pt::YulSwitchOptions::Default(loc!(), yul_block()) => "default {}",
2715 }
2716 ];
2717 }
2718}