use crate::ast::nodes::{Symbol, SyntaxKind, SyntaxNode}; use crate::ast::types::{Identity, Value}; use std::collections::HashMap; use std::rc::Rc; /// Trait for evaluating expressions during macro expansion. pub trait MacroEvaluator { fn evaluate( &self, node: &SyntaxNode, bindings: &HashMap, SyntaxNode>, ) -> Result; } /// Internal state for template expansion (Hygiene context + Parameter binding) struct ExpansionState<'a> { bindings: &'a HashMap, SyntaxNode>, /// The identity of the current expansion instance, used to "color" internal symbols. expansion_id: Identity, } type MacroMap = HashMap, (Vec>, SyntaxNode)>; /// A registry for macro declarations. #[derive(Clone)] pub struct MacroRegistry { scopes: Vec>, } impl Default for MacroRegistry { fn default() -> Self { Self::new() } } impl MacroRegistry { pub fn new() -> Self { Self { scopes: vec![Rc::new(HashMap::new())], } } pub fn push(&mut self) { self.scopes.push(Rc::new(HashMap::new())); } pub fn pop(&mut self) { if self.scopes.len() > 1 { self.scopes.pop(); } } pub fn define(&mut self, name: Rc, params: Vec>, body: SyntaxNode) { if let Some(current_rc) = self.scopes.last_mut() { // Copy-on-Write: If the Rc is shared, clone the map before modifying. let current = Rc::make_mut(current_rc); current.insert(name, (params, body)); } } pub fn lookup(&self, name: &str) -> Option<(Vec>, SyntaxNode)> { for scope in self.scopes.iter().rev() { if let Some(m) = scope.get(name) { return Some(m.clone()); } } None } } pub struct MacroExpander { registry: MacroRegistry, evaluator: E, } impl MacroExpander { pub fn new(registry: MacroRegistry, evaluator: E) -> Self { Self { registry, evaluator, } } pub fn into_registry(self) -> MacroRegistry { self.registry } pub fn expand(&mut self, node: SyntaxNode) -> Result { self.expand_recursive(node) } fn expand_recursive(&mut self, node: SyntaxNode) -> Result { match node.kind { SyntaxKind::MacroDecl { name, params, body } => { let p_names = self.extract_param_names(¶ms)?; self.registry.define(name.name, p_names, (*body).clone()); Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Nop, ty: (), }) } SyntaxKind::Call { callee, args } => { if let SyntaxKind::Identifier { symbol: ref sym, .. } = callee.kind && let Some((params, body)) = self.registry.lookup(&sym.name) { let expanded_args = self.expand_recursive((*args).clone())?; // Extract argument nodes from the expanded tuple let arg_elements = if let SyntaxKind::Tuple { elements } = expanded_args.kind { elements.into_iter().map(|e| (*e).clone()).collect() } else { vec![expanded_args] }; let expanded = self.expand_call( node.identity.clone(), &sym.name, params, arg_elements, body, )?; return self.expand_recursive(expanded); } let expanded_callee = self.expand_recursive((*callee).clone())?; let expanded_args = self.expand_recursive((*args).clone())?; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Call { callee: Rc::new(expanded_callee), args: Rc::new(expanded_args), }, ty: (), }) } SyntaxKind::Block { exprs } => { self.registry.push(); let mut expanded_exprs = Vec::new(); for expr in exprs { expanded_exprs.push(Rc::new(self.expand_recursive((*expr).clone())?)); } self.registry.pop(); Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Block { exprs: expanded_exprs, }, ty: (), }) } SyntaxKind::Lambda { params, body, .. } => { self.registry.push(); let expanded_params = self.expand_recursive((*params).clone())?; let expanded_body = self.expand_recursive((*body).clone())?; self.registry.pop(); Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Lambda { params: Rc::new(expanded_params), body: Rc::new(expanded_body), info: (), }, ty: (), }) } SyntaxKind::If { cond, then_br, else_br, } => { let cond = self.expand_recursive((*cond).clone())?; let then_br = self.expand_recursive((*then_br).clone())?; let else_br = if let Some(e) = else_br { Some(Rc::new(self.expand_recursive((*e).clone())?)) } else { None }; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::If { cond: Rc::new(cond), then_br: Rc::new(then_br), else_br, }, ty: (), }) } SyntaxKind::Def { pattern, value, .. } => { let pattern = self.expand_recursive((*pattern).clone())?; let value = self.expand_recursive((*value).clone())?; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Def { pattern: Rc::new(pattern), value: Rc::new(value), info: (), }, ty: (), }) } SyntaxKind::Assign { target, value, .. } => { let target = self.expand_recursive((*target).clone())?; let value = self.expand_recursive((*value).clone())?; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Assign { target: Rc::new(target), value: Rc::new(value), info: (), }, ty: (), }) } SyntaxKind::Tuple { elements } => { let mut expanded_elements = Vec::new(); for e in elements { expanded_elements.push(Rc::new(self.expand_recursive((*e).clone())?)); } Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Tuple { elements: expanded_elements, }, ty: (), }) } SyntaxKind::Record { fields, .. } => { let mut expanded_fields = Vec::new(); for (k, v) in fields { expanded_fields.push(( Rc::new(self.expand_recursive((*k).clone())?), Rc::new(self.expand_recursive((*v).clone())?), )); } Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Record { fields: expanded_fields, layout: (), }, ty: (), }) } SyntaxKind::Expansion { original_call, expanded } => { let expanded = self.expand_recursive((*expanded).clone())?; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Expansion { original_call, expanded: Rc::new(expanded), }, ty: (), }) } SyntaxKind::Again { args } => { let expanded_args = self.expand_recursive((*args).clone())?; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Again { args: Rc::new(expanded_args), }, ty: (), }) } _ => Ok(node), } } fn expand_call( &self, identity: Identity, name: &str, params: Vec>, args: Vec, body: SyntaxNode, ) -> Result { if params.len() != args.len() { return Err(format!( "Macro {} expects {} arguments, but got {}", name, params.len(), args.len() )); } let mut bindings = HashMap::new(); for (p, a) in params.into_iter().zip(args.into_iter()) { bindings.insert(p, a); } // AST-Authority: Substitution and Hygiene ONLY happen if there is a Template node. let expanded_body = if let SyntaxKind::Template(inner) = body.kind { let mut state = ExpansionState { bindings: &bindings, expansion_id: identity.clone(), }; self.expand_template((*inner).clone(), &mut state)? } else { // Static AST fragment: No substitution, no hygiene. body }; let original_call = SyntaxNode { comments: std::rc::Rc::from([]), identity: identity.clone(), kind: SyntaxKind::Call { callee: Rc::new(SyntaxNode { comments: std::rc::Rc::from([]), identity: identity.clone(), kind: SyntaxKind::Identifier { symbol: Symbol::from(name), binding: (), }, ty: (), }), args: Rc::new(SyntaxNode { comments: std::rc::Rc::from([]), identity: identity.clone(), kind: SyntaxKind::Tuple { elements: bindings.into_values().map(Rc::new).collect(), }, ty: (), }), }, ty: (), }; Ok(SyntaxNode { comments: std::rc::Rc::from([]), identity, kind: SyntaxKind::Expansion { original_call: Rc::new(original_call), expanded: Rc::new(expanded_body), }, ty: (), }) } fn extract_param_names(&self, node: &SyntaxNode) -> Result>, String> { match &node.kind { SyntaxKind::Identifier { symbol: sym, .. } => Ok(vec![sym.name.clone()]), SyntaxKind::Tuple { elements } => { let mut names = Vec::new(); for el in elements { names.extend(self.extract_param_names(el)?); } Ok(names) } _ => Err("Invalid parameter pattern in macro declaration".to_string()), } } fn expand_template( &self, node: SyntaxNode, state: &mut ExpansionState, ) -> Result { match node.kind { SyntaxKind::Identifier { mut symbol, .. } => { // Inside a template, all internal identifiers are colored. symbol.context = Some(state.expansion_id.clone()); Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Identifier { symbol, binding: (), }, ty: (), }) } SyntaxKind::Placeholder(inner) => { // Break out of template for substitution/evaluation if let SyntaxKind::Identifier { symbol: ref sym, .. } = inner.kind { if let Some(arg) = state.bindings.get(&sym.name) { return Ok(arg.clone()); } // Non-parameter identifier: return bare symbol without hygiene context. // This is the explicit unhygienic escape — ~x reaches into the call site. return Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Identifier { symbol: sym.clone(), binding: (), }, ty: (), }); } let val = self.evaluator.evaluate(&inner, state.bindings)?; Ok(self.value_to_node(val, node.identity)) } SyntaxKind::Splice(inner) => { // Splicing is also a form of substitution if let SyntaxKind::Identifier { symbol: ref sym, .. } = inner.kind && let Some(arg) = state.bindings.get(&sym.name) { return Ok(arg.clone()); } let val = self.evaluator.evaluate(&inner, state.bindings)?; Ok(self.value_to_node(val, node.identity)) } SyntaxKind::Def { pattern, value, .. } => { let pattern = self.expand_template((*pattern).clone(), state)?; let val = self.expand_template((*value).clone(), state)?; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Def { pattern: Rc::new(pattern), value: Rc::new(val), info: (), }, ty: (), }) } SyntaxKind::Assign { target, value, .. } => { let target = self.expand_template((*target).clone(), state)?; let value = self.expand_template((*value).clone(), state)?; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Assign { target: Rc::new(target), value: Rc::new(value), info: (), }, ty: (), }) } SyntaxKind::Tuple { elements } => { let mut new_elements = Vec::new(); for e in elements { if let SyntaxKind::Splice(ref inner) = e.kind { let val = self.evaluator.evaluate(inner, state.bindings)?; self.handle_splice_value(val, node.identity.clone(), &mut new_elements)?; } else { new_elements.push(Rc::new(self.expand_template((*e).clone(), state)?)); } } Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Tuple { elements: new_elements, }, ty: (), }) } SyntaxKind::Block { exprs } => { let mut new_exprs = Vec::new(); for e in exprs { if let SyntaxKind::Splice(ref inner) = e.kind { let val = self.evaluator.evaluate(inner, state.bindings)?; self.handle_splice_value(val, node.identity.clone(), &mut new_exprs)?; } else { new_exprs.push(Rc::new(self.expand_template((*e).clone(), state)?)); } } Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Block { exprs: new_exprs }, ty: (), }) } SyntaxKind::Record { fields, .. } => { let mut new_fields = Vec::new(); for (k, v) in fields { new_fields.push(( Rc::new(self.expand_template((*k).clone(), state)?), Rc::new(self.expand_template((*v).clone(), state)?), )); } Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Record { fields: new_fields, layout: (), }, ty: (), }) } SyntaxKind::Call { callee, args } => { let expanded_callee = self.expand_template((*callee).clone(), state)?; let expanded_args = self.expand_template((*args).clone(), state)?; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Call { callee: Rc::new(expanded_callee), args: Rc::new(expanded_args), }, ty: (), }) } SyntaxKind::If { cond, then_br, else_br, } => { let cond = self.expand_template((*cond).clone(), state)?; let then_br = self.expand_template((*then_br).clone(), state)?; let else_br = if let Some(e) = else_br { Some(Rc::new(self.expand_template((*e).clone(), state)?)) } else { None }; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::If { cond: Rc::new(cond), then_br: Rc::new(then_br), else_br, }, ty: (), }) } SyntaxKind::Lambda { params, body, .. } => { let expanded_params = self.expand_template((*params).clone(), state)?; let body = self.expand_template((*body).clone(), state)?; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Lambda { params: Rc::new(expanded_params), body: Rc::new(body), info: (), }, ty: (), }) } SyntaxKind::Again { args } => { let expanded_args = self.expand_template((*args).clone(), state)?; Ok(SyntaxNode { comments: node.comments.clone(), identity: node.identity, kind: SyntaxKind::Again { args: Rc::new(expanded_args), }, ty: (), }) } _ => Ok(node), } } fn handle_splice_value( &self, val: Value, _identity: Identity, target: &mut Vec>, ) -> Result<(), String> { match val { Value::Quote(node) => match &node.kind { SyntaxKind::Tuple { elements } => { for e in elements { target.push(e.clone()); } Ok(()) } SyntaxKind::Block { exprs } => { for e in exprs { target.push(e.clone()); } Ok(()) } _ => Err("Strict Splicing: Expected Tuple or Block node".to_string()), }, _ => Err(format!( "Strict Splicing: Expected sequence (Tuple/Block Node), but found Value: {}", val )), } } fn value_to_node(&self, val: Value, identity: Identity) -> SyntaxNode { match val { Value::Quote(rc) => rc.as_ref().clone(), _ => SyntaxNode { comments: std::rc::Rc::from([]), identity, kind: SyntaxKind::Constant(val), ty: (), }, } } } #[cfg(test)] mod tests { use super::*; use crate::ast::compiler::binder::{CompilerScope, LocalInfo}; use crate::ast::compiler::Binder; use crate::ast::diagnostics::Diagnostics; use crate::ast::nodes::{Address, VirtualId}; use crate::ast::parser::Parser; use crate::ast::types::{NodeIdentity, Purity, SourceLocation, StaticType, Value}; struct SimpleEvaluator; impl MacroEvaluator for SimpleEvaluator { fn evaluate( &self, node: &SyntaxNode, bindings: &HashMap, SyntaxNode>, ) -> Result { if let SyntaxKind::Identifier { symbol: ref sym, .. } = node.kind && let Some(arg) = bindings.get(&sym.name) { return Ok(Value::Quote(Rc::new(arg.clone()))); } Err(format!( "SimpleEvaluator cannot evaluate complex expression: {:?}", node.kind )) } } #[test] fn test_macro_expansion_hygiene() { let source = " (do (macro m [] `(def y 10)) (m)) "; let mut parser = Parser::new(source); let syntax = parser.parse_expression(); let mut expander = MacroExpander::new(MacroRegistry::new(), SimpleEvaluator); let expanded = expander.expand(syntax).unwrap(); if let SyntaxKind::Block { exprs } = &expanded.kind && let SyntaxKind::Expansion { expanded: result, original_call, } = &exprs[1].kind { if let SyntaxKind::Def { pattern, .. } = &result.kind { if let SyntaxKind::Identifier { symbol: sym, .. } = &pattern.kind { assert_eq!(sym.context, Some(original_call.identity.clone())); assert_eq!(sym.name.as_ref(), "y"); } else { panic!("Expected Identifier target, got {:?}", pattern.kind); } } else { panic!("Expected Def result, got {:?}", result.kind); } } } #[test] fn test_macro_expansion_unless() { let source = " (do (macro unless [c b] `(if ~c ... ~b)) (unless false 42)) "; let mut parser = Parser::new(source); let syntax = parser.parse_expression(); let mut expander = MacroExpander::new(MacroRegistry::new(), SimpleEvaluator); let expanded = expander.expand(syntax).unwrap(); if let SyntaxKind::Block { exprs } = &expanded.kind && let SyntaxKind::Expansion { original_call: _, expanded: result, } = &exprs[1].kind && let SyntaxKind::If { cond, then_br, else_br, } = &result.kind { if let SyntaxKind::Identifier { symbol: sym, .. } = &cond.kind { assert_eq!(sym.name.as_ref(), "false"); } else { panic!("Expected identifier 'false', got {:?}", cond.kind); } assert!(matches!(then_br.kind, SyntaxKind::Nop)); if let Some(eb) = else_br { if let SyntaxKind::Constant(Value::Int(n)) = &eb.kind { assert_eq!(*n, 42); } else { panic!("Expected 42, got {:?}", eb.kind); } } else { panic!("Else branch missing"); } } } #[test] fn test_macro_expansion_splice() { let source = " (do (macro wrap [items] `[0 ~@items 4]) (def t (wrap [1 2 3]))) "; let mut parser = Parser::new(source); let syntax = parser.parse_expression(); let mut expander = MacroExpander::new(MacroRegistry::new(), SimpleEvaluator); let expanded = expander.expand(syntax).unwrap(); if let SyntaxKind::Block { exprs } = &expanded.kind && let SyntaxKind::Def { value, .. } = &exprs[1].kind && let SyntaxKind::Expansion { expanded: result, .. } = &value.kind && let SyntaxKind::Tuple { elements } = &result.kind { assert_eq!(elements.len(), 5); if let SyntaxKind::Constant(Value::Int(n)) = &elements[0].kind { assert_eq!(*n, 0); } if let SyntaxKind::Constant(Value::Int(n)) = &elements[4].kind { assert_eq!(*n, 4); } } } #[test] fn test_repro_macro_global_lookup() { let source = " (do (macro square [x] `(* ~x ~x)) (square 3)) "; let mut parser = Parser::new(source); let syntax = parser.parse_expression(); let mut expander = MacroExpander::new(MacroRegistry::new(), SimpleEvaluator); let expanded = expander.expand(syntax).unwrap(); // Convert test globals into a CompilerScope let mut locals = HashMap::new(); locals.insert( Symbol::from("*"), LocalInfo { addr: Address::Local(VirtualId(0)), identity: NodeIdentity::new(SourceLocation { line: 0, col: 0, }), _ty: StaticType::Any, purity: Purity::Pure, }, ); let initial_scopes = vec![CompilerScope { locals }]; let mut diag = Diagnostics::new(); // fixed_scope_idx = 0 means scope 0 is frozen (Global) let result = Binder::bind_root(initial_scopes, 1, 0, &expanded, &mut diag); assert!( result.is_ok(), "Should find global '*' Error: {:?}", result.err() ); } #[test] fn test_repro_macro_hygiene_success() { let source = " (do (def y 1) (macro m [] `(def y 10)) (m) y) "; let mut parser = Parser::new(source); let syntax = parser.parse_expression(); let mut expander = MacroExpander::new(MacroRegistry::new(), SimpleEvaluator); let expanded = expander.expand(syntax).unwrap(); let mut diag = Diagnostics::new(); let result = Binder::bind_root(vec![], 0, 0, &expanded, &mut diag); assert!(result.is_ok(), "Hygiene failed: {:?}", result.err()); } #[test] fn test_repro_macro_hygiene_clash_fixed() { let source = " (do (def y 1) (macro m1 [x] `(do (def y 10) (assign y 4))) (m1 8) y) "; let mut parser = Parser::new(source); let syntax = parser.parse_expression(); let mut expander = MacroExpander::new(MacroRegistry::new(), SimpleEvaluator); let expanded = expander.expand(syntax).unwrap(); let mut diag = Diagnostics::new(); let result = Binder::bind_root(vec![], 0, 0, &expanded, &mut diag); assert!( result.is_ok(), "Explicit Hygiene with Backticks failed: {:?}", result.err() ); } #[test] fn test_macro_tilde_nonparam_assign() { // ~x where x is not a parameter should produce a bare identifier, // allowing it to resolve against the call-site variable. let source = " (do (def x 0) (macro inc-x [] `(assign ~x (+ ~x 1))) (inc-x) x) "; let mut parser = Parser::new(source); let syntax = parser.parse_expression(); let mut expander = MacroExpander::new(MacroRegistry::new(), SimpleEvaluator); let expanded = expander.expand(syntax).unwrap(); let mut diag = Diagnostics::new(); let result = Binder::bind_root(vec![], 0, 0, &expanded, &mut diag); assert!( result.is_ok(), "~nonparam should resolve to call-site variable: {:?}", result.err() ); } #[test] fn test_macro_hygiene_def_still_isolated() { // A plain template `def` (without ~) still creates a hygienically // isolated binding, so the call-site variable is unchanged. let source = " (do (def x 99) (macro reset [] `(def x 0)) (reset) x) "; let mut parser = Parser::new(source); let syntax = parser.parse_expression(); let mut expander = MacroExpander::new(MacroRegistry::new(), SimpleEvaluator); let expanded = expander.expand(syntax).unwrap(); let mut diag = Diagnostics::new(); let result = Binder::bind_root(vec![], 0, 0, &expanded, &mut diag); assert!( result.is_ok(), "Hygiene isolation for def should still hold: {:?}", result.err() ); } }