diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
| commit | 8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch) | |
| tree | 22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/logos-codegen/src/graph/rope.rs | |
| parent | 4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff) | |
chore: add vendor directory
Diffstat (limited to 'vendor/logos-codegen/src/graph/rope.rs')
| -rw-r--r-- | vendor/logos-codegen/src/graph/rope.rs | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/vendor/logos-codegen/src/graph/rope.rs b/vendor/logos-codegen/src/graph/rope.rs new file mode 100644 index 00000000..6e563fac --- /dev/null +++ b/vendor/logos-codegen/src/graph/rope.rs @@ -0,0 +1,330 @@ +use std::ops::Deref; + +use crate::graph::{Disambiguate, Fork, Graph, NodeId, Range}; + +#[derive(PartialEq, Clone, Hash)] +pub struct Rope { + pub pattern: Pattern, + pub then: NodeId, + pub miss: Miss, +} + +#[derive(PartialEq, Clone, Hash)] +pub struct Pattern(pub Vec<Range>); + +impl Deref for Pattern { + type Target = [Range]; + + fn deref(&self) -> &[Range] { + &self.0 + } +} + +/// Because Ropes could potentially fail a match mid-pattern, +/// a regular `Option` is not sufficient here. +#[derive(PartialEq, Clone, Copy, Hash)] +pub enum Miss { + /// Same as Option::None, error on fail + None, + /// Jump to id if first byte does not match, fail on partial match + First(NodeId), + /// Jump to id on partial or empty match + Any(NodeId), +} + +impl Miss { + pub fn is_none(&self) -> bool { + matches!(self, Miss::None) + } + + pub fn first(self) -> Option<NodeId> { + match self { + Miss::First(id) | Miss::Any(id) => Some(id), + _ => None, + } + } + + pub fn take_first(&mut self) -> Option<NodeId> { + match *self { + Miss::First(id) => { + *self = Miss::None; + + Some(id) + } + Miss::Any(id) => Some(id), + Miss::None => None, + } + } +} + +impl From<Option<NodeId>> for Miss { + fn from(miss: Option<NodeId>) -> Self { + match miss { + Some(id) => Miss::First(id), + None => Miss::None, + } + } +} + +impl From<NodeId> for Miss { + fn from(id: NodeId) -> Self { + Miss::First(id) + } +} + +impl Rope { + pub fn new<P>(pattern: P, then: NodeId) -> Self + where + P: Into<Pattern>, + { + Rope { + pattern: pattern.into(), + then, + miss: Miss::None, + } + } + + pub fn miss<M>(mut self, miss: M) -> Self + where + M: Into<Miss>, + { + self.miss = miss.into(); + self + } + + pub fn miss_any(mut self, miss: NodeId) -> Self { + self.miss = Miss::Any(miss); + self + } + + pub fn into_fork<T>(mut self, graph: &mut Graph<T>) -> Fork + where + T: Disambiguate, + { + let first = self.pattern.0.remove(0); + let miss = self.miss.take_first(); + + // The new fork will lead to a new rope, + // or the old target if no new rope was created + let then = match self.pattern.len() { + 0 => self.then, + _ => graph.push(self), + }; + + Fork::new().branch(first, then).miss(miss) + } + + pub fn prefix(&self, other: &Self) -> Option<(Pattern, Miss)> { + let count = self + .pattern + .iter() + .zip(other.pattern.iter()) + .take_while(|(a, b)| a == b) + .count(); + + let pattern = match count { + 0 => return None, + n => self.pattern[..n].into(), + }; + let miss = match (self.miss, other.miss) { + (Miss::None, miss) => miss, + (miss, Miss::None) => miss, + _ => return None, + }; + + Some((pattern, miss)) + } + + pub fn split_at<T>(mut self, at: usize, graph: &mut Graph<T>) -> Option<Rope> + where + T: Disambiguate, + { + match at { + 0 => return None, + n if n == self.pattern.len() => return Some(self), + _ => (), + } + + let (this, next) = self.pattern.split_at(at); + + let next_miss = match self.miss { + Miss::Any(_) => self.miss, + _ => Miss::None, + }; + + let next = graph.push(Rope { + pattern: next.into(), + miss: next_miss, + then: self.then, + }); + + self.pattern = this.into(); + self.then = next; + + Some(self) + } + + pub fn remainder<T>(mut self, at: usize, graph: &mut Graph<T>) -> NodeId + where + T: Disambiguate, + { + self.pattern = self.pattern[at..].into(); + + match self.pattern.len() { + 0 => self.then, + _ => graph.push(self), + } + } + + pub fn shake<T>(&self, graph: &Graph<T>, filter: &mut [bool]) { + if let Some(id) = self.miss.first() { + if !filter[id.get()] { + filter[id.get()] = true; + graph[id].shake(graph, filter); + } + } + + if !filter[self.then.get()] { + filter[self.then.get()] = true; + graph[self.then].shake(graph, filter); + } + } +} + +impl Pattern { + pub fn to_bytes(&self) -> Option<Vec<u8>> { + let mut out = Vec::with_capacity(self.len()); + + for range in self.iter() { + out.push(range.as_byte()?); + } + + Some(out) + } +} + +impl<T> From<&[T]> for Pattern +where + T: Into<Range> + Copy, +{ + fn from(slice: &[T]) -> Self { + Pattern(slice.iter().copied().map(Into::into).collect()) + } +} + +impl<T> From<Vec<T>> for Pattern +where + T: Into<Range>, +{ + fn from(vec: Vec<T>) -> Self { + Pattern(vec.into_iter().map(Into::into).collect()) + } +} + +impl From<&str> for Pattern { + fn from(slice: &str) -> Self { + slice.as_bytes().into() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::graph::Node; + use pretty_assertions::assert_eq; + + #[test] + fn into_fork() { + let mut graph = Graph::new(); + + let leaf = graph.push(Node::Leaf("LEAF")); + let rope = Rope::new("foobar", leaf); + + let fork = rope.into_fork(&mut graph); + + assert_eq!(leaf, NodeId::new(1)); + assert_eq!(fork, Fork::new().branch(b'f', NodeId::new(2))); + assert_eq!(graph[NodeId::new(2)], Rope::new("oobar", leaf)); + } + + #[test] + fn into_fork_one_byte() { + let mut graph = Graph::new(); + + let leaf = graph.push(Node::Leaf("LEAF")); + let rope = Rope::new("!", leaf); + + let fork = rope.into_fork(&mut graph); + + assert_eq!(leaf, NodeId::new(1)); + assert_eq!(fork, Fork::new().branch(b'!', NodeId::new(1))); + } + + #[test] + fn into_fork_miss_any() { + let mut graph = Graph::new(); + + let leaf = graph.push(Node::Leaf("LEAF")); + let rope = Rope::new("42", leaf).miss_any(NodeId::new(42)); + + let fork = rope.into_fork(&mut graph); + + assert_eq!(leaf, NodeId::new(1)); + assert_eq!( + fork, + Fork::new() + .branch(b'4', NodeId::new(2)) + .miss(NodeId::new(42)) + ); + assert_eq!( + graph[NodeId::new(2)], + Rope::new("2", leaf).miss_any(NodeId::new(42)) + ); + } + + #[test] + fn into_fork_miss_first() { + let mut graph = Graph::new(); + + let leaf = graph.push(Node::Leaf("LEAF")); + let rope = Rope::new("42", leaf).miss(Miss::First(NodeId::new(42))); + + let fork = rope.into_fork(&mut graph); + + assert_eq!(leaf, NodeId::new(1)); + assert_eq!( + fork, + Fork::new() + .branch(b'4', NodeId::new(2)) + .miss(NodeId::new(42)) + ); + assert_eq!(graph[NodeId::new(2)], Rope::new("2", leaf)); + } + + #[test] + fn split_at() { + let mut graph = Graph::new(); + + let leaf = graph.push(Node::Leaf("LEAF")); + let rope = Rope::new("foobar", leaf); + + assert_eq!(rope.clone().split_at(6, &mut graph).unwrap(), rope); + + let split = rope.split_at(3, &mut graph).unwrap(); + let expected_id = NodeId::new(leaf.get() + 1); + + assert_eq!(split, Rope::new("foo", expected_id)); + assert_eq!(graph[expected_id], Rope::new("bar", leaf)); + } + + #[test] + fn pattern_to_bytes() { + let pat = Pattern::from("foobar"); + + assert_eq!(pat.to_bytes().unwrap(), b"foobar"); + + let ranges = Pattern::from(vec![0..=0, 42..=42, b'{'..=b'}']); + + assert_eq!(ranges.to_bytes(), None); + } +} |
