xref: /third_party/rust/crates/syn/json/src/lib.rs (revision fad3a1d3)
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
49use indexmap::IndexMap;
50use semver::Version;
51use serde::de::{Deserialize, Deserializer};
52use serde_derive::{Deserialize, Serialize};
53use std::collections::{BTreeMap, BTreeSet};
54
55/// Top-level content of the syntax tree description.
56#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
57pub 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)]
76pub 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)]
99pub 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.
115pub 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.
123pub 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")]
128pub 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)]
182pub 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)]
189pub 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
195fn is_private(data: &Data) -> bool {
196    match data {
197        Data::Private => true,
198        Data::Struct(_) | Data::Enum(_) => false,
199    }
200}
201
202fn private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error>
203where
204    D: Deserializer<'de>,
205{
206    let option = Option::deserialize(deserializer)?;
207    Ok(option.unwrap_or(Data::Private))
208}
209
210fn is_true(b: &bool) -> bool {
211    *b
212}
213
214fn bool_true() -> bool {
215    true
216}
217