Skip to content

Commit 1d1b1a9

Browse files
committed
Fixed inconsistent use of parentheses for outputs
1 parent 831541b commit 1d1b1a9

File tree

5 files changed

+76
-2
lines changed

5 files changed

+76
-2
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "masm-decompiler"
3-
version = "0.4.2"
3+
version = "0.4.3"
44
edition = "2024"
55

66
[dependencies]

src/fmt/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,8 @@ impl CodeDisplay for Stmt {
887887
.join(", ");
888888
if outs.is_empty() {
889889
f.write_line(&format!("{}();", function_name("adv_load")));
890+
} else if outputs.len() > 1 {
891+
f.write_line(&format!("({outs}) = {}();", function_name("adv_load")));
890892
} else {
891893
f.write_line(&format!("{outs} = {}();", function_name("adv_load")));
892894
}
@@ -970,6 +972,8 @@ impl CodeDisplay for Stmt {
970972
.join(", ");
971973
if outs.is_empty() {
972974
f.write_line(&format!("{}({args});", function_name("dyncall")));
975+
} else if results.len() > 1 {
976+
f.write_line(&format!("({outs}) = {}({args});", function_name("dyncall")));
973977
} else {
974978
f.write_line(&format!("{outs} = {}({args});", function_name("dyncall")));
975979
}
@@ -1006,6 +1010,8 @@ impl CodeDisplay for Stmt {
10061010
}
10071011
if outs.is_empty() {
10081012
f.write_line(&format!("{}({args});", function_name(name)));
1013+
} else if results.len() > 1 {
1014+
f.write_line(&format!("({outs}) = {}({args});", function_name(name)));
10091015
} else {
10101016
f.write_line(&format!("{outs} = {}({args});", function_name(name)));
10111017
}
@@ -1292,6 +1298,8 @@ fn write_call_like(kind: &str, call: &Call, f: &mut CodeWriter) {
12921298
let head = format!("{} {}", keyword(kind), function_name(&call.target));
12931299
if outs.is_empty() {
12941300
f.write_line(&format!("{head}({args});"));
1301+
} else if call.results.len() > 1 {
1302+
f.write_line(&format!("({outs}) = {head}({args});"));
12951303
} else {
12961304
f.write_line(&format!("{outs} = {head}({args});"));
12971305
}

tests/fixtures/word_mem_stack_ops.masm

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,23 @@ proc uses_adv_pipe
214214
push.0
215215
adv_pipe
216216
end
217+
218+
#! Helper that returns two values.
219+
proc helper_two_outputs
220+
push.1.2
221+
end
222+
223+
#! Calls a helper that returns two values.
224+
proc uses_exec_multi_output
225+
exec.helper_two_outputs
226+
end
227+
228+
#! Helper that returns one value.
229+
proc helper_one_output
230+
push.42
231+
end
232+
233+
#! Calls a helper that returns one value.
234+
proc uses_exec_single_output
235+
exec.helper_one_output
236+
end

tests/word_instruction_formatting.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,49 @@ fn formats_mem_stream_and_adv_pipe_intrinsics() {
204204
let adv_pipe_fmt = format_proc(source, "uses_adv_pipe");
205205
assert!(adv_pipe_fmt.contains("adv_pipe("), "{adv_pipe_fmt}");
206206
}
207+
208+
#[test]
209+
fn parenthesizes_multi_output_intrinsics() {
210+
let source = include_str!("fixtures/word_mem_stack_ops.masm");
211+
212+
// u32widening_add returns 2 values — outputs must be parenthesized.
213+
let widening_fmt = format_proc(source, "uses_u32widening_add");
214+
assert!(
215+
widening_fmt.contains(") = u32widening_add("),
216+
"multi-output intrinsic should parenthesize LHS: {widening_fmt}"
217+
);
218+
219+
// u32wrapping_add3 returns 1 value — output must NOT be parenthesized.
220+
let wrapping_fmt = format_proc(source, "uses_u32wrapping_add3");
221+
assert!(
222+
!wrapping_fmt.contains("(") || !wrapping_fmt.contains(") = u32wrapping_add3("),
223+
"single-output intrinsic should not parenthesize LHS: {wrapping_fmt}"
224+
);
225+
226+
// mem_stream returns 13 values — outputs must be parenthesized.
227+
let mem_stream_fmt = format_proc(source, "uses_mem_stream");
228+
assert!(
229+
mem_stream_fmt.contains(") = mem_stream("),
230+
"multi-output intrinsic should parenthesize LHS: {mem_stream_fmt}"
231+
);
232+
}
233+
234+
#[test]
235+
fn parenthesizes_multi_output_calls() {
236+
let source = include_str!("fixtures/word_mem_stack_ops.masm");
237+
238+
// exec returning 2 values — outputs must be parenthesized.
239+
let multi_fmt = format_proc(source, "uses_exec_multi_output");
240+
assert!(
241+
multi_fmt.contains(") = exec helper_two_outputs("),
242+
"multi-output call should parenthesize LHS: {multi_fmt}"
243+
);
244+
245+
// exec returning 1 value — output must NOT be parenthesized.
246+
let single_fmt = format_proc(source, "uses_exec_single_output");
247+
assert!(
248+
single_fmt.contains(" = exec helper_one_output(")
249+
&& !single_fmt.contains(") = exec helper_one_output("),
250+
"single-output call should not parenthesize LHS: {single_fmt}"
251+
);
252+
}

0 commit comments

Comments
 (0)