Skip to main content

antlr4_runtime/
tree.rs

1use crate::errors::AntlrError;
2use crate::recognizer::Recognizer;
3use std::any::Any;
4use std::fmt;
5use std::rc::Rc;
6
7use crate::token::{CommonToken, Token, TokenRef};
8use std::collections::BTreeMap;
9
10#[derive(Clone, Debug, Eq, PartialEq)]
11pub enum ParseTree {
12    Rule(RuleNode),
13    Terminal(TerminalNode),
14    Error(ErrorNode),
15}
16
17impl ParseTree {
18    /// Returns this node's direct children.
19    ///
20    /// Rule nodes return their context children; terminal and error nodes
21    /// return an empty slice, so generic recursive walks can start from a
22    /// `&ParseTree` without matching on every variant first.
23    pub fn children(&self) -> &[Self] {
24        match self {
25            Self::Rule(rule) => rule.context().children(),
26            Self::Terminal(_) | Self::Error(_) => &[],
27        }
28    }
29
30    /// Iterates this tree in pre-order, starting with `self`.
31    pub fn descendants(&self) -> ParseTreeDescendants<'_> {
32        ParseTreeDescendants { stack: vec![self] }
33    }
34
35    /// Iterates this tree in pre-order, starting with `self`.
36    ///
37    /// This is an alias for [`Self::descendants`] for callers that prefer to
38    /// name the traversal order explicitly.
39    pub fn pre_order(&self) -> ParseTreeDescendants<'_> {
40        self.descendants()
41    }
42
43    pub fn text(&self) -> String {
44        match self {
45            Self::Rule(rule) => rule.text(),
46            Self::Terminal(node) => node.text(),
47            Self::Error(node) => node.text(),
48        }
49    }
50
51    pub fn to_string_tree_with_names<S: AsRef<str>>(&self, rule_names: &[S]) -> String {
52        match self {
53            Self::Rule(rule) => rule.to_string_tree_with_names(rule_names),
54            Self::Terminal(node) => escape_tree_text(&node.text()),
55            Self::Error(node) => escape_tree_text(&node.text()),
56        }
57    }
58
59    /// Renders the LISP-style tree using rule names resolved through a
60    /// recognizer, matching ANTLR's `toStringTree(parser)` shape used by
61    /// generated test actions (`<tree>.to_string_tree(Some(self))`).
62    pub fn to_string_tree<R: Recognizer>(&self, recognizer: Option<&R>) -> String {
63        recognizer.map_or_else(
64            || self.to_string_tree_with_names::<&str>(&[]),
65            |recognizer| self.to_string_tree_with_names(recognizer.data().rule_names()),
66        )
67    }
68
69    /// Finds the first rule node with `rule_index` in a depth-first walk.
70    pub fn first_rule(&self, rule_index: usize) -> Option<&Self> {
71        match self {
72            Self::Rule(rule) => {
73                if rule.context().rule_index() == rule_index {
74                    return Some(self);
75                }
76                rule.context()
77                    .children()
78                    .iter()
79                    .find_map(|child| child.first_rule(rule_index))
80            }
81            Self::Terminal(_) | Self::Error(_) => None,
82        }
83    }
84
85    /// Finds the stop token for the first rule node with `rule_index`.
86    pub fn first_rule_stop(&self, rule_index: usize) -> Option<&CommonToken> {
87        let Self::Rule(rule) = self else {
88            return None;
89        };
90        if rule.context().rule_index() == rule_index {
91            return rule.context().stop();
92        }
93        rule.context()
94            .children()
95            .iter()
96            .find_map(|child| child.first_rule_stop(rule_index))
97    }
98
99    /// Reads an integer return value from the first rule node with
100    /// `rule_index`, matching ANTLR's `$label.value` resolution for labeled
101    /// rule references in the runtime testsuite.
102    pub fn first_rule_int_return(&self, rule_index: usize, name: &str) -> Option<i64> {
103        let Self::Rule(rule) = self else {
104            return None;
105        };
106        if rule.context().rule_index() == rule_index {
107            return rule.context().int_return(name);
108        }
109        rule.context()
110            .children()
111            .iter()
112            .find_map(|child| child.first_rule_int_return(rule_index, name))
113    }
114
115    /// Reads the typed attribute snapshot from this tree's root rule node.
116    ///
117    /// Generated parsers use this for `$label.attr` / `$rule.attr` reads on a
118    /// child subtree returned by a rule call.
119    pub fn rule_attrs<T: Any>(&self) -> Option<&T> {
120        let Self::Rule(rule) = self else {
121            return None;
122        };
123        rule.context().generated_attrs::<T>()
124    }
125
126    /// Finds the first recovery error token in a depth-first walk.
127    pub fn first_error_token(&self) -> Option<&CommonToken> {
128        match self {
129            Self::Rule(rule) => rule
130                .context()
131                .children()
132                .iter()
133                .find_map(Self::first_error_token),
134            Self::Terminal(_) => None,
135            Self::Error(node) => Some(node.symbol()),
136        }
137    }
138
139    /// Returns the first rule invocation stack for `rule_index`, ordered from
140    /// the selected rule outward to the root rule.
141    pub fn rule_invocation_stack<S: AsRef<str>>(
142        &self,
143        rule_index: usize,
144        rule_names: &[S],
145    ) -> Option<Vec<String>> {
146        let mut stack = Vec::new();
147        if self.find_rule_path(rule_index, rule_names, &mut stack) {
148            stack.reverse();
149            return Some(stack);
150        }
151        None
152    }
153
154    fn find_rule_path<S: AsRef<str>>(
155        &self,
156        rule_index: usize,
157        rule_names: &[S],
158        stack: &mut Vec<String>,
159    ) -> bool {
160        let Self::Rule(rule) = self else {
161            return false;
162        };
163        let current_index = rule.context().rule_index();
164        stack.push(
165            rule_names
166                .get(current_index)
167                .map_or("<unknown>", |name| name.as_ref())
168                .to_owned(),
169        );
170        if current_index == rule_index
171            || rule
172                .context()
173                .children()
174                .iter()
175                .any(|child| child.find_rule_path(rule_index, rule_names, stack))
176        {
177            return true;
178        }
179        stack.pop();
180        false
181    }
182}
183
184#[derive(Clone, Debug)]
185pub struct ParseTreeDescendants<'a> {
186    stack: Vec<&'a ParseTree>,
187}
188
189impl<'a> Iterator for ParseTreeDescendants<'a> {
190    type Item = &'a ParseTree;
191
192    fn next(&mut self) -> Option<Self::Item> {
193        let tree = self.stack.pop()?;
194        self.stack.extend(tree.children().iter().rev());
195        Some(tree)
196    }
197}
198
199fn escape_tree_text(text: &str) -> String {
200    let mut escaped = String::with_capacity(text.len());
201    for ch in text.chars() {
202        match ch {
203            '\n' => escaped.push_str("\\n"),
204            '\r' => escaped.push_str("\\r"),
205            '\t' => escaped.push_str("\\t"),
206            _ => escaped.push(ch),
207        }
208    }
209    escaped
210}
211
212#[derive(Clone, Debug, Eq, PartialEq)]
213pub struct RuleNode {
214    context: ParserRuleContext,
215}
216
217impl RuleNode {
218    pub const fn new(context: ParserRuleContext) -> Self {
219        Self { context }
220    }
221
222    pub const fn context(&self) -> &ParserRuleContext {
223        &self.context
224    }
225
226    pub const fn context_mut(&mut self) -> &mut ParserRuleContext {
227        &mut self.context
228    }
229
230    pub fn text(&self) -> String {
231        self.context.text()
232    }
233
234    pub fn to_string_tree_with_names<S: AsRef<str>>(&self, rule_names: &[S]) -> String {
235        self.context.to_string_tree_with_names(rule_names)
236    }
237}
238
239#[derive(Clone, Debug, Eq, PartialEq)]
240pub struct ParserRuleContext {
241    rule_index: usize,
242    invoking_state: isize,
243    alt_number: usize,
244    start: Option<TokenRef>,
245    stop: Option<TokenRef>,
246    int_returns: Option<Box<IntReturns>>,
247    children: Vec<ParseTree>,
248    /// Whether any child has been offered to this context, independent of whether
249    /// the tree was actually built. `children` stays empty when
250    /// `Parser::set_build_parse_trees(false)`, so generated recovery uses this
251    /// flag (not `children.is_empty()`) to tell whether the rule has matched
252    /// anything yet.
253    matched_child: bool,
254    // Boxed: an `AntlrError` is large and only set on the rare error path, so
255    // keeping it behind a pointer keeps `ParserRuleContext` (and thus the
256    // `ParseTree::Rule` variant) compact.
257    exception: Option<Box<AntlrError>>,
258    /// Typed generated-rule attribute snapshot (see [`GeneratedAttrs`]).
259    attrs: Option<GeneratedAttrs>,
260}
261
262#[derive(Clone, Debug, Default, Eq, PartialEq)]
263struct IntReturns(BTreeMap<String, i64>);
264
265/// Typed rule-attribute storage attached to a [`ParserRuleContext`].
266///
267/// Generated parsers keep each rule's `returns`/`locals`/argument attributes
268/// in a generated per-rule struct and seal a shared snapshot onto the finished
269/// context, so a parent rule (or a listener) can read `$child.attr` /
270/// `ctx.attr` with its real Rust type — the analog of ANTLR's attribute
271/// fields on generated context classes.
272#[derive(Clone)]
273pub struct GeneratedAttrs(Rc<dyn Any>);
274
275impl GeneratedAttrs {
276    pub fn new<T: Any>(attrs: T) -> Self {
277        Self(Rc::new(attrs))
278    }
279
280    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
281        self.0.downcast_ref::<T>()
282    }
283}
284
285impl fmt::Debug for GeneratedAttrs {
286    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287        f.write_str("GeneratedAttrs(..)")
288    }
289}
290
291// Attribute snapshots are sealed once per finished rule; two contexts are the
292// same context (and thus equal) exactly when they share the same snapshot.
293impl PartialEq for GeneratedAttrs {
294    fn eq(&self, other: &Self) -> bool {
295        Rc::ptr_eq(&self.0, &other.0)
296    }
297}
298
299impl Eq for GeneratedAttrs {}
300
301impl ParserRuleContext {
302    pub const fn new(rule_index: usize, invoking_state: isize) -> Self {
303        Self {
304            rule_index,
305            invoking_state,
306            alt_number: 0,
307            start: None,
308            stop: None,
309            int_returns: None,
310            children: Vec::new(),
311            matched_child: false,
312            exception: None,
313            attrs: None,
314        }
315    }
316
317    pub(crate) fn with_child_capacity(
318        rule_index: usize,
319        invoking_state: isize,
320        capacity: usize,
321    ) -> Self {
322        Self {
323            rule_index,
324            invoking_state,
325            alt_number: 0,
326            start: None,
327            stop: None,
328            int_returns: None,
329            children: Vec::with_capacity(capacity),
330            matched_child: false,
331            exception: None,
332            attrs: None,
333        }
334    }
335
336    pub const fn rule_index(&self) -> usize {
337        self.rule_index
338    }
339
340    pub const fn invoking_state(&self) -> isize {
341        self.invoking_state
342    }
343
344    pub const fn alt_number(&self) -> usize {
345        self.alt_number
346    }
347
348    pub const fn set_alt_number(&mut self, alt_number: usize) {
349        self.alt_number = alt_number;
350    }
351
352    pub fn start(&self) -> Option<&CommonToken> {
353        self.start.as_deref()
354    }
355
356    pub(crate) fn start_ref(&self) -> Option<TokenRef> {
357        self.start.as_ref().map(Rc::clone)
358    }
359
360    pub fn stop(&self) -> Option<&CommonToken> {
361        self.stop.as_deref()
362    }
363
364    pub fn set_start(&mut self, token: CommonToken) {
365        self.start = Some(Rc::new(token));
366    }
367
368    pub(crate) fn set_start_ref(&mut self, token: TokenRef) {
369        self.start = Some(token);
370    }
371
372    pub fn set_stop(&mut self, token: CommonToken) {
373        self.stop = Some(Rc::new(token));
374    }
375
376    pub(crate) fn set_stop_ref(&mut self, token: TokenRef) {
377        self.stop = Some(token);
378    }
379
380    /// Stores a generated integer return value on this rule context.
381    pub fn set_int_return(&mut self, name: impl Into<String>, value: i64) {
382        self.int_returns
383            .get_or_insert_with(Box::default)
384            .0
385            .insert(name.into(), value);
386    }
387
388    /// Reads a generated integer return value from this rule context.
389    pub fn int_return(&self, name: &str) -> Option<i64> {
390        self.int_returns
391            .as_ref()
392            .and_then(|values| values.0.get(name).copied())
393    }
394
395    /// Seals the generated rule-attribute snapshot on this context.
396    pub fn set_generated_attrs(&mut self, attrs: GeneratedAttrs) {
397        self.attrs = Some(attrs);
398    }
399
400    /// Reads the typed generated rule-attribute snapshot, if sealed.
401    pub fn generated_attrs<T: Any>(&self) -> Option<&T> {
402        self.attrs.as_ref().and_then(GeneratedAttrs::downcast_ref)
403    }
404
405    pub fn exception(&self) -> Option<&AntlrError> {
406        self.exception.as_deref()
407    }
408
409    pub fn set_exception(&mut self, error: AntlrError) {
410        self.exception = Some(Box::new(error));
411    }
412
413    pub fn children(&self) -> &[ParseTree] {
414        &self.children
415    }
416
417    /// Returns the number of direct children in this context.
418    pub const fn child_count(&self) -> usize {
419        self.children.len()
420    }
421
422    /// Finds the first direct child rule with `rule_index`.
423    pub fn child_rule(&self, rule_index: usize) -> Option<&Self> {
424        self.child_rules(rule_index).next()
425    }
426
427    /// Iterates over direct child rules with `rule_index`.
428    pub fn child_rules(&self, rule_index: usize) -> impl Iterator<Item = &Self> + '_ {
429        self.children.iter().filter_map(move |child| match child {
430            ParseTree::Rule(rule) if rule.context().rule_index() == rule_index => {
431                Some(rule.context())
432            }
433            _ => None,
434        })
435    }
436
437    /// Finds the first direct token child with `token_type`.
438    ///
439    /// Includes recovery error nodes, which ANTLR treats as terminal nodes for
440    /// token-getter helpers.
441    pub fn child_token(&self, token_type: i32) -> Option<&TerminalNode> {
442        self.child_tokens(token_type).next()
443    }
444
445    /// Iterates over direct child subtrees whose root rule has `rule_index`.
446    ///
447    /// Like [`Self::child_rules`] but yielding the full [`ParseTree`] child,
448    /// for generated `$label.ctx` reads and listener walks over a labeled
449    /// subtree.
450    pub fn child_rule_trees(&self, rule_index: usize) -> impl Iterator<Item = &ParseTree> + '_ {
451        self.children.iter().filter(move |child| match child {
452            ParseTree::Rule(rule) => rule.context().rule_index() == rule_index,
453            ParseTree::Terminal(_) | ParseTree::Error(_) => false,
454        })
455    }
456
457    /// Iterates over direct token children with `token_type`, including
458    /// recovery error nodes (ANTLR treats those as terminals for getters).
459    pub fn child_tokens(&self, token_type: i32) -> impl Iterator<Item = &TerminalNode> + '_ {
460        self.children.iter().filter_map(move |child| match child {
461            ParseTree::Terminal(node) if node.symbol().token_type() == token_type => Some(node),
462            ParseTree::Error(node) if node.symbol().token_type() == token_type => {
463                Some(node.terminal())
464            }
465            _ => None,
466        })
467    }
468
469    /// Iterates over all direct terminal children regardless of token type.
470    pub fn terminal_children(&self) -> impl Iterator<Item = &TerminalNode> + '_ {
471        self.children.iter().filter_map(|child| match child {
472            ParseTree::Terminal(node) => Some(node),
473            ParseTree::Error(node) => Some(node.terminal()),
474            ParseTree::Rule(_) => None,
475        })
476    }
477
478    /// Downcast-style conversion to a generated typed context view.
479    ///
480    /// Generated parsers implement [`FromRuleContext`] for each context type;
481    /// this mirrors ANTLR's `((BinaryContext) $ctx)` cast in test actions
482    /// (`$ctx.downcast_ref::<BinaryContext>()`).
483    pub fn downcast_ref<T: FromRuleContext>(&self) -> Option<T> {
484        T::from_rule_context(self)
485    }
486
487    /// Returns whether this context has a direct token child with `token_type`.
488    pub fn has_token(&self, token_type: i32) -> bool {
489        self.child_token(token_type).is_some()
490    }
491
492    pub fn add_child(&mut self, child: ParseTree) {
493        self.matched_child = true;
494        self.children.push(child);
495    }
496
497    /// Records that a child was matched without storing it (used when parse-tree
498    /// construction is disabled). Keeps `has_matched_child` accurate even though
499    /// `children` stays empty.
500    pub const fn note_matched_child(&mut self) {
501        self.matched_child = true;
502    }
503
504    /// Whether this context has matched at least one child (token, rule, or error
505    /// node) so far, regardless of whether parse-tree construction is enabled.
506    pub const fn has_matched_child(&self) -> bool {
507        self.matched_child
508    }
509
510    pub fn text(&self) -> String {
511        self.children.iter().map(ParseTree::text).collect()
512    }
513
514    pub fn to_string_tree_with_names<S: AsRef<str>>(&self, rule_names: &[S]) -> String {
515        let name = rule_names
516            .get(self.rule_index)
517            .map_or("<unknown>", |name| name.as_ref());
518        let display_name = if self.alt_number == 0 {
519            name.to_owned()
520        } else {
521            format!("{name}:{}", self.alt_number)
522        };
523        if self.children.is_empty() {
524            return display_name;
525        }
526        let children = self
527            .children
528            .iter()
529            .map(|child| child.to_string_tree_with_names(rule_names))
530            .collect::<Vec<_>>()
531            .join(" ");
532        format!("({display_name} {children})")
533    }
534
535    /// Renders the LISP-style tree using rule names resolved through a
536    /// recognizer, matching ANTLR's `toStringTree(parser)` shape used by
537    /// generated test actions on a mid-rule `$ctx`.
538    pub fn to_string_tree<R: Recognizer>(&self, recognizer: Option<&R>) -> String {
539        recognizer.map_or_else(
540            || self.to_string_tree_with_names::<&str>(&[]),
541            |recognizer| self.to_string_tree_with_names(recognizer.data().rule_names()),
542        )
543    }
544}
545
546#[derive(Clone, Debug, Eq, PartialEq)]
547pub struct TerminalNode {
548    token: TokenRef,
549}
550
551impl TerminalNode {
552    pub fn new(token: CommonToken) -> Self {
553        Self {
554            token: Rc::new(token),
555        }
556    }
557
558    pub(crate) const fn from_ref(token: TokenRef) -> Self {
559        Self { token }
560    }
561
562    pub fn symbol(&self) -> &CommonToken {
563        self.token.as_ref()
564    }
565
566    pub fn text(&self) -> String {
567        self.token.text().to_owned()
568    }
569}
570
571/// Java's `TerminalNodeImpl.toString()` returns the token text; generated
572/// test listeners print terminal nodes directly (`java_style_list(&ctx.INT_all())`).
573impl fmt::Display for TerminalNode {
574    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
575        f.write_str(self.token.text())
576    }
577}
578
579#[derive(Clone, Debug, Eq, PartialEq)]
580pub struct ErrorNode {
581    terminal: TerminalNode,
582}
583
584impl ErrorNode {
585    pub fn new(token: CommonToken) -> Self {
586        Self {
587            terminal: TerminalNode::new(token),
588        }
589    }
590
591    pub(crate) const fn from_ref(token: TokenRef) -> Self {
592        Self {
593            terminal: TerminalNode::from_ref(token),
594        }
595    }
596
597    const fn terminal(&self) -> &TerminalNode {
598        &self.terminal
599    }
600
601    pub fn symbol(&self) -> &CommonToken {
602        self.terminal.symbol()
603    }
604
605    pub fn text(&self) -> String {
606        self.terminal.text()
607    }
608}
609
610/// Conversion from a dynamic [`ParserRuleContext`] into a generated typed
611/// context view.
612///
613/// Implemented by generated per-rule / per-labeled-alternative context types
614/// so `ctx.downcast_ref::<XContext>()` can check the rule shape and
615/// materialize the typed view, mirroring ANTLR's context-class casts.
616pub trait FromRuleContext: Sized {
617    fn from_rule_context(context: &ParserRuleContext) -> Option<Self>;
618}
619
620pub trait ParseTreeListener {
621    fn enter_every_rule(&mut self, _ctx: &ParserRuleContext) -> Result<(), AntlrError> {
622        Ok(())
623    }
624
625    fn exit_every_rule(&mut self, _ctx: &ParserRuleContext) -> Result<(), AntlrError> {
626        Ok(())
627    }
628
629    fn visit_terminal(&mut self, _node: &TerminalNode) -> Result<(), AntlrError> {
630        Ok(())
631    }
632
633    fn visit_error_node(&mut self, _node: &ErrorNode) -> Result<(), AntlrError> {
634        Ok(())
635    }
636}
637
638#[derive(Debug, Default)]
639pub struct ParseTreeWalker;
640
641impl ParseTreeWalker {
642    /// Walks a parse tree depth-first, invoking listener callbacks in ANTLR's
643    /// enter/child/exit order for rule nodes.
644    pub fn walk<L: ParseTreeListener>(
645        listener: &mut L,
646        tree: &ParseTree,
647    ) -> Result<(), AntlrError> {
648        match tree {
649            ParseTree::Rule(rule) => {
650                listener.enter_every_rule(rule.context())?;
651                for child in rule.context().children() {
652                    Self::walk(listener, child)?;
653                }
654                listener.exit_every_rule(rule.context())
655            }
656            ParseTree::Terminal(node) => listener.visit_terminal(node),
657            ParseTree::Error(node) => listener.visit_error_node(node),
658        }
659    }
660}
661
662#[cfg(test)]
663mod tests {
664    use super::*;
665    use crate::token::CommonToken;
666
667    #[test]
668    fn renders_rule_tree() {
669        let mut ctx = ParserRuleContext::new(0, -1);
670        ctx.add_child(ParseTree::Terminal(TerminalNode::new(
671            CommonToken::new(1).with_text("x"),
672        )));
673        let tree = ParseTree::Rule(RuleNode::new(ctx));
674        assert_eq!(tree.to_string_tree_with_names(&["expr"]), "(expr x)");
675    }
676
677    #[test]
678    fn finds_first_rule_depth_first() {
679        let mut nested = ParserRuleContext::new(1, -1);
680        nested.add_child(ParseTree::Terminal(TerminalNode::new(
681            CommonToken::new(1).with_text("x"),
682        )));
683
684        let mut root = ParserRuleContext::new(0, -1);
685        root.add_child(ParseTree::Rule(RuleNode::new(nested)));
686        let tree = ParseTree::Rule(RuleNode::new(root));
687
688        let rule = tree.first_rule(1).expect("nested rule should be found");
689        assert_eq!(
690            rule.to_string_tree_with_names(&["root".to_owned(), "child".to_owned()]),
691            "(child x)"
692        );
693        assert!(tree.first_rule(2).is_none());
694    }
695
696    #[test]
697    fn reports_rule_invocation_stack_from_leaf_to_root() {
698        let mut nested = ParserRuleContext::new(1, -1);
699        nested.add_child(ParseTree::Terminal(TerminalNode::new(
700            CommonToken::new(1).with_text("x"),
701        )));
702
703        let mut root = ParserRuleContext::new(0, -1);
704        root.add_child(ParseTree::Rule(RuleNode::new(nested)));
705        let tree = ParseTree::Rule(RuleNode::new(root));
706
707        assert_eq!(
708            tree.rule_invocation_stack(1, &["s", "a"]),
709            Some(vec!["a".to_owned(), "s".to_owned()])
710        );
711    }
712
713    #[test]
714    fn parse_tree_children_returns_rule_children_and_empty_leaf_slices() {
715        let terminal =
716            ParseTree::Terminal(TerminalNode::new(CommonToken::new(1).with_text("terminal")));
717        let error = ParseTree::Error(ErrorNode::new(CommonToken::new(2).with_text("error")));
718
719        let mut root = ParserRuleContext::new(0, -1);
720        root.add_child(terminal);
721        root.add_child(error);
722        let tree = ParseTree::Rule(RuleNode::new(root));
723
724        let children = tree.children();
725        let [first, second] = children else {
726            panic!("expected exactly 2 children");
727        };
728        assert_eq!(first.text(), "terminal");
729        assert_eq!(second.text(), "error");
730        assert!(first.children().is_empty());
731        assert!(second.children().is_empty());
732    }
733
734    #[test]
735    fn iterates_descendants_in_pre_order() {
736        let mut nested = ParserRuleContext::new(1, -1);
737        nested.add_child(ParseTree::Terminal(TerminalNode::new(
738            CommonToken::new(10).with_text("child"),
739        )));
740
741        let mut root = ParserRuleContext::new(0, -1);
742        root.add_child(ParseTree::Terminal(TerminalNode::new(
743            CommonToken::new(11).with_text("prefix"),
744        )));
745        root.add_child(ParseTree::Rule(RuleNode::new(nested)));
746        root.add_child(ParseTree::Error(ErrorNode::new(
747            CommonToken::new(12).with_text("error"),
748        )));
749        let tree = ParseTree::Rule(RuleNode::new(root));
750
751        let visited = tree
752            .descendants()
753            .map(|node| match node {
754                ParseTree::Rule(rule) => format!("rule:{}", rule.context().rule_index()),
755                ParseTree::Terminal(terminal) => format!("terminal:{}", terminal.text()),
756                ParseTree::Error(error) => format!("error:{}", error.text()),
757            })
758            .collect::<Vec<_>>();
759
760        assert_eq!(
761            visited,
762            vec![
763                "rule:0".to_owned(),
764                "terminal:prefix".to_owned(),
765                "rule:1".to_owned(),
766                "terminal:child".to_owned(),
767                "error:error".to_owned(),
768            ]
769        );
770
771        let preorder = tree.pre_order().map(ParseTree::text).collect::<Vec<_>>();
772        assert_eq!(
773            preorder,
774            vec!["prefixchilderror", "prefix", "child", "child", "error"]
775        );
776    }
777
778    #[test]
779    fn finds_direct_child_rules_by_index() {
780        let mut direct = ParserRuleContext::new(1, -1);
781        direct.add_child(ParseTree::Terminal(TerminalNode::new(
782            CommonToken::new(10).with_text("direct"),
783        )));
784
785        let mut nested_match = ParserRuleContext::new(1, -1);
786        nested_match.add_child(ParseTree::Terminal(TerminalNode::new(
787            CommonToken::new(11).with_text("nested"),
788        )));
789        let mut wrapper = ParserRuleContext::new(2, -1);
790        wrapper.add_child(ParseTree::Rule(RuleNode::new(nested_match)));
791
792        let mut root = ParserRuleContext::new(0, -1);
793        root.add_child(ParseTree::Terminal(TerminalNode::new(
794            CommonToken::new(12).with_text("prefix"),
795        )));
796        root.add_child(ParseTree::Rule(RuleNode::new(direct)));
797        root.add_child(ParseTree::Rule(RuleNode::new(wrapper)));
798
799        assert_eq!(root.child_count(), 3);
800        assert_eq!(root.child_rules(1).count(), 1);
801        assert_eq!(
802            root.child_rule(1).map(ParserRuleContext::text),
803            Some("direct".to_owned())
804        );
805        assert_eq!(
806            root.child_rule(2).map(ParserRuleContext::rule_index),
807            Some(2)
808        );
809        assert!(root.child_rule(3).is_none());
810    }
811
812    #[test]
813    fn finds_direct_terminal_children_by_token_type() {
814        let mut nested = ParserRuleContext::new(1, -1);
815        nested.add_child(ParseTree::Terminal(TerminalNode::new(
816            CommonToken::new(13).with_text("nested"),
817        )));
818
819        let mut root = ParserRuleContext::new(0, -1);
820        root.add_child(ParseTree::Error(ErrorNode::new(
821            CommonToken::new(12).with_text("error"),
822        )));
823        root.add_child(ParseTree::Terminal(TerminalNode::new(
824            CommonToken::new(10).with_text("direct"),
825        )));
826        root.add_child(ParseTree::Terminal(TerminalNode::new(
827            CommonToken::new(11).with_text("other"),
828        )));
829        root.add_child(ParseTree::Rule(RuleNode::new(nested)));
830
831        assert_eq!(root.child_count(), 4);
832        assert!(root.has_token(10));
833        assert!(root.has_token(12));
834        assert_eq!(
835            root.child_token(10).map(TerminalNode::text),
836            Some("direct".to_owned())
837        );
838        assert_eq!(
839            root.child_token(11).map(TerminalNode::text),
840            Some("other".to_owned())
841        );
842        assert_eq!(
843            root.child_token(12).map(TerminalNode::text),
844            Some("error".to_owned())
845        );
846        assert!(root.child_token(13).is_none());
847    }
848}