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 Self::Transient(_) => "transient",
1037 }
1038 }
1039}
1040
1041impl Display for pt::Type {
1042 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1043 match self {
1044 Self::Address => f.write_str("address"),
1045 Self::AddressPayable => f.write_str("address payable"),
1046 Self::Payable => f.write_str("payable"),
1047 Self::Bool => f.write_str("bool"),
1048 Self::String => f.write_str("string"),
1049 Self::Rational => f.write_str("fixed"),
1050 Self::DynamicBytes => f.write_str("bytes"),
1051 Self::Bytes(n) => {
1052 f.write_str("bytes")?;
1053 n.fmt(f)
1054 }
1055 Self::Int(n) => {
1056 f.write_str("int")?;
1057 n.fmt(f)
1058 }
1059 Self::Uint(n) => {
1060 f.write_str("uint")?;
1061 n.fmt(f)
1062 }
1063 Self::Mapping {
1064 key,
1065 key_name,
1066 value,
1067 value_name,
1068 ..
1069 } => {
1070 f.write_str("mapping(")?;
1071
1072 key.fmt(f)?;
1073 write_opt!(f, ' ', key_name);
1074
1075 f.write_str(" => ")?;
1076
1077 value.fmt(f)?;
1078 write_opt!(f, ' ', value_name);
1079
1080 f.write_char(')')
1081 }
1082 Self::Function {
1083 params,
1084 attributes,
1085 returns,
1086 } => {
1087 f.write_str("function (")?;
1088 fmt_parameter_list(params, f)?;
1089 f.write_char(')')?;
1090
1091 if !attributes.is_empty() {
1092 f.write_char(' ')?;
1093 write_separated(attributes, f, " ")?;
1094 }
1095
1096 if let Some((returns, attrs)) = returns {
1097 if !attrs.is_empty() {
1098 f.write_char(' ')?;
1099 write_separated(attrs, f, " ")?;
1100 }
1101
1102 if !returns.is_empty() {
1103 f.write_str(" returns (")?;
1104 fmt_parameter_list(returns, f)?;
1105 f.write_char(')')?;
1106 }
1107 }
1108 Ok(())
1109 }
1110 }
1111 }
1112}
1113
1114impl Display for pt::UserDefinedOperator {
1115 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1116 f.write_str(self.as_str())
1117 }
1118}
1119
1120impl pt::UserDefinedOperator {
1121 pub const fn as_str(&self) -> &'static str {
1123 match self {
1124 Self::BitwiseAnd => "&",
1125 Self::BitwiseNot => "~",
1126 Self::Negate => "-",
1127 Self::BitwiseOr => "|",
1128 Self::BitwiseXor => "^",
1129 Self::Add => "+",
1130 Self::Divide => "/",
1131 Self::Modulo => "%",
1132 Self::Multiply => "*",
1133 Self::Subtract => "-",
1134 Self::Equal => "==",
1135 Self::More => ">",
1136 Self::MoreEqual => ">=",
1137 Self::Less => "<",
1138 Self::LessEqual => "<=",
1139 Self::NotEqual => "!=",
1140 }
1141 }
1142}
1143
1144impl Display for pt::UsingList {
1145 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1146 match self {
1147 Self::Library(ident) => ident.fmt(f),
1148 Self::Functions(list) => {
1149 f.write_char('{')?;
1150 write_separated(list, f, ", ")?;
1151 f.write_char('}')
1152 }
1153 Self::Error => Ok(()),
1154 }
1155 }
1156}
1157
1158impl Display for pt::VariableAttribute {
1159 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1160 match self {
1161 Self::Visibility(vis) => vis.fmt(f),
1162 Self::Constant(_) => f.write_str("constant"),
1163 Self::Immutable(_) => f.write_str("immutable"),
1164 Self::Override(_, idents) => {
1165 f.write_str("override")?;
1166 if !idents.is_empty() {
1167 f.write_char('(')?;
1168 write_separated(idents, f, ", ")?;
1169 f.write_char(')')?;
1170 }
1171 Ok(())
1172 }
1173 Self::StorageType(storage) => match storage {
1174 StorageType::Instance(_) => f.write_str("instance"),
1175 StorageType::Temporary(_) => f.write_str("temporary"),
1176 StorageType::Persistent(_) => f.write_str("persistent"),
1177 },
1178 Self::StorageLocation(s) => s.fmt(f),
1179 }
1180 }
1181}
1182
1183impl Display for pt::Visibility {
1184 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1185 f.write_str(self.as_str())
1186 }
1187}
1188impl pt::Visibility {
1189 pub const fn as_str(&self) -> &'static str {
1191 match self {
1192 Self::Public(_) => "public",
1193 Self::Internal(_) => "internal",
1194 Self::Private(_) => "private",
1195 Self::External(_) => "external",
1196 }
1197 }
1198}
1199
1200impl Display for pt::YulExpression {
1201 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1202 match self {
1203 Self::BoolLiteral(_, value, ident) => {
1204 let value = if *value { "true" } else { "false" };
1205 f.write_str(value)?;
1206 write_opt!(f, ": ", ident);
1207 Ok(())
1208 }
1209 Self::NumberLiteral(_, value, exponent, ident) => {
1210 f.write_str(value)?;
1211 if !exponent.is_empty() {
1212 f.write_char('e')?;
1213 f.write_str(exponent)?;
1214 }
1215 write_opt!(f, ": ", ident);
1216 Ok(())
1217 }
1218 Self::HexNumberLiteral(_, value, ident) => {
1219 f.write_str(value)?;
1220 write_opt!(f, ": ", ident);
1221 Ok(())
1222 }
1223 Self::HexStringLiteral(value, ident) => {
1224 value.fmt(f)?;
1225 write_opt!(f, ": ", ident);
1226 Ok(())
1227 }
1228 Self::StringLiteral(value, ident) => {
1229 value.fmt(f)?;
1230 write_opt!(f, ": ", ident);
1231 Ok(())
1232 }
1233 Self::Variable(ident) => ident.fmt(f),
1234 Self::FunctionCall(call) => call.fmt(f),
1235 Self::SuffixAccess(_, l, r) => {
1236 l.fmt(f)?;
1237 f.write_char('.')?;
1238 r.fmt(f)
1239 }
1240 }
1241 }
1242}
1243
1244impl Display for pt::YulStatement {
1245 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1246 match self {
1247 Self::Block(inner) => inner.fmt(f),
1248 Self::FunctionDefinition(inner) => inner.fmt(f),
1249 Self::FunctionCall(inner) => inner.fmt(f),
1250 Self::For(inner) => inner.fmt(f),
1251 Self::Switch(inner) => inner.fmt(f),
1252
1253 Self::Assign(_, exprs, eq_expr) => {
1254 write_separated(exprs, f, ", ")?;
1255 f.write_str(" := ")?;
1256 eq_expr.fmt(f)
1257 }
1258 Self::VariableDeclaration(_, vars, eq_expr) => {
1259 f.write_str("let")?;
1260 if !vars.is_empty() {
1261 f.write_char(' ')?;
1262 write_separated(vars, f, ", ")?;
1263 }
1264 write_opt!(f, " := ", eq_expr);
1265 Ok(())
1266 }
1267
1268 Self::If(_, expr, block) => {
1269 f.write_str("if ")?;
1270 expr.fmt(f)?;
1271 f.write_char(' ')?;
1272 block.fmt(f)
1273 }
1274
1275 Self::Leave(_) => f.write_str("leave"),
1276 Self::Break(_) => f.write_str("break"),
1277 Self::Continue(_) => f.write_str("continue"),
1278
1279 Self::Error(_) => Ok(()),
1280 }
1281 }
1282}
1283
1284impl Display for pt::YulSwitchOptions {
1285 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
1286 match self {
1287 Self::Case(_, expr, block) => {
1288 f.write_str("case ")?;
1289 expr.fmt(f)?;
1290 f.write_str(" ")?;
1291 block.fmt(f)
1292 }
1293 Self::Default(_, block) => {
1294 f.write_str("default ")?;
1295 block.fmt(f)
1296 }
1297 }
1298 }
1299}
1300
1301#[inline]
1306fn fmt_parameter_list(list: &pt::ParameterList, f: &mut Formatter<'_>) -> Result {
1307 let iter = list.iter().flat_map(|(_, param)| param);
1308 write_separated_iter(iter, f, ", ")
1309}
1310
1311#[inline]
1312fn write_separated<T: Display>(slice: &[T], f: &mut Formatter<'_>, sep: &str) -> Result {
1313 write_separated_iter(slice.iter(), f, sep)
1314}
1315
1316fn write_separated_iter<T, I>(mut iter: I, f: &mut Formatter<'_>, sep: &str) -> Result
1317where
1318 I: Iterator<Item = T>,
1319 T: Display,
1320{
1321 if let Some(first) = iter.next() {
1322 first.fmt(f)?;
1323 for item in iter {
1324 f.write_str(sep)?;
1325 item.fmt(f)?;
1326 }
1327 }
1328 Ok(())
1329}
1330
1331fn rm_underscores(s: &str) -> Cow<'_, str> {
1332 if s.is_empty() {
1333 Cow::Borrowed("0")
1334 } else if s.contains('_') {
1335 let mut s = s.to_string();
1336 s.retain(|c| c != '_');
1337 Cow::Owned(s)
1338 } else {
1339 Cow::Borrowed(s)
1340 }
1341}
1342
1343#[cfg(test)]
1344mod tests {
1345 use super::*;
1346 use crate::pt::{Annotation, Loc};
1347
1348 macro_rules! struct_tests {
1349 ($(pt::$t:ident { $( $f:ident: $e:expr ),* $(,)? } => $expected:expr),* $(,)?) => {
1350 $(
1351 assert_eq_display(
1352 pt::$t {
1353 loc: loc!(),
1354 $( $f: $e, )*
1355 },
1356 $expected,
1357 );
1358 )*
1359 };
1360 }
1361
1362 macro_rules! enum_tests {
1363 ($(
1364 $t:ty: {
1365 $($p:expr => $expected:expr,)+
1366 }
1367 )+) => {
1368 $(
1369 $(
1370 assert_eq_display($p, $expected);
1371 )+
1372 )+
1373 };
1374 }
1375
1376 macro_rules! expr {
1378 (this) => {
1379 pt::Expression::This(loc!())
1380 };
1381
1382 ($i:ident) => {
1383 pt::Expression::Variable(id(stringify!($i)))
1384 };
1385
1386 ($l:literal) => {
1387 pt::Expression::Variable(id(stringify!($l)))
1388 };
1389
1390 (++ $($t:tt)+) => {
1391 pt::Expression::PreIncrement(loc!(), Box::new(expr!($($t)+)))
1392 };
1393
1394 ($($t:tt)+ ++) => {
1395 pt::Expression::PostIncrement(loc!(), Box::new(expr!($($t)+)))
1396 };
1397 }
1398 macro_rules! yexpr {
1399 ($i:ident) => {
1400 pt::YulExpression::Variable(id(stringify!($i)))
1401 };
1402 ($l:literal) => {
1403 pt::YulExpression::Variable(id(stringify!($l)))
1404 };
1405 }
1406
1407 macro_rules! ty {
1409 (uint256) => {
1410 pt::Type::Uint(256)
1411 };
1412 (string) => {
1413 pt::Type::String
1414 };
1415 (bytes) => {
1416 pt::Type::DynamicBytes
1417 };
1418 (address) => {
1419 pt::Type::Address
1420 };
1421 }
1422 macro_rules! expr_ty {
1423 ($($t:tt)+) => {
1424 pt::Expression::Type(loc!(), ty!($($t)+))
1425 };
1426 }
1427
1428 macro_rules! lit {
1430 (unicode $($l:literal)+) => {
1432 pt::StringLiteral {
1433 loc: loc!(),
1434 unicode: true,
1435 string: concat!( $($l),+ ).to_string(),
1436 }
1437 };
1438
1439 (hex $($l:literal)+) => {
1440 pt::HexLiteral {
1441 loc: loc!(),
1442 hex: concat!( "hex\"", $($l),+ , "\"" ).to_string(),
1443 }
1444 };
1445
1446 ($($l:literal)+) => {
1447 pt::StringLiteral {
1448 loc: loc!(),
1449 unicode: false,
1450 string: concat!( $($l),+ ).to_string(),
1451 }
1452 };
1453 }
1454
1455 macro_rules! version {
1457 ($($l:literal),+) => {
1458 <[_]>::into_vec(Box::new([ $( $l.into() ),+ ]))
1459 }
1460 }
1461
1462 macro_rules! plain_version {
1463 ($($l:literal),+) => {
1464 pt::VersionComparator::Plain {
1465 loc: loc!(),
1466 version: <[_]>::into_vec(Box::new([ $( $l.into() ),+ ])),
1467 }
1468 };
1469 }
1470
1471 macro_rules! op_version {
1472 ($op:expr, $($l:literal),+) => {
1473 pt::VersionComparator::Operator {
1474 loc: loc!(),
1475 op: $op,
1476 version: <[_]>::into_vec(Box::new([ $( $l.into() ),+ ])),
1477 }
1478 };
1479 }
1480
1481 macro_rules! range_version {
1482 ($from:expr, $to:expr) => {
1483 pt::VersionComparator::Range {
1484 loc: loc!(),
1485 from: $from,
1486 to: $to,
1487 }
1488 };
1489 }
1490
1491 macro_rules! or_version {
1492 ($left:expr, $right:expr) => {
1493 pt::VersionComparator::Or {
1494 loc: loc!(),
1495 left: $left.into(),
1496 right: $right.into(),
1497 }
1498 };
1499 }
1500
1501 macro_rules! stmt {
1503 ( {} ) => {
1504 pt::Statement::Block {
1505 loc: loc!(),
1506 unchecked: false,
1507 statements: vec![],
1508 }
1509 };
1510
1511 ( unchecked { $($t:tt)* } ) => {
1512 pt::Statement::Block {
1513 loc: loc!(),
1514 unchecked: true,
1515 statements: vec![stmt!($(t)*)],
1516 }
1517 };
1518 ( { $($t:tt)* } ) => {
1519 pt::Statement::Block {
1520 loc: loc!(),
1521 unchecked: false,
1522 statements: vec![stmt!($(t)*)],
1523 }
1524 };
1525 }
1526
1527 macro_rules! idp {
1529 ($($e:expr),* $(,)?) => {
1530 pt::IdentifierPath {
1531 loc: loc!(),
1532 identifiers: vec![$(id($e)),*],
1533 }
1534 };
1535 }
1536
1537 macro_rules! loc {
1538 () => {
1539 pt::Loc::File(0, 0, 0)
1540 };
1541 }
1542
1543 macro_rules! param {
1545 ($i:ident) => {
1546 pt::Parameter {
1547 loc: loc!(),
1548 ty: expr_ty!($i),
1549 storage: None,
1550 name: None,
1551 annotation: None,
1552 }
1553 };
1554
1555 ($i:ident $n:ident) => {
1556 pt::Parameter {
1557 loc: loc!(),
1558 ty: expr_ty!($i),
1559 storage: None,
1560 name: Some(id(stringify!($n))),
1561 annotation: None,
1562 }
1563 };
1564
1565 ($i:ident $s:ident $n:ident) => {
1566 pt::Parameter {
1567 loc: loc!(),
1568 ty: expr_ty!($i),
1569 storage: Some(storage!($s)),
1570 name: Some(id(stringify!($n))),
1571 annotation: None,
1572 }
1573 };
1574 }
1575
1576 macro_rules! storage {
1577 (memory) => {
1578 pt::StorageLocation::Memory(loc!())
1579 };
1580 (storage) => {
1581 pt::StorageLocation::Storage(loc!())
1582 };
1583 (calldata) => {
1584 pt::StorageLocation::Calldata(loc!())
1585 };
1586 (transient) => {
1587 pt::StorageLocation::Transient(loc!())
1588 };
1589 }
1590
1591 fn id(s: &str) -> pt::Identifier {
1593 pt::Identifier {
1594 loc: loc!(),
1595 name: s.to_string(),
1596 }
1597 }
1598
1599 macro_rules! yid {
1600 ($i:ident) => {
1601 pt::YulTypedIdentifier {
1602 loc: loc!(),
1603 id: id(stringify!($i)),
1604 ty: None,
1605 }
1606 };
1607
1608 ($i:ident : $t:ident) => {
1609 pt::YulTypedIdentifier {
1610 loc: loc!(),
1611 id: id(stringify!($i)),
1612 ty: Some(id(stringify!($t))),
1613 }
1614 };
1615 }
1616
1617 fn var(s: &str) -> Box<pt::Expression> {
1618 Box::new(pt::Expression::Variable(id(s)))
1619 }
1620
1621 fn yul_block() -> pt::YulBlock {
1622 pt::YulBlock {
1623 loc: loc!(),
1624 statements: vec![],
1625 }
1626 }
1627
1628 fn assert_eq_display<T: Display + std::fmt::Debug>(item: T, expected: &str) {
1629 let ty = std::any::type_name::<T>();
1630 let actual = item.to_string();
1631 assert_eq!(actual, expected, "\"{ty}\": {item:?}");
1632 }
1636
1637 #[test]
1638 fn display_structs_simple() {
1639 struct_tests![
1640 pt::Annotation {
1641 id: id("name"),
1642 value: Some(expr!(value)),
1643 } => "@name(value)",
1644
1645 pt::Base {
1646 name: idp!("id", "path"),
1647 args: None,
1648 } => "id.path",
1649 pt::Base {
1650 name: idp!("id", "path"),
1651 args: Some(vec![expr!(value)]),
1652 } => "id.path(value)",
1653 pt::Base {
1654 name: idp!("id", "path"),
1655 args: Some(vec![expr!(value1), expr!(value2)]),
1656 } => "id.path(value1, value2)",
1657
1658 pt::ErrorParameter {
1659 ty: expr_ty!(uint256),
1660 name: None,
1661 } => "uint256",
1662 pt::ErrorParameter {
1663 ty: expr_ty!(uint256),
1664 name: Some(id("name")),
1665 } => "uint256 name",
1666
1667 pt::EventParameter {
1668 ty: expr_ty!(uint256),
1669 indexed: false,
1670 name: None,
1671 } => "uint256",
1672 pt::EventParameter {
1673 ty: expr_ty!(uint256),
1674 indexed: true,
1675 name: None,
1676 } => "uint256 indexed",
1677 pt::EventParameter {
1678 ty: expr_ty!(uint256),
1679 indexed: false,
1680 name: Some(id("name")),
1681 } => "uint256 name",
1682 pt::EventParameter {
1683 ty: expr_ty!(uint256),
1684 indexed: true,
1685 name: Some(id("name")),
1686 } => "uint256 indexed name",
1687
1688 pt::HexLiteral {
1689 hex: "hex\"1234\"".into(),
1690 } => "hex\"1234\"",
1691 pt::HexLiteral {
1692 hex: "hex\"455318975130845\"".into(),
1693 } => "hex\"455318975130845\"",
1694
1695 pt::Identifier {
1696 name: "name".to_string(),
1697 } => "name",
1698
1699 pt::IdentifierPath {
1700 identifiers: vec![id("id")],
1701 } => "id",
1702 pt::IdentifierPath {
1703 identifiers: vec![id("id"), id("path")],
1704 } => "id.path",
1705 pt::IdentifierPath {
1706 identifiers: vec![id("long"), id("id"), id("path")],
1707 } => "long.id.path",
1708
1709 pt::NamedArgument {
1710 name: id("name"),
1711 expr: expr!(expr),
1712 } => "name: expr",
1713
1714 pt::Parameter {
1715 ty: expr_ty!(uint256),
1716 storage: None,
1717 name: None,
1718 annotation: None,
1719 } => "uint256",
1720 pt::Parameter {
1721 ty: expr_ty!(uint256),
1722 storage: None,
1723 name: Some(id("name")),
1724 annotation: None,
1725 } => "uint256 name",
1726 pt::Parameter {
1727 ty: expr_ty!(uint256),
1728 storage: Some(pt::StorageLocation::Calldata(Default::default())),
1729 name: Some(id("name")),
1730 annotation: None,
1731 } => "uint256 calldata name",
1732 pt::Parameter {
1733 ty: expr_ty!(uint256),
1734 storage: Some(pt::StorageLocation::Calldata(Default::default())),
1735 name: None,
1736 annotation: None,
1737 } => "uint256 calldata",
1738 pt::Parameter {
1739 ty: expr_ty!(bytes),
1740 storage: None,
1741 name: Some(id("my_seed")),
1742 annotation: Some(Annotation {
1743 loc: Loc::Builtin,
1744 id: id("name"),
1745 value: None,
1746 }),
1747 } => "@name bytes my_seed",
1748
1749 pt::StringLiteral {
1750 unicode: false,
1751 string: "string".into(),
1752 } => "\"string\"",
1753 pt::StringLiteral {
1754 unicode: true,
1755 string: "string".into(),
1756 } => "unicode\"string\"",
1757
1758 pt::UsingFunction {
1759 path: idp!["id", "path"],
1760 oper: None,
1761 } => "id.path",
1762 pt::UsingFunction {
1763 path: idp!["id", "path"],
1764 oper: Some(pt::UserDefinedOperator::Add),
1765 } => "id.path as +",
1766
1767 pt::VariableDeclaration {
1768 ty: expr_ty!(uint256),
1769 storage: None,
1770 name: None,
1771 } => "uint256",
1772 pt::VariableDeclaration {
1773 ty: expr_ty!(uint256),
1774 storage: None,
1775 name: Some(id("name")),
1776 } => "uint256 name",
1777 pt::VariableDeclaration {
1778 ty: expr_ty!(uint256),
1779 storage: Some(pt::StorageLocation::Calldata(Default::default())),
1780 name: Some(id("name")),
1781 } => "uint256 calldata name",
1782 pt::VariableDeclaration {
1783 ty: expr_ty!(uint256),
1784 storage: Some(pt::StorageLocation::Calldata(Default::default())),
1785 name: None,
1786 } => "uint256 calldata",
1787
1788 pt::VariableDefinition {
1789 ty: expr_ty!(uint256),
1790 attrs: vec![],
1791 name: None,
1792 initializer: None,
1793 } => "uint256;",
1794 pt::VariableDefinition {
1795 ty: expr_ty!(uint256),
1796 attrs: vec![],
1797 name: Some(id("name")),
1798 initializer: None,
1799 } => "uint256 name;",
1800 pt::VariableDefinition {
1801 ty: expr_ty!(uint256),
1802 attrs: vec![],
1803 name: Some(id("name")),
1804 initializer: Some(expr!(value)),
1805 } => "uint256 name = value;",
1806 pt::VariableDefinition {
1807 ty: expr_ty!(uint256),
1808 attrs: vec![pt::VariableAttribute::Constant(loc!())],
1809 name: Some(id("name")),
1810 initializer: Some(expr!(value)),
1811 } => "uint256 constant name = value;",
1812 pt::VariableDefinition {
1813 ty: expr_ty!(uint256),
1814 attrs: vec![
1815 pt::VariableAttribute::Visibility(pt::Visibility::Public(None)),
1816 pt::VariableAttribute::Constant(loc!())
1817 ],
1818 name: Some(id("name")),
1819 initializer: Some(expr!(value)),
1820 } => "uint256 public constant name = value;",
1821
1822 pt::YulTypedIdentifier {
1823 id: id("name"),
1824 ty: None,
1825 } => "name",
1826 pt::YulTypedIdentifier {
1827 id: id("name"),
1828 ty: Some(id("uint256")),
1829 } => "name: uint256",
1830 ];
1831 }
1832
1833 #[test]
1834 fn display_structs_complex() {
1835 struct_tests![
1836 pt::ContractDefinition {
1837 ty: pt::ContractTy::Contract(loc!()),
1838 name: Some(id("name")),
1839 base: vec![],
1840 layout: None,
1841 parts: vec![],
1842 } => "contract name {}",
1843 pt::ContractDefinition {
1844 ty: pt::ContractTy::Contract(loc!()),
1845 name: Some(id("name")),
1846 base: vec![pt::Base {
1847 loc: loc!(),
1848 name: idp!("base"),
1849 args: None
1850 }],
1851 layout: None,
1852 parts: vec![],
1853 } => "contract name base {}",
1854 pt::ContractDefinition {
1855 ty: pt::ContractTy::Contract(loc!()),
1856 name: Some(id("name")),
1857 base: vec![pt::Base {
1858 loc: loc!(),
1859 name: idp!("base"),
1860 args: Some(vec![])
1861 }],
1862 layout: None,
1863 parts: vec![],
1864 } => "contract name base() {}",
1865 pt::ContractDefinition {
1866 ty: pt::ContractTy::Contract(loc!()),
1867 name: Some(id("name")),
1868 base: vec![pt::Base {
1869 loc: loc!(),
1870 name: idp!("base"),
1871 args: Some(vec![expr!(expr)])
1872 }],
1873 layout: None,
1874 parts: vec![],
1875 } => "contract name base(expr) {}",
1876 pt::ContractDefinition {
1877 ty: pt::ContractTy::Contract(loc!()),
1878 name: Some(id("name")),
1879 base: vec![
1880 pt::Base {
1881 loc: loc!(),
1882 name: idp!("base1"),
1883 args: None
1884 },
1885 pt::Base {
1886 loc: loc!(),
1887 name: idp!("base2"),
1888 args: None
1889 },
1890 ],
1891 layout: None,
1892 parts: vec![],
1893 } => "contract name base1 base2 {}",
1894
1895 pt::EnumDefinition {
1896 name: Some(id("name")),
1897 values: vec![]
1898 } => "enum name {}",
1899 pt::EnumDefinition {
1900 name: Some(id("name")),
1901 values: vec![Some(id("variant"))]
1902 } => "enum name {variant}",
1903 pt::EnumDefinition {
1904 name: Some(id("name")),
1905 values: vec![
1906 Some(id("variant1")),
1907 Some(id("variant2")),
1908 ]
1909 } => "enum name {variant1, variant2}",
1910
1911 pt::ErrorDefinition {
1912 keyword: expr!(error),
1913 name: Some(id("name")),
1914 fields: vec![],
1915 } => "error name();",
1916 pt::ErrorDefinition {
1917 keyword: expr!(error),
1918 name: Some(id("name")),
1919 fields: vec![pt::ErrorParameter {
1920 loc: loc!(),
1921 ty: expr_ty!(uint256),
1922 name: None,
1923 }],
1924 } => "error name(uint256);",
1925
1926 pt::EventDefinition {
1927 name: Some(id("name")),
1928 fields: vec![],
1929 anonymous: false,
1930 } => "event name();",
1931 pt::EventDefinition {
1932 name: Some(id("name")),
1933 fields: vec![pt::EventParameter {
1934 loc: loc!(),
1935 ty: expr_ty!(uint256),
1936 indexed: false,
1937 name: None,
1938 }],
1939 anonymous: false,
1940 } => "event name(uint256);",
1941 pt::EventDefinition {
1942 name: Some(id("name")),
1943 fields: vec![pt::EventParameter {
1944 loc: loc!(),
1945 ty: expr_ty!(uint256),
1946 indexed: true,
1947 name: None,
1948 }],
1949 anonymous: false,
1950 } => "event name(uint256 indexed);",
1951 pt::EventDefinition {
1952 name: Some(id("name")),
1953 fields: vec![],
1954 anonymous: true,
1955 } => "event name() anonymous;",
1956
1957 pt::FunctionDefinition {
1958 loc_prototype: loc!(),
1959 ty: pt::FunctionTy::Function,
1960 name: Some(id("name")),
1961 name_loc: loc!(),
1962 params: vec![],
1963 attributes: vec![],
1964 return_not_returns: None,
1965 returns: vec![],
1966 body: None,
1967 } => "function name();",
1968 pt::FunctionDefinition {
1969 loc_prototype: loc!(),
1970 ty: pt::FunctionTy::Function,
1971 name: Some(id("name")),
1972 name_loc: loc!(),
1973 params: vec![],
1974 attributes: vec![],
1975 return_not_returns: None,
1976 returns: vec![],
1977 body: Some(stmt!({})),
1978 } => "function name() {}",
1979 pt::FunctionDefinition {
1980 loc_prototype: loc!(),
1981 ty: pt::FunctionTy::Function,
1982 name: Some(id("name")),
1983 name_loc: loc!(),
1984 params: vec![],
1985 attributes: vec![],
1986 return_not_returns: None,
1987 returns: vec![(loc!(), Some(param!(uint256)))],
1988 body: Some(stmt!({})),
1989 } => "function name() returns (uint256) {}",
1990 pt::FunctionDefinition {
1991 loc_prototype: loc!(),
1992 ty: pt::FunctionTy::Function,
1993 name: Some(id("name")),
1994 name_loc: loc!(),
1995 params: vec![],
1996 attributes: vec![pt::FunctionAttribute::Virtual(loc!())],
1997 return_not_returns: None,
1998 returns: vec![(loc!(), Some(param!(uint256)))],
1999 body: Some(stmt!({})),
2000 } => "function name() virtual returns (uint256) {}",
2001
2002 pt::StructDefinition {
2003 name: Some(id("name")),
2004 fields: vec![],
2005 } => "struct name {}",
2006 pt::StructDefinition {
2007 name: Some(id("name")),
2008 fields: vec![pt::VariableDeclaration {
2009 loc: loc!(),
2010 ty: expr_ty!(uint256),
2011 storage: None,
2012 name: Some(id("a")),
2013 }],
2014 } => "struct name {uint256 a;}",
2015 pt::StructDefinition {
2016 name: Some(id("name")),
2017 fields: vec![
2018 pt::VariableDeclaration {
2019 loc: loc!(),
2020 ty: expr_ty!(uint256),
2021 storage: None,
2022 name: Some(id("a")),
2023 },
2024 pt::VariableDeclaration {
2025 loc: loc!(),
2026 ty: expr_ty!(uint256),
2027 storage: None,
2028 name: Some(id("b")),
2029 }
2030 ],
2031 } => "struct name {uint256 a; uint256 b;}",
2032
2033 pt::TypeDefinition {
2034 name: id("MyType"),
2035 ty: expr_ty!(uint256),
2036 } => "type MyType is uint256;",
2037
2038 pt::Using {
2039 list: pt::UsingList::Library(idp!["id", "path"]),
2040 ty: None,
2041 global: None,
2042 } => "using id.path for *;",
2043 pt::Using {
2044 list: pt::UsingList::Library(idp!["id", "path"]),
2045 ty: Some(expr_ty!(uint256)),
2046 global: None,
2047 } => "using id.path for uint256;",
2048 pt::Using {
2049 list: pt::UsingList::Library(idp!["id", "path"]),
2050 ty: Some(expr_ty!(uint256)),
2051 global: Some(id("global")),
2052 } => "using id.path for uint256 global;",
2053 pt::Using {
2054 list: pt::UsingList::Functions(vec![]),
2055 ty: None,
2056 global: None,
2057 } => "using {} for *;",
2058 pt::Using {
2059 list: pt::UsingList::Functions(vec![
2060 pt::UsingFunction {
2061 loc: loc!(),
2062 path: idp!("id", "path"),
2063 oper: None,
2064 }
2065 ]),
2066 ty: None,
2067 global: None,
2068 } => "using {id.path} for *;",
2069 pt::Using {
2070 list: pt::UsingList::Functions(vec![
2071 pt::UsingFunction {
2072 loc: loc!(),
2073 path: idp!("id", "path"),
2074 oper: Some(pt::UserDefinedOperator::Add),
2075 }
2076 ]),
2077 ty: Some(expr_ty!(uint256)),
2078 global: None,
2079 } => "using {id.path as +} for uint256;",
2080 pt::Using {
2081 list: pt::UsingList::Functions(vec![
2082 pt::UsingFunction {
2083 loc: loc!(),
2084 path: idp!("id", "path1"),
2085 oper: None,
2086 },
2087 pt::UsingFunction {
2088 loc: loc!(),
2089 path: idp!("id", "path2"),
2090 oper: None,
2091 }
2092 ]),
2093 ty: Some(expr_ty!(uint256)),
2094 global: Some(id("global")),
2095 } => "using {id.path1, id.path2} for uint256 global;",
2096
2097 pt::YulBlock {
2098 statements: vec![]
2099 } => "{}",
2100
2101 pt::YulFor {
2102 init_block: yul_block(),
2103 condition: yexpr!(cond),
2104 post_block: yul_block(),
2105 execution_block: yul_block(),
2106 } => "for {} cond {} {}",
2107
2108 pt::YulFunctionCall {
2109 id: id("name"),
2110 arguments: vec![],
2111 } => "name()",
2112 pt::YulFunctionCall {
2113 id: id("name"),
2114 arguments: vec![yexpr!(arg)],
2115 } => "name(arg)",
2116 pt::YulFunctionCall {
2117 id: id("name"),
2118 arguments: vec![yexpr!(arg1), yexpr!(arg2)],
2119 } => "name(arg1, arg2)",
2120
2121 pt::YulFunctionDefinition {
2122 id: id("name"),
2123 params: vec![],
2124 returns: vec![],
2125 body: yul_block(),
2126 } => "function name() {}",
2127 pt::YulFunctionDefinition {
2128 id: id("name"),
2129 params: vec![yid!(param1: a), yid!(param2: b)],
2130 returns: vec![],
2131 body: yul_block(),
2132 } => "function name(param1: a, param2: b) {}",
2133 pt::YulFunctionDefinition {
2134 id: id("name"),
2135 params: vec![yid!(param1: a), yid!(param2: b)],
2136 returns: vec![yid!(ret1: c), yid!(ret2: d)],
2137 body: yul_block(),
2138 } => "function name(param1: a, param2: b) -> (ret1: c, ret2: d) {}",
2139
2140 pt::YulSwitch {
2141 condition: yexpr!(cond),
2142 cases: vec![pt::YulSwitchOptions::Case(loc!(), yexpr!(expr), yul_block())],
2143 default: None,
2144 } => "switch cond case expr {}",
2145 pt::YulSwitch {
2146 condition: yexpr!(cond),
2147 cases: vec![
2148 pt::YulSwitchOptions::Case(loc!(), yexpr!(0), yul_block()),
2149 pt::YulSwitchOptions::Case(loc!(), yexpr!(1), yul_block()),
2150 ],
2151 default: None,
2152 } => "switch cond case 0 {} case 1 {}",
2153 pt::YulSwitch {
2154 condition: yexpr!(cond),
2155 cases: vec![pt::YulSwitchOptions::Case(loc!(), yexpr!(0), yul_block())],
2156 default: Some(pt::YulSwitchOptions::Default(loc!(), yul_block())),
2157 } => "switch cond case 0 {} default {}",
2158 ];
2159 }
2160
2161 #[test]
2162 fn display_enums() {
2163 enum_tests![
2164 pt::CatchClause: {
2166 pt::CatchClause::Named(loc!(), id("Error"), param!(string memory reason), stmt!({}))
2167 => "catch Error(string memory reason) {}",
2168 pt::CatchClause::Named(loc!(), id("Panic"), param!(uint256 errorCode), stmt!({}))
2169 => "catch Panic(uint256 errorCode) {}",
2170
2171 pt::CatchClause::Simple(loc!(), None, stmt!({})) => "catch {}",
2172 pt::CatchClause::Simple(loc!(), Some(param!(uint256)), stmt!({}))
2173 => "catch (uint256) {}",
2174 pt::CatchClause::Simple(loc!(), Some(param!(bytes memory data)), stmt!({}))
2175 => "catch (bytes memory data) {}",
2176 }
2177
2178 pt::Comment: {
2179 pt::Comment::Line(loc!(), "// line".into()) => "// line",
2180 pt::Comment::Block(loc!(), "/* \nblock\n*/".into()) => "/* \nblock\n*/",
2181 pt::Comment::DocLine(loc!(), "/// doc line".into()) => "/// doc line",
2182 pt::Comment::DocBlock(loc!(), "/**\n * doc block\n */".into()) => "/**\n * doc block\n */",
2183 }
2184
2185 pt::ContractPart: {
2187 pt::ContractPart::StraySemicolon(loc!()) => ";",
2188 }
2189
2190 pt::ContractTy: {
2191 pt::ContractTy::Abstract(loc!()) => "abstract contract",
2192 pt::ContractTy::Contract(loc!()) => "contract",
2193 pt::ContractTy::Interface(loc!()) => "interface",
2194 pt::ContractTy::Library(loc!()) => "library",
2195 }
2196
2197 pt::Expression: {
2198 pt::Expression::New(loc!(), Box::new(expr_ty!(uint256))) => "new uint256",
2199 pt::Expression::Delete(loc!(), Box::new(expr_ty!(uint256))) => "delete uint256",
2200
2201 pt::Expression::Type(loc!(), ty!(uint256)) => "uint256",
2202 pt::Expression::Variable(id("myVar")) => "myVar",
2203
2204 pt::Expression::ArrayLiteral(loc!(), vec![expr!(1), expr!(2)]) => "[1, 2]",
2205
2206 pt::Expression::ArraySubscript(loc!(), Box::new(expr!(arr)), None) => "arr[]",
2207 pt::Expression::ArraySubscript(loc!(), Box::new(expr!(arr)), Some(Box::new(expr!(0)))) => "arr[0]",
2208 pt::Expression::ArraySlice(loc!(), Box::new(expr!(arr)), None, None) => "arr[:]",
2209 pt::Expression::ArraySlice(loc!(), Box::new(expr!(arr)), Some(Box::new(expr!(left))), None)
2210 => "arr[left:]",
2211 pt::Expression::ArraySlice(loc!(), Box::new(expr!(arr)), None, Some(Box::new(expr!(right))))
2212 => "arr[:right]",
2213 pt::Expression::ArraySlice(loc!(), Box::new(expr!(arr)), Some(Box::new(expr!(left))), Some(Box::new(expr!(right))))
2214 => "arr[left:right]",
2215
2216 pt::Expression::MemberAccess(loc!(), Box::new(expr!(struct)), id("access")) => "struct.access",
2217
2218 pt::Expression::Parenthesis(loc!(), Box::new(expr!(var))) => "(var)",
2219 pt::Expression::List(loc!(), vec![]) => "()",
2220 pt::Expression::List(loc!(), vec![(loc!(), Some(param!(address)))])
2221 => "(address)",
2222 pt::Expression::List(loc!(), vec![(loc!(), Some(param!(address))), (loc!(), Some(param!(uint256)))])
2223 => "(address, uint256)",
2224
2225 pt::Expression::AddressLiteral(loc!(), "0x1234".into()) => "0x1234",
2226 pt::Expression::StringLiteral(vec![lit!(unicode "¹²³")]) => "unicode\"¹²³\"",
2227 pt::Expression::HexLiteral(vec![lit!(hex "00112233")]) => "hex\"00112233\"",
2228 pt::Expression::BoolLiteral(loc!(), true) => "true",
2229 pt::Expression::BoolLiteral(loc!(), false) => "false",
2230
2231 pt::Expression::HexNumberLiteral(loc!(), "0x1234".into(), None) => "0x1234",
2232 pt::Expression::HexNumberLiteral(loc!(), "0x1234".into(), Some(id("gwei"))) => "0x1234 gwei",
2233 pt::Expression::NumberLiteral(loc!(), "_123_4_".into(), "".into(), None)
2234 => "1234",
2235 pt::Expression::NumberLiteral(loc!(), "_1_234_".into(), "_2".into(), None)
2236 => "1234e2",
2237 pt::Expression::NumberLiteral(loc!(), "_1_23_4".into(), "".into(), Some(id("gwei")))
2238 => "1234 gwei",
2239 pt::Expression::NumberLiteral(loc!(), "1_23_4_".into(), "2_".into(), Some(id("gwei")))
2240 => "1234e2 gwei",
2241 pt::Expression::RationalNumberLiteral(loc!(), "1_23_4_".into(), "".into(), "".into(), None)
2242 => "1234.0",
2243 pt::Expression::RationalNumberLiteral(loc!(), "_1_23_4".into(), "0".into(), "_2".into(), None)
2244 => "1234.0e2",
2245 pt::Expression::RationalNumberLiteral(loc!(), "_1_234_".into(), "09".into(), "".into(), Some(id("gwei")))
2246 => "1234.09 gwei",
2247 pt::Expression::RationalNumberLiteral(loc!(), "_123_4_".into(), "90".into(), "2_".into(), Some(id("gwei")))
2248 => "1234.9e2 gwei",
2249
2250 pt::Expression::FunctionCall(loc!(), Box::new(expr!(func)), vec![]) => "func()",
2251 pt::Expression::FunctionCall(loc!(), Box::new(expr!(func)), vec![expr!(arg)])
2252 => "func(arg)",
2253 pt::Expression::FunctionCall(loc!(), Box::new(expr!(func)), vec![expr!(arg1), expr!(arg2)])
2254 => "func(arg1, arg2)",
2255 pt::Expression::FunctionCallBlock(loc!(), Box::new(expr!(func)), Box::new(stmt!({})))
2256 => "func{}",
2257 pt::Expression::NamedFunctionCall(loc!(), Box::new(expr!(func)), vec![])
2258 => "func({})",
2259 pt::Expression::NamedFunctionCall(loc!(), Box::new(expr!(func)), vec![pt::NamedArgument {
2260 loc: loc!(),
2261 name: id("arg"),
2262 expr: expr!(value),
2263 }]) => "func({arg: value})",
2264 pt::Expression::NamedFunctionCall(loc!(), Box::new(expr!(func)), vec![
2265 pt::NamedArgument {
2266 loc: loc!(),
2267 name: id("arg1"),
2268 expr: expr!(value1),
2269 },
2270 pt::NamedArgument {
2271 loc: loc!(),
2272 name: id("arg2"),
2273 expr: expr!(value2),
2274 }
2275 ]) => "func({arg1: value1, arg2: value2})",
2276
2277 pt::Expression::PreIncrement(loc!(), var("a")) => "++a",
2278 pt::Expression::PostIncrement(loc!(), var("a")) => "a++",
2279 pt::Expression::PreDecrement(loc!(), var("a")) => "--a",
2280 pt::Expression::PostDecrement(loc!(), var("a")) => "a--",
2281 pt::Expression::Not(loc!(), var("a")) => "!a",
2282 pt::Expression::BitwiseNot(loc!(), var("a")) => "~a",
2283 pt::Expression::UnaryPlus(loc!(), var("a")) => "+a",
2284 pt::Expression::Negate(loc!(), var("a")) => "-a",
2285
2286 pt::Expression::Add(loc!(), var("a"), var("b")) => "a + b",
2287 pt::Expression::Subtract(loc!(), var("a"), var("b")) => "a - b",
2288 pt::Expression::Power(loc!(), var("a"), var("b")) => "a ** b",
2289 pt::Expression::Multiply(loc!(), var("a"), var("b")) => "a * b",
2290 pt::Expression::Divide(loc!(), var("a"), var("b")) => "a / b",
2291 pt::Expression::Modulo(loc!(), var("a"), var("b")) => "a % b",
2292 pt::Expression::ShiftLeft(loc!(), var("a"), var("b")) => "a << b",
2293 pt::Expression::ShiftRight(loc!(), var("a"), var("b")) => "a >> b",
2294 pt::Expression::BitwiseAnd(loc!(), var("a"), var("b")) => "a & b",
2295 pt::Expression::BitwiseXor(loc!(), var("a"), var("b")) => "a ^ b",
2296 pt::Expression::BitwiseOr(loc!(), var("a"), var("b")) => "a | b",
2297 pt::Expression::Less(loc!(), var("a"), var("b")) => "a < b",
2298 pt::Expression::More(loc!(), var("a"), var("b")) => "a > b",
2299 pt::Expression::LessEqual(loc!(), var("a"), var("b")) => "a <= b",
2300 pt::Expression::MoreEqual(loc!(), var("a"), var("b")) => "a >= b",
2301 pt::Expression::And(loc!(), var("a"), var("b")) => "a && b",
2302 pt::Expression::Or(loc!(), var("a"), var("b")) => "a || b",
2303 pt::Expression::Equal(loc!(), var("a"), var("b")) => "a == b",
2304 pt::Expression::NotEqual(loc!(), var("a"), var("b")) => "a != b",
2305
2306 pt::Expression::Assign(loc!(), var("a"), var("b")) => "a = b",
2307 pt::Expression::AssignOr(loc!(), var("a"), var("b")) => "a |= b",
2308 pt::Expression::AssignAnd(loc!(), var("a"), var("b")) => "a &= b",
2309 pt::Expression::AssignXor(loc!(), var("a"), var("b")) => "a ^= b",
2310 pt::Expression::AssignShiftLeft(loc!(), var("a"), var("b")) => "a <<= b",
2311 pt::Expression::AssignShiftRight(loc!(), var("a"), var("b")) => "a >>= b",
2312 pt::Expression::AssignAdd(loc!(), var("a"), var("b")) => "a += b",
2313 pt::Expression::AssignSubtract(loc!(), var("a"), var("b")) => "a -= b",
2314 pt::Expression::AssignMultiply(loc!(), var("a"), var("b")) => "a *= b",
2315 pt::Expression::AssignDivide(loc!(), var("a"), var("b")) => "a /= b",
2316 pt::Expression::AssignModulo(loc!(), var("a"), var("b")) => "a %= b",
2317 }
2318
2319 pt::FunctionAttribute: {
2320 pt::FunctionAttribute::Virtual(loc!()) => "virtual",
2321 pt::FunctionAttribute::Immutable(loc!()) => "immutable",
2322
2323 pt::FunctionAttribute::Override(loc!(), vec![]) => "override",
2324 pt::FunctionAttribute::Override(loc!(), vec![idp!["a", "b"]]) => "override(a.b)",
2325 pt::FunctionAttribute::Override(loc!(), vec![idp!["a", "b"], idp!["c", "d"]])
2326 => "override(a.b, c.d)",
2327 }
2328
2329 pt::FunctionTy: {
2330 pt::FunctionTy::Constructor => "constructor",
2331 pt::FunctionTy::Function => "function",
2332 pt::FunctionTy::Fallback => "fallback",
2333 pt::FunctionTy::Receive => "receive",
2334 pt::FunctionTy::Modifier => "modifier",
2335 }
2336
2337 pt::Import: {
2338 pt::Import::Plain(pt::ImportPath::Filename(lit!("path/to/import")), loc!()) => "import \"path/to/import\";",
2339
2340 pt::Import::GlobalSymbol(pt::ImportPath::Filename(lit!("path-to-import")), id("ImportedContract"), loc!())
2341 => "import \"path-to-import\" as ImportedContract;",
2342
2343 pt::Import::Rename(pt::ImportPath::Filename(lit!("import\\to\\path")), vec![], loc!())
2344 => "import {} from \"import\\to\\path\";",
2345 pt::Import::Rename(pt::ImportPath::Filename(lit!("import\\to\\path")), vec![(id("A"), None), (id("B"), Some(id("C")))], loc!())
2346 => "import {A, B as C} from \"import\\to\\path\";",
2347
2348 pt::Import::Plain(pt::ImportPath::Path(idp!("std", "stub")), loc!()) => "import std.stub;",
2349
2350 pt::Import::GlobalSymbol(pt::ImportPath::Path(idp!("a", "b", "c")), id("ImportedContract"), loc!())
2351 => "import a.b.c as ImportedContract;",
2352
2353 pt::Import::Rename(pt::ImportPath::Path(idp!("std", "stub")), vec![], loc!())
2354 => "import {} from std.stub;",
2355 pt::Import::Rename(pt::ImportPath::Path(idp!("std", "stub")), vec![(id("A"), None), (id("B"), Some(id("C")))], loc!())
2356 => "import {A, B as C} from std.stub;",
2357 }
2358
2359 pt::Mutability: {
2360 pt::Mutability::Pure(loc!()) => "pure",
2361 pt::Mutability::View(loc!()) => "view",
2362 pt::Mutability::Constant(loc!()) => "view",
2363 pt::Mutability::Payable(loc!()) => "payable",
2364 }
2365
2366 pt::SourceUnitPart: {
2367 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Identifier(loc!(), None, None).into()) => "pragma;",
2370 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Identifier(loc!(), Some(id("solidity")), None).into())
2371 => "pragma solidity;",
2372 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::StringLiteral(loc!(), id("abi"), lit!("v2")).into())
2373 => "pragma abi \"v2\";",
2374 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Version(loc!(), id("solidity"), vec![plain_version!("0", "8", "0")]).into())
2375 => "pragma solidity 0.8.0;",
2376 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Version(loc!(), id("solidity"), vec![
2377 op_version!(pt::VersionOp::Exact, "0", "5", "16"),
2378 op_version!(pt::VersionOp::GreaterEq, "0", "5"),
2379 op_version!(pt::VersionOp::Greater, "0"),
2380 op_version!(pt::VersionOp::Less, "1"),
2381 op_version!(pt::VersionOp::LessEq, "1"),
2382 op_version!(pt::VersionOp::Caret, "0", "5", "16"),
2383 op_version!(pt::VersionOp::Wildcard, "5", "5")]
2384 ).into())
2385 => "pragma solidity =0.5.16 >=0.5 >0 <1 <=1 ^0.5.16 *5.5;",
2386 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Version(loc!(), id("solidity"), vec![or_version!(plain_version!("0"), op_version!(pt::VersionOp::Caret, "1", "0"))]).into())
2387 => "pragma solidity 0 || ^1.0;",
2388 pt::SourceUnitPart::PragmaDirective(pt::PragmaDirective::Version(loc!(), id("solidity"), vec![range_version!(version!["0"], version!["1", "0"])]).into())
2389 => "pragma solidity 0 - 1.0;",
2390 pt::SourceUnitPart::StraySemicolon(loc!()) => ";",
2391 }
2392
2393 pt::Statement: {
2394 pt::Statement::Assembly {
2395 loc: loc!(),
2396 dialect: None,
2397 flags: None,
2398 block: yul_block(),
2399 } => "assembly {}",
2400 pt::Statement::Assembly {
2401 loc: loc!(),
2402 dialect: None,
2403 flags: Some(vec![lit!("memory-safe")]),
2404 block: yul_block(),
2405 } => "assembly (\"memory-safe\") {}",
2406 pt::Statement::Assembly {
2407 loc: loc!(),
2408 dialect: None,
2409 flags: Some(vec![lit!("memory-safe"), lit!("second-flag")]),
2410 block: yul_block(),
2411 } => "assembly (\"memory-safe\", \"second-flag\") {}",
2412
2413 pt::Statement::Args(loc!(), vec![]) => "{}",
2414 pt::Statement::Args(loc!(), vec![
2415 pt::NamedArgument {
2416 loc: loc!(),
2417 name: id("name"),
2418 expr: expr!(value),
2419 },
2420 ]) => "{name: value}",
2421 pt::Statement::Args(loc!(), vec![
2422 pt::NamedArgument {
2423 loc: loc!(),
2424 name: id("name1"),
2425 expr: expr!(value1),
2426 },
2427 pt::NamedArgument {
2428 loc: loc!(),
2429 name: id("name2"),
2430 expr: expr!(value2),
2431 },
2432 ]) => "{name1: value1, name2: value2}",
2433
2434 pt::Statement::If(loc!(), expr!(true), Box::new(stmt!({})), None) => "if (true) {}",
2435 pt::Statement::If(loc!(), expr!(true), Box::new(stmt!({})), Some(Box::new(stmt!({}))))
2436 => "if (true) {} else {}",
2437
2438 pt::Statement::While(loc!(), expr!(true), Box::new(stmt!({}))) => "while (true) {}",
2439
2440 pt::Statement::Expression(loc!(), expr!(true)) => "true;",
2441
2442 pt::Statement::VariableDefinition(loc!(), pt::VariableDeclaration {
2443 loc: loc!(),
2444 ty: expr_ty!(uint256),
2445 storage: None,
2446 name: Some(id("a")),
2447 }, None) => "uint256 a;",
2448 pt::Statement::VariableDefinition(loc!(), pt::VariableDeclaration {
2449 loc: loc!(),
2450 ty: expr_ty!(uint256),
2451 storage: None,
2452 name: Some(id("a")),
2453 }, Some(expr!(0))) => "uint256 a = 0;",
2454
2455 pt::Statement::For(loc!(), None, None, None, Some(Box::new(stmt!({}))))
2456 => "for (;;) {}",
2457 pt::Statement::For(loc!(), Some(Box::new(pt::Statement::VariableDefinition(
2458 loc!(),
2459 pt::VariableDeclaration {
2460 loc: loc!(),
2461 ty: expr_ty!(uint256),
2462 storage: None,
2463 name: Some(id("a")),
2464 },
2465 None
2466 ))), None, None, Some(Box::new(stmt!({}))))
2467 => "for (uint256 a;;) {}",
2468 pt::Statement::For(loc!(), None, Some(Box::new(expr!(true))), None, Some(Box::new(stmt!({}))))
2469 => "for (; true;) {}",
2470 pt::Statement::For(
2471 loc!(),
2472 None,
2473 Some(Box::new(expr!(true))),
2474 Some(Box::new(expr!(++i))),
2475 Some(Box::new(stmt!({})))
2476 ) => "for (; true; ++i) {}",
2477
2478 pt::Statement::DoWhile(loc!(), Box::new(stmt!({})), expr!(true))
2479 => "do {} while (true);",
2480
2481 pt::Statement::Continue(loc!()) => "continue;",
2482 pt::Statement::Break(loc!()) => "break;",
2483
2484 pt::Statement::Return(loc!(), None) => "return;",
2485 pt::Statement::Return(loc!(), Some(expr!(true))) => "return true;",
2486
2487 pt::Statement::Revert(loc!(), None, vec![]) => "revert();",
2488 pt::Statement::Revert(loc!(), None, vec![expr!("error")])
2489 => "revert(\"error\");",
2490 pt::Statement::Revert(loc!(), Some(idp!("my", "error")), vec![expr!("error")])
2491 => "revert my.error(\"error\");",
2492
2493 pt::Statement::RevertNamedArgs(loc!(), None, vec![]) => "revert();",
2494 pt::Statement::RevertNamedArgs(loc!(), None, vec![pt::NamedArgument {
2495 loc: loc!(),
2496 name: id("name"),
2497 expr: expr!(value),
2498 }]) => "revert({name: value});",
2499 pt::Statement::RevertNamedArgs(loc!(), Some(idp!("my", "error")), vec![pt::NamedArgument {
2500 loc: loc!(),
2501 name: id("name"),
2502 expr: expr!(value),
2503 }]) => "revert my.error({name: value});",
2504
2505 pt::Statement::Emit(loc!(), expr!(true)) => "emit true;",
2506
2507 pt::Statement::Try(loc!(), expr!(true), None, vec![]) => "try true",
2508 pt::Statement::Try(loc!(), expr!(true), None, vec![pt::CatchClause::Simple(loc!(), None, stmt!({}))])
2509 => "try true catch {}",
2510 pt::Statement::Try(loc!(), expr!(true), Some((vec![], Box::new(stmt!({})))), vec![])
2511 => "try true returns () {}",
2512 pt::Statement::Try(
2513 loc!(),
2514 expr!(true),
2515 Some((vec![], Box::new(stmt!({})))),
2516 vec![pt::CatchClause::Simple(loc!(), None, stmt!({}))]
2517 ) => "try true returns () {} catch {}",
2518 pt::Statement::Try(
2519 loc!(),
2520 expr!(true),
2521 Some((vec![(loc!(), Some(param!(uint256 a)))], Box::new(stmt!({})))),
2522 vec![pt::CatchClause::Simple(loc!(), None, stmt!({}))]
2523 ) => "try true returns (uint256 a) {} catch {}",
2524 }
2525
2526 pt::StorageLocation: {
2527 pt::StorageLocation::Memory(loc!()) => "memory",
2528 pt::StorageLocation::Storage(loc!()) => "storage",
2529 pt::StorageLocation::Calldata(loc!()) => "calldata",
2530 pt::StorageLocation::Transient(loc!()) => "transient",
2531 }
2532
2533 pt::Type: {
2534 pt::Type::Address => "address",
2535 pt::Type::AddressPayable => "address payable",
2536 pt::Type::Payable => "payable",
2537 pt::Type::Bool => "bool",
2538 pt::Type::String => "string",
2539 pt::Type::Int(256) => "int256",
2540 pt::Type::Uint(256) => "uint256",
2541 pt::Type::Bytes(32) => "bytes32",
2542 pt::Type::Rational => "fixed",
2543 pt::Type::DynamicBytes => "bytes",
2544
2545 pt::Type::Mapping {
2546 loc: loc!(),
2547 key: Box::new(expr_ty!(uint256)),
2548 key_name: None,
2549 value: Box::new(expr_ty!(uint256)),
2550 value_name: None,
2551 } => "mapping(uint256 => uint256)",
2552 pt::Type::Mapping {
2553 loc: loc!(),
2554 key: Box::new(expr_ty!(uint256)),
2555 key_name: Some(id("key")),
2556 value: Box::new(expr_ty!(uint256)),
2557 value_name: None,
2558 } => "mapping(uint256 key => uint256)",
2559 pt::Type::Mapping {
2560 loc: loc!(),
2561 key: Box::new(expr_ty!(uint256)),
2562 key_name: Some(id("key")),
2563 value: Box::new(expr_ty!(uint256)),
2564 value_name: Some(id("value")),
2565 } => "mapping(uint256 key => uint256 value)",
2566
2567 pt::Type::Function {
2568 params: vec![],
2569 attributes: vec![],
2570 returns: None
2571 } => "function ()",
2572 pt::Type::Function {
2573 params: vec![(loc!(), Some(param!(uint256)))],
2574 attributes: vec![],
2575 returns: None
2576 } => "function (uint256)",
2577 pt::Type::Function {
2578 params: vec![(loc!(), Some(param!(uint256))), (loc!(), Some(param!(address)))],
2579 attributes: vec![],
2580 returns: None
2581 } => "function (uint256, address)",
2582 pt::Type::Function {
2583 params: vec![(loc!(), Some(param!(uint256)))],
2584 attributes: vec![pt::FunctionAttribute::Virtual(loc!())],
2585 returns: None
2586 } => "function (uint256) virtual",
2587 pt::Type::Function {
2588 params: vec![(loc!(), Some(param!(uint256)))],
2589 attributes: vec![pt::FunctionAttribute::Virtual(loc!()), pt::FunctionAttribute::Override(loc!(), vec![])],
2590 returns: None
2591 } => "function (uint256) virtual override",
2592 pt::Type::Function {
2593 params: vec![(loc!(), Some(param!(uint256)))],
2594 attributes: vec![pt::FunctionAttribute::Virtual(loc!()), pt::FunctionAttribute::Override(loc!(), vec![idp!["a", "b"]])],
2595 returns: None
2596 } => "function (uint256) virtual override(a.b)",
2597 pt::Type::Function {
2598 params: vec![(loc!(), Some(param!(uint256)))],
2599 attributes: vec![],
2600 returns: Some((vec![], vec![])),
2601 } => "function (uint256)",
2602 pt::Type::Function {
2603 params: vec![(loc!(), Some(param!(uint256)))],
2604 attributes: vec![],
2605 returns: Some((vec![(loc!(), Some(param!(uint256)))], vec![])),
2606 } => "function (uint256) returns (uint256)",
2607 pt::Type::Function {
2608 params: vec![(loc!(), Some(param!(uint256)))],
2609 attributes: vec![],
2610 returns: Some((vec![(loc!(), Some(param!(uint256))), (loc!(), Some(param!(address)))], vec![])),
2611 } => "function (uint256) returns (uint256, address)",
2612 }
2613
2614 pt::UserDefinedOperator: {
2615 pt::UserDefinedOperator::BitwiseAnd => "&",
2616 pt::UserDefinedOperator::BitwiseNot => "~",
2617 pt::UserDefinedOperator::Negate => "-",
2618 pt::UserDefinedOperator::BitwiseOr => "|",
2619 pt::UserDefinedOperator::BitwiseXor => "^",
2620 pt::UserDefinedOperator::Add => "+",
2621 pt::UserDefinedOperator::Divide => "/",
2622 pt::UserDefinedOperator::Modulo => "%",
2623 pt::UserDefinedOperator::Multiply => "*",
2624 pt::UserDefinedOperator::Subtract => "-",
2625 pt::UserDefinedOperator::Equal => "==",
2626 pt::UserDefinedOperator::More => ">",
2627 pt::UserDefinedOperator::MoreEqual => ">=",
2628 pt::UserDefinedOperator::Less => "<",
2629 pt::UserDefinedOperator::LessEqual => "<=",
2630 pt::UserDefinedOperator::NotEqual => "!=",
2631 }
2632
2633 pt::UsingList: {
2634 pt::UsingList::Library(idp!("id", "path")) => "id.path",
2635
2636 pt::UsingList::Functions(vec![]) => "{}",
2637 pt::UsingList::Functions(vec![
2638 pt::UsingFunction {
2639 loc: loc!(),
2640 path: idp!["id", "path"],
2641 oper: None,
2642 },
2643 pt::UsingFunction {
2644 loc: loc!(),
2645 path: idp!["id", "path"],
2646 oper: Some(pt::UserDefinedOperator::Add),
2647 }]) => "{id.path, id.path as +}",
2648 }
2649
2650 pt::VariableAttribute: {
2651 pt::VariableAttribute::Constant(loc!()) => "constant",
2652 pt::VariableAttribute::Immutable(loc!()) => "immutable",
2653
2654 pt::VariableAttribute::Override(loc!(), vec![]) => "override",
2655 pt::VariableAttribute::Override(loc!(), vec![idp!["a", "b"]]) => "override(a.b)",
2656 pt::VariableAttribute::Override(loc!(), vec![idp!["a", "b"], idp!["c", "d"]])
2657 => "override(a.b, c.d)",
2658 }
2659
2660 pt::Visibility: {
2661 pt::Visibility::Public(Some(loc!())) => "public",
2662 pt::Visibility::Internal(Some(loc!())) => "internal",
2663 pt::Visibility::Private(Some(loc!())) => "private",
2664 pt::Visibility::External(Some(loc!())) => "external",
2665 }
2666
2667 pt::YulExpression: {
2668 pt::YulExpression::BoolLiteral(loc!(), false, None) => "false",
2669 pt::YulExpression::BoolLiteral(loc!(), true, None) => "true",
2670 pt::YulExpression::BoolLiteral(loc!(), false, Some(id("name"))) => "false: name",
2671 pt::YulExpression::BoolLiteral(loc!(), true, Some(id("name"))) => "true: name",
2672
2673 pt::YulExpression::NumberLiteral(loc!(), "1234".into(), "".into(), None) => "1234",
2674 pt::YulExpression::NumberLiteral(loc!(), "1234".into(), "9".into(), None) => "1234e9",
2675 pt::YulExpression::NumberLiteral(loc!(), "1234".into(), "".into(), Some(id("name"))) => "1234: name",
2676 pt::YulExpression::NumberLiteral(loc!(), "1234".into(), "9".into(), Some(id("name"))) => "1234e9: name",
2677
2678 pt::YulExpression::HexNumberLiteral(loc!(), "0x1234".into(), None) => "0x1234",
2679 pt::YulExpression::HexNumberLiteral(loc!(), "0x1234".into(), Some(id("name"))) => "0x1234: name",
2680
2681 pt::YulExpression::HexStringLiteral(lit!(hex "1234"), None) => "hex\"1234\"",
2682 pt::YulExpression::HexStringLiteral(lit!(hex "1234"), Some(id("name"))) => "hex\"1234\": name",
2683
2684 pt::YulExpression::StringLiteral(lit!("1234"), None) => "\"1234\"",
2685 pt::YulExpression::StringLiteral(lit!("1234"), Some(id("name"))) => "\"1234\": name",
2686
2687 pt::YulExpression::Variable(id("name")) => "name",
2688
2689 pt::YulExpression::FunctionCall(Box::new(pt::YulFunctionCall {
2690 loc: loc!(),
2691 id: id("name"),
2692 arguments: vec![],
2693 })) => "name()",
2694
2695 pt::YulExpression::SuffixAccess(loc!(), Box::new(yexpr!(struct)), id("access"))
2696 => "struct.access",
2697 }
2698
2699 pt::YulStatement: {
2700 pt::YulStatement::Assign(loc!(), vec![yexpr!(var)], yexpr!(eq))
2703 => "var := eq",
2704 pt::YulStatement::Assign(loc!(), vec![yexpr!(a), yexpr!(b)], yexpr!(eq))
2705 => "a, b := eq",
2706
2707 pt::YulStatement::VariableDeclaration(loc!(), vec![yid!(var)], None)
2708 => "let var",
2709 pt::YulStatement::VariableDeclaration(loc!(), vec![yid!(a), yid!(b)], None)
2710 => "let a, b",
2711 pt::YulStatement::VariableDeclaration(loc!(), vec![yid!(var)], Some(yexpr!(eq)))
2712 => "let var := eq",
2713 pt::YulStatement::VariableDeclaration(loc!(), vec![yid!(a), yid!(b)], Some(yexpr!(eq)))
2714 => "let a, b := eq",
2715
2716 pt::YulStatement::If(loc!(), yexpr!(expr), yul_block()) => "if expr {}",
2717
2718 pt::YulStatement::Leave(loc!()) => "leave",
2719 pt::YulStatement::Break(loc!()) => "break",
2720 pt::YulStatement::Continue(loc!()) => "continue",
2721 }
2722
2723 pt::YulSwitchOptions: {
2724 pt::YulSwitchOptions::Case(loc!(), yexpr!(expr), yul_block()) => "case expr {}",
2725 pt::YulSwitchOptions::Default(loc!(), yul_block()) => "default {}",
2726 }
2727 ];
2728 }
2729}