1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use super::super::{HighLevelEmitter, HighLevelOutput};
impl HighLevelEmitter {
pub(crate) fn finish(mut self) -> HighLevelOutput {
self.flush_pending_closers();
self.postprocess_statements();
self.statements.retain(|line| !line.trim().is_empty());
HighLevelOutput {
statements: self.statements,
warnings: self.warnings,
}
}
fn flush_pending_closers(&mut self) {
// Flush remaining block closers (BTreeMap iterates in key order; no
// sort needed). Clamp to the current open-brace depth: malformed TRY
// operands can register a closer whose catch/finally header is never
// emitted, and clamping avoids a stray `}` in that case.
let mut depth = Self::open_brace_depth(&self.statements);
for (_, count) in std::mem::take(&mut self.pending_closers) {
for _ in 0..count {
if depth <= 0 {
break;
}
self.statements.push("}".into());
depth -= 1;
}
}
}
fn postprocess_statements(&mut self) {
Self::rewrite_else_if_chains(&mut self.statements);
Self::collapse_overflow_checks(&mut self.statements);
Self::rewrite_goto_do_while(&mut self.statements);
Self::rewrite_if_goto_to_while(&mut self.statements);
Self::eliminate_fallthrough_gotos(&mut self.statements);
Self::rewrite_label_goto_to_loop(&mut self.statements);
Self::remove_orphaned_labels(&mut self.statements);
Self::rewrite_for_loops(&mut self.statements);
// Note: inline_single_use_temps is available but disabled by default
// as it can be too aggressive for some use cases. Enable selectively.
Self::inline_condition_temps(&mut self.statements);
Self::inline_for_increment_temps(&mut self.statements);
if self.inline_single_use_temps {
Self::inline_single_use_temps(&mut self.statements);
}
Self::rewrite_compound_assignments(&mut self.statements);
Self::rewrite_indexing_syntax(&mut self.statements);
Self::collapse_if_true(&mut self.statements);
Self::invert_empty_if_else(&mut self.statements);
Self::remove_empty_if(&mut self.statements);
Self::strip_stack_comments(&mut self.statements);
Self::eliminate_identity_temps(&mut self.statements);
Self::collapse_temp_into_store(&mut self.statements);
if self.inline_single_use_temps {
// Pairs with the inliner: removing dead `let tN = pure_value;`
// makes outputs after empty-if elimination read as natural code.
Self::eliminate_dead_temps(&mut self.statements);
// Inliner adds parentheses around multi-token substitutions for
// precedence safety; collapse redundant nested pairs afterwards.
Self::reduce_double_parens(&mut self.statements);
}
// Inlining and dead-temp removal can collapse the body between a
// preserved transfer and its label target. Re-run elimination and
// orphan-label cleanup so those pairs drop from clean output.
Self::eliminate_fallthrough_gotos(&mut self.statements);
Self::remove_orphaned_labels(&mut self.statements);
Self::rewrite_switch_statements(&mut self.statements);
Self::rewrite_switch_break_gotos(&mut self.statements);
// Final formatting cleanup: join `}\n<chain>` pairs into K&R form.
// Runs last so other passes can keep asserting intermediate line
// vectors with separate `}` and `else {` entries.
Self::join_close_brace_with_chain(&mut self.statements);
}
/// Net open-brace depth across the emitted statements, using the same
/// structural heuristic as the postprocess passes: a line that ends with
/// `{` opens a block and a line that is exactly `}` (or starts with `} `)
/// closes one. Braces inside string literals never reach the end of a
/// statement line, so they do not affect the count.
fn open_brace_depth(statements: &[String]) -> i32 {
let mut depth = 0i32;
for line in statements {
let trimmed = line.trim();
if trimmed.ends_with('{') {
depth += 1;
} else if trimmed == "}" || trimmed.starts_with("} ") {
depth -= 1;
}
}
depth
}
}