use crate::xpath::ast::AstNode;
pub type AstNodeId = u32;
pub const NO_NODE: AstNodeId = u32::MAX;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct SourceSpan {
pub start: usize,
pub end: usize,
}
impl SourceSpan {
#[inline]
pub fn new(start: usize, end: usize) -> Self {
Self { start, end }
}
#[inline]
pub fn at(pos: usize) -> Self {
Self {
start: pos,
end: pos,
}
}
#[inline]
pub fn merge(self, other: Self) -> Self {
Self {
start: self.start.min(other.start),
end: self.end.max(other.end),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.start >= self.end
}
#[inline]
pub fn len(&self) -> usize {
self.end.saturating_sub(self.start)
}
}
#[derive(Debug, Default, Clone)]
pub struct AstArena {
nodes: Vec<AstNode>,
}
impl AstArena {
#[inline]
pub fn new() -> Self {
Self { nodes: Vec::new() }
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
nodes: Vec::with_capacity(capacity),
}
}
#[inline]
pub fn add(&mut self, node: AstNode) -> AstNodeId {
let id = self.nodes.len() as AstNodeId;
self.nodes.push(node);
id
}
#[inline]
pub fn get(&self, id: AstNodeId) -> &AstNode {
&self.nodes[id as usize]
}
#[inline]
pub fn get_mut(&mut self, id: AstNodeId) -> &mut AstNode {
&mut self.nodes[id as usize]
}
#[inline]
pub fn try_get(&self, id: AstNodeId) -> Option<&AstNode> {
self.nodes.get(id as usize)
}
#[inline]
pub fn try_get_mut(&mut self, id: AstNodeId) -> Option<&mut AstNode> {
self.nodes.get_mut(id as usize)
}
#[inline]
pub fn len(&self) -> usize {
self.nodes.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
#[inline]
pub fn clear(&mut self) {
self.nodes.clear();
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (AstNodeId, &AstNode)> {
self.nodes
.iter()
.enumerate()
.map(|(i, n)| (i as AstNodeId, n))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::xpath::ast::{AstNode, ValueNode};
#[test]
fn test_source_span() {
let span = SourceSpan::new(10, 20);
assert_eq!(span.start, 10);
assert_eq!(span.end, 20);
assert_eq!(span.len(), 10);
assert!(!span.is_empty());
let empty = SourceSpan::at(5);
assert!(empty.is_empty());
assert_eq!(empty.len(), 0);
}
#[test]
fn test_span_merge() {
let a = SourceSpan::new(10, 20);
let b = SourceSpan::new(15, 30);
let merged = a.merge(b);
assert_eq!(merged.start, 10);
assert_eq!(merged.end, 30);
}
#[test]
fn test_arena_basic() {
let mut arena = AstArena::new();
assert!(arena.is_empty());
let id1 = arena.add(AstNode::Value(ValueNode::Empty));
let id2 = arena.add(AstNode::Value(ValueNode::Boolean(true)));
assert_eq!(arena.len(), 2);
assert_eq!(id1, 0);
assert_eq!(id2, 1);
}
#[test]
fn test_arena_get() {
let mut arena = AstArena::new();
let id = arena.add(AstNode::Value(ValueNode::String("test".to_string())));
match arena.get(id) {
AstNode::Value(ValueNode::String(s)) => assert_eq!(s, "test"),
_ => panic!("Unexpected node type"),
}
}
#[test]
fn test_arena_try_get() {
let arena = AstArena::new();
assert!(arena.try_get(0).is_none());
assert!(arena.try_get(100).is_none());
}
#[test]
fn test_arena_iter() {
let mut arena = AstArena::new();
arena.add(AstNode::Value(ValueNode::Empty));
arena.add(AstNode::Value(ValueNode::Boolean(true)));
let ids: Vec<_> = arena.iter().map(|(id, _)| id).collect();
assert_eq!(ids, vec![0, 1]);
}
}