use crate::instruction::Instruction;
use super::super::super::super::HighLevelEmitter;
const PACK_MAX_INLINE: usize = 64;
impl HighLevelEmitter {
pub(in super::super::super::super) fn emit_pack(
&mut self,
instruction: &Instruction,
kind: &str,
) {
self.push_comment(instruction);
let Some(count_name) = self.stack.pop() else {
self.stack_underflow(instruction, 1);
return;
};
if let Some(need) = self.take_usize_literal(&count_name) {
self.emit_literal_pack(kind, need);
} else {
self.emit_dynamic_pack(count_name);
}
}
fn emit_literal_pack(&mut self, kind: &str, need: usize) {
let is_map = kind == "map";
let unit = if is_map { 2 } else { 1 };
let avail = self.stack.len() / unit;
let cap = PACK_MAX_INLINE.min(need).min(avail);
let mut rendered = Vec::with_capacity(cap);
let mut elements = Vec::with_capacity(cap * unit);
for _ in 0..cap {
let unit_values = self.pop_pack_unit(unit);
if is_map {
rendered.push(format!("{}: {}", unit_values[0], unit_values[1]));
} else {
rendered.push(unit_values[0].clone());
}
elements.extend(unit_values);
}
if need > cap {
self.drain_elided_pack_items(need, cap, unit);
let marker = pack_remainder_marker(is_map, need - cap);
rendered.push(marker.clone());
elements.push(marker);
}
let temp = self.next_temp();
let body = rendered.join(", ");
let (ctor, noun) = match kind {
"map" => (format!("Map({body})"), "entry(s)"),
"struct" => (format!("Struct({body})"), "element(s)"),
_ => (format!("[{body}]"), "element(s)"),
};
self.statements
.push(format!("let {temp} = {ctor}; // pack {need} {noun}"));
if !is_map {
self.packed_values_by_name.insert(temp.clone(), elements);
}
self.stack.push(temp);
}
fn emit_dynamic_pack(&mut self, count_name: String) {
let temp = self.next_temp();
self.statements.push(format!(
"let {temp} = pack_dynamic({count_name}); // pack with dynamic count"
));
self.packed_values_by_name.remove(&temp);
self.stack.push(temp);
}
fn pop_pack_unit(&mut self, unit: usize) -> Vec<String> {
let mut values = Vec::with_capacity(unit);
for _ in 0..unit {
if let Some((value, literal)) = self.pop_stack_value_with_literal() {
if let Some(literal) = literal {
self.literal_values.insert(value.clone(), literal);
}
values.push(value);
} else {
let missing_temp = self.next_temp();
self.statements.push(format!(
"let {missing_temp} = missing_pack_item(); // synthetic missing element for literal pack"
));
values.push(missing_temp);
}
}
values
}
fn drain_elided_pack_items(&mut self, need: usize, cap: usize, unit: usize) {
let mut excess = (need - cap).saturating_mul(unit);
while excess > 0 && self.pop_stack_value().is_some() {
excess -= 1;
}
}
}
fn pack_remainder_marker(is_map: bool, remainder: usize) -> String {
let noun = match (is_map, remainder == 1) {
(true, true) => "entry",
(true, false) => "entries",
(false, true) => "element",
(false, false) => "elements",
};
format!("/* {remainder} more {noun} */")
}