use std::collections::HashSet;
use std::fmt::Write;
use crate::manifest::{ContractManifest, ManifestMethod};
use super::super::super::super::helpers::next_inferred_method_offset;
use super::super::super::helpers::collect_csharp_parameters;
use super::super::body;
use super::util::{
instruction_slice, method_offset, method_render_info, non_empty_or_all, write_method_close,
write_method_open,
};
use super::MethodsContext;
pub(super) fn write_manifest_methods(
output: &mut String,
manifest: &ContractManifest,
context: &MethodsContext<'_>,
warnings: &mut Vec<String>,
) {
let entry_method =
super::entry::write_script_entry_if_needed(output, manifest, context, warnings);
let entry_offset = context
.instructions
.first()
.map(|ins| ins.offset)
.unwrap_or(0);
let mut used_signatures: HashSet<(String, String)> = HashSet::new();
let mut sorted_methods: Vec<&ManifestMethod> = manifest.abi.methods.iter().collect();
sorted_methods.sort_by_key(|m| m.offset.unwrap_or(i32::MAX));
let (with_offsets, without_offsets): (Vec<_>, Vec<_>) =
sorted_methods.into_iter().partition(|m| m.offset.is_some());
for method in with_offsets {
write_offset_manifest_method(output, method, context, warnings, &mut used_signatures);
}
for method in without_offsets {
write_offsetless_manifest_method(
output,
method,
entry_method,
entry_offset,
context,
warnings,
&mut used_signatures,
);
}
}
fn write_offset_manifest_method(
output: &mut String,
method: &ManifestMethod,
context: &MethodsContext<'_>,
warnings: &mut Vec<String>,
used_signatures: &mut HashSet<(String, String)>,
) {
let start = method_offset(method);
let end = next_inferred_method_offset(context.inferred_method_starts, start)
.or_else(|| context.instructions.last().map(|i| i.offset + 1))
.unwrap_or(start);
let slice = instruction_slice(context.instructions, start, Some(end));
let info = method_render_info(method, used_signatures);
write_method_open(output, &info);
if slice.is_empty() {
writeln!(output, " throw new NotImplementedException();").unwrap();
} else {
let params = collect_csharp_parameters(&method.parameters);
let labels: Vec<String> = params.iter().map(|p| p.name.clone()).collect();
body::write_lifted_body(
output,
&slice,
Some(&labels),
warnings,
&context.body_context,
info.return_type == "void",
);
}
write_method_close(output);
}
fn write_offsetless_manifest_method(
output: &mut String,
method: &ManifestMethod,
entry_method: Option<(&ManifestMethod, bool)>,
entry_offset: usize,
context: &MethodsContext<'_>,
warnings: &mut Vec<String>,
used_signatures: &mut HashSet<(String, String)>,
) {
let info = method_render_info(method, used_signatures);
write_method_open(output, &info);
if entry_method
.as_ref()
.map(|(entry, _)| std::ptr::eq(*entry, method))
.unwrap_or(false)
{
let end = next_inferred_method_offset(context.inferred_method_starts, entry_offset);
let slice = non_empty_or_all(
instruction_slice(context.instructions, entry_offset, end),
context.instructions,
);
let params = collect_csharp_parameters(&method.parameters);
let labels: Vec<String> = params.iter().map(|p| p.name.clone()).collect();
body::write_lifted_body(
output,
&slice,
Some(&labels),
warnings,
&context.body_context,
info.return_type == "void",
);
} else {
writeln!(output, " throw new NotImplementedException();").unwrap();
}
write_method_close(output);
}