use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, LocalSlot, UpvalueIdx, UpvalueSource}; use crate::ast::nodes::Node; use crate::ast::types::Value; use std::collections::{HashMap, HashSet}; use std::rc::Rc; #[derive(Default)] pub struct SubstitutionMap { pub values: HashMap, pub ast_substitutions: HashMap>, pub slot_mapping: HashMap, pub assigned: HashSet
, pub next_slot: u32, pub used: HashSet
, pub captured_slots: HashSet, } impl SubstitutionMap { pub fn new() -> Self { Self::default() } /// Creates a new SubstitutionMap for an inner scope (like an inlined Lambda). /// Safely inherits only Global substitutions, because Local and Upvalue /// addresses are relative to the specific function frame and would overlap. pub fn new_inner(&self) -> Self { let mut inner = Self::new(); for (k, v) in &self.values { if matches!(k, Address::Global(_)) { inner.values.insert(*k, v.clone()); } } for (k, v) in &self.ast_substitutions { if matches!(k, Address::Global(_)) { inner.ast_substitutions.insert(*k, v.clone()); } } inner } pub fn new_for_inlining(&self) -> Self { let mut inner = self.new_inner(); inner.next_slot = self.next_slot; inner } pub fn add_ast_substitution(&mut self, addr: Address, node: AnalyzedNode) { self.ast_substitutions.insert(addr, Rc::new(node)); } pub fn map_slot(&mut self, old_slot: LocalSlot) -> LocalSlot { if let Some(&new_slot) = self.slot_mapping.get(&old_slot) { return new_slot; } let new_slot = LocalSlot(self.next_slot); self.slot_mapping.insert(old_slot, new_slot); self.next_slot += 1; new_slot } pub fn map_address(&mut self, addr: Address) -> Address { match addr { Address::Local(slot) => Address::Local(self.map_slot(slot)), other => other, } } pub fn add_value(&mut self, addr: Address, val: Value) { self.values.insert(addr, val); } pub fn get_value(&self, addr: &Address) -> Option<&Value> { self.values.get(addr) } pub fn remove_value(&mut self, addr: &Address) { self.values.remove(addr); } fn reindex_addr(&self, addr: Address, mapping: &[Option]) -> Address { if let Address::Upvalue(idx) = addr && let Some(res) = mapping.get(idx.0 as usize) && let Some(new_idx) = res { Address::Upvalue(UpvalueIdx(*new_idx)) } else { addr } } fn reindex_source(&self, source: UpvalueSource, mapping: &[Option]) -> UpvalueSource { match source { UpvalueSource::Upvalue(idx) => { if let Some(res) = mapping.get(idx.0 as usize) && let Some(new_idx) = res { UpvalueSource::Upvalue(UpvalueIdx(*new_idx)) } else { source } } _ => source } } pub fn reindex_upvalues(&self, node_rc: Rc, mapping: &[Option]) -> Rc { let node = &*node_rc; let (new_kind, metrics) = match &node.kind { BoundKind::Get { addr, name } => ( BoundKind::Get { addr: self.reindex_addr(*addr, mapping), name: name.clone(), }, node.ty.clone(), ), BoundKind::Lambda { params, upvalues, body, positional_count, max_slots, } => { let mut next_upvalues = Vec::new(); for source in upvalues { next_upvalues.push(self.reindex_source(*source, mapping)); } ( BoundKind::Lambda { params: params.clone(), upvalues: next_upvalues, body: body.clone(), positional_count: *positional_count, max_slots: *max_slots, }, node.ty.clone(), ) } BoundKind::If { cond, then_br, else_br, } => { let cond = self.reindex_upvalues(cond.clone(), mapping); let then_br = self.reindex_upvalues(then_br.clone(), mapping); let else_br = else_br.as_ref().map(|e| self.reindex_upvalues(e.clone(), mapping)); ( BoundKind::If { cond, then_br, else_br, }, node.ty.clone(), ) } BoundKind::Block { statements, result } => { let t_statements = statements .iter() .map(|s| self.reindex_upvalues(s.clone(), mapping)) .collect(); let t_result = self.reindex_upvalues(result.clone(), mapping); (BoundKind::Block { statements: t_statements, result: t_result }, node.ty.clone()) } BoundKind::Call { callee, args } => { let callee = self.reindex_upvalues(callee.clone(), mapping); let args = self.reindex_upvalues(args.clone(), mapping); (BoundKind::Call { callee, args }, node.ty.clone()) } BoundKind::Define { name, addr, kind, value, identity, captured_by, } => { let value = self.reindex_upvalues(value.clone(), mapping); ( BoundKind::Define { name: name.clone(), addr: *addr, kind: *kind, value, identity: identity.clone(), captured_by: captured_by.clone(), }, node.ty.clone(), ) } BoundKind::Set { addr, value } => { let value = self.reindex_upvalues(value.clone(), mapping); ( BoundKind::Set { addr: self.reindex_addr(*addr, mapping), value, }, node.ty.clone(), ) } BoundKind::Tuple { elements } => { let elements = elements .iter() .map(|e| self.reindex_upvalues(e.clone(), mapping)) .collect(); (BoundKind::Tuple { elements }, node.ty.clone()) } BoundKind::Record { layout, values } => { let values = values .iter() .map(|v| self.reindex_upvalues(v.clone(), mapping)) .collect(); (BoundKind::Record { layout: layout.clone(), values }, node.ty.clone()) } BoundKind::Expansion { original_call, bound_expanded } => { let bound_expanded = self.reindex_upvalues(bound_expanded.clone(), mapping); ( BoundKind::Expansion { original_call: original_call.clone(), bound_expanded, }, node.ty.clone(), ) } k => (k.clone(), node.ty.clone()), }; Rc::new(Node { identity: node.identity.clone(), kind: new_kind, ty: metrics, }) } }