Skip to main content

Ast

Struct Ast 

Source
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

Source

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.

Source

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.

Source

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.

Source

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.

Source

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);
Source

pub fn language(&self) -> LANG

Source language of the parsed tree.

Source

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).

Source

pub fn name(&self) -> Option<&str>

Display name carried through to FuncSpace::name by every Ast::metrics call.

Source

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).

Source

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"//"));
Source

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);
Source

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");
Source

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);
Source

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).

Source

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.

Source

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.

Trait Implementations§

Source§

impl Debug for Ast

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Ast

§

impl RefUnwindSafe for Ast

§

impl Send for Ast

§

impl Sync for Ast

§

impl Unpin for Ast

§

impl UnsafeUnpin for Ast

§

impl UnwindSafe for Ast

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.