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/1.0/syn/visit/index.html
17 //! [`visit_mut`]: https://docs.rs/syn/1.0/syn/visit_mut/index.html
18 //! [`fold`]: https://docs.rs/syn/1.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.2.0")]
48
49 use indexmap::IndexMap;
50 use semver::Version;
51 use serde::{Deserialize, Deserializer, Serialize};
52 use std::collections::{BTreeMap, BTreeSet};
53
54 /// Top-level content of the syntax tree description.
55 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
56 pub struct Definitions {
57 /// The Syn version whose syntax tree is described by this data.
58 pub version: Version,
59
60 /// Syntax tree types defined by Syn.
61 pub types: Vec<Node>,
62
63 /// Token types defined by Syn (keywords as well as punctuation).
64 ///
65 /// The keys in the map are the Rust type name for the token. The values in
66 /// the map are the printed token representation.
67 ///
68 /// These tokens are accessible in the Syn public API as `syn::token::#name`
69 /// or alternatively `syn::Token![#repr]`.
70 pub tokens: BTreeMap<String, String>,
71 }
72
73 /// Syntax tree type defined by Syn.
74 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
75 pub struct Node {
76 /// Name of the type.
77 ///
78 /// This type is accessible in the Syn public API as `syn::#name`.
79 pub ident: String,
80
81 /// Features behind which this type is cfg gated.
82 pub features: Features,
83
84 /// Content of the data structure.
85 #[serde(
86 flatten,
87 skip_serializing_if = "is_private",
88 deserialize_with = "private_if_absent"
89 )]
90 pub data: Data,
91
92 #[serde(skip_serializing_if = "is_true", default = "bool_true")]
93 pub exhaustive: bool,
94 }
95
96 /// Content of a syntax tree data structure.
97 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
98 pub enum Data {
99 /// This is an opaque type with no publicy accessible structure.
100 Private,
101
102 /// This type is a braced struct with named fields.
103 #[serde(rename = "fields")]
104 Struct(Fields),
105
106 /// This type is an enum.
107 #[serde(rename = "variants")]
108 Enum(Variants),
109 }
110
111 /// Fields of a braced struct syntax tree node with named fields.
112 ///
113 /// The keys in the map are the field names.
114 pub type Fields = IndexMap<String, Type>;
115
116 /// Variants of an enum syntax tree node.
117 ///
118 /// The keys in the map are the variant names.
119 ///
120 /// Variants are unit variants if they hold no data and tuple variants
121 /// otherwise. The Syn syntax tree does not make use of braced variants.
122 pub type Variants = IndexMap<String, Vec<Type>>;
123
124 /// Type of a struct field or tuple variant field in the syntax tree.
125 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
126 #[serde(rename_all = "lowercase")]
127 pub enum Type {
128 /// Syntax tree type defined by Syn.
129 ///
130 /// This name will match the ident of some `Node`.
131 Syn(String),
132
133 /// Type defined by the Rust language or standard library.
134 ///
135 /// All such types used by Syn are accessible in the Rust prelude and can be
136 /// used without a qualifying path in most Rust code.
137 Std(String),
138
139 /// Type defined by proc-macro2.
140 ///
141 /// The type is accessible in the proc-macro2 public API as
142 /// `proc_macro2::#name`.
143 #[serde(rename = "proc_macro2")]
144 Ext(String),
145
146 /// Keyword or punctuation token type defined by Syn.
147 ///
148 /// This name will match one of the keys in the `tokens` map.
149 Token(String),
150
151 /// Grouping token defined by Syn.
152 ///
153 /// The type is accessible in the Syn public API as `syn::token::#name`.
154 Group(String),
155
156 /// Punctuated list.
157 ///
158 /// This refers to `syn::punctuated::Punctuated<T, P>` with the specified
159 /// element type and punctuation.
160 Punctuated(Punctuated),
161
162 /// `std::option::Option`
163 Option(Box<Type>),
164
165 /// `std::boxed::Box`
166 Box(Box<Type>),
167
168 /// `std::vec::Vec`
169 Vec(Box<Type>),
170
171 /// Rust tuple with two or more fields.
172 Tuple(Vec<Type>),
173 }
174
175 /// Type of a punctuated list.
176 ///
177 /// This refers to `syn::punctuated::Punctuated<#element, #punct>`.
178 ///
179 /// The punct string will match one of the keys in the `tokens` map.
180 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
181 pub struct Punctuated {
182 pub element: Box<Type>,
183 pub punct: String,
184 }
185
186 /// Features behind which a syntax tree type is cfg gated.
187 #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
188 pub struct Features {
189 /// Type is accessible if at least one of these features is enabled against
190 /// the Syn dependency.
191 pub any: BTreeSet<String>,
192 }
193
is_private(data: &Data) -> bool194 fn is_private(data: &Data) -> bool {
195 match data {
196 Data::Private => true,
197 Data::Struct(_) | Data::Enum(_) => false,
198 }
199 }
200
private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error> where D: Deserializer<'de>,201 fn private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error>
202 where
203 D: Deserializer<'de>,
204 {
205 let option = Option::deserialize(deserializer)?;
206 Ok(option.unwrap_or(Data::Private))
207 }
208
is_true(b: &bool) -> bool209 fn is_true(b: &bool) -> bool {
210 *b
211 }
212
bool_true() -> bool213 fn bool_true() -> bool {
214 true
215 }
216