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