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