5 releases

0.0.5 Nov 4, 2023
0.0.4 Oct 22, 2023
0.0.3 Aug 8, 2023
0.0.2 Jul 5, 2023
0.0.1 Jul 5, 2023

#979 in Parser implementations

Download history 2/week @ 2024-02-23 11/week @ 2024-03-01 57/week @ 2024-03-08 3/week @ 2024-03-15

71 downloads per month

MIT/Apache

165KB
5.5K SLoC

ruast

This crate provides a printable & modifiable Rust AST.

Basic usage

Hello world

use ruast::*;

let mut krate = Crate::new();
let def = Fn::main(
    None,
    Block::from(Path::single("println").mac_call(vec![Token::lit("Hello, world!")])),
);
krate.add_item(def);
println!("{krate}");
krate.dump("test.rs")?;
krate.remove_item_by_id("main");
assert!(krate.is_empty());

This is equivalent to:

use ruast::*;

let mut krate = Crate::new();
krate.add_item(Fn {
    ident: "main".to_string(),
    generics: vec![],
    fn_decl: FnDecl::new(vec![], None),
    body: Some(Block::from(
        Stmt::Expr(Expr::new(MacCall {
            path: Path::single("println!"),
            args: DelimArgs::from(vec![Token::lit("Hello, world!")]),
        })),
    )),
});
println!("{krate}");
krate.dump("test.rs")?;
krate.remove_item_by_id("main");
assert!(krate.is_empty());

Building struct, enum, and impl

use ruast::*;

let mut krate = Crate::new();
let def = StructDef::empty("Foo")
    .with_field(FieldDef::inherited("foo", Type::from("u32")))
    .with_field(FieldDef::inherited("bar", Type::from("u32")));
krate.add_item(def);
let imp = Impl::empty("Foo")
    .with_item(Fn::empty_method("test", Pat::ref_self()));
krate.add_item(imp);
println!("{krate}");
use ruast::*;

let mut krate = Crate::new();
let def = EnumDef::empty("Foo")
    .with_variant(Variant::empty("Bar"))
    .with_variant(Variant::tuple("Baz", vec![FieldDef::anonymous("u32")]));
krate.add_item(def);
let imp = Impl::empty("Foo")
    .with_item(Fn::empty_method("test", Pat::ref_self()));
krate.add_item(imp);
println!("{krate}");

Convert to proc_macro2::TokenStream

By enabling a feature tokenize, you can convert ruast ASTs to proc_macro2::TokenStream.

You can build ASTs systematically without using syn or quote macros.

use ruast::*;

let mut krate = Crate::new();
let def = Fn::main(
    None,
    Block::from(Path::single("println").mac_call(vec![Token::lit("Hello, world!")])),
);
krate.add_item(def);
let tokens = krate.to_token_stream();
println!("{krate}");
println!("{tokens}");

Why this is needed?

The Rust project has a submodule called rustc_ast that defines an AST, but it is not published on crates.io and requires a huge build of rust itself. Also, rustc_ast is not designed for third parties to build ASTs by hand.

There is a codegen crate for Rust code generation, but this crate has not been maintained for some time and only supports basic syntax elements.

There is also a syn crate that can parse proc_macro::TokenStream into an AST, but its AST elements don't implement Display trait and are not designed for direct construction & modification.

Goals

The goal of this project is to provide a simple and portable Rust AST building/Rust code generation library.

Non-goals

This library is not directly related to the Rust compiler AST, and ASTs built with this library cannot be directly given as input to the compiler.

License

This project is licensed under either of Apache license version 2.0 or MIT license at your option.

Dependencies