use std::fmt::Write;
use crate::instruction::Instruction;
use crate::manifest::{ContractManifest, ManifestMethod};
use super::super::super::super::helpers::{
find_manifest_entry_method, next_inferred_method_offset,
};
use super::super::super::helpers::format_method_signature;
use super::super::body;
use super::util::{
instruction_slice, non_empty_or_all, synthetic_entry_arguments, write_method_close,
};
use super::MethodsContext;
pub(super) fn write_script_entry_if_needed<'a>(
output: &mut String,
manifest: &'a ContractManifest,
context: &MethodsContext<'_>,
warnings: &mut Vec<String>,
) -> Option<(&'a ManifestMethod, bool)> {
let entry_offset = context.instructions.first().map(|ins| ins.offset)?;
let entry_method = find_manifest_entry_method(manifest, entry_offset);
if entry_method.is_some() {
return entry_method;
}
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,
);
writeln!(
output,
" // warning: manifest entry offset did not match script entry at 0x{entry_offset:04X}; using synthetic ScriptEntry"
)
.unwrap();
write_script_entry_body(output, &slice, entry_offset, context, warnings);
None
}
pub(super) fn write_fallback_entry(
output: &mut String,
context: &MethodsContext<'_>,
warnings: &mut Vec<String>,
) {
let entry_offset = context
.instructions
.first()
.map(|ins| ins.offset)
.unwrap_or(0);
let end = next_inferred_method_offset(context.inferred_method_starts, entry_offset)
.or_else(|| context.instructions.last().map(|i| i.offset + 1));
let slice = non_empty_or_all(
instruction_slice(context.instructions, entry_offset, end),
context.instructions,
);
write_script_entry_body(output, &slice, entry_offset, context, warnings);
}
fn write_script_entry_body(
output: &mut String,
slice: &[Instruction],
entry_offset: usize,
context: &MethodsContext<'_>,
warnings: &mut Vec<String>,
) {
let (parameters, argument_labels) = synthetic_entry_arguments(
slice,
entry_offset,
context,
context.body_context.typed_declarations,
);
let entry_signature = format_method_signature("ScriptEntry", ¶meters, "object");
writeln!(output, " {entry_signature}").unwrap();
writeln!(output, " {{").unwrap();
body::write_lifted_body(
output,
slice,
(!argument_labels.is_empty()).then_some(argument_labels.as_slice()),
warnings,
&context.body_context,
false,
);
write_method_close(output);
}