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