pub struct Ast { /* private fields */ }Expand description
Parse-once, compute-many handle.
Owns the parsed tree_sitter::Tree and the source bytes it was parsed
from, so callers can run Ast::metrics repeatedly against the same
parse — with different MetricsOptions subsets, interleaved with
custom tree_sitter traversal via Ast::as_tree_sitter, or cached
across configuration changes in an analysis pipeline.
Build one via Ast::parse (the seam behind analyze) or
Ast::from_tree_sitter to reuse a caller-supplied
tree_sitter::Tree, carrying an explicit display name.
Ast is a snapshot — it does not pick up changes to the source after
construction. Incremental reparse via tree_sitter::InputEdit is out
of scope for this seam.
§C++ preprocessor
When Ast::parse is given a Source carrying preprocessor inputs
and the language is LANG::Cpp, Ast::source returns the expanded
bytes the parser actually saw (the macro pre-pass runs before
tree-sitter does). Ast::from_tree_sitter adopts whatever tree the
caller supplied; whatever expansion they applied before building it is
what Ast::source reflects.
§Examples
Parse once, run two disjoint metric subsets without re-parsing:
use big_code_analysis::{Ast, LANG, Metric, MetricsOptions, Source};
let ast = Ast::parse(
Source::new(LANG::Rust, b"fn f() { if true { 1 } else { 2 }; }"),
)
.expect("rust feature enabled");
let loc = ast
.metrics(MetricsOptions::default().with_only(&[Metric::Loc]))
.expect("walker succeeds");
let cyc = ast
.metrics(MetricsOptions::default().with_only(&[Metric::Cyclomatic]))
.expect("walker succeeds");
// Each call's `with_only` filters to its requested family — the other
// metric stays at its `Default` (zero) value, confirming options are
// honored per call rather than carried over.
assert!(loc.metrics.loc.ploc() > 0);
assert_eq!(loc.metrics.cyclomatic.cyclomatic_sum(), 0);
assert!(cyc.metrics.cyclomatic.cyclomatic_sum() > 0);
assert_eq!(cyc.metrics.loc.ploc(), 0);Walk the underlying tree_sitter::Tree and then run metrics on the
same parse:
use big_code_analysis::{Ast, LANG, MetricsOptions, Source};
let ast = Ast::parse(Source::new(LANG::Rust, b"fn f() {}"))
.expect("rust feature enabled");
let root = ast.as_tree_sitter().root_node();
assert_eq!(root.kind(), "source_file");
let _ = ast.metrics(MetricsOptions::default()).expect("walker succeeds");Implementations§
Source§impl Ast
impl Ast
Sourcepub fn parse(source: Source<'_>) -> Result<Self, MetricsError>
pub fn parse(source: Source<'_>) -> Result<Self, MetricsError>
Parse source into a reusable Ast. Equivalent to the parse half
of analyze: every Ast::metrics call on the returned handle
produces the same FuncSpace as a freshly-issued
analyze(source, options) would.
§Errors
Returns MetricsError::LanguageDisabled when the source language’s
per-language Cargo feature is not enabled in this build.
Sourcepub fn from_tree_sitter(
lang: LANG,
tree: Tree,
code: Vec<u8>,
name: Option<String>,
) -> Result<Self, MetricsError>
pub fn from_tree_sitter( lang: LANG, tree: Tree, code: Vec<u8>, name: Option<String>, ) -> Result<Self, MetricsError>
Adopt a caller-built tree_sitter::Tree, reusing it instead of
running the bundled parser, with name: Option<String> carried
end-to-end.
The supplied tree must have been produced from code with the
tree_sitter::Language returned by
LANG::tree_sitter_language for lang; a mismatch is not
unsafe but yields nonsensical metric values.
§Errors
Returns MetricsError::LanguageDisabled when lang’s
per-language Cargo feature is not enabled in this build.
Sourcepub fn from_path(path: &Path) -> Result<Self, FromPathError>
pub fn from_path(path: &Path) -> Result<Self, FromPathError>
Read path, detect its language, and parse it into a reusable
Ast — the file-backed counterpart to Ast::parse.
The file is read through the same text reader analyze uses, so
the bytes (after end-of-line normalization and UTF-8 BOM stripping)
are byte-identical and from_path(p)?.metrics(opts) equals
analyze over the same file. The detected language follows the same
extension / shebang / mode-line rules as the CLI and analyze.
Unlike analyze, from_path is no-magic: it does not skip
generated files — the caller asked for this file’s tree, so a
generated file is parsed like any other. It also does not run the
C/C++ preprocessor pass (matching the in-memory parse path); the
tree reflects the source as written.
§Errors
Returns a FromPathError variant for each
distinct failure: a real I/O fault
(Io), a non-UTF-8 path
(NonUtf8Path), an empty /
binary / non-UTF-8 file
(Unreadable), an unrecognized
language (UnknownLanguage),
or a disabled-language build
(Parse). from_path never silently
returns a tree-less success.
Sourcepub fn metrics(
&self,
options: MetricsOptions,
) -> Result<FuncSpace, MetricsError>
pub fn metrics( &self, options: MetricsOptions, ) -> Result<FuncSpace, MetricsError>
Run the metric walker against the held parse. Safe to call repeatedly — the tree is reused.
Two metrics calls with different MetricsOptions::with_only
selections walk the tree twice; the savings versus analyze come
from not re-parsing the source.
§Errors
The return type carries MetricsError::EmptyRoot for forward
compatibility, but the walker always pushes a synthetic top-level
SpaceKind::Unit FuncSpace before walking, so this method
does not return Err in practice today.
Sourcepub fn ops(&self) -> Result<Ops, MetricsError>
pub fn ops(&self) -> Result<Ops, MetricsError>
Return every operator and operand of each space in the held parse.
The top-level crate::Ops::name is the Source::name supplied
to Ast::parse / Ast::from_tree_sitter — carried explicitly
rather than derived from a filesystem path via lossy UTF-8
conversion, so crate::Ops::name_was_lossy is never set on this
path. Safe to call repeatedly; the tree is reused.
§Errors
The return type carries MetricsError::EmptyRoot for forward
compatibility, but the walker always pushes a synthetic top-level
space before walking, so this method does not return Err in
practice today (see the variant doc).
§Examples
use big_code_analysis::{Ast, LANG, Source};
let ops = Ast::parse(
Source::new(LANG::Cpp, b"int a = 42;")
.with_name(Some("foo.c".to_owned())),
)
.expect("cpp feature enabled")
.ops()
.expect("walker succeeds");
assert_eq!(ops.name.as_deref(), Some("foo.c"));
assert!(!ops.name_was_lossy);Sourcepub fn source(&self) -> &[u8] ⓘ
pub fn source(&self) -> &[u8] ⓘ
Source bytes the held tree was parsed from. For LANG::Cpp with
preprocessor inputs supplied to Ast::parse, these are the
expanded bytes (see the type-level “C++ preprocessor” note).
Sourcepub fn name(&self) -> Option<&str>
pub fn name(&self) -> Option<&str>
Display name carried through to FuncSpace::name by every
Ast::metrics call.
Sourcepub fn as_tree_sitter(&self) -> &Tree
pub fn as_tree_sitter(&self) -> &Tree
Borrow the underlying tree_sitter::Tree for callers that want
to drive their own traversal alongside the metric walker.
The returned reference is valid only while self lives; nodes
obtained from it must be resolved against Ast::source (the
tree_sitter::Tree is lazy and lifetime-bound to that byte
buffer).
Sourcepub fn strip_comments(&self) -> Option<Vec<u8>>
pub fn strip_comments(&self) -> Option<Vec<u8>>
Strip non-doc comments from the held parse, returning the source
with those byte ranges removed. None when there is nothing to
strip. Safe to call repeatedly; the tree is reused.
§Examples
use big_code_analysis::{Ast, LANG, Source};
let stripped = Ast::parse(Source::new(LANG::Rust, b"// gone\nfn f() {}\n"))
.expect("rust feature enabled")
.strip_comments()
.expect("a comment was present");
assert!(!stripped.windows(2).any(|w| w == b"//"));Sourcepub fn functions(&self) -> Vec<FunctionSpan>
pub fn functions(&self) -> Vec<FunctionSpan>
Detect the span of every function in the held parse. Safe to call repeatedly; the tree is reused.
§Examples
use big_code_analysis::{Ast, LANG, Source};
let funcs = Ast::parse(Source::new(LANG::Rust, b"fn a() {}\nfn b() {}\n"))
.expect("rust feature enabled")
.functions();
assert_eq!(funcs.len(), 2);Sourcepub fn dump(&self, cfg: AstCfg) -> AstResponse
pub fn dump(&self, cfg: AstCfg) -> AstResponse
Build the AstResponse node tree for the held
parse under cfg. The Source-based counterpart of the deprecated
AstCallback dispatch. Safe to call repeatedly; the tree is reused.
§Examples
use big_code_analysis::{Ast, AstCfg, LANG, Source};
let resp = Ast::parse(Source::new(LANG::Rust, b"fn f() {}"))
.expect("rust feature enabled")
.dump(AstCfg {
id: String::new(),
language: "rust".to_owned(),
comment: false,
span: false,
});
assert_eq!(resp.language, "rust");
assert_eq!(resp.root.expect("root node").r#type, "source_file");Sourcepub fn count(&self, filters: &[String]) -> (usize, usize)
pub fn count(&self, filters: &[String]) -> (usize, usize)
Count (matching, total) nodes in the held parse, where a node
matches when its kind is named in filters (the same vocabulary
the bca count CLI accepts — all, call, comment, error,
string, function, a numeric kind_id, or an exact
node.kind()). Safe to call repeatedly; the tree is reused.
§Examples
use big_code_analysis::{Ast, LANG, Source};
let (matching, total) = Ast::parse(Source::new(LANG::Rust, b"fn f() {}"))
.expect("rust feature enabled")
.count(&["function_item".to_owned()]);
assert_eq!(matching, 1);
assert!(total > matching);Sourcepub fn find(&self, filters: &[String]) -> Result<Vec<Node<'_>>, MetricsError>
pub fn find(&self, filters: &[String]) -> Result<Vec<Node<'_>>, MetricsError>
Find every node in the held parse whose kind is named in
filters. The returned Nodes borrow the held tree, so they
must be resolved against Ast::source. Safe to call
repeatedly; the tree is reused.
§Errors
Currently infallible; the Result wrapper is reserved for a
future strict-parsing mode (matching the other Ast walkers).
Sourcepub fn suppressions(&self) -> Vec<SuppressionMarker>
pub fn suppressions(&self) -> Vec<SuppressionMarker>
Collect every in-source suppression marker (// bca: suppress …)
in the held parse, sorted by line. Safe to call repeatedly; the
tree is reused.
Sourcepub fn root_node(&self) -> Node<'_>
pub fn root_node(&self) -> Node<'_>
Borrow the root Node of the held parse for callers that drive
their own traversal (e.g. rendering an AST dump). Nodes obtained
from it must be resolved against Ast::source.