Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ __pycache__/

design/

# Ad-hoc scratch probe / calibration example binaries (never committed).
# The one real tracked example, crates/travsr-rerank/examples/rerank_bench.rs,
# does not match these patterns and stays tracked.
crates/*/examples/probe_*.rs
crates/*/examples/*_probe.rs
crates/*/examples/calib_*.rs

# travsr:begin (generated AI-tool config, `travsr connect --remove` to undo)
/.mcp.json
# travsr:end
1 change: 1 addition & 0 deletions crates/travsr-analysis/src/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub const CONFIG: LanguageConfig = LanguageConfig {
],
decl_kinds: &["function_definition"],
type_refinements: &[],
post_parse: None,
get_grammar: || tree_sitter::Language::new(tree_sitter_c::LANGUAGE),
};

Expand Down
1 change: 1 addition & 0 deletions crates/travsr-analysis/src/cpp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub const CONFIG: LanguageConfig = LanguageConfig {
],
decl_kinds: &["function_definition"],
type_refinements: &[],
post_parse: None,
get_grammar: || tree_sitter::Language::new(tree_sitter_cpp::LANGUAGE),
};

Expand Down
1 change: 1 addition & 0 deletions crates/travsr-analysis/src/csharp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub const CONFIG: LanguageConfig = LanguageConfig {
],
decl_kinds: &[],
type_refinements: &[],
post_parse: None,
get_grammar: || tree_sitter::Language::new(tree_sitter_c_sharp::LANGUAGE),
};

Expand Down
1 change: 1 addition & 0 deletions crates/travsr-analysis/src/dart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub const CONFIG: LanguageConfig = LanguageConfig {
// file node instead of the enclosing function (E5).
decl_kinds: &["function_declaration", "method_declaration"],
type_refinements: &[],
post_parse: None,
get_grammar: || tree_sitter::Language::new(tree_sitter_dart::LANGUAGE),
};

Expand Down
51 changes: 50 additions & 1 deletion crates/travsr-analysis/src/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ pub struct LanguageConfig {
/// ancestor whose kind is listed here. Empty ⇒ the 1-hop span is already
/// correct for this grammar (name is a direct child of its declaration).
pub decl_kinds: &'static [&'static str],
/// Optional post-parse expansion hook, run once after the capture pass with
/// the parsed tree and source so a language can synthesize nodes the shared
/// capture pipeline cannot express. Used by Ruby (#780) to expand
/// `attr_accessor`/`attr_reader`/`attr_writer` macros into their reader/writer
/// accessor method nodes (one macro → N synthetic names with a derived `=`
/// writer, which no single capture can produce). `None` for every language
/// whose definitions are all direct captures.
pub post_parse: Option<PostParseHook>,
/// N4d refiners for grammars that fold several type kinds into one AST node
/// with no distinguishing field (unlike Swift's `declaration_kind`).
/// tree-sitter-kotlin-ng folds `class`/`interface`/`enum class` into
Expand All @@ -73,6 +81,31 @@ pub struct LanguageConfig {
pub get_grammar: fn() -> tree_sitter::Language,
}

/// A language-specific post-parse expansion pass (see [`LanguageConfig::post_parse`]).
/// Receives the parsed tree/source via [`PostParseCtx`] and appends synthetic
/// nodes and their containment edges to the accumulating output.
pub type PostParseHook = fn(&PostParseCtx<'_>, &mut Vec<Node>, &mut Vec<Edge>);

/// Context handed to a [`PostParseHook`]: everything it needs to build VNames and
/// containment edges consistent with the capture pass that ran before it.
pub struct PostParseCtx<'a> {
/// Root of the parsed tree.
pub root: tree_sitter::Node<'a>,
/// File bytes (for `utf8_text` on captured nodes).
pub source: &'a [u8],
/// The corpus this file belongs to.
pub corpus: &'a str,
/// VName path of the file being parsed.
pub vname_path: &'a str,
/// Language string (`config.language.as_str()`), for VName construction.
pub lang: &'a str,
/// The file node's id, for edges parented to the file.
pub file_id: travsr_core::NodeId,
/// The parser config, so the hook can reuse `method_containers` /
/// `type_refinements` (e.g. via [`enclosing_container`]).
pub config: &'a LanguageConfig,
}

/// N4d: refine a folded type declaration's kind by the presence of a signal
/// node (`has_child_kind`) among the decl's direct children OR inside its
/// `modifiers` subtree. The modifiers subtree is scanned because grammars put
Expand Down Expand Up @@ -265,6 +298,22 @@ pub fn parse_with_config(
}
}

// #780: language-specific expansion the shared capture pipeline cannot
// express (Ruby `attr_*` macros → accessor method nodes). No-op for every
// config that leaves `post_parse` unset.
if let Some(hook) = config.post_parse {
let ctx = PostParseCtx {
root: tree.root_node(),
source: &source,
corpus,
vname_path,
lang: lang_str,
file_id,
config,
};
hook(&ctx, &mut nodes, &mut edges);
}

// #479: single language-agnostic post-pass sets test_role from the collected
// signals (no-op when the file has no test captures).
crate::test_role::apply_test_roles(&test_signals, &mut nodes);
Expand Down Expand Up @@ -313,7 +362,7 @@ fn decl_end_line(node: tree_sitter::Node<'_>, decl_kinds: &[&str]) -> Option<u32
/// signature prefix that container is captured under, so the caller can
/// reconstruct the container's own VName (`{prefix}:{name}`) for the
/// containment edge.
fn enclosing_container<'a>(
pub(crate) fn enclosing_container<'a>(
node: tree_sitter::Node<'_>,
method_containers: &[(&'static str, &'a str)],
type_refinements: &[TypeRefinement],
Expand Down
1 change: 1 addition & 0 deletions crates/travsr-analysis/src/kotlin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub const CONFIG: LanguageConfig = LanguageConfig {
prefix: "enum",
},
],
post_parse: None,
get_grammar: || tree_sitter::Language::new(tree_sitter_kotlin_ng::LANGUAGE),
};

Expand Down
1 change: 1 addition & 0 deletions crates/travsr-analysis/src/objc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub const CONFIG: LanguageConfig = LanguageConfig {
],
decl_kinds: &["function_definition"],
type_refinements: &[],
post_parse: None,
get_grammar: || tree_sitter::Language::new(tree_sitter_objc::LANGUAGE),
};

Expand Down
1 change: 1 addition & 0 deletions crates/travsr-analysis/src/php.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub const CONFIG: LanguageConfig = LanguageConfig {
],
decl_kinds: &[],
type_refinements: &[],
post_parse: None,
get_grammar: || tree_sitter::Language::new(tree_sitter_php::LANGUAGE_PHP),
};

Expand Down
Loading
Loading