use crate::ns::*;
use by_address::ByAddress;
const LARGE_BYTES: usize = 26_000;
pub struct TreeSemantics<S> {
common: TreeSemantics1<S>,
large_units: RefCell<HashMap<ByAddress<Rc<CompilationUnit>>, TreeSemantics1<S>>>,
}
impl<S: Clone> TreeSemantics<S> {
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();
}
}
pub trait TreeSemanticsAccessor<T, S: Clone> {
fn get(&self, node: &Rc<T>) -> Option<S>;
fn set(&self, node: &Rc<T>, symbol: Option<S>);
fn delete(&self, node: &Rc<T>) -> bool;
fn has(&self, node: &Rc<T>) -> bool;
}
macro impl_semantics_with_loc_call {
(struct $tree_semantics_id:ident, $($nodetype:ident),*$(,)?) => {
$(
impl<S: Clone> TreeSemanticsAccessor<$nodetype, S> for $tree_semantics_id<S> {
fn get(&self, node: &Rc<$nodetype>) -> Option<S> {
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<S>) {
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<S: Clone> TreeSemanticsAccessor<$nodetype, S> for $tree_semantics_id<S> {
fn get(&self, node: &Rc<$nodetype>) -> Option<S> {
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<S>) {
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<S> {
$($nodetype: RefCell<HashMap<NodeAsKey<Rc<$nodetype>>, Option<S>>>,)*
}
impl<S: Clone> $tree_semantics_1_id<S> {
pub fn $new_id() -> Self {
Self {
$($nodetype: RefCell::new(HashMap::new()),)*
}
}
pub fn $clear_id(&self) {
$(self.$nodetype.borrow_mut().clear();)*
}
}
$(
impl<S: Clone> TreeSemanticsAccessor<$nodetype, S> for $tree_semantics_1_id<S> {
fn get(&self, node: &Rc<$nodetype>) -> Option<S> {
self.$nodetype.borrow().get(&NodeAsKey(node.clone())).map(|v| v.clone().unwrap())
}
fn set(&self, node: &Rc<$nodetype>, symbol: Option<S>) {
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,
);