Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/mtshiba/ruast

Printable & modifiable Rust AST library
https://github.com/mtshiba/ruast

ast compiler library rust

Last synced: 3 months ago
JSON representation

Printable & modifiable Rust AST library

Awesome Lists containing this project

README

        

# `ruast`

This crate provides a printable & modifiable Rust AST.

## Basic usage

### Hello world

```rust
use ruast::*;

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

This is equivalent to:

```rust
use ruast::*;

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

```rust
> cargo run --example hello

fn main() {
println!("Hello, world!");
}
```

### Building struct, enum, trait and impl

The source code is available in the [`examples`](https://github.com/mtshiba/ruast/tree/main/examples) directory.

```rust
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}");
```

```rust
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}");
```

```rust
use ruast::*;

let mut krate = Crate::new();

let partial_eq = Type::simple_path("PartialEq");
let trait_def = TraitDef::new("Eq", vec![], vec![partial_eq], vec![]);
krate.add_item(trait_def);
let arg_t = GenericArg::Type(Type::simple_path("T"));
let eq_bound = GenericBound::Trait(PolyTraitRef::simple("Eq"));
let eq = Type::simple_path("Eq");
let param_t = GenericParam::new("T", vec![eq_bound]);
let self_ty = Type::poly_path("Vec", vec![arg_t]);
let imp = Impl::trait_impl(vec![param_t], self_ty, eq, None, vec![]);
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.

```rust
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](https://github.com/rust-lang/rust) has a submodule called [`rustc_ast`](https://github.com/rust-lang/rust/tree/master/compiler/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`](https://github.com/carllerche/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`](https://github.com/dtolnay/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](./LICENSE-APACHE) or [MIT license](./LICENSE-MIT) at your option.