{"id":16753508,"url":"https://github.com/optimalstrategy/ast2str","last_synced_at":"2026-03-14T16:42:58.464Z","repository":{"id":47289590,"uuid":"361154884","full_name":"optimalstrategy/ast2str","owner":"optimalstrategy","description":"A derive macro for printing ASTs","archived":false,"fork":false,"pushed_at":"2022-08-23T02:46:41.000Z","size":63,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-08T12:17:33.027Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/optimalstrategy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-04-24T12:22:00.000Z","updated_at":"2025-03-25T12:06:58.000Z","dependencies_parsed_at":"2022-08-28T19:41:29.185Z","dependency_job_id":null,"html_url":"https://github.com/optimalstrategy/ast2str","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimalstrategy%2Fast2str","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimalstrategy%2Fast2str/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimalstrategy%2Fast2str/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimalstrategy%2Fast2str/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/optimalstrategy","download_url":"https://codeload.github.com/optimalstrategy/ast2str/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248250743,"owners_count":21072682,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T02:50:18.402Z","updated_at":"2025-10-28T06:38:33.123Z","avatar_url":"https://github.com/optimalstrategy.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ast2str\n\n[![crates.io][crate logo]][crate]\n[![Documentation][doc logo]][doc]\n[![Build Status][ci logo]][ci]\n\nA proc macro for pretty-printing ASTs and other recursive data structures.\n\n# Basic Usage\n\nRefer to the snippet below for a basic usage example, and see the [integration test](./tests/ast.rs) and these two repos ([#1.1](https://github.com/ves-lang/ves/blob/master/ves-parser/src/ast/mod.rs) + [#1.2](https://github.com/ves-lang/ves/blob/master/ves-parser/tests/t32_fn_if_expr_regression.test), [#2.1](https://github.com/langjam/jam0001/blob/main/dank/src/ast.rs)) for larger samples.\n\n```rust\n// Import the macro\nuse ast2str::AstToStr;\n\ntype Span = std::ops::Range\u003cusize\u003e;\n\n// Annotate some structs and enums as desired\n#[derive(AstToStr)]\nstruct Label {\n   #[quoted]\n   name: \u0026'static str,\n   #[default = \"Unresolved\"]\n   location: Option\u003cusize\u003e,\n}\n\n#[derive(AstToStr)]\nenum Expr {\n    Binary {\n        left: Box\u003cExpr\u003e,\n        #[quoted]\n        operator: \u0026'static str,\n        right: Box\u003cExpr\u003e\n    },\n    Literal(#[rename = \"value\"] i32, #[skip] Span),\n    List { items: Vec\u003cExpr\u003e },\n    Label(#[forward] Label),\n    Optional {\n        #[skip_if = \"Option::is_none\"]\n        value: Option\u003c\u0026'static str\u003e\n    }\n}\n\nlet expr = Expr::Binary {\n    left: Box::new(Expr::Literal(5, Span::default())),\n    operator: \"+\",\n    right: Box::new(Expr::List { items: vec![\n       Expr::Label(Label { name: \"x\", location: Some(0) }),\n       Expr::Label(Label { name: \"y\", location: Some(1) }),\n       Expr::Label(Label { name: \"z\", location: None }),\n       Expr::Optional { value: None },\n       Expr::Optional { value: Some(\"a string\") },\n    ]})\n};\nassert_eq!(expr.ast_to_str(), r#\"\nExpr::Binary\n├─left: Expr::Literal\n│ ╰─value: 5\n├─operator: `+`\n╰─right: Expr::List\n  ╰─items=↓\n    ├─Label\n    │ ├─name: `x`\n    │ ╰─location: 0\n    ├─Label\n    │ ├─name: `y`\n    │ ╰─location: 1\n    ├─Label\n    │ ├─name: `z`\n    │ ╰─location: Unresolved\n    ├─Expr::Optional\n    ╰─Expr::Optional\n      ╰─value: \"a string\"\n\"#.trim());\n\n// The symbols used to draw the tree can be configured using the [`Symbols`] trait:\nassert_eq!(expr.ast_to_str_impl(\u0026ast2str::TestSymbols), r#\"\nExpr::Binary\n  left: Expr::Literal\n    value: 5\n  operator: `+`\n  right: Expr::List\n    items=\n      Label\n        name: `x`\n        location: 0\n      Label\n        name: `y`\n        location: 1\n      Label\n        name: `z`\n        location: Unresolved\n      Expr::Optional\n      Expr::Optional\n        value: \"a string\"\n\"#.trim());\n```\n\n# Available Attributes\n\n| Attribute    |                                                                          |\n|--------------|--------------------------------------------------------------------------|\n| None         | Format the value with [`AstToStr`]                                       |\n| `#[forward]` | Skip all other fields and return the [`AstToStr`] of the annotated field |\n| `#[skip]`    | Skip the annotated field                                                 |\n| `#[display]` | Format the annotated field with [`Display`] instead of [`AstToStr`]      |\n| `#[debug]`   | Format the annotated field with [`Debug`] instead of [`AstToStr`]        |\n| `#[quoted]`  | Like `#[display]` but also wraps the value with backticks                |\n| `#[list]`    | Format the annotated field by executing AstToStr on every element of `(\u0026field).into_iter()` |\n| `#[list(name_or_closure)`        | Format the annotated field by applying the callback on every element of `(\u0026field).into_iter()` |\n| `#[callback(name_or_closure)]`   | Apply the given function or closure to `\u0026field` and return the result |\n| `#[delegate = \"getter\"]`         | Call `self.getter()` and format the result as a field |\n| `#[default = \"value\"]`           | Only applies to `Option` types. If the value is `Some(T)`, format \u0026T with AstToStr. Otherwise, return the value of `default` |\n| `#[skip_if = \"my_condition_fn\"]` | Skip the annotated field if the specified function returns `true` |\n\n[crate]: https://crates.io/crates/ast2str\n[crate logo]: https://img.shields.io/crates/v/ast2str.svg\n[doc]: https://docs.rs/ast2str\n[doc logo]: https://docs.rs/ast2str/badge.svg\n[ci]: https://github.com/optimalstrategy/ast2str/actions\n[ci logo]: https://github.com/optimalstrategy/ast2str/actions/workflows/rust.yml/badge.svg\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foptimalstrategy%2Fast2str","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foptimalstrategy%2Fast2str","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foptimalstrategy%2Fast2str/lists"}