conjure_cp_essence_parser/parser/
util.rs1use tree_sitter::{Node, Parser, Tree};
2use tree_sitter_essence::LANGUAGE;
3
4use super::traversal::WalkDFS;
5
6pub fn get_tree(src: &str) -> Option<(Tree, String)> {
14 let mut parser = Parser::new();
15 parser.set_language(&LANGUAGE.into()).unwrap();
16
17 parser.parse(src, None).and_then(|tree| {
18 let root = tree.root_node();
19 if root.is_error() {
20 return None;
21 }
22
23 let children: Vec<_> = named_children(&root).collect();
24 let first_child = children.first()?;
25
26 if first_child.is_error() {
32 if src.starts_with("_FRAGMENT_EXPRESSION") {
33 None
34 } else {
35 get_tree(&format!("_FRAGMENT_EXPRESSION {src}"))
36 }
37 } else {
38 Some((tree, src.to_string()))
39 }
40 })
41}
42
43pub fn named_children<'a>(node: &'a Node<'a>) -> impl Iterator<Item = Node<'a>> + 'a {
45 (0..node.named_child_count())
46 .filter_map(|i| u32::try_from(i).ok().and_then(|i| node.named_child(i)))
47}
48
49pub fn node_is_expression(node: &Node) -> bool {
50 matches!(
51 node.kind(),
52 "bool_expr" | "arithmetic_expr" | "comparison_expr" | "atom"
53 )
54}
55
56pub fn query_toplevel<'a>(
58 node: &'a Node<'a>,
59 predicate: &'a dyn Fn(&Node<'a>) -> bool,
60) -> impl Iterator<Item = Node<'a>> + 'a {
61 WalkDFS::with_retract(node, predicate).filter(|n| n.is_named() && predicate(n))
62}
63
64pub fn get_metavars<'a>(node: &'a Node<'a>, src: &'a str) -> impl Iterator<Item = String> + 'a {
66 query_toplevel(node, &|n| n.kind() == "metavar").filter_map(|child| {
67 child
68 .named_child(0)
69 .map(|name| src[name.start_byte()..name.end_byte()].to_string())
70 })
71}
72
73mod test {
74 #[allow(unused)]
75 use super::*;
76
77 #[test]
78 fn test_get_metavars() {
79 let src = "such that &x = y";
80 let (tree, _) = get_tree(src).unwrap();
81 let root = tree.root_node();
82 let metavars = get_metavars(&root, src).collect::<Vec<_>>();
83 assert_eq!(metavars, vec!["x"]);
84 }
85}