Add ability to walk the capture group tree
This commit is contained in:
+48
-1
@@ -10,6 +10,7 @@ pub struct Captures<'a, T: Clone> {
|
|||||||
input: &'a str,
|
input: &'a str,
|
||||||
raw: &'a [RawCapture<T>],
|
raw: &'a [RawCapture<T>],
|
||||||
index: usize,
|
index: usize,
|
||||||
|
walk: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Capture<'a, T: Clone> {
|
pub struct Capture<'a, T: Clone> {
|
||||||
@@ -38,8 +39,15 @@ impl<T: Clone> ParseState<T> {
|
|||||||
input: &self.input,
|
input: &self.input,
|
||||||
raw: &self.captures,
|
raw: &self.captures,
|
||||||
index: 0,
|
index: 0,
|
||||||
|
walk: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_captures<'a>(&'a self) -> Captures<'a, T> {
|
||||||
|
let mut result = self.captures();
|
||||||
|
result.walk = true;
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod backend {
|
pub mod backend {
|
||||||
@@ -159,7 +167,7 @@ impl<'a, T: Clone> Iterator for Captures<'a, T> {
|
|||||||
let head = self.raw.get(self.index)?;
|
let head = self.raw.get(self.index)?;
|
||||||
let subtree_len = head.subtree_len.unwrap().get();
|
let subtree_len = head.subtree_len.unwrap().get();
|
||||||
let subtree_slice = &self.raw[self.index..self.index + subtree_len];
|
let subtree_slice = &self.raw[self.index..self.index + subtree_len];
|
||||||
self.index += subtree_len;
|
self.index += if self.walk { 1 } else { subtree_len };
|
||||||
Some(Capture {
|
Some(Capture {
|
||||||
input: &self.input,
|
input: &self.input,
|
||||||
raw: subtree_slice,
|
raw: subtree_slice,
|
||||||
@@ -173,9 +181,16 @@ impl<'a, T: Clone> Capture<'a, T> {
|
|||||||
input: &self.input,
|
input: &self.input,
|
||||||
raw: &self.raw[1..],
|
raw: &self.raw[1..],
|
||||||
index: 0,
|
index: 0,
|
||||||
|
walk: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_children(&self) -> Captures<'a, T> {
|
||||||
|
let mut result = self.children();
|
||||||
|
result.walk = true;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> T {
|
pub fn kind(&self) -> T {
|
||||||
self.raw[0].kind.clone()
|
self.raw[0].kind.clone()
|
||||||
}
|
}
|
||||||
@@ -223,6 +238,7 @@ mod tests {
|
|||||||
hex_config = "let " var_name " = 0x" ('a'..'f' / '0'..'9')+;
|
hex_config = "let " var_name " = 0x" ('a'..'f' / '0'..'9')+;
|
||||||
var_name = "foo" / "bar"; // case must match
|
var_name = "foo" / "bar"; // case must match
|
||||||
|
|
||||||
|
email_text = (!email ANY / email)*;
|
||||||
email = #Email:(#User:user "@" #Domain:domain);
|
email = #Email:(#User:user "@" #Domain:domain);
|
||||||
user = ('a'..'z'i)+;
|
user = ('a'..'z'i)+;
|
||||||
domain = user+ ("." user)+;
|
domain = user+ ("." user)+;
|
||||||
@@ -358,4 +374,35 @@ mod tests {
|
|||||||
]
|
]
|
||||||
"#);
|
"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_walk_captures() {
|
||||||
|
let mut p = ParseState::new("Contact alice@foo.com or bob@bar.net.");
|
||||||
|
assert!(email_text(&mut p));
|
||||||
|
let extract_by_tag = |tag| {
|
||||||
|
p.walk_captures()
|
||||||
|
.filter_map(|c| {
|
||||||
|
if c.kind() == tag {
|
||||||
|
Some(c.text())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
};
|
||||||
|
let users = extract_by_tag(Tag::User);
|
||||||
|
let domains = extract_by_tag(Tag::Domain);
|
||||||
|
assert_debug_snapshot!(users, @r#"
|
||||||
|
[
|
||||||
|
"alice",
|
||||||
|
"bob",
|
||||||
|
]
|
||||||
|
"#);
|
||||||
|
assert_debug_snapshot!(domains, @r#"
|
||||||
|
[
|
||||||
|
"foo.com",
|
||||||
|
"bar.net",
|
||||||
|
]
|
||||||
|
"#);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user