use dfwasm_template::{Args, Item, Template};
pub trait TemplateExt {
fn push_op_stack(&mut self, var_to_push: Item) -> &mut Self;
fn pop_op_stack(&mut self, var_to_pop: Item) -> &mut Self;
fn compare_and_push(&mut self, action: impl Into<String>, a: Item, b: Item) -> &mut Self;
}
impl TemplateExt for Template {
fn push_op_stack(&mut self, var_to_push: Item) -> &mut Self {
self.set_var(
"AppendValue",
Args::with(vec![Item::var(DF_VAR_OP_STACK), var_to_push]),
)
}
fn pop_op_stack(&mut self, var_to_pop: Item) -> &mut Self {
self.set_var(
"PopListValue",
Args::with(vec![var_to_pop, Item::var(DF_VAR_OP_STACK)]),
)
}
fn compare_and_push(&mut self, action: impl Into<String>, a: Item, b: Item) -> &mut Self {
self.if_var(action, Args::with(vec![a, b]))
.open_bracket()
.push_op_stack(num(format_df_number_usize(1)))
.close_bracket()
.else_block()
.open_bracket()
.push_op_stack(num(format_df_number_usize(0)))
.close_bracket()
}
}
pub fn format_df_number_i64(value: i64) -> String {
let abs = value.unsigned_abs();
let int_part = abs / 1000;
let frac_part = abs % 1000;
let sign = if value < 0 { "-" } else { "" };
let mut frac_str = format!("{frac_part:03}");
while frac_str.ends_with('0') {
frac_str.pop();
}
if frac_str.is_empty() {
format!("{sign}{int_part}",)
} else {
format!("{sign}{int_part}.{frac_str}")
}
}
pub fn format_df_number_i32(value: i32) -> String {
let value_bytes: [u8; 4] = value.to_le_bytes();
let value_bytes: [u8; 8] = [
value_bytes[0],
value_bytes[1],
value_bytes[2],
value_bytes[3],
0,
0,
0,
0,
];
let value = i64::from_le_bytes(value_bytes);
let abs = value.unsigned_abs();
let int_part = abs / 1000;
let frac_part = abs % 1000;
let sign = if value < 0 { "-" } else { "" };
let mut frac_str = format!("{frac_part:03}");
while frac_str.ends_with('0') {
frac_str.pop();
}
if frac_str.is_empty() {
format!("{sign}{int_part}",)
} else {
format!("{sign}{int_part}.{frac_str}")
}
}
pub fn format_df_number_u64(value: u64) -> String {
let int_part = value / 1000;
let frac_part = value % 1000;
let mut frac_str = format!("{frac_part:03}");
while frac_str.ends_with('0') {
frac_str.pop();
}
if frac_str.is_empty() {
format!("{int_part}")
} else {
format!("{int_part}.{frac_str}")
}
}
pub fn format_df_number_u32(value: u32) -> String {
let value_bytes: [u8; 4] = value.to_le_bytes();
let value_bytes: [u8; 8] = [
value_bytes[0],
value_bytes[1],
value_bytes[2],
value_bytes[3],
0,
0,
0,
0,
];
let value = i64::from_le_bytes(value_bytes);
let abs = value.unsigned_abs();
let int_part = abs / 1000;
let frac_part = abs % 1000;
let sign = if value < 0 { "-" } else { "" };
let mut frac_str = format!("{frac_part:03}");
while frac_str.ends_with('0') {
frac_str.pop();
}
if frac_str.is_empty() {
format!("{sign}{int_part}",)
} else {
format!("{sign}{int_part}.{frac_str}")
}
}
pub fn format_df_number_usize(value: usize) -> String {
let int_part = value / 1000;
let frac_part = value % 1000;
let mut frac_str = format!("{frac_part:03}");
while frac_str.ends_with('0') {
frac_str.pop();
}
if frac_str.is_empty() {
format!("{int_part}")
} else {
format!("{int_part}.{frac_str}")
}
}
pub fn generate_function_name(index: usize, module_name: Option<&str>) -> String {
match module_name {
Some(name) => format!("wasm.{name}.func_{index}"),
None => format!("wasm.module.func_{index}"),
}
}
pub fn generate_table_name(index: usize) -> String {
format!("wasm.$table_{index}")
}
pub fn generate_block_name(index: usize, module_name: Option<&str>) -> String {
match module_name {
Some(name) => format!("wasm.{name}.block_{index}"),
None => format!("wasm.module.{index}"),
}
}
pub fn generate_loop_name(index: usize, module_name: Option<&str>) -> String {
match module_name {
Some(name) => format!("wasm.{name}.loop_{index}"),
None => format!("wasm.module.loop_{index}"),
}
}
pub fn generate_conditional_name(index: usize, module_name: Option<&str>) -> String {
match module_name {
Some(name) => format!("wasm.{name}.if_{index}"),
None => format!("wasm.module.if_{index}"),
}
}
pub fn var(name: impl Into<String>) -> Item {
Item::var(name)
}
pub fn num(name: impl ToString) -> Item {
Item::num(name)
}
pub fn string(value: impl Into<String>) -> Item {
Item::string(value)
}
pub const DF_VAR_OP_STACK: &str = "wasm.$op_stack";
pub const DF_VAR_MEM_SIZE: &str = "wasm.$memSize";
pub const DF_VAR_STORE_FUNCS: &str = "wasm.$store_funcs";
pub const DF_VAR_STORE_TABLES: &str = "wasm.$store_tables";
pub const DF_VAR_STORE_GLOBALS: &str = "wasm.$store_globals";
pub const DF_FUNC_CALL_FUNC: &str = "wasm.internal.call_func";
pub const DF_FUNC_GROW_TABLE: &str = "wasm.internal.grow_table";
pub const DF_FUNC_FILL_TABLE: &str = "wasm.internal.fill_table";
pub const DF_FUNC_MEM_LOAD: &str = "wasm.internal.mem_load";
pub const DF_FUNC_MEM_STORE: &str = "wasm.internal.mem_store";
pub const DF_FUNC_SIGN_EXTEND: &str = "wasm.internal.sign_extend";
pub const DF_FUNC_BATCH_DATA_SECTION: &str = "wasm.internal.batch_data_section";
pub const DF_FUNC_TRAP: &str = "wasm.internal.trap";
pub const DF_VAR_BRANCH_COUNTER: &str = "wasm.$branch_counter";
pub const DF_FUNC_CONTROL_LOOP_CHECK: &str = "wasm.internal.control_loop_check";
pub const DF_VAR_CURRENT_STACK_FRAME: &str = "wasm.$current_stack_frame";
pub const DF_VAR_IMPORTS: &str = "wasm.$imports";
pub const DF_VAR_EXPORTS: &str = "wasm.$exports";
pub const DF_VAR_EXPORT_SIGNATURES: &str = "wasm.$export_signatures";
pub const DF_FUNC_HOOK_INSTRUCTION: &str = "wasm.internal.hook_instruction";
pub const DF_FUNC_I64_MUL: &str = "wasm.internal.i64_mul";
pub fn get_local_name(local_index: u32) -> String {
format!(
"wasm.$frame%var({})_local_{}",
DF_VAR_CURRENT_STACK_FRAME, local_index
)
}