General Programming Language Parsing

RecipeCratesCategories
Parse JavaScriptswc_ecma_parsercat-parser-implementations
sqlparsercat-parser-implementations

Parse JavaScript

swc_ecma_parser swc_ecma_parser-crates.io swc_ecma_parser-github swc_ecma_parser-lib.rs

swc_ecma_parser⮳ is a feature-complete ECMAScript / TypeScript parser written in Rust.

use swc_common::FileName;
use swc_common::input::StringInput;
use swc_common::sync::Lrc;
use swc_ecma_ast::EsVersion;
use swc_ecma_ast::Program;
use swc_ecma_parser::EsSyntax;
use swc_ecma_parser::Parser;
use swc_ecma_parser::Syntax;
use swc_ecma_parser::lexer::Lexer;

// `swc_ecma_parser` is a library for parsing ECMAScript (JavaScript) code.

// In `Cargo.toml`:
// swc_ecma_parser = "6.0.1" # or latest
// swc_ecma_ast = "5.0.1"
// swc_common = "5.0.0"

fn main() {
    let cm: Lrc<swc_common::SourceMap> = Default::default();
    let fm = cm.new_source_file(
        FileName::Custom("example.js".into()).into(),
        "const a = 1;".into(),
    );

    let lexer = Lexer::new(
        Syntax::Es(EsSyntax {
            jsx: true,
            ..Default::default()
        }),
        EsVersion::latest(),
        StringInput::from(&*fm),
        None,
    );

    let mut parser = Parser::new_from(lexer);
    let program: Program = parser.parse_program().expect("Failed to parse");

    // Print the parsed program
    println!("{:#?}", program);
}

Parse SQL

sqlparser sqlparser-crates.io sqlparser-github sqlparser-lib.rs

sqlparser is a general SQL lexer and parser with support for ANSI SQL:2011.

use std::ops::ControlFlow;

use sqlparser::ast::SetExpr;
use sqlparser::ast::Statement;
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;

// `sqlparser` can be used as a foundation for SQL query engines and SQL
// analysis.
//
// Add to your `Cargo.toml`:
// sqlparser = { version = "0.54.0", features = ["visitor"] }

fn main() -> anyhow::Result<()> {
    let sql = "SELECT * FROM users WHERE age > 18";

    let dialect = GenericDialect {}; // Or AnsiDialect, PostgreSqlDialect, etc.

    // Create a parser for a `Dialect`:
    let mut parser = Parser::new(&dialect).try_with_sql(sql)?;
    // You may configure the parser with e.g.
    // .with_recursion_limit(n).with_options(options)

    // Parse potentially multiple statements; tokenize the sql string and sets
    // this parser's state to parse the resulting tokens.
    let statements = parser.parse_statements()?;

    // You may also use `parse_sql`:
    // let statements = Parser::parse_sql(
    //   &dialect, "SELECT * FROM foo"
    // )?;

    for statement in statements.clone() {
        // `statement` is a top-level construct: SELECT, INSERT, CREATE, etc.
        match statement {
            // SELECT statment.
            Statement::Query(query) => match *query.body {
                // SELECT .. FROM .. HAVING (no ORDER BY or set operations).
                SetExpr::Select(select) => {
                    println!("SELECT statement:");
                    println!("  Projection: {:?}", select.projection);
                    println!("  From: {:?}", select.from);
                    println!("  Where: {:?}", select.selection);
                }
                _ => println!("Not a SELECT statement"),
            },
            _ => println!("Not a Query statement"),
        }
    }

    // The original SQL text can be generated from the AST
    // (Abstract Syntax Tree).
    assert_eq!(statements[0].to_string(), sql);

    // You may also visit all statements, expressions, or tables.
    // You can also implement a custom `Visitor`.
    let mut visited = vec![];
    sqlparser::ast::visit_statements(&statements, |stmt| {
        visited.push(format!("Statement: {}", stmt));
        ControlFlow::<()>::Continue(())
    });
    println!("{:?}", visited);

    Ok(())
}

See also

diesel is an ORM that includes SQL parsing.