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