LCOV - code coverage report
Current view: top level - src - parse_tree_walker.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 81.4 % 43 35
Test Date: 2026-08-24 04:55:06 Functions: - 0 0
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright 2026 The Authors. See the AUTHORS file for details.
       2              : //
       3              : // Licensed under the Apache License, Version 2.0 (the "License");
       4              : // you may not use this file except in compliance with the License.
       5              : // You may obtain a copy of the License at
       6              : //
       7              : //      https://www.apache.org/licenses/LICENSE-2.0
       8              : //
       9              : // Unless required by applicable law or agreed to in writing, software
      10              : // distributed under the License is distributed on an "AS IS" BASIS,
      11              : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12              : // See the License for the specific language governing permissions and
      13              : // limitations under the License.
      14              : 
      15              : import 'parse.dart';
      16              : 
      17              : /// A visitor function that is called for each node in the parse tree.
      18              : /// Return false to stop traversal, true to continue.
      19              : typedef ParseTreeVisitor = bool Function(ParseTreeNode node);
      20              : 
      21              : /// Represents a node in the parse tree with its full context
      22              : class ParseTreeNode {
      23              :   /// The parse result for this node
      24              :   final ParseResult result;
      25              : 
      26              :   /// The parent node, null for root
      27              :   final ParseTreeNode? parent;
      28              : 
      29              :   /// The depth of this node in the tree (0 = root)
      30              :   final int depth;
      31              : 
      32            2 :   ParseTreeNode(this.result, {this.parent, this.depth = 0});
      33              : 
      34              :   /// Get the lexeme (matched text) for this node
      35            3 :   String? get lexeme => result.lexeme;
      36              : 
      37              :   /// Get the rule name that created this node
      38            6 :   String? get ruleName => result.ruleName;
      39              : 
      40              :   /// Get the parser element name
      41            3 :   String? get element => result.element;
      42              : 
      43              :   /// Get all child nodes
      44            2 :   List<ParseTreeNode> get children {
      45            4 :     return result.stack
      46            2 :         .toList()
      47           10 :         .map((r) => ParseTreeNode(r, parent: this, depth: depth + 1))
      48            2 :         .toList();
      49              :   }
      50              : 
      51              :   /// Returns true if this node has any children
      52            0 :   bool get hasChildren => result.stack.isNotEmpty;
      53              : 
      54            1 :   @override
      55              :   String toString() {
      56            1 :     final sb = StringBuffer();
      57            3 :     sb.write('  ' * depth);
      58            4 :     if (ruleName != null) sb.write('$ruleName: ');
      59            4 :     if (lexeme != null) sb.write('"$lexeme"');
      60            4 :     if (element != null) sb.write(' ($element)');
      61            2 :     if (!result.success) sb.write(' <FAILED>');
      62            1 :     return sb.toString();
      63              :   }
      64              : }
      65              : 
      66              : /// A walker that traverses a parse tree created by a successful parse
      67              : class ParseTreeWalker {
      68              :   /// The root node of the parse tree
      69              :   final ParseTreeNode root;
      70              : 
      71              :   /// Create a new walker from a successful parse result
      72              :   /// Throws if the parse result indicates failure
      73            4 :   ParseTreeWalker(ParseResult parseResult) : root = ParseTreeNode(parseResult);
      74              : 
      75              :   /// Visit all nodes in the tree in pre-order (parent before children)
      76              :   /// Returns false if traversal was stopped by the visitor
      77            1 :   bool visitPreOrder(ParseTreeVisitor visitor) {
      78            2 :     return _visitPreOrder(root, visitor);
      79              :   }
      80              : 
      81            1 :   bool _visitPreOrder(ParseTreeNode node, ParseTreeVisitor visitor) {
      82            1 :     if (!visitor(node)) return false;
      83              : 
      84            2 :     for (final child in node.children) {
      85            1 :       if (!_visitPreOrder(child, visitor)) return false;
      86              :     }
      87              : 
      88              :     return true;
      89              :   }
      90              : 
      91              :   /// Visit all nodes in the tree in post-order (children before parent)
      92              :   /// Returns false if traversal was stopped by the visitor
      93            1 :   bool visitPostOrder(ParseTreeVisitor visitor) {
      94            2 :     return _visitPostOrder(root, visitor);
      95              :   }
      96              : 
      97            1 :   bool _visitPostOrder(ParseTreeNode node, ParseTreeVisitor visitor) {
      98            2 :     for (final child in node.children) {
      99            1 :       if (!_visitPostOrder(child, visitor)) return false;
     100              :     }
     101              : 
     102            1 :     return visitor(node);
     103              :   }
     104              : 
     105              :   /// Find all nodes matching a given rule name
     106            0 :   List<ParseTreeNode> findByRuleName(String ruleName) {
     107            0 :     final matches = <ParseTreeNode>[];
     108            0 :     visitPreOrder((node) {
     109            0 :       if (node.ruleName == ruleName) matches.add(node);
     110              :       return true;
     111              :     });
     112              :     return matches;
     113              :   }
     114              : 
     115              :   /// Find the first node matching a given rule name
     116            0 :   ParseTreeNode? findFirstByRuleName(String ruleName) {
     117              :     ParseTreeNode? match;
     118            0 :     visitPreOrder((node) {
     119            0 :       if (node.ruleName == ruleName) {
     120              :         match = node;
     121              :         return false;
     122              :       }
     123              :       return true;
     124              :     });
     125              :     return match;
     126              :   }
     127              : 
     128              :   /// Get a string representation of the parse tree
     129            1 :   @override
     130              :   String toString() {
     131            1 :     final sb = StringBuffer();
     132            2 :     visitPreOrder((node) {
     133            2 :       sb.writeln(node.toString());
     134              :       return true;
     135              :     });
     136            1 :     return sb.toString();
     137              :   }
     138              : }
        

Generated by: LCOV version 2.0-1