blob: be0ac5fc7e2c59ee34facfe62457356b4b71a6c3 [file] [log] [blame]
David Tolnay35f071f2019-05-08 12:40:13 -07001//! # 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/0.15/syn/visit/index.html
17//! [`visit_mut`]: https://docs.rs/syn/0.15/syn/visit_mut/index.html
18//! [`fold`]: https://docs.rs/syn/0.15/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
David Tolnayb7622c92019-05-08 13:17:59 -070027//!
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//! ```
David Tolnay35f071f2019-05-08 12:40:13 -070046
David Tolnay14d463e2019-02-15 14:23:51 -080047use indexmap::IndexMap;
David Tolnay822790e2019-02-15 21:12:30 -080048use semver::Version;
David Tolnay10227122019-02-15 20:53:45 -080049use serde::{Deserialize, Deserializer, Serialize};
David Tolnay14d463e2019-02-15 14:23:51 -080050
David Tolnay440fe582019-02-15 20:23:14 -080051use std::collections::{BTreeMap, BTreeSet};
Carl Lerche058ff472019-02-13 16:23:52 -080052
David Tolnay5b2cd852019-05-08 13:09:33 -070053/// Top-level content of the syntax tree description.
David Tolnay4bc55232019-02-15 21:09:00 -080054#[derive(Debug, PartialEq, Serialize, Deserialize)]
David Tolnayf9bb8ff2019-02-15 13:10:14 -080055pub struct Definitions {
David Tolnay5b2cd852019-05-08 13:09:33 -070056 /// The Syn version whose syntax tree is described by this data.
David Tolnay822790e2019-02-15 21:12:30 -080057 pub version: Version,
David Tolnay5b2cd852019-05-08 13:09:33 -070058
59 /// Syntax tree types defined by Syn.
David Tolnayf9bb8ff2019-02-15 13:10:14 -080060 pub types: Vec<Node>,
David Tolnay5b2cd852019-05-08 13:09:33 -070061
62 /// Token types defined by Syn (keywords as well as punctuation).
63 ///
64 /// The keys in the map are the Rust type name for the token. The values in
65 /// the map are the printed token representation.
66 ///
67 /// These tokens are accessible in the Syn public API as `syn::token::#name`
68 /// or alternatively `syn::Token![#repr]`.
David Tolnayf9bb8ff2019-02-15 13:10:14 -080069 pub tokens: BTreeMap<String, String>,
70}
71
David Tolnay5b2cd852019-05-08 13:09:33 -070072/// Syntax tree type defined by Syn.
David Tolnay4bc55232019-02-15 21:09:00 -080073#[derive(Debug, PartialEq, Serialize, Deserialize)]
David Tolnayc2be7b22019-02-15 18:48:31 -080074pub struct Node {
David Tolnay5b2cd852019-05-08 13:09:33 -070075 /// Name of the type.
76 ///
77 /// This type is accessible in the Syn public API as `syn::#name`.
David Tolnayc2be7b22019-02-15 18:48:31 -080078 pub ident: String,
David Tolnay5b2cd852019-05-08 13:09:33 -070079
80 /// Features behind which this type is cfg gated.
David Tolnayc2be7b22019-02-15 18:48:31 -080081 pub features: Features,
David Tolnay5b2cd852019-05-08 13:09:33 -070082
83 /// Content of the data structure.
David Tolnayc2be7b22019-02-15 18:48:31 -080084 #[serde(
85 flatten,
86 skip_serializing_if = "is_private",
David Tolnay6f1b7f22019-02-15 21:38:54 -080087 deserialize_with = "private_if_absent"
David Tolnayc2be7b22019-02-15 18:48:31 -080088 )]
89 pub data: Data,
Carl Lerche058ff472019-02-13 16:23:52 -080090}
91
David Tolnay5b2cd852019-05-08 13:09:33 -070092/// Content of a syntax tree data structure.
David Tolnay4bc55232019-02-15 21:09:00 -080093#[derive(Debug, PartialEq, Serialize, Deserialize)]
David Tolnayc2be7b22019-02-15 18:48:31 -080094pub enum Data {
David Tolnay5b2cd852019-05-08 13:09:33 -070095 /// This is an opaque type with no publicy accessible structure.
David Tolnayc2be7b22019-02-15 18:48:31 -080096 Private,
David Tolnay5b2cd852019-05-08 13:09:33 -070097
98 /// This type is a braced struct with named fields.
David Tolnayc2be7b22019-02-15 18:48:31 -080099 #[serde(rename = "fields")]
David Tolnay75c5a172019-02-15 20:35:41 -0800100 Struct(Fields),
David Tolnay5b2cd852019-05-08 13:09:33 -0700101
102 /// This type is an enum.
David Tolnayc2be7b22019-02-15 18:48:31 -0800103 #[serde(rename = "variants")]
David Tolnay75c5a172019-02-15 20:35:41 -0800104 Enum(Variants),
Carl Lerche058ff472019-02-13 16:23:52 -0800105}
106
David Tolnay5b2cd852019-05-08 13:09:33 -0700107/// Fields of a braced struct syntax tree node with named fields.
108///
109/// The keys in the map are the field names.
David Tolnay75c5a172019-02-15 20:35:41 -0800110pub type Fields = IndexMap<String, Type>;
David Tolnay5b2cd852019-05-08 13:09:33 -0700111
112/// Variants of an enum syntax tree node.
113///
114/// The keys in the map are the variant names.
115///
116/// Variants are unit variants if they hold no data and tuple variants
117/// otherwise. The Syn syntax tree does not make use of braced variants.
David Tolnay75c5a172019-02-15 20:35:41 -0800118pub type Variants = IndexMap<String, Vec<Type>>;
Carl Lerche058ff472019-02-13 16:23:52 -0800119
David Tolnay5b2cd852019-05-08 13:09:33 -0700120/// Type of a struct field or tuple variant field in the syntax tree.
David Tolnay4bc55232019-02-15 21:09:00 -0800121#[derive(Debug, PartialEq, Serialize, Deserialize)]
David Tolnay295141b2019-02-15 12:45:33 -0800122#[serde(rename_all = "lowercase")]
Carl Lerche058ff472019-02-13 16:23:52 -0800123pub enum Type {
David Tolnay5b2cd852019-05-08 13:09:33 -0700124 /// Syntax tree type defined by Syn.
125 ///
126 /// This name will match the ident of some `Node`.
David Tolnayd3076572019-02-15 13:32:44 -0800127 Syn(String),
Carl Lerche058ff472019-02-13 16:23:52 -0800128
David Tolnay5b2cd852019-05-08 13:09:33 -0700129 /// Type defined by the Rust language or standard library.
130 ///
131 /// All such types used by Syn are accessible in the Rust prelude and can be
132 /// used without a qualifying path in most Rust code.
Carl Lerche058ff472019-02-13 16:23:52 -0800133 Std(String),
134
David Tolnay5b2cd852019-05-08 13:09:33 -0700135 /// Type defined by proc-macro2.
136 ///
137 /// The type is accessible in the proc-macro2 public API as
138 /// `proc_macro2::#name`.
David Tolnayd3076572019-02-15 13:32:44 -0800139 #[serde(rename = "proc_macro2")]
Carl Lerche058ff472019-02-13 16:23:52 -0800140 Ext(String),
141
David Tolnay5b2cd852019-05-08 13:09:33 -0700142 /// Keyword or punctuation token type defined by Syn.
143 ///
144 /// This name will match one of the keys in the `tokens` map.
David Tolnay157c7eb2019-02-15 13:21:48 -0800145 Token(String),
Carl Lerche058ff472019-02-13 16:23:52 -0800146
David Tolnay5b2cd852019-05-08 13:09:33 -0700147 /// Grouping token defined by Syn.
148 ///
149 /// The type is accessible in the Syn public API as `syn::token::#name`.
David Tolnay295141b2019-02-15 12:45:33 -0800150 Group(String),
Carl Lerche058ff472019-02-13 16:23:52 -0800151
David Tolnay5b2cd852019-05-08 13:09:33 -0700152 /// Punctuated list.
153 ///
154 /// This refers to `syn::punctuated::Punctuated<T, P>` with the specified
155 /// element type and punctuation.
David Tolnay295141b2019-02-15 12:45:33 -0800156 Punctuated(Punctuated),
157
David Tolnay5b2cd852019-05-08 13:09:33 -0700158 /// `std::option::Option`
Carl Lerche058ff472019-02-13 16:23:52 -0800159 Option(Box<Type>),
David Tolnay5b2cd852019-05-08 13:09:33 -0700160
161 /// `std::boxed::Box`
Carl Lerche058ff472019-02-13 16:23:52 -0800162 Box(Box<Type>),
David Tolnay5b2cd852019-05-08 13:09:33 -0700163
164 /// `std::vec::Vec`
Carl Lerche058ff472019-02-13 16:23:52 -0800165 Vec(Box<Type>),
David Tolnay5b2cd852019-05-08 13:09:33 -0700166
167 /// Rust tuple with two or more fields.
Carl Lerche058ff472019-02-13 16:23:52 -0800168 Tuple(Vec<Type>),
169}
170
David Tolnay5b2cd852019-05-08 13:09:33 -0700171/// Type of a punctuated list.
172///
173/// This refers to `syn::punctuated::Punctuated<#element, #punct>`.
174///
175/// The punct string will match one of the keys in the `tokens` map.
David Tolnay4bc55232019-02-15 21:09:00 -0800176#[derive(Debug, PartialEq, Serialize, Deserialize)]
David Tolnay295141b2019-02-15 12:45:33 -0800177pub struct Punctuated {
David Tolnay485973a2019-02-15 14:42:48 -0800178 pub element: Box<Type>,
179 pub punct: String,
David Tolnay295141b2019-02-15 12:45:33 -0800180}
181
David Tolnay5b2cd852019-05-08 13:09:33 -0700182/// Features behind which a syntax tree type is cfg gated.
David Tolnay4bc55232019-02-15 21:09:00 -0800183#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
Carl Lerche058ff472019-02-13 16:23:52 -0800184pub struct Features {
David Tolnay5b2cd852019-05-08 13:09:33 -0700185 /// Type is accessible if at least one of these features is enabled against
186 /// the Syn dependency.
David Tolnay440fe582019-02-15 20:23:14 -0800187 pub any: BTreeSet<String>,
Carl Lerche058ff472019-02-13 16:23:52 -0800188}
David Tolnayc2be7b22019-02-15 18:48:31 -0800189
190fn is_private(data: &Data) -> bool {
191 match data {
192 Data::Private => true,
193 Data::Struct(_) | Data::Enum(_) => false,
194 }
195}
196
David Tolnay6f1b7f22019-02-15 21:38:54 -0800197fn private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error>
David Tolnayc2be7b22019-02-15 18:48:31 -0800198where
199 D: Deserializer<'de>,
200{
201 let option = Option::deserialize(deserializer)?;
202 Ok(option.unwrap_or(Data::Private))
203}