blob: 82bd1ac632735fc04b3e2766470e2524841b8c91 [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
27
David Tolnay14d463e2019-02-15 14:23:51 -080028use indexmap::IndexMap;
David Tolnay822790e2019-02-15 21:12:30 -080029use semver::Version;
David Tolnay10227122019-02-15 20:53:45 -080030use serde::{Deserialize, Deserializer, Serialize};
David Tolnay14d463e2019-02-15 14:23:51 -080031
David Tolnay440fe582019-02-15 20:23:14 -080032use std::collections::{BTreeMap, BTreeSet};
Carl Lerche058ff472019-02-13 16:23:52 -080033
David Tolnay4bc55232019-02-15 21:09:00 -080034#[derive(Debug, PartialEq, Serialize, Deserialize)]
David Tolnayf9bb8ff2019-02-15 13:10:14 -080035pub struct Definitions {
David Tolnay10227122019-02-15 20:53:45 -080036 /// The Syn version used to generate the introspection file.
David Tolnay822790e2019-02-15 21:12:30 -080037 pub version: Version,
David Tolnayf9bb8ff2019-02-15 13:10:14 -080038 pub types: Vec<Node>,
39 pub tokens: BTreeMap<String, String>,
40}
41
David Tolnay4bc55232019-02-15 21:09:00 -080042#[derive(Debug, PartialEq, Serialize, Deserialize)]
David Tolnayc2be7b22019-02-15 18:48:31 -080043pub struct Node {
44 pub ident: String,
45 pub features: Features,
46 #[serde(
47 flatten,
48 skip_serializing_if = "is_private",
David Tolnay6f1b7f22019-02-15 21:38:54 -080049 deserialize_with = "private_if_absent"
David Tolnayc2be7b22019-02-15 18:48:31 -080050 )]
51 pub data: Data,
Carl Lerche058ff472019-02-13 16:23:52 -080052}
53
David Tolnay4bc55232019-02-15 21:09:00 -080054#[derive(Debug, PartialEq, Serialize, Deserialize)]
David Tolnayc2be7b22019-02-15 18:48:31 -080055pub enum Data {
56 Private,
57 #[serde(rename = "fields")]
David Tolnay75c5a172019-02-15 20:35:41 -080058 Struct(Fields),
David Tolnayc2be7b22019-02-15 18:48:31 -080059 #[serde(rename = "variants")]
David Tolnay75c5a172019-02-15 20:35:41 -080060 Enum(Variants),
Carl Lerche058ff472019-02-13 16:23:52 -080061}
62
David Tolnay75c5a172019-02-15 20:35:41 -080063pub type Fields = IndexMap<String, Type>;
64pub type Variants = IndexMap<String, Vec<Type>>;
Carl Lerche058ff472019-02-13 16:23:52 -080065
David Tolnay4bc55232019-02-15 21:09:00 -080066#[derive(Debug, PartialEq, Serialize, Deserialize)]
David Tolnay295141b2019-02-15 12:45:33 -080067#[serde(rename_all = "lowercase")]
Carl Lerche058ff472019-02-13 16:23:52 -080068pub enum Type {
69 /// Type defined by `syn`
David Tolnayd3076572019-02-15 13:32:44 -080070 Syn(String),
Carl Lerche058ff472019-02-13 16:23:52 -080071
72 /// Type defined in `std`.
73 Std(String),
74
75 /// Type external to `syn`
David Tolnayd3076572019-02-15 13:32:44 -080076 #[serde(rename = "proc_macro2")]
Carl Lerche058ff472019-02-13 16:23:52 -080077 Ext(String),
78
79 /// Token type
David Tolnay157c7eb2019-02-15 13:21:48 -080080 Token(String),
Carl Lerche058ff472019-02-13 16:23:52 -080081
82 /// Token group
David Tolnay295141b2019-02-15 12:45:33 -080083 Group(String),
Carl Lerche058ff472019-02-13 16:23:52 -080084
85 /// Punctuated list
David Tolnay295141b2019-02-15 12:45:33 -080086 Punctuated(Punctuated),
87
Carl Lerche058ff472019-02-13 16:23:52 -080088 Option(Box<Type>),
89 Box(Box<Type>),
90 Vec(Box<Type>),
91 Tuple(Vec<Type>),
92}
93
David Tolnay4bc55232019-02-15 21:09:00 -080094#[derive(Debug, PartialEq, Serialize, Deserialize)]
David Tolnay295141b2019-02-15 12:45:33 -080095pub struct Punctuated {
David Tolnay485973a2019-02-15 14:42:48 -080096 pub element: Box<Type>,
97 pub punct: String,
David Tolnay295141b2019-02-15 12:45:33 -080098}
99
David Tolnay4bc55232019-02-15 21:09:00 -0800100#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
Carl Lerche058ff472019-02-13 16:23:52 -0800101pub struct Features {
David Tolnay440fe582019-02-15 20:23:14 -0800102 pub any: BTreeSet<String>,
Carl Lerche058ff472019-02-13 16:23:52 -0800103}
David Tolnayc2be7b22019-02-15 18:48:31 -0800104
105fn is_private(data: &Data) -> bool {
106 match data {
107 Data::Private => true,
108 Data::Struct(_) | Data::Enum(_) => false,
109 }
110}
111
David Tolnay6f1b7f22019-02-15 21:38:54 -0800112fn private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error>
David Tolnayc2be7b22019-02-15 18:48:31 -0800113where
114 D: Deserializer<'de>,
115{
116 let option = Option::deserialize(deserializer)?;
117 Ok(option.unwrap_or(Data::Private))
118}