Skip to main content

semantic/parser/
comment_walk.rs

1// SPDX-License-Identifier: Apache-2.0
2//! The single source of truth for "which tree-sitter nodes are comments" and
3//! the non-comment leaf walk built on it.
4//!
5//! Both change-classification (`strip_comments`) and the semantic-index token
6//! stream (`hd-sem-sym-v1`) need to walk an AST in document order while
7//! skipping comment subtrees. Keeping the predicate and the walk here — in the
8//! parser crate — means there is exactly one definition of "comment" and one
9//! traversal shape; the consumers only differ in what they do with each leaf.
10
11use tree_sitter::Node;
12
13/// Whether a tree-sitter node kind names a comment. Comment subtrees are
14/// skipped wholesale by [`walk_non_comment_leaves`], so doc-comments and
15/// ordinary comments alike are excluded from semantic fingerprints.
16pub fn is_comment_node(kind: &str) -> bool {
17    matches!(
18        kind,
19        "comment" | "line_comment" | "block_comment" | "doc_comment" | "string_comment"
20    )
21}
22
23/// DFS in document order over `node`'s subtree, invoking `on_leaf` for each
24/// non-comment leaf (a node with no children). Comment nodes — and their
25/// entire subtrees — are skipped.
26///
27/// The stack pushes children in reverse so they pop in source order, giving a
28/// stable pre-order document-order traversal. Iterative (not recursive) so
29/// deeply-nested-but-valid input drives heap, not call depth.
30pub fn walk_non_comment_leaves<'tree>(node: Node<'tree>, mut on_leaf: impl FnMut(Node<'tree>)) {
31    let mut stack = vec![node];
32    while let Some(current) = stack.pop() {
33        if is_comment_node(current.kind()) {
34            continue;
35        }
36        if current.child_count() == 0 {
37            on_leaf(current);
38            continue;
39        }
40        let child_count = current.child_count();
41        for index in (0..child_count).rev() {
42            if let Some(child) = current.child(index as u32) {
43                stack.push(child);
44            }
45        }
46    }
47}