use crate::ast::nodes::{ Address, AnalyzedNode, IdentifierBinding, Node, NodeKind, NodeMetrics, }; use crate::ast::types::{Purity, RecordLayout, StaticType, Value}; use std::cell::RefCell; use std::rc::Rc; pub struct Folder<'a> { pub globals: &'a Option>>>, } impl<'a> Folder<'a> { pub fn new(globals: &'a Option>>>) -> Self { Self { globals } } pub fn make_constant_node(&self, val: Value, template: &AnalyzedNode) -> AnalyzedNode { let ty = val.static_type(); let typed_original = Rc::new(Node { identity: template.identity.clone(), kind: NodeKind::Constant(val.clone()), ty: ty.clone(), }); Node { identity: template.identity.clone(), kind: NodeKind::Constant(val), ty: NodeMetrics { original: typed_original, purity: Purity::Pure, is_recursive: false, }, } } pub fn make_nop_node(&self, template: &AnalyzedNode) -> AnalyzedNode { let typed_original = Rc::new(Node { identity: template.identity.clone(), kind: NodeKind::Nop, ty: StaticType::Void, }); Node { identity: template.identity.clone(), kind: NodeKind::Nop, ty: NodeMetrics { original: typed_original, purity: Purity::Pure, is_recursive: false, }, } } pub fn try_fold_record( &self, layout: &std::sync::Arc, values: &[Rc], template: &AnalyzedNode, ) -> Option { let mut constant_values = Vec::with_capacity(values.len()); for v_node in values { if let NodeKind::Constant(val) = &v_node.kind { constant_values.push(val.clone()); } else { return None; } } let record_val = Value::Record(layout.clone(), Rc::new(constant_values)); Some(self.make_constant_node(record_val, template)) } pub fn try_fold_pure( &self, callee: &AnalyzedNode, arg_nodes: &[Rc], ) -> Option { if callee.ty.purity < Purity::Pure { return None; } let mut arg_values = Vec::with_capacity(arg_nodes.len()); for node in arg_nodes { if let NodeKind::Constant(val) = &node.kind { arg_values.push(val.clone()); } else { return None; } } let func_val = match &callee.kind { NodeKind::Identifier { binding: IdentifierBinding::Reference(Address::Global(idx)), .. } => self.globals.as_ref()?.borrow().get(idx.0 as usize)?.clone(), NodeKind::Constant(val) => val.clone(), _ => return None, }; let result = match func_val { Value::Function(f) => (f.func)(&arg_values), _ => return None, }; Some(self.make_constant_node(result, callee)) } }