Crate fuzzy_pickles

source ·
Expand description

Fuzzy Pickles

This is a library for parsing Rust code, paying specific attention to locations of items in the source code — their Extents*.

Examples

Parsing a Rust file returns an AST of the file. You can delve into individual parts of a given AST node; every field is public. Enums contain is_X, as_X, and into_X methods to quickly narrow down to specific variant. If you’d like to see the raw text of the node, you can index the original source code text with the AST node.

extern crate fuzzy_pickles;

use fuzzy_pickles::parse_rust_file;

fn main() {
    let example_source = r#"
    fn main() { let the_variable_name = 1 + 1; }
    "#;

    let file = parse_rust_file(example_source)
        .expect("Unable to parse source");

    let main_fn = file.items[0].value.as_function()
        .expect("Not a function");

    let first_expr = main_fn.body.statements[0].as_expression()
        .expect("Not an expression");

    let let_expr = first_expr.value.as_let()
        .expect("Not a let expression");

    let name_pat = let_expr.pattern.kind.as_ident()
        .expect("Not an ident pattern");
    assert_eq!("the_variable_name", &example_source[name_pat]);

    let value = let_expr.value.as_ref()
        .expect("No value for let");

    let addition_expr = value.value.as_binary()
        .expect("Not a binary expression");
    assert_eq!("1 + 1", &example_source[addition_expr]);
}

Using a visitor

Doing this amount of digging can be tedious and error prone, however. The crate also comes with visitor traits allowing you to quickly find relevant nodes.

extern crate fuzzy_pickles;

use fuzzy_pickles::{parse_rust_file, ast, visit::{Visit, Visitor}};

#[derive(Debug, Default)]
struct AddVisitor<'ast>(Vec<&'ast ast::Binary>);

impl<'ast> Visitor<'ast> for AddVisitor<'ast> {
    fn exit_binary(&mut self, binary: &'ast ast::Binary) {
        self.0.push(binary)
    }
}

fn main() {
    let example_source = r#"
    fn main() { let the_variable_name = 1 + 1; }
    "#;

    let file = parse_rust_file(example_source)
        .expect("Unable to parse source");

    let mut v = AddVisitor::default();
    file.visit(&mut v);

    let binary = v.0.pop().expect("Didn't find the binary operator");
    assert!(v.0.is_empty(), "Found additional binary operators");
    assert_eq!("1 + 1", &example_source[binary])
}

Reporting errors

The parser attempts to have a reasonable level of detail when the input source code is malformed.

extern crate fuzzy_pickles;

use fuzzy_pickles::parse_rust_file;

fn main() {
    // Oops, we forgot to close our parenthesis!
    let example_source = r#"
    fn main( { let the_variable_name = 1 + 1; }
    "#;

    let error = parse_rust_file(example_source)
        .unwrap_err();

    let pretty_error = error.with_text(example_source);
    panic!("{}", pretty_error);
}

This produces an error that shows the offending location and what possible symbols were expected. We’ve truncated this output:

Unable to parse text (line 2, column 14)

    fn main( { let the_variable_name = 1 + 1; }
             ^
Expected:
  ExpectedAmpersand
  ExpectedBox
  ...

Modules

The components of a Rust Abstract Syntax Tree (AST)
Visitors of the AST

Structs

Information about a tokenization or parsing error including original source code
A pair of (start, end) points corresponding to something interesting in the source text.

Enums

Information about a tokenization or parsing error

Traits

A type that has an extent

Functions

The entrypoint to parsing Rust code.