use crate::ns::*; use by_address::ByAddress; const LARGE_BYTES: usize = 26_000; /// Represents a mapping of nodes to something. /// /// A limited set of nodes may be mapped to something within this /// structure through using the implemented `TreeSemanticsAccessor` /// methods, such as `.get()` and `.set()`. pub struct TreeSemantics { common: TreeSemantics1, large_units: RefCell>, TreeSemantics1>>, } impl TreeSemantics { pub fn new() -> Self { Self { common: TreeSemantics1::new(), large_units: RefCell::new(HashMap::new()), } } pub fn clear(&self) { self.common.clear(); self.large_units.borrow_mut().clear(); } } /// Defines access methods for the `TreeSemantics` structure, /// used for attaching semantics to the syntactic tree, /// where `T` is the node type, and `S` is the symbol type. pub trait TreeSemanticsAccessor { fn get(&self, node: &Rc) -> Option; fn set(&self, node: &Rc, symbol: Option); fn delete(&self, node: &Rc) -> bool; fn has(&self, node: &Rc) -> bool; } macro impl_semantics_with_loc_call { (struct $tree_semantics_id:ident, $($nodetype:ident),*$(,)?) => { $( impl TreeSemanticsAccessor<$nodetype, S> for $tree_semantics_id { fn get(&self, node: &Rc<$nodetype>) -> Option { let cu = node.location().compilation_unit(); if cu.text().len() < LARGE_BYTES { self.common.get(node) } else { let large_units = self.large_units.borrow(); let m1 = large_units.get(&ByAddress(cu)); m1.and_then(|m1| m1.get(node)) } } fn set(&self, node: &Rc<$nodetype>, symbol: Option) { let cu = node.location().compilation_unit(); if cu.text().len() < LARGE_BYTES { self.common.set(node, symbol); } else { let mut large_units = self.large_units.borrow_mut(); let m1 = large_units.get_mut(&ByAddress(cu.clone())); if let Some(m1) = m1 { m1.set(node, symbol); } else { let m1 = TreeSemantics1::new(); m1.set(node, symbol); large_units.insert(ByAddress(cu), m1); } } } fn delete(&self, node: &Rc<$nodetype>) -> bool { let cu = node.location().compilation_unit(); if cu.text().len() < LARGE_BYTES { self.common.delete(node) } else { let mut large_units = self.large_units.borrow_mut(); let m1 = large_units.get_mut(&ByAddress(cu)); m1.map(|m1| m1.delete(node)).unwrap_or(false) } } fn has(&self, node: &Rc<$nodetype>) -> bool { let cu = node.location().compilation_unit(); if cu.text().len() < LARGE_BYTES { self.common.has(node) } else { let large_units = self.large_units.borrow(); let m1 = large_units.get(&ByAddress(cu)); m1.map(|m1| m1.has(node)).unwrap_or(false) } } } )* }, } macro impl_semantics_with_loc_field { (struct $tree_semantics_id:ident, $($nodetype:ident),*$(,)?) => { $( impl TreeSemanticsAccessor<$nodetype, S> for $tree_semantics_id { fn get(&self, node: &Rc<$nodetype>) -> Option { let cu = node.location.compilation_unit(); if cu.text().len() < LARGE_BYTES { self.common.get(node) } else { let large_units = self.large_units.borrow(); let m1 = large_units.get(&ByAddress(cu)); m1.and_then(|m1| m1.get(node)) } } fn set(&self, node: &Rc<$nodetype>, symbol: Option) { let cu = node.location.compilation_unit(); if cu.text().len() < LARGE_BYTES { self.common.set(node, symbol); } else { let mut large_units = self.large_units.borrow_mut(); let m1 = large_units.get_mut(&ByAddress(cu.clone())); if let Some(m1) = m1 { m1.set(node, symbol); } else { let m1 = TreeSemantics1::new(); m1.set(node, symbol); large_units.insert(ByAddress(cu), m1); } } } fn delete(&self, node: &Rc<$nodetype>) -> bool { let cu = node.location.compilation_unit(); if cu.text().len() < LARGE_BYTES { self.common.delete(node) } else { let mut large_units = self.large_units.borrow_mut(); let m1 = large_units.get_mut(&ByAddress(cu)); m1.map(|m1| m1.delete(node)).unwrap_or(false) } } fn has(&self, node: &Rc<$nodetype>) -> bool { let cu = node.location.compilation_unit(); if cu.text().len() < LARGE_BYTES { self.common.has(node) } else { let large_units = self.large_units.borrow(); let m1 = large_units.get(&ByAddress(cu)); m1.map(|m1| m1.has(node)).unwrap_or(false) } } } )* }, } macro impl_semantics_1 { (struct $tree_semantics_1_id:ident, fn $new_id:ident, fn $clear_id:ident, $($nodetype:ident),*$(,)?) => { #[allow(non_snake_case)] struct $tree_semantics_1_id { $($nodetype: RefCell>, Option>>,)* } impl $tree_semantics_1_id { pub fn $new_id() -> Self { Self { $($nodetype: RefCell::new(HashMap::new()),)* } } pub fn $clear_id(&self) { $(self.$nodetype.borrow_mut().clear();)* } } $( impl TreeSemanticsAccessor<$nodetype, S> for $tree_semantics_1_id { fn get(&self, node: &Rc<$nodetype>) -> Option { self.$nodetype.borrow().get(&NodeAsKey(node.clone())).map(|v| v.clone().unwrap()) } fn set(&self, node: &Rc<$nodetype>, symbol: Option) { self.$nodetype.borrow_mut().insert(NodeAsKey(node.clone()), symbol); } fn delete(&self, node: &Rc<$nodetype>) -> bool { self.$nodetype.borrow_mut().remove(&NodeAsKey(node.clone())).is_some() } fn has(&self, node: &Rc<$nodetype>) -> bool { self.$nodetype.borrow().contains_key(&NodeAsKey(node.clone())) } } )* }, } impl_semantics_with_loc_call!( struct TreeSemantics, Expression, InitializerField, Directive, MxmlContent, CssDirective, CssMediaQueryCondition, CssSelectorCondition, CssPropertyValue, CssSelector, ); impl_semantics_with_loc_field!( struct TreeSemantics, FunctionCommon, Block, Program, PackageDefinition, SimpleVariableDefinition, Mxml, MxmlElement, MxmlAttribute, CssProperty, CssRule, CssDocument, QualifiedIdentifier, ); impl_semantics_1!( struct TreeSemantics1, fn new, fn clear, Expression, InitializerField, Directive, FunctionCommon, Block, Program, PackageDefinition, SimpleVariableDefinition, QualifiedIdentifier, Mxml, MxmlContent, MxmlElement, MxmlAttribute, CssDirective, CssRule, CssMediaQueryCondition, CssSelectorCondition, CssPropertyValue, CssSelector, CssProperty, CssDocument, );