syn_codegen/lib.rs
1//! # Data structures that describe Syn's syntax tree.
2//!
3//! The Syn syntax tree is made up of more than 200 types. Occasionally it can
4//! come up that you need to implement some behavior across them all.
5//!
6//! - For example [the Rust integration for AST Explorer][astexplorer] wants to
7//! turn a syntax tree from Syn into a JavaScript value understood by the
8//! platform's existing cross-language syntax tree visualization code.
9//!
10//! [astexplorer]: https://astexplorer.net/#/gist/388150a52f74d45a355d2b5e865ded96/0c6d563f28d900472f699c21a1845ad20ae9927f
11//!
12//! - As another example from within Syn itself, the traits and implementations
13//! of the [`visit`], [`visit_mut`], and [`fold`] modules can be generated
14//! programmatically from a description of the syntax tree.
15//!
16//! [`visit`]: https://docs.rs/syn/2.0/syn/visit/index.html
17//! [`visit_mut`]: https://docs.rs/syn/2.0/syn/visit_mut/index.html
18//! [`fold`]: https://docs.rs/syn/2.0/syn/fold/index.html
19//!
20//! To make this type of code as easy as possible to implement in any language,
21//! every Syn release comes with a machine-readable description of that version
22//! of the syntax tree as a JSON file [syn.json]. This `syn-codegen` crate
23//! provides the canonical data structures for parsing and making use of the
24//! representation in syn.json from Rust code.
25//!
26//! [syn.json]: https://raw.githubusercontent.com/dtolnay/syn/master/syn.json
27//!
28//! ## Example
29//!
30//! ```
31//! use syn_codegen::Definitions;
32//!
33//! # const IGNORE: &str = stringify! {
34//! const SYN: &str = include_str!("syn.json");
35//! # };
36//! # const SYN: &str = include_str!("../../syn.json");
37//!
38//! fn main() {
39//! let defs: Definitions = serde_json::from_str(SYN).unwrap();
40//!
41//! for node in &defs.types {
42//! println!("syn::{}", node.ident);
43//! }
44//! }
45//! ```
46
47#![doc(html_root_url = "https://docs.rs/syn-codegen/0.4.2")]
48
49use indexmap::IndexMap;
50use semver::Version;
51#[cfg(feature = "serde")]
52use serde::de::{Deserialize, Deserializer};
53#[cfg(feature = "serde")]
54use serde_derive::{Deserialize, Serialize};
55use std::collections::{BTreeMap, BTreeSet};
56
57/// Top-level content of the syntax tree description.
58#[derive(Clone, Debug, PartialEq)]
59#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60pub struct Definitions {
61 /// The Syn version whose syntax tree is described by this data.
62 pub version: Version,
63
64 /// Syntax tree types defined by Syn.
65 pub types: Vec<Node>,
66
67 /// Token types defined by Syn (keywords as well as punctuation).
68 ///
69 /// The keys in the map are the Rust type name for the token. The values in
70 /// the map are the printed token representation.
71 ///
72 /// These tokens are accessible in the Syn public API as `syn::token::#name`
73 /// or alternatively `syn::Token![#repr]`.
74 pub tokens: BTreeMap<String, String>,
75}
76
77/// Syntax tree type defined by Syn.
78#[derive(Clone, Debug, PartialEq)]
79#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
80pub struct Node {
81 /// Name of the type.
82 ///
83 /// This type is accessible in the Syn public API as `syn::#name`.
84 pub ident: String,
85
86 /// Features behind which this type is cfg gated.
87 pub features: Features,
88
89 /// Content of the data structure.
90 #[cfg_attr(
91 feature = "serde",
92 serde(
93 flatten,
94 skip_serializing_if = "is_private",
95 deserialize_with = "private_if_absent"
96 )
97 )]
98 pub data: Data,
99
100 #[cfg_attr(
101 feature = "serde",
102 serde(skip_serializing_if = "is_true", default = "bool_true")
103 )]
104 pub exhaustive: bool,
105}
106
107/// Content of a syntax tree data structure.
108#[derive(Clone, Debug, PartialEq)]
109#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
110pub enum Data {
111 /// This is an opaque type with no publicly accessible structure.
112 Private,
113
114 /// This type is a braced struct with named fields.
115 #[cfg_attr(feature = "serde", serde(rename = "fields"))]
116 Struct(Fields),
117
118 /// This type is an enum.
119 #[cfg_attr(feature = "serde", serde(rename = "variants"))]
120 Enum(Variants),
121}
122
123/// Fields of a braced struct syntax tree node with named fields.
124///
125/// The keys in the map are the field names.
126pub type Fields = IndexMap<String, Type>;
127
128/// Variants of an enum syntax tree node.
129///
130/// The keys in the map are the variant names.
131///
132/// Variants are unit variants if they hold no data and tuple variants
133/// otherwise. The Syn syntax tree does not make use of braced variants.
134pub type Variants = IndexMap<String, Vec<Type>>;
135
136/// Type of a struct field or tuple variant field in the syntax tree.
137#[derive(Clone, Debug, PartialEq)]
138#[cfg_attr(
139 feature = "serde",
140 derive(Serialize, Deserialize),
141 serde(rename_all = "lowercase")
142)]
143pub enum Type {
144 /// Syntax tree type defined by Syn.
145 ///
146 /// This name will match the ident of some `Node`.
147 Syn(String),
148
149 /// Type defined by the Rust language or standard library.
150 ///
151 /// All such types used by Syn are accessible in the Rust prelude and can be
152 /// used without a qualifying path in most Rust code.
153 Std(String),
154
155 /// Type defined by proc-macro2.
156 ///
157 /// The type is accessible in the proc-macro2 public API as
158 /// `proc_macro2::#name`.
159 #[cfg_attr(feature = "serde", serde(rename = "proc_macro2"))]
160 Ext(String),
161
162 /// Keyword or punctuation token type defined by Syn.
163 ///
164 /// This name will match one of the keys in the `tokens` map.
165 Token(String),
166
167 /// Grouping token defined by Syn.
168 ///
169 /// The type is accessible in the Syn public API as `syn::token::#name`.
170 Group(String),
171
172 /// Punctuated list.
173 ///
174 /// This refers to `syn::punctuated::Punctuated<T, P>` with the specified
175 /// element type and punctuation.
176 Punctuated(Punctuated),
177
178 /// `std::option::Option`
179 Option(Box<Type>),
180
181 /// `std::boxed::Box`
182 Box(Box<Type>),
183
184 /// `std::vec::Vec`
185 Vec(Box<Type>),
186
187 /// Rust tuple with two or more fields.
188 Tuple(Vec<Type>),
189}
190
191/// Type of a punctuated list.
192///
193/// This refers to `syn::punctuated::Punctuated<#element, #punct>`.
194///
195/// The punct string will match one of the keys in the `tokens` map.
196#[derive(Clone, Debug, PartialEq)]
197#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
198pub struct Punctuated {
199 pub element: Box<Type>,
200 pub punct: String,
201}
202
203/// Features behind which a syntax tree type is cfg gated.
204#[derive(Clone, Debug, Default, PartialEq)]
205#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
206pub struct Features {
207 /// Type is accessible if at least one of these features is enabled against
208 /// the Syn dependency.
209 pub any: BTreeSet<String>,
210}
211
212#[cfg(feature = "serde")]
213fn is_private(data: &Data) -> bool {
214 match data {
215 Data::Private => true,
216 Data::Struct(_) | Data::Enum(_) => false,
217 }
218}
219
220#[cfg(feature = "serde")]
221fn private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error>
222where
223 D: Deserializer<'de>,
224{
225 let option = Option::deserialize(deserializer)?;
226 Ok(option.unwrap_or(Data::Private))
227}
228
229#[cfg(feature = "serde")]
230fn is_true(b: &bool) -> bool {
231 *b
232}
233
234#[cfg(feature = "serde")]
235fn bool_true() -> bool {
236 true
237}