traverse_solidity/
solidity_writer.rs

1//! Writes a Solidity AST to textual Solidity source code format.
2
3use crate::ast::*;
4use std::fmt::Write;
5
6const INDENT_STEP: &str = "    ";
7
8pub fn write_source_unit(source_unit: &SourceUnit) -> String {
9    let mut output = String::new();
10    let mut indent = String::new(); 
11
12    for item in &source_unit.items {
13        write_source_unit_item(&mut output, item, &mut indent);
14        writeln!(output).unwrap();
15    }
16
17    output.trim_end().to_string()
18}
19
20fn write_source_unit_item(output: &mut String, item: &SourceUnitItem, indent: &mut String) {
21    match item {
22        SourceUnitItem::Pragma(pragma) => write_pragma(output, pragma, indent),
23        SourceUnitItem::Import(import) => write_import(output, import, indent),
24        SourceUnitItem::Contract(contract) => write_contract(output, contract, indent),
25        SourceUnitItem::Interface(interface) => write_interface(output, interface, indent),
26        SourceUnitItem::Library(library) => write_library(output, library, indent),
27        SourceUnitItem::Function(function) => write_function(output, function, indent),
28        SourceUnitItem::ConstantVariable(var) => write_constant_variable(output, var, indent),
29        SourceUnitItem::Struct(struct_def) => write_struct(output, struct_def, indent),
30        SourceUnitItem::Enum(enum_def) => write_enum(output, enum_def, indent),
31        SourceUnitItem::Error(error_def) => write_error(output, error_def, indent),
32        SourceUnitItem::Event(event_def) => write_event(output, event_def, indent),
33        SourceUnitItem::Using(using_def) => write_using(output, using_def, indent),
34    }
35}
36
37fn write_pragma(output: &mut String, pragma: &PragmaDirective, indent: &str) {
38    write!(output, "{}pragma", indent).unwrap();
39    for token in &pragma.tokens {
40        write!(output, " {}", token).unwrap();
41    }
42    writeln!(output, ";").unwrap();
43}
44
45fn write_import(output: &mut String, import: &ImportDirective, indent: &str) {
46    write!(output, "{}import", indent).unwrap();
47
48    if let Some(symbols) = &import.symbols {
49        write!(output, " {{").unwrap();
50        for (i, symbol) in symbols.iter().enumerate() {
51            if i > 0 {
52                write!(output, ", ").unwrap();
53            }
54            write!(output, "{}", symbol.name).unwrap();
55            if let Some(alias) = &symbol.alias {
56                write!(output, " as {}", alias).unwrap();
57            }
58        }
59        write!(output, "}} from \"{}\"", import.path).unwrap();
60    } else if let Some(alias) = &import.alias {
61        write!(output, " * as {} from \"{}\"", alias, import.path).unwrap();
62    } else {
63        write!(output, " \"{}\"", import.path).unwrap();
64    }
65
66    writeln!(output, ";").unwrap();
67}
68
69fn write_contract(output: &mut String, contract: &ContractDefinition, indent: &mut String) {
70    if contract.is_abstract {
71        write!(output, "{}abstract ", indent).unwrap();
72    }
73    write!(output, "contract {}", contract.name).unwrap();
74
75    if !contract.inheritance.is_empty() {
76        write!(output, " is ").unwrap();
77        for (i, inheritance) in contract.inheritance.iter().enumerate() {
78            if i > 0 {
79                write!(output, ", ").unwrap();
80            }
81            write_identifier_path(output, &inheritance.name);
82            if let Some(args) = &inheritance.arguments {
83                write!(output, "(").unwrap();
84                write_expression_list(output, args);
85                write!(output, ")").unwrap();
86            }
87        }
88    }
89
90    writeln!(output, " {{").unwrap();
91
92    indent.push_str(INDENT_STEP);
93    for element in &contract.body {
94        write_contract_body_element(output, element, indent);
95        writeln!(output).unwrap();
96    }
97    indent.truncate(indent.len() - INDENT_STEP.len());
98
99    writeln!(output, "{}}}", indent).unwrap();
100}
101
102fn write_interface(output: &mut String, interface: &InterfaceDefinition, indent: &mut String) {
103    write!(output, "{}interface {}", indent, interface.name).unwrap();
104
105    if !interface.inheritance.is_empty() {
106        write!(output, " is ").unwrap();
107        for (i, inheritance) in interface.inheritance.iter().enumerate() {
108            if i > 0 {
109                write!(output, ", ").unwrap();
110            }
111            write_identifier_path(output, &inheritance.name);
112            if let Some(args) = &inheritance.arguments {
113                write!(output, "(").unwrap();
114                write_expression_list(output, args);
115                write!(output, ")").unwrap();
116            }
117        }
118    }
119
120    writeln!(output, " {{").unwrap();
121
122    indent.push_str(INDENT_STEP);
123    for element in &interface.body {
124        write_contract_body_element(output, element, indent);
125        writeln!(output).unwrap();
126    }
127    indent.truncate(indent.len() - INDENT_STEP.len());
128
129    writeln!(output, "{}}}", indent).unwrap();
130}
131
132fn write_library(output: &mut String, library: &LibraryDefinition, indent: &mut String) {
133    write!(output, "{}library {}", indent, library.name).unwrap();
134    writeln!(output, " {{").unwrap();
135
136    indent.push_str(INDENT_STEP);
137    for element in &library.body {
138        write_contract_body_element(output, element, indent);
139        writeln!(output).unwrap();
140    }
141    indent.truncate(indent.len() - INDENT_STEP.len());
142
143    writeln!(output, "{}}}", indent).unwrap();
144}
145
146fn write_contract_body_element(
147    output: &mut String,
148    element: &ContractBodyElement,
149    indent: &mut str,
150) {
151    match element {
152        ContractBodyElement::Constructor(constructor) => {
153            write_constructor(output, constructor, indent)
154        }
155        ContractBodyElement::Function(function) => write_function(output, function, indent),
156        ContractBodyElement::Modifier(modifier) => write_modifier(output, modifier, indent),
157        ContractBodyElement::StateVariable(var) => write_state_variable(output, var, indent),
158        ContractBodyElement::Event(event) => write_event(output, event, indent),
159        ContractBodyElement::Error(error) => write_error(output, error, indent),
160        ContractBodyElement::Struct(struct_def) => write_struct(output, struct_def, indent),
161        ContractBodyElement::Enum(enum_def) => write_enum(output, enum_def, indent),
162        ContractBodyElement::Using(using_def) => write_using(output, using_def, indent),
163    }
164}
165
166fn write_function(output: &mut String, function: &FunctionDefinition, indent: &str) {
167    write!(output, "{}function", indent).unwrap();
168
169    if let Some(name) = &function.name {
170        write!(output, " {}", name).unwrap();
171    }
172
173    write!(output, "(").unwrap();
174    write_parameter_list(output, &function.parameters);
175    write!(output, ")").unwrap();
176
177    if let Some(visibility) = &function.visibility {
178        write!(output, " {}", visibility.to_string()).unwrap();
179    }
180
181    if let Some(state_mutability) = &function.state_mutability {
182        write!(output, " {}", state_mutability.to_string()).unwrap();
183    }
184
185    if function.is_virtual {
186        write!(output, " virtual").unwrap();
187    }
188
189    if let Some(override_spec) = &function.override_specifier {
190        write!(output, " override").unwrap();
191        if !override_spec.overrides.is_empty() {
192            write!(output, "(").unwrap();
193            for (i, path) in override_spec.overrides.iter().enumerate() {
194                if i > 0 {
195                    write!(output, ", ").unwrap();
196                }
197                write_identifier_path(output, path);
198            }
199            write!(output, ")").unwrap();
200        }
201    }
202
203    for modifier in &function.modifiers {
204        write!(output, " ").unwrap();
205        write_identifier_path(output, &modifier.name);
206        if let Some(args) = &modifier.arguments {
207            write!(output, "(").unwrap();
208            write_expression_list(output, args);
209            write!(output, ")").unwrap();
210        }
211    }
212
213    if let Some(returns) = &function.returns {
214        write!(output, " returns (").unwrap();
215        write_parameter_list(output, returns);
216        write!(output, ")").unwrap();
217    }
218
219    if let Some(body) = &function.body {
220        write!(output, " ").unwrap();
221        write_block(output, body, &mut indent.to_string());
222    } else {
223        writeln!(output, ";").unwrap();
224    }
225}
226
227fn write_constructor(output: &mut String, constructor: &ConstructorDefinition, indent: &str) {
228    write!(output, "{}constructor(", indent).unwrap();
229    write_parameter_list(output, &constructor.parameters);
230    write!(output, ")").unwrap();
231
232    if let Some(visibility) = &constructor.visibility {
233        write!(output, " {}", visibility.to_string()).unwrap();
234    }
235
236    if constructor.is_payable {
237        write!(output, " payable").unwrap();
238    }
239
240    for modifier in &constructor.modifiers {
241        write!(output, " ").unwrap();
242        write_identifier_path(output, &modifier.name);
243        if let Some(args) = &modifier.arguments {
244            write!(output, "(").unwrap();
245            write_expression_list(output, args);
246            write!(output, ")").unwrap();
247        }
248    }
249
250    write!(output, " ").unwrap();
251    write_block(output, &constructor.body, &mut indent.to_string());
252}
253
254fn write_modifier(output: &mut String, modifier: &ModifierDefinition, indent: &str) {
255    write!(output, "{}modifier {}(", indent, modifier.name).unwrap();
256    write_parameter_list(output, &modifier.parameters);
257    write!(output, ")").unwrap();
258
259    if modifier.is_virtual {
260        write!(output, " virtual").unwrap();
261    }
262
263    if let Some(override_spec) = &modifier.override_specifier {
264        write!(output, " override").unwrap();
265        if !override_spec.overrides.is_empty() {
266            write!(output, "(").unwrap();
267            for (i, path) in override_spec.overrides.iter().enumerate() {
268                if i > 0 {
269                    write!(output, ", ").unwrap();
270                }
271                write_identifier_path(output, path);
272            }
273            write!(output, ")").unwrap();
274        }
275    }
276
277    if let Some(body) = &modifier.body {
278        write!(output, " ").unwrap();
279        write_block(output, body, &mut indent.to_string());
280    } else {
281        writeln!(output, ";").unwrap();
282    }
283}
284
285fn write_state_variable(output: &mut String, var: &StateVariableDeclaration, indent: &str) {
286    write!(output, "{}", indent).unwrap();
287    write_type_name(output, &var.type_name);
288
289    if let Some(visibility) = &var.visibility {
290        write!(output, " {}", visibility.to_string()).unwrap();
291    }
292
293    if var.is_constant {
294        write!(output, " constant").unwrap();
295    }
296
297    if var.is_immutable {
298        write!(output, " immutable").unwrap();
299    }
300
301    if var.is_transient {
302        write!(output, " transient").unwrap();
303    }
304
305    if let Some(override_spec) = &var.override_specifier {
306        write!(output, " override").unwrap();
307        if !override_spec.overrides.is_empty() {
308            write!(output, "(").unwrap();
309            for (i, path) in override_spec.overrides.iter().enumerate() {
310                if i > 0 {
311                    write!(output, ", ").unwrap();
312                }
313                write_identifier_path(output, path);
314            }
315            write!(output, ")").unwrap();
316        }
317    }
318
319    write!(output, " {}", var.name).unwrap();
320
321    if let Some(initial_value) = &var.initial_value {
322        write!(output, " = ").unwrap();
323        write_expression(output, initial_value);
324    }
325
326    writeln!(output, ";").unwrap();
327}
328
329fn write_constant_variable(output: &mut String, var: &ConstantVariableDeclaration, indent: &str) {
330    write!(output, "{}", indent).unwrap();
331    write_type_name(output, &var.type_name);
332    write!(output, " constant {} = ", var.name).unwrap();
333    write_expression(output, &var.initial_value);
334    writeln!(output, ";").unwrap();
335}
336
337fn write_struct(output: &mut String, struct_def: &StructDefinition, indent: &str) {
338    writeln!(output, "{}struct {} {{", indent, struct_def.name).unwrap();
339
340    let mut inner_indent = indent.to_string();
341    inner_indent.push_str(INDENT_STEP);
342
343    for member in &struct_def.members {
344        write!(output, "{}", inner_indent).unwrap();
345        write_type_name(output, &member.type_name);
346        writeln!(output, " {};", member.name).unwrap();
347    }
348
349    writeln!(output, "{}}}", indent).unwrap();
350}
351
352fn write_enum(output: &mut String, enum_def: &EnumDefinition, indent: &str) {
353    write!(output, "{}enum {} {{ ", indent, enum_def.name).unwrap();
354    for (i, value) in enum_def.values.iter().enumerate() {
355        if i > 0 {
356            write!(output, ", ").unwrap();
357        }
358        write!(output, "{}", value).unwrap();
359    }
360    writeln!(output, " }}").unwrap();
361}
362
363/// Writes an event definition.
364fn write_event(output: &mut String, event: &EventDefinition, indent: &str) {
365    write!(output, "{}event {}(", indent, event.name).unwrap();
366
367    for (i, param) in event.parameters.iter().enumerate() {
368        if i > 0 {
369            write!(output, ", ").unwrap();
370        }
371        write_type_name(output, &param.type_name);
372        if param.is_indexed {
373            write!(output, " indexed").unwrap();
374        }
375        if let Some(name) = &param.name {
376            write!(output, " {}", name).unwrap();
377        }
378    }
379
380    write!(output, ")").unwrap();
381
382    if event.is_anonymous {
383        write!(output, " anonymous").unwrap();
384    }
385
386    writeln!(output, ";").unwrap();
387}
388
389fn write_error(output: &mut String, error: &ErrorDefinition, indent: &str) {
390    write!(output, "{}error {}(", indent, error.name).unwrap();
391
392    for (i, param) in error.parameters.iter().enumerate() {
393        if i > 0 {
394            write!(output, ", ").unwrap();
395        }
396        write_type_name(output, &param.type_name);
397        if let Some(name) = &param.name {
398            write!(output, " {}", name).unwrap();
399        }
400    }
401
402    writeln!(output, ");").unwrap();
403}
404
405fn write_using(output: &mut String, using: &UsingDirective, indent: &str) {
406    write!(output, "{}using ", indent).unwrap();
407    write_identifier_path(output, &using.library);
408    write!(output, " for").unwrap();
409
410    if let Some(type_name) = &using.type_name {
411        write!(output, " ").unwrap();
412        write_type_name(output, type_name);
413    } else {
414        write!(output, " *").unwrap();
415    }
416
417    if using.is_global {
418        write!(output, " global").unwrap();
419    }
420
421    writeln!(output, ";").unwrap();
422}
423
424fn write_parameter_list(output: &mut String, parameters: &[Parameter]) {
425    for (i, param) in parameters.iter().enumerate() {
426        if i > 0 {
427            write!(output, ", ").unwrap();
428        }
429        write_type_name(output, &param.type_name);
430        if let Some(data_location) = &param.data_location {
431            write!(output, " {}", data_location.to_string()).unwrap();
432        }
433        if let Some(name) = &param.name {
434            write!(output, " {}", name).unwrap();
435        }
436    }
437}
438
439fn write_type_name(output: &mut String, type_name: &TypeName) {
440    match type_name {
441        TypeName::Elementary(elem) => write_elementary_type(output, elem),
442        TypeName::UserDefined(path) => write_identifier_path(output, path),
443        TypeName::Array(base_type, size) => {
444            write_type_name(output, base_type);
445            write!(output, "[").unwrap();
446            if let Some(size_expr) = size {
447                write_expression(output, size_expr);
448            }
449            write!(output, "]").unwrap();
450        }
451        TypeName::Mapping(mapping) => {
452            write!(output, "mapping(").unwrap();
453            write_type_name(output, &mapping.key_type);
454            if let Some(key_name) = &mapping.key_name {
455                write!(output, " {}", key_name).unwrap();
456            }
457            write!(output, " => ").unwrap();
458            write_type_name(output, &mapping.value_type);
459            if let Some(value_name) = &mapping.value_name {
460                write!(output, " {}", value_name).unwrap();
461            }
462            write!(output, ")").unwrap();
463        }
464        TypeName::Function(func_type) => {
465            write!(output, "function(").unwrap();
466            write_parameter_list(output, &func_type.parameters);
467            write!(output, ")").unwrap();
468
469            if let Some(visibility) = &func_type.visibility {
470                write!(output, " {}", visibility.to_string()).unwrap();
471            }
472
473            if let Some(state_mutability) = &func_type.state_mutability {
474                write!(output, " {}", state_mutability.to_string()).unwrap();
475            }
476
477            if let Some(returns) = &func_type.returns {
478                write!(output, " returns (").unwrap();
479                write_parameter_list(output, returns);
480                write!(output, ")").unwrap();
481            }
482        }
483    }
484}
485
486fn write_elementary_type(output: &mut String, elem_type: &ElementaryTypeName) {
487    match elem_type {
488        ElementaryTypeName::Address => write!(output, "address").unwrap(),
489        ElementaryTypeName::AddressPayable => write!(output, "address payable").unwrap(),
490        ElementaryTypeName::Bool => write!(output, "bool").unwrap(),
491        ElementaryTypeName::String => write!(output, "string").unwrap(),
492        ElementaryTypeName::Bytes => write!(output, "bytes").unwrap(),
493        ElementaryTypeName::SignedInteger(size) => {
494            write!(output, "int").unwrap();
495            if let Some(bits) = size {
496                write!(output, "{}", bits).unwrap();
497            }
498        }
499        ElementaryTypeName::UnsignedInteger(size) => {
500            write!(output, "uint").unwrap();
501            if let Some(bits) = size {
502                write!(output, "{}", bits).unwrap();
503            }
504        }
505        ElementaryTypeName::FixedBytes(size) => {
506            write!(output, "bytes").unwrap();
507            if let Some(bytes) = size {
508                write!(output, "{}", bytes).unwrap();
509            }
510        }
511        ElementaryTypeName::Fixed => write!(output, "fixed").unwrap(),
512        ElementaryTypeName::Ufixed => write!(output, "ufixed").unwrap(),
513    }
514}
515
516fn write_identifier_path(output: &mut String, path: &IdentifierPath) {
517    for (i, part) in path.parts.iter().enumerate() {
518        if i > 0 {
519            write!(output, ".").unwrap();
520        }
521        write!(output, "{}", part).unwrap();
522    }
523}
524
525fn write_expression_list(output: &mut String, expressions: &[Expression]) {
526    for (i, expr) in expressions.iter().enumerate() {
527        if i > 0 {
528            write!(output, ", ").unwrap();
529        }
530        write_expression(output, expr);
531    }
532}
533
534fn write_expression(output: &mut String, expression: &Expression) {
535    match expression {
536        Expression::Identifier(name) => write!(output, "{}", name).unwrap(),
537        Expression::Literal(literal) => write_literal(output, literal),
538        Expression::Binary(binary) => {
539            write_expression(output, &binary.left);
540            write!(output, " {} ", binary.operator.to_string()).unwrap();
541            write_expression(output, &binary.right);
542        }
543        Expression::Unary(unary) => {
544            if unary.is_prefix {
545                write!(output, "{}", unary.operator.to_string()).unwrap();
546                write_expression(output, &unary.operand);
547            } else {
548                write_expression(output, &unary.operand);
549                write!(output, "{}", unary.operator.to_string()).unwrap();
550            }
551        }
552        Expression::FunctionCall(call) => {
553            write_expression(output, &call.function);
554            write!(output, "(").unwrap();
555            write_expression_list(output, &call.arguments);
556            write!(output, ")").unwrap();
557        }
558        Expression::MemberAccess(access) => {
559            write_expression(output, &access.object);
560            write!(output, ".{}", access.member).unwrap();
561        }
562        Expression::IndexAccess(access) => {
563            write_expression(output, &access.object);
564            write!(output, "[").unwrap();
565            if let Some(index) = &access.index {
566                write_expression(output, index);
567            }
568            write!(output, "]").unwrap();
569        }
570        Expression::Conditional(conditional) => {
571            write_expression(output, &conditional.condition);
572            write!(output, " ? ").unwrap();
573            write_expression(output, &conditional.true_expr);
574            write!(output, " : ").unwrap();
575            write_expression(output, &conditional.false_expr);
576        }
577        Expression::Assignment(assignment) => {
578            write_expression(output, &assignment.left);
579            write!(output, " {} ", assignment.operator.to_string()).unwrap();
580            write_expression(output, &assignment.right);
581        }
582        Expression::Tuple(tuple) => {
583            write!(output, "(").unwrap();
584            for (i, element) in tuple.elements.iter().enumerate() {
585                if i > 0 {
586                    write!(output, ", ").unwrap();
587                }
588                if let Some(expr) = element {
589                    write_expression(output, expr);
590                }
591            }
592            write!(output, ")").unwrap();
593        }
594        Expression::Array(array) => {
595            write!(output, "[").unwrap();
596            write_expression_list(output, &array.elements);
597            write!(output, "]").unwrap();
598        }
599        Expression::TypeConversion(conversion) => {
600            write_type_name(output, &conversion.type_name);
601            write!(output, "(").unwrap();
602            write_expression(output, &conversion.expression);
603            write!(output, ")").unwrap();
604        }
605        Expression::New(new_expr) => {
606            write!(output, "new ").unwrap();
607            write_type_name(output, &new_expr.type_name);
608        }
609    }
610}
611
612fn write_literal(output: &mut String, literal: &Literal) {
613    match literal {
614        Literal::Boolean(value) => write!(output, "{}", value).unwrap(),
615        Literal::Number(number) => {
616            write!(output, "{}", number.value).unwrap();
617            if let Some(sub_denom) = &number.sub_denomination {
618                write!(output, " {}", sub_denom).unwrap();
619            }
620        }
621        Literal::String(string) => write!(output, "\"{}\"", string.value).unwrap(),
622        Literal::HexString(hex_string) => write!(output, "hex\"{}\"", hex_string.value).unwrap(),
623        Literal::UnicodeString(unicode_string) => {
624            write!(output, "unicode\"{}\"", unicode_string.value).unwrap()
625        }
626    }
627}
628
629fn write_block(output: &mut String, block: &Block, indent: &mut String) {
630    writeln!(output, "{{").unwrap();
631
632    indent.push_str(INDENT_STEP);
633    for statement in &block.statements {
634        write_statement(output, statement, indent);
635    }
636    indent.truncate(indent.len() - INDENT_STEP.len());
637
638    writeln!(output, "{}}}", indent).unwrap();
639}
640
641/// Writes a statement.
642fn write_statement(output: &mut String, statement: &Statement, indent: &str) {
643    match statement {
644        Statement::Block(block) => {
645            write!(output, "{}", indent).unwrap();
646            write_block(output, block, &mut indent.to_string());
647        }
648        Statement::Expression(expr_stmt) => {
649            write!(output, "{}", indent).unwrap();
650            write_expression(output, &expr_stmt.expression);
651            writeln!(output, ";").unwrap();
652        }
653        Statement::Variable(var_stmt) => {
654            write!(output, "{}", indent).unwrap();
655            write_type_name(output, &var_stmt.declaration.type_name);
656            if let Some(data_location) = &var_stmt.declaration.data_location {
657                write!(output, " {}", data_location.to_string()).unwrap();
658            }
659            write!(output, " {}", var_stmt.declaration.name).unwrap();
660            if let Some(initial_value) = &var_stmt.initial_value {
661                write!(output, " = ").unwrap();
662                write_expression(output, initial_value);
663            }
664            writeln!(output, ";").unwrap();
665        }
666        Statement::If(if_stmt) => {
667            write!(output, "{}if (", indent).unwrap();
668            write_expression(output, &if_stmt.condition);
669            write!(output, ") ").unwrap();
670            write_statement(output, &if_stmt.then_statement, "");
671            if let Some(else_stmt) = &if_stmt.else_statement {
672                write!(output, " else ").unwrap();
673                write_statement(output, else_stmt, "");
674            }
675        }
676        Statement::For(for_stmt) => {
677            write!(output, "{}for (", indent).unwrap();
678            if let Some(init) = &for_stmt.init {
679                write_statement(output, init, "");
680            } else {
681                write!(output, ";").unwrap();
682            }
683            write!(output, " ").unwrap();
684            if let Some(condition) = &for_stmt.condition {
685                write_expression(output, condition);
686            }
687            write!(output, "; ").unwrap();
688            if let Some(update) = &for_stmt.update {
689                write_expression(output, update);
690            }
691            write!(output, ") ").unwrap();
692            write_statement(output, &for_stmt.body, "");
693        }
694        Statement::While(while_stmt) => {
695            write!(output, "{}while (", indent).unwrap();
696            write_expression(output, &while_stmt.condition);
697            write!(output, ") ").unwrap();
698            write_statement(output, &while_stmt.body, "");
699        }
700        Statement::DoWhile(do_while_stmt) => {
701            write!(output, "{}do ", indent).unwrap();
702            write_statement(output, &do_while_stmt.body, "");
703            write!(output, " while (").unwrap();
704            write_expression(output, &do_while_stmt.condition);
705            writeln!(output, ");").unwrap();
706        }
707        Statement::Continue(_) => writeln!(output, "{}continue;", indent).unwrap(),
708        Statement::Break(_) => writeln!(output, "{}break;", indent).unwrap(),
709        Statement::Return(return_stmt) => {
710            write!(output, "{}return", indent).unwrap();
711            if let Some(expr) = &return_stmt.expression {
712                write!(output, " ").unwrap();
713                write_expression(output, expr);
714            }
715            writeln!(output, ";").unwrap();
716        }
717        Statement::Emit(emit_stmt) => {
718            write!(output, "{}emit ", indent).unwrap();
719            write_expression(output, &emit_stmt.event_call);
720            writeln!(output, ";").unwrap();
721        }
722        Statement::Revert(revert_stmt) => {
723            write!(output, "{}revert ", indent).unwrap();
724            write_expression(output, &revert_stmt.error_call);
725            writeln!(output, ";").unwrap();
726        }
727        Statement::Try(try_stmt) => {
728            write!(output, "{}try ", indent).unwrap();
729            write_expression(output, &try_stmt.expression);
730            if let Some(returns) = &try_stmt.returns {
731                write!(output, " returns (").unwrap();
732                write_parameter_list(output, returns);
733                write!(output, ")").unwrap();
734            }
735            write!(output, " ").unwrap();
736            write_block(output, &try_stmt.body, &mut indent.to_string());
737            for catch_clause in &try_stmt.catch_clauses {
738                write!(output, " catch").unwrap();
739                if let Some(identifier) = &catch_clause.identifier {
740                    write!(output, " {}", identifier).unwrap();
741                }
742                if let Some(parameters) = &catch_clause.parameters {
743                    write!(output, "(").unwrap();
744                    write_parameter_list(output, parameters);
745                    write!(output, ")").unwrap();
746                }
747                write!(output, " ").unwrap();
748                write_block(output, &catch_clause.body, &mut indent.to_string());
749            }
750        }
751        Statement::Assembly(assembly_stmt) => {
752            write!(output, "{}assembly", indent).unwrap();
753            if let Some(dialect) = &assembly_stmt.dialect {
754                write!(output, " \"{}\"", dialect).unwrap();
755            }
756            for flag in &assembly_stmt.flags {
757                write!(output, " (\"{}\"))", flag).unwrap();
758            }
759            write!(output, " ").unwrap();
760            write_yul_block(output, &assembly_stmt.body, &mut indent.to_string());
761        }
762        Statement::Unchecked(unchecked_stmt) => {
763            write!(output, "{}unchecked ", indent).unwrap();
764            write_block(output, &unchecked_stmt.body, &mut indent.to_string());
765        }
766    }
767}
768
769fn write_yul_block(output: &mut String, block: &YulBlock, indent: &mut String) {
770    writeln!(output, "{{").unwrap();
771
772    indent.push_str(INDENT_STEP);
773    for statement in &block.statements {
774        write_yul_statement(output, statement, indent);
775    }
776    indent.truncate(indent.len() - INDENT_STEP.len());
777
778    writeln!(output, "{}}}", indent).unwrap();
779}
780
781fn write_yul_statement(output: &mut String, statement: &YulStatement, indent: &str) {
782    match statement {
783        YulStatement::Block(block) => {
784            write!(output, "{}", indent).unwrap();
785            write_yul_block(output, block, &mut indent.to_string());
786        }
787        YulStatement::VariableDeclaration(var_decl) => {
788            write!(output, "{}let ", indent).unwrap();
789            for (i, var) in var_decl.variables.iter().enumerate() {
790                if i > 0 {
791                    write!(output, ", ").unwrap();
792                }
793                write!(output, "{}", var).unwrap();
794            }
795            if let Some(expr) = &var_decl.expression {
796                write!(output, " := ").unwrap();
797                write_yul_expression(output, expr);
798            }
799            writeln!(output).unwrap();
800        }
801        YulStatement::Assignment(assignment) => {
802            write!(output, "{}", indent).unwrap();
803            for (i, var) in assignment.variables.iter().enumerate() {
804                if i > 0 {
805                    write!(output, ", ").unwrap();
806                }
807                write_yul_path(output, var);
808            }
809            write!(output, " := ").unwrap();
810            write_yul_expression(output, &assignment.expression);
811            writeln!(output).unwrap();
812        }
813        YulStatement::FunctionCall(call) => {
814            write!(output, "{}", indent).unwrap();
815            write_yul_function_call(output, call);
816            writeln!(output).unwrap();
817        }
818        YulStatement::If(if_stmt) => {
819            write!(output, "{}if ", indent).unwrap();
820            write_yul_expression(output, &if_stmt.condition);
821            write!(output, " ").unwrap();
822            write_yul_block(output, &if_stmt.body, &mut indent.to_string());
823        }
824        YulStatement::For(for_stmt) => {
825            write!(output, "{}for ", indent).unwrap();
826            write_yul_block(output, &for_stmt.init, &mut indent.to_string());
827            write!(output, " ").unwrap();
828            write_yul_expression(output, &for_stmt.condition);
829            write!(output, " ").unwrap();
830            write_yul_block(output, &for_stmt.post, &mut indent.to_string());
831            write!(output, " ").unwrap();
832            write_yul_block(output, &for_stmt.body, &mut indent.to_string());
833        }
834        YulStatement::Switch(switch_stmt) => {
835            write!(output, "{}switch ", indent).unwrap();
836            write_yul_expression(output, &switch_stmt.expression);
837            writeln!(output).unwrap();
838            for case in &switch_stmt.cases {
839                write!(output, "{}case ", indent).unwrap();
840                write_yul_literal(output, &case.value);
841                write!(output, " ").unwrap();
842                write_yul_block(output, &case.body, &mut indent.to_string());
843            }
844            if let Some(default) = &switch_stmt.default {
845                write!(output, "{}default ", indent).unwrap();
846                write_yul_block(output, default, &mut indent.to_string());
847            }
848        }
849        YulStatement::FunctionDefinition(func_def) => {
850            write!(output, "{}function {}(", indent, func_def.name).unwrap();
851            for (i, param) in func_def.parameters.iter().enumerate() {
852                if i > 0 {
853                    write!(output, ", ").unwrap();
854                }
855                write!(output, "{}", param).unwrap();
856            }
857            write!(output, ")").unwrap();
858            if !func_def.returns.is_empty() {
859                write!(output, " -> ").unwrap();
860                for (i, ret) in func_def.returns.iter().enumerate() {
861                    if i > 0 {
862                        write!(output, ", ").unwrap();
863                    }
864                    write!(output, "{}", ret).unwrap();
865                }
866            }
867            write!(output, " ").unwrap();
868            write_yul_block(output, &func_def.body, &mut indent.to_string());
869        }
870        YulStatement::Leave => writeln!(output, "{}leave", indent).unwrap(),
871        YulStatement::Break => writeln!(output, "{}break", indent).unwrap(),
872        YulStatement::Continue => writeln!(output, "{}continue", indent).unwrap(),
873    }
874}
875
876fn write_yul_expression(output: &mut String, expression: &YulExpression) {
877    match expression {
878        YulExpression::Path(path) => write_yul_path(output, path),
879        YulExpression::FunctionCall(call) => write_yul_function_call(output, call),
880        YulExpression::Literal(literal) => write_yul_literal(output, literal),
881    }
882}
883
884fn write_yul_path(output: &mut String, path: &YulPath) {
885    for (i, part) in path.parts.iter().enumerate() {
886        if i > 0 {
887            write!(output, ".").unwrap();
888        }
889        write!(output, "{}", part).unwrap();
890    }
891}
892
893fn write_yul_function_call(output: &mut String, call: &YulFunctionCall) {
894    write!(output, "{}(", call.function).unwrap();
895    for (i, arg) in call.arguments.iter().enumerate() {
896        if i > 0 {
897            write!(output, ", ").unwrap();
898        }
899        write_yul_expression(output, arg);
900    }
901    write!(output, ")").unwrap();
902}
903
904fn write_yul_literal(output: &mut String, literal: &YulLiteral) {
905    match literal {
906        YulLiteral::Number(value) => write!(output, "{}", value).unwrap(),
907        YulLiteral::String(value) => write!(output, "\"{}\"", value).unwrap(),
908        YulLiteral::HexNumber(value) => write!(output, "{}", value).unwrap(),
909        YulLiteral::Boolean(value) => write!(output, "{}", value).unwrap(),
910        YulLiteral::HexString(value) => write!(output, "hex\"{}\"", value).unwrap(),
911    }
912}
913
914impl Visibility {
915    pub fn to_string(&self) -> &'static str {
916        match self {
917            Visibility::Public => "public",
918            Visibility::Private => "private",
919            Visibility::Internal => "internal",
920            Visibility::External => "external",
921        }
922    }
923}
924
925impl StateMutability {
926    pub fn to_string(&self) -> &'static str {
927        match self {
928            StateMutability::Pure => "pure",
929            StateMutability::View => "view",
930            StateMutability::Payable => "payable",
931        }
932    }
933}
934
935impl DataLocation {
936    pub fn to_string(&self) -> &'static str {
937        match self {
938            DataLocation::Memory => "memory",
939            DataLocation::Storage => "storage",
940            DataLocation::Calldata => "calldata",
941        }
942    }
943}
944
945impl BinaryOperator {
946    pub fn to_string(&self) -> &'static str {
947        match self {
948            BinaryOperator::Add => "+",
949            BinaryOperator::Sub => "-",
950            BinaryOperator::Mul => "*",
951            BinaryOperator::Div => "/",
952            BinaryOperator::Mod => "%",
953            BinaryOperator::Exp => "**",
954            BinaryOperator::Equal => "==",
955            BinaryOperator::NotEqual => "!=",
956            BinaryOperator::LessThan => "<",
957            BinaryOperator::LessThanOrEqual => "<=",
958            BinaryOperator::GreaterThan => ">",
959            BinaryOperator::GreaterThanOrEqual => ">=",
960            BinaryOperator::And => "&&",
961            BinaryOperator::Or => "||",
962            BinaryOperator::BitAnd => "&",
963            BinaryOperator::BitOr => "|",
964            BinaryOperator::BitXor => "^",
965            BinaryOperator::ShiftLeft => "<<",
966            BinaryOperator::ShiftRight => ">>",
967            BinaryOperator::ShiftRightArithmetic => ">>>",
968        }
969    }
970}
971
972impl UnaryOperator {
973    pub fn to_string(&self) -> &'static str {
974        match self {
975            UnaryOperator::Plus => "+",
976            UnaryOperator::Minus => "-",
977            UnaryOperator::Not => "!",
978            UnaryOperator::BitNot => "~",
979            UnaryOperator::Increment => "++",
980            UnaryOperator::Decrement => "--",
981            UnaryOperator::Delete => "delete ",
982        }
983    }
984}
985
986impl AssignmentOperator {
987    pub fn to_string(&self) -> &'static str {
988        match self {
989            AssignmentOperator::Assign => "=",
990            AssignmentOperator::AddAssign => "+=",
991            AssignmentOperator::SubAssign => "-=",
992            AssignmentOperator::MulAssign => "*=",
993            AssignmentOperator::DivAssign => "/=",
994            AssignmentOperator::ModAssign => "%=",
995            AssignmentOperator::BitAndAssign => "&=",
996            AssignmentOperator::BitOrAssign => "|=",
997            AssignmentOperator::BitXorAssign => "^=",
998            AssignmentOperator::ShiftLeftAssign => "<<=",
999            AssignmentOperator::ShiftRightAssign => ">>=",
1000            AssignmentOperator::ShiftRightArithmeticAssign => ">>>=",
1001        }
1002    }
1003}
1004
1005pub fn write_expression_to_string(expression: &Expression) -> String {
1006    let mut output = String::new();
1007    write_expression(&mut output, expression);
1008    output
1009}
1010
1011pub fn write_literal_to_string(literal: &Literal) -> String {
1012    let mut output = String::new();
1013    write_literal(&mut output, literal);
1014    output
1015}
1016
1017pub fn write_type_name_to_string(type_name: &TypeName) -> String {
1018    let mut output = String::new();
1019    write_type_name(&mut output, type_name);
1020    output
1021}
1022
1023pub fn format_value_for_expression(value: &crate::interpreter::Value) -> String {
1024    use crate::interpreter::Value;
1025    match value {
1026        Value::Bool(b) => b.to_string(),
1027        Value::UInt(n) => n.to_string(),
1028        Value::Int(n) => n.to_string(),
1029        Value::String(s) => format!("\"{}\"", s),
1030        Value::Address(addr) => addr.clone(),
1031        Value::Bytes(b) => format!("0x{}", hex::encode(b)),
1032        Value::Null => "null".to_string(),
1033    }
1034}