/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //! AST nodes and code to parse them from syn use proc_macro2::Literal; // Use IndexMap for mappings. This preserves the field order and makes the diffs look nicer. use syn::{Generics, Ident, Type, Visibility}; /// Struct/Enum node in the IR #[derive(Clone)] #[allow(dead_code)] pub struct Node { pub attrs: Attributes, pub vis: Visibility, pub ident: Ident, pub generics: Generics, pub def: NodeDef, } #[derive(Clone)] pub enum NodeDef { Struct(Struct), Enum(Vec), } pub enum NodeKind<'a> { Struct { type_name: &'a Ident, }, Variant { type_name: &'a Ident, variant_name: &'a Ident, }, } #[derive(Clone, Default)] pub struct Attributes { pub from: Option, pub wraps: bool, } #[derive(Clone)] #[allow(dead_code)] pub struct Struct { pub fields: Fields, pub wraps_field: Option, } #[derive(Clone)] #[allow(dead_code)] pub struct Variant { pub attrs: Attributes, pub vis: Visibility, pub ident: Ident, pub fields: Fields, pub discriminant: Option, } #[derive(Clone)] pub enum Fields { Unit, Named(Vec), Unnamed(Vec), } #[derive(Clone)] #[allow(dead_code)] pub struct Field { pub attrs: Attributes, pub vis: Visibility, pub ident: Option, pub ty: Type, /// Variable name used it patterns, this will be `ident` for named fields and `var{idx}` for /// unnamed fields. pub var_name: Ident, } impl Node { pub fn prev_node_ident(&self) -> &Ident { self.attrs.from.as_ref().unwrap_or(&self.ident) } } impl NodeKind<'_> { pub fn field_name(&self, field: &Field) -> String { match (self, &field.ident) { (NodeKind::Struct { .. }, Some(name)) => format!(".{name}"), (NodeKind::Struct { .. }, None) => format!( ".{}", field.var_name.to_string().strip_prefix("var").unwrap() ), (NodeKind::Variant { variant_name, .. }, Some(name)) => { format!(".{variant_name}::{name}") } (NodeKind::Variant { variant_name, .. }, None) => format!( ".{variant_name}::{}", field.var_name.to_string().strip_prefix("var").unwrap() ), } } } impl Variant { pub fn prev_node_ident(&self) -> &Ident { self.attrs.from.as_ref().unwrap_or(&self.ident) } } impl Fields { pub fn iter(&self) -> impl Iterator { match self { Self::Named(fields) => fields.iter(), Self::Unnamed(fields) => fields.iter(), Self::Unit => [].iter(), } } pub fn var_names(&self) -> impl Iterator { self.iter().map(|f| &f.var_name) } pub fn not_named(&self) -> bool { !matches!(self, Fields::Named(_)) } } impl Field { pub fn prev_node_ident(&self) -> Option<&Ident> { self.attrs.from.as_ref().or(self.ident.as_ref()) } }