use crate::grove::{Grove, Node, NodeList};
use crate::scheme::SchemeEngine;
use anyhow::Result;
pub fn register_grove_primitives(engine: &mut SchemeEngine) -> Result<()> {
engine.register_fn("grove-root", grove_root);
engine.register_fn("grove-gi-impl", grove_gi);
engine.register_fn("grove-id-impl", grove_id);
engine.register_fn("grove-data-impl", grove_data);
engine.register_fn("grove-attribute-string-impl", grove_attribute_string_impl);
engine.register_fn("children", grove_children);
engine.register_fn("parent", grove_parent);
engine.register_fn("node-list-from-vec", grove_node_list);
engine.register_fn("node-list-empty?", grove_node_list_empty);
engine.register_fn("node-list-first", grove_node_list_first);
engine.register_fn("node-list-rest", grove_node_list_rest);
engine.register_fn("node-list-length", grove_node_list_length);
engine.register_fn("node-list->list", grove_node_list_to_list);
engine.register_fn("element?", grove_element_p);
engine.register_fn("text?", grove_text_p);
engine.register_fn("select-elements", grove_select_elements);
engine.register_fn("select-children", grove_select_children);
engine.register_fn("descendants", grove_descendants);
engine.register_fn("empty-node-list", grove_empty_node_list);
engine.register_fn("node-list-reverse", grove_node_list_reverse);
engine.register_fn("node-list-last", grove_node_list_last);
engine.register_fn("node-list=?", grove_node_list_equal);
engine.register_fn("grove-element-with-id", grove_element_with_id);
engine.register_fn("child-number", grove_child_number);
Ok(())
}
fn grove_root(grove: &Grove) -> Node {
grove.root().clone()
}
fn grove_gi(node: &Node) -> String {
node.gi()
}
fn grove_id(node: &Node) -> Option<String> {
node.id()
}
fn grove_data(node: &Node) -> String {
node.data()
}
fn grove_attribute_string_impl(name: String, node: &Node) -> Option<String> {
node.attribute(&name)
}
fn grove_children(node: &Node) -> NodeList {
node.children()
}
fn grove_parent(node: &Node) -> Option<Node> {
node.parent()
}
fn grove_node_list(nodes: Vec<Node>) -> NodeList {
NodeList::from_vec(nodes)
}
fn grove_node_list_empty(nl: &NodeList) -> bool {
nl.is_empty()
}
fn grove_node_list_first(nl: &NodeList) -> Option<Node> {
nl.first()
}
fn grove_node_list_rest(nl: &NodeList) -> NodeList {
nl.rest()
}
fn grove_node_list_length(nl: &NodeList) -> usize {
nl.len()
}
fn grove_node_list_to_list(nl: &NodeList) -> Vec<Node> {
nl.iter().cloned().collect()
}
fn grove_element_p(node: &Node) -> bool {
node.is_element()
}
fn grove_text_p(node: &Node) -> bool {
node.is_text()
}
fn grove_select_elements(nl: &NodeList, gi: String) -> NodeList {
let filtered: Vec<Node> = nl.iter()
.filter(|node| node.is_element() && node.gi() == gi)
.cloned()
.collect();
NodeList::from_vec(filtered)
}
fn grove_select_children(node: &Node, gi: String) -> NodeList {
let children = node.children();
grove_select_elements(&children, gi)
}
fn grove_descendants(node: &Node) -> NodeList {
fn collect_descendants(node: &Node, acc: &mut Vec<Node>) {
let children = node.children();
for child in children.iter() {
acc.push(child.clone());
collect_descendants(child, acc);
}
}
let mut all_descendants = Vec::new();
collect_descendants(node, &mut all_descendants);
NodeList::from_vec(all_descendants)
}
fn grove_empty_node_list() -> NodeList {
NodeList::from_vec(vec![])
}
fn grove_node_list_reverse(nl: &NodeList) -> NodeList {
let mut nodes: Vec<Node> = nl.iter().cloned().collect();
nodes.reverse();
NodeList::from_vec(nodes)
}
fn grove_node_list_last(nl: &NodeList) -> Option<Node> {
nl.iter().last().cloned()
}
fn grove_node_list_equal(nl1: &NodeList, nl2: &NodeList) -> bool {
if nl1.len() != nl2.len() {
return false;
}
nl1.iter().zip(nl2.iter()).all(|(n1, n2)| n1.ptr_eq(n2))
}
fn grove_element_with_id(grove: &Grove, id: String) -> Option<Node> {
fn search_for_id(node: &Node, target_id: &str) -> Option<Node> {
if node.is_element() {
if let Some(node_id) = node.id() {
if node_id == target_id {
return Some(node.clone());
}
}
}
let children = node.children();
for child in children.iter() {
if let Some(found) = search_for_id(child, target_id) {
return Some(found);
}
}
None
}
search_for_id(&grove.root(), &id)
}
fn grove_child_number(node: &Node) -> usize {
if let Some(parent) = node.parent() {
let siblings = parent.children();
let node_gi = node.gi();
let mut count = 0;
for sibling in siblings.iter() {
if sibling.gi() == node_gi {
count += 1;
if sibling.ptr_eq(node) {
return count; }
}
}
1
} else {
1
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_grove_primitives() {
}
}