1use std::{2 collections::{BTreeSet, HashSet},3 path::PathBuf,4};56use anyhow::Result;7use ast::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field};8use itertools::Itertools;9use proc_macro2::{Punct, Spacing, TokenStream};10use quote::{format_ident, quote};11use ungrammar::{Grammar, Rule};12use util::{13 ensure_file_contents, pluralize, reformat, to_lower_snake_case, to_pascal_case,14 to_upper_snake_case,15};1617mod ast;18mod util;1920pub fn generate_ungrammar() -> Result<()> {21 let grammar: Grammar = include_str!(concat!(22 env!("CARGO_MANIFEST_DIR"),23 "/../crates/jrsonnet-rowan-parser/jsonnet.ungram"24 ))25 .parse()?;2627 let mut kinds: KindsSrc = KindsSrc {28 punct: puncts![29 "||" => "OR";30 "&&" => "AND";31 "|" => "BIT_OR";32 "^" => "BIT_XOR";33 "&" => "BIT_AND";34 "==" => "EQ";35 "!=" => "NE";36 "<" => "LT";37 ">" => "GT";38 "<=" => "LE";39 ">=" => "GE";40 "<<" => "LHS";41 ">>" => "RHS";42 "+" => "PLUS";43 "-" => "MINUS";44 "*" => "MUL";45 "/" => "DIV";46 "%" => "MODULO";47 "!" => "NOT";48 "~" => "BIT_NOT";49 "[" => "L_BRACK";50 "]" => "R_BRACK";51 "(" => "L_PAREN";52 ")" => "R_PAREN";53 "{" => "L_BRACE";54 "}" => "R_BRACE";55 ":" => "COLON";56 "::" => "COLONCOLON";57 ":::" => "COLONCOLONCOLON";58 ";" => "SEMI";59 "." => "DOT";60 "..." => "DOTDOTDOT";61 "," => "COMMA";62 "$" => "DOLLAR";63 "=" => "ASSIGN";64 "?" => "QUESTION_MARK";65 "$intrinsicThisFile" => "INTRINSIC_THIS_FILE";66 "$intrinsicId" => "INTRINSIC_ID";67 "$intrinsic" => "INTRINSIC";68 ],69 keywords: vec![],70 literals: literals![71 "NUMBER" => r"(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?";72 "STRING_DOUBLE" => "\"(?s:[^\"\\\\]|\\\\.)*\"";73 "STRING_SINGLE" => "'(?s:[^'\\\\]|\\\\.)*'";74 "STRING_DOUBLE_VERBATIM" => "@\"(?:[^\"]|\"\")*\"";75 "STRING_SINGLE_VERBATIM" => "@'(?:[^']|'')*'";76 "STRING_BLOCK" => r"\|\|\|";7778 "IDENT" => r"[_a-zA-Z][_a-zA-Z0-9]*";79 "WHITESPACE" => r"[ \t\n\r]+";80 "SINGLE_LINE_SLASH_COMMENT" => r"//[^\r\n]*(\r\n|\n)?";81 "SINGLE_LINE_HASH_COMMENT" => r"#[^\r\n]*(\r\n|\n)?";82 "MULTI_LINE_COMMENT" => r"/\*([^*]|\*[^/])*\*/";83 ],84 nodes: vec![],85 };8687 let ast = lower(&kinds, &grammar);8889 for node in &ast.nodes {90 let name = to_upper_snake_case(&node.name);91 if !kinds.is_literal(&name) {92 kinds.nodes.push(name);93 }94 }95 for enum_ in &ast.enums {96 let name = to_upper_snake_case(&enum_.name);97 if !kinds.is_literal(&name) {98 kinds.nodes.push(name);99 }100 }101 for token in grammar.tokens() {102 let token = &grammar[token];103 let token = &token.name.clone();104 let name = to_upper_snake_case(token);105 if !kinds.is_punct(token) && !kinds.is_literal(&name) {106 kinds.keywords.push(token.to_owned());107 }108 }109110 let syntax_kinds = generate_syntax_kinds(&kinds)?;111112 let tokens = generate_tokens(&ast)?;113114 let nodes = generate_nodes(&kinds, &ast)?;115 ensure_file_contents(116 &PathBuf::from(concat!(117 env!("CARGO_MANIFEST_DIR"),118 "/../crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs",119 )),120 &syntax_kinds,121 )?;122 ensure_file_contents(123 &PathBuf::from(concat!(124 env!("CARGO_MANIFEST_DIR"),125 "/../crates/jrsonnet-rowan-parser/src/generated/tokens.rs",126 )),127 &tokens,128 )?;129 ensure_file_contents(130 &PathBuf::from(concat!(131 env!("CARGO_MANIFEST_DIR"),132 "/../crates/jrsonnet-rowan-parser/src/generated/nodes.rs",133 )),134 &nodes,135 )?;136 Ok(())137}138139fn generate_tokens(grammar: &AstSrc) -> Result<String> {140 let tokens = grammar.tokens.iter().map(|token| {141 let name = format_ident!("{}", token);142 let kind = format_ident!("{}", to_upper_snake_case(token));143 quote! {144 #[derive(Debug, Clone, PartialEq, Eq, Hash)]145 pub struct #name {146 pub(crate) syntax: SyntaxToken,147 }148 impl std::fmt::Display for #name {149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {150 std::fmt::Display::fmt(&self.syntax, f)151 }152 }153 impl AstToken for #name {154 fn can_cast(kind: SyntaxKind) -> bool { kind == #kind }155 fn cast(syntax: SyntaxToken) -> Option<Self> {156 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }157 }158 fn syntax(&self) -> &SyntaxToken { &self.syntax }159 }160 }161 });162163 Ok(reformat(164 "e! {165 use crate::{SyntaxKind::{self, *}, SyntaxToken, ast::AstToken};166 #(#tokens)*167 }168 .to_string(),169 )?170 .replace("#[derive", "\n#[derive"))171}172173fn generate_syntax_kinds(grammar: &KindsSrc) -> Result<String> {174 let (single_byte_tokens_values, single_byte_tokens): (Vec<_>, Vec<_>) = grammar175 .punct176 .iter()177 .filter(|(token, _name)| token.len() == 1)178 .map(|(token, name)| (token.chars().next().unwrap(), format_ident!("{}", name)))179 .unzip();180181 let punctuation_values = grammar182 .punct183 .iter()184 .map(|(token, _name)| escape_token_macro(token));185 let punctuation = grammar186 .punct187 .iter()188 .map(|(_token, name)| format_ident!("{}", name))189 .collect::<Vec<_>>();190 let punctuation_enum = grammar191 .punct192 .iter()193 .map(|(token, name)| {194 let id = format_ident!("{}", name);195 quote! {196 #[token(#token)]197 #id198 }199 })200 .collect::<Vec<_>>();201202 let x = |name: &str| format_ident!("{}_KW", to_upper_snake_case(name));203 let full_keywords_values = &grammar.keywords;204 let full_keywords = full_keywords_values.iter().map(|s| x(s.as_str()));205206 let all_keywords_values = grammar.keywords.to_vec();207 let all_keywords_idents = all_keywords_values.iter().map(|kw| format_ident!("{}", kw));208 let all_keywords = all_keywords_values209 .iter()210 .map(|s| x(&**s))211 .collect::<Vec<_>>();212 let all_keywords_enum = all_keywords_values213 .iter()214 .map(|s| {215 let id = x(&**s);216 quote! {217 #[token(#s)]218 #id219 }220 })221 .collect::<Vec<_>>();222223 let tokens_enum = grammar224 .literals225 .iter()226 .map(|l| {227 let regex = &l.regex;228 let id = format_ident!("{}", l.name);229 let lexer = l230 .lexer231 .as_ref()232 .map(|l| {233 let id: TokenStream = l.parse().expect("path");234 quote! {235 , #id236 }237 })238 .unwrap_or_else(|| quote! {});239 quote! {240 #[regex(#regex #lexer)]241 #id242 }243 })244 .collect::<Vec<_>>();245246 let nodes = grammar247 .nodes248 .iter()249 .map(|name| format_ident!("{}", name))250 .collect::<Vec<_>>();251252 let ast = quote! {253 #![allow(bad_style, missing_docs, unreachable_pub)]254 use logos::Logos;255256 257 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Logos)]258 #[repr(u16)]259 pub enum SyntaxKind {260 #[doc(hidden)]261 TOMBSTONE,262 #[doc(hidden)]263 EOF,264 #(#punctuation_enum,)*265 #(#all_keywords_enum,)*266 #(#tokens_enum,)*267 #[error]268 ERROR,269 #(#nodes,)*270 #[doc(hidden)]271 __LAST,272 }273 use self::SyntaxKind::*;274275 impl SyntaxKind {276 pub fn is_keyword(self) -> bool {277 match self {278 #(#all_keywords)|* => true,279 _ => false,280 }281 }282283 pub fn is_punct(self) -> bool {284 match self {285 #(#punctuation)|* => true,286 _ => false,287 }288 }289290 pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {291 let kw = match ident {292 #(#full_keywords_values => #full_keywords,)*293 _ => return None,294 };295 Some(kw)296 }297298 pub fn from_char(c: char) -> Option<SyntaxKind> {299 let tok = match c {300 #(#single_byte_tokens_values => #single_byte_tokens,)*301 _ => return None,302 };303 Some(tok)304 }305306 pub fn from_raw(r: u16) -> Self {307 assert!(r < Self::__LAST as u16);308 unsafe { std::mem::transmute(r) }309 }310 pub fn into_raw(self) -> u16 {311 self as u16312 }313 }314315 #[macro_export]316 macro_rules! T {317 #([#punctuation_values] => { $crate::SyntaxKind::#punctuation };)*318 #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)*319 [lifetime_ident] => { $crate::SyntaxKind::LIFETIME_IDENT };320 [ident] => { $crate::SyntaxKind::IDENT };321 [shebang] => { $crate::SyntaxKind::SHEBANG };322 }323 pub use T;324 };325326 reformat(&ast.to_string())327}328329pub struct KindsSrc {330 pub punct: Vec<(String, String)>,331 pub keywords: Vec<String>,332 pub literals: Vec<LiteralKind>,333 pub nodes: Vec<String>,334}335336pub struct LiteralKind {337 name: String,338 regex: String,339 lexer: Option<String>,340}341342#[macro_export]343macro_rules! literals {344 ($($name:expr => $regex:expr $(, $lexer:expr)?);* $(;)?) => {345 vec![346 $(LiteralKind {347 name: $name.to_owned(),348 regex: $regex.to_owned(),349 lexer: None $(.or_else(|| Some($lexer.to_string())))?,350 }),*351 ]352 };353}354355#[macro_export]356macro_rules! puncts {357 ($($tok:expr => $name:expr);* $(;)?) => {358 vec![359 $(($tok.to_owned(), $name.to_owned())),*360 ]361 };362}363use crate::{literals, puncts};364365impl KindsSrc {366 pub fn is_punct(&self, tok: &str) -> bool {367 self.punct.iter().any(|(t, _)| *t == tok)368 }369 pub fn is_literal(&self, tok: &str) -> bool {370 self.literals.iter().any(|l| l.name == tok)371 }372373 fn get_punct_name(&self, tok: &str) -> Option<&str> {374 self.punct375 .iter()376 .find(|(t, _)| *t == tok)377 .map(|(_, n)| n.as_str())378 }379}380381fn generate_nodes(kinds: &KindsSrc, grammar: &AstSrc) -> Result<String> {382 let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar383 .nodes384 .iter()385 .map(|node| {386 let name = format_ident!("{}", node.name);387 let kind = format_ident!("{}", to_upper_snake_case(&node.name));388 let traits = node.traits.iter().map(|trait_name| {389 let trait_name = format_ident!("{}", trait_name);390 quote!(impl ast::#trait_name for #name {})391 });392393 let methods = node.fields.iter().map(|field| {394 let method_name = field.method_name(kinds);395 let ty = field.ty();396397 if field.is_many() {398 quote! {399 pub fn #method_name(&self) -> AstChildren<#ty> {400 support::children(&self.syntax)401 }402 }403 } else if let Some(token_kind) = field.token_kind() {404 quote! {405 pub fn #method_name(&self) -> Option<#ty> {406 support::token(&self.syntax, #token_kind)407 }408 }409 } else {410 quote! {411 pub fn #method_name(&self) -> Option<#ty> {412 support::child(&self.syntax)413 }414 }415 }416 });417 (418 quote! {419 #[pretty_doc_comment_placeholder_workaround]420 #[derive(Debug, Clone, PartialEq, Eq, Hash)]421 pub struct #name {422 pub(crate) syntax: SyntaxNode,423 }424425 #(#traits)*426427 impl #name {428 #(#methods)*429 }430 },431 quote! {432 impl AstNode for #name {433 fn can_cast(kind: SyntaxKind) -> bool {434 kind == #kind435 }436 fn cast(syntax: SyntaxNode) -> Option<Self> {437 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }438 }439 fn syntax(&self) -> &SyntaxNode { &self.syntax }440 }441 },442 )443 })444 .unzip();445446 let (enum_defs, enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar447 .enums448 .iter()449 .map(|en| {450 let variants: Vec<_> = en451 .variants452 .iter()453 .map(|var| format_ident!("{}", var))454 .collect();455 let name = format_ident!("{}", en.name);456 let kinds: Vec<_> = variants457 .iter()458 .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))459 .collect();460 let traits = en.traits.iter().map(|trait_name| {461 let trait_name = format_ident!("{}", trait_name);462 quote!(impl ast::#trait_name for #name {})463 });464465 let ast_node = quote! {466 impl AstNode for #name {467 fn can_cast(kind: SyntaxKind) -> bool {468 match kind {469 #(#kinds)|* => true,470 _ => false,471 }472 }473 fn cast(syntax: SyntaxNode) -> Option<Self> {474 let res = match syntax.kind() {475 #(476 #kinds => #name::#variants(#variants { syntax }),477 )*478 _ => return None,479 };480 Some(res)481 }482 fn syntax(&self) -> &SyntaxNode {483 match self {484 #(485 #name::#variants(it) => &it.syntax,486 )*487 }488 }489 }490 };491492 (493 quote! {494 #[pretty_doc_comment_placeholder_workaround]495 #[derive(Debug, Clone, PartialEq, Eq, Hash)]496 pub enum #name {497 #(#variants(#variants),)*498 }499500 #(#traits)*501 },502 quote! {503 #(504 impl From<#variants> for #name {505 fn from(node: #variants) -> #name {506 #name::#variants(node)507 }508 }509 )*510 #ast_node511 },512 )513 })514 .unzip();515516 let (any_node_defs, any_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar517 .nodes518 .iter()519 .flat_map(|node| node.traits.iter().map(move |t| (t, node)))520 .into_group_map()521 .into_iter()522 .sorted_by_key(|(k, _)| *k)523 .map(|(trait_name, nodes)| {524 let name = format_ident!("Any{}", trait_name);525 let trait_name = format_ident!("{}", trait_name);526 let kinds: Vec<_> = nodes527 .iter()528 .map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string())))529 .collect();530531 (532 quote! {533 #[pretty_doc_comment_placeholder_workaround]534 #[derive(Debug, Clone, PartialEq, Eq, Hash)]535 pub struct #name {536 pub(crate) syntax: SyntaxNode,537 }538 impl ast::#trait_name for #name {}539 },540 quote! {541 impl #name {542 #[inline]543 pub fn new<T: ast::#trait_name>(node: T) -> #name {544 #name {545 syntax: node.syntax().clone()546 }547 }548 }549 impl AstNode for #name {550 fn can_cast(kind: SyntaxKind) -> bool {551 match kind {552 #(#kinds)|* => true,553 _ => false,554 }555 }556 fn cast(syntax: SyntaxNode) -> Option<Self> {557 Self::can_cast(syntax.kind()).then(|| #name { syntax })558 }559 fn syntax(&self) -> &SyntaxNode {560 &self.syntax561 }562 }563 },564 )565 })566 .unzip();567568 let enum_names = grammar.enums.iter().map(|it| &it.name);569 let node_names = grammar.nodes.iter().map(|it| &it.name);570571 let display_impls = enum_names572 .chain(node_names.clone())573 .map(|it| format_ident!("{}", it))574 .map(|name| {575 quote! {576 impl std::fmt::Display for #name {577 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {578 std::fmt::Display::fmt(self.syntax(), f)579 }580 }581 }582 });583584 let defined_nodes: HashSet<_> = node_names.collect();585586 for node in kinds587 .nodes588 .iter()589 .map(|kind| to_pascal_case(kind))590 .filter(|name| !defined_nodes.iter().any(|&it| it == name))591 {592 drop(node)593 594 595 }596597 let ast = quote! {598 #![allow(non_snake_case)]599 use crate::{600 SyntaxNode, SyntaxToken, SyntaxKind::{self, *},601 ast::{self, AstNode, AstChildren, support},602 T,603 };604605 #(#node_defs)*606 #(#enum_defs)*607 #(#any_node_defs)*608 #(#node_boilerplate_impls)*609 #(#enum_boilerplate_impls)*610 #(#any_node_boilerplate_impls)*611 #(#display_impls)*612 };613614 let ast = ast.to_string().replace("T ! [", "T![");615616 let mut res = String::with_capacity(ast.len() * 2);617618 let mut docs = grammar619 .nodes620 .iter()621 .map(|it| &it.doc)622 .chain(grammar.enums.iter().map(|it| &it.doc));623624 for chunk in ast.split("# [pretty_doc_comment_placeholder_workaround] ") {625 res.push_str(chunk);626 if let Some(doc) = docs.next() {627 write_doc_comment(doc, &mut res);628 }629 }630631 let res = reformat(&res)?;632 Ok(res.replace("#[derive", "\n#[derive"))633}634635fn write_doc_comment(contents: &[String], dest: &mut String) {636 use std::fmt::Write;637 for line in contents {638 writeln!(dest, "///{}", line).unwrap();639 }640}641642fn lower(kinds: &KindsSrc, grammar: &Grammar) -> AstSrc {643 let tokens = "Whitespace Comment String StringVerbantim StringBlock Number Ident"644 .split_ascii_whitespace()645 .map(|it| it.to_string())646 .collect::<Vec<_>>();647648 let mut res = AstSrc {649 tokens,650 ..Default::default()651 };652653 let nodes = grammar.iter().collect::<Vec<_>>();654655 for &node in &nodes {656 let name = grammar[node].name.clone();657 let rule = &grammar[node].rule;658 match lower_enum(grammar, rule) {659 Some(variants) => {660 let enum_src = AstEnumSrc {661 doc: Vec::new(),662 name,663 traits: Vec::new(),664 variants,665 };666 res.enums.push(enum_src);667 }668 None => {669 let mut fields = Vec::new();670 lower_rule(&mut fields, grammar, None, rule);671 res.nodes.push(AstNodeSrc {672 doc: Vec::new(),673 name,674 traits: Vec::new(),675 fields,676 });677 }678 }679 }680681 deduplicate_fields(&mut res);682 extract_enums(&mut res);683 extract_struct_traits(kinds, &mut res);684 extract_enum_traits(&mut res);685 res686}687688fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {689 let alternatives = match rule {690 Rule::Alt(it) => it,691 _ => return None,692 };693 let mut variants = Vec::new();694 for alternative in alternatives {695 match alternative {696 Rule::Node(it) => variants.push(grammar[*it].name.clone()),697 Rule::Token(it) if grammar[*it].name == ";" => (),698 _ => return None,699 }700 }701 Some(variants)702}703704fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {705 if lower_comma_list(acc, grammar, label, rule) {706 return;707 }708709 match rule {710 Rule::Node(node) => {711 let ty = grammar[*node].name.clone();712 let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty));713 let field = Field::Node {714 name,715 ty,716 cardinality: Cardinality::Optional,717 };718 acc.push(field);719 }720 Rule::Token(token) => {721 assert!(label.is_none(), "uexpected label: {:?}", label);722 let name = grammar[*token].name.clone();723 let field = Field::Token(name);724 acc.push(field);725 }726 Rule::Rep(inner) => {727 if let Rule::Node(node) = &**inner {728 let ty = grammar[*node].name.clone();729 let name = label730 .cloned()731 .unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));732 let field = Field::Node {733 name,734 ty,735 cardinality: Cardinality::Many,736 };737 acc.push(field);738 return;739 }740 todo!("unsupported repitition: {:?}", rule)741 }742 Rule::Labeled { label: l, rule } => {743 assert!(label.is_none());744 lower_rule(acc, grammar, Some(l), rule);745 }746 Rule::Seq(rules) | Rule::Alt(rules) => {747 for rule in rules {748 lower_rule(acc, grammar, label, rule)749 }750 }751 Rule::Opt(rule) => lower_rule(acc, grammar, label, rule),752 }753}754755756fn lower_comma_list(757 acc: &mut Vec<Field>,758 grammar: &Grammar,759 label: Option<&String>,760 rule: &Rule,761) -> bool {762 let rule = match rule {763 Rule::Seq(it) => it,764 _ => return false,765 };766 let (node, repeat, trailing_comma) = match rule.as_slice() {767 [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {768 (node, repeat, trailing_comma)769 }770 _ => return false,771 };772 let repeat = match &**repeat {773 Rule::Seq(it) => it,774 _ => return false,775 };776 match repeat.as_slice() {777 [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),778 _ => return false,779 }780 let ty = grammar[*node].name.clone();781 let name = label782 .cloned()783 .unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));784 let field = Field::Node {785 name,786 ty,787 cardinality: Cardinality::Many,788 };789 acc.push(field);790 true791}792793fn deduplicate_fields(ast: &mut AstSrc) {794 for node in &mut ast.nodes {795 let mut i = 0;796 'outer: while i < node.fields.len() {797 for j in 0..i {798 let f1 = &node.fields[i];799 let f2 = &node.fields[j];800 if f1 == f2 {801 node.fields.remove(i);802 continue 'outer;803 }804 }805 i += 1;806 }807 }808}809810fn extract_enums(ast: &mut AstSrc) {811 for node in &mut ast.nodes {812 for enm in &ast.enums {813 let mut to_remove = Vec::new();814 for (i, field) in node.fields.iter().enumerate() {815 let ty = field.ty().to_string();816 if enm.variants.iter().any(|it| it == &ty) {817 to_remove.push(i);818 }819 }820 if to_remove.len() == enm.variants.len() {821 node.remove_field(to_remove);822 let ty = enm.name.clone();823 let name = to_lower_snake_case(&ty);824 node.fields.push(Field::Node {825 name,826 ty,827 cardinality: Cardinality::Optional,828 });829 }830 }831 }832}833834fn extract_struct_traits(kinds: &KindsSrc, ast: &mut AstSrc) {835 836 let traits: &[(&str, &[&str])] = &[];837838 for node in &mut ast.nodes {839 for (name, methods) in traits {840 extract_struct_trait(kinds, node, name, methods);841 }842 }843}844845fn extract_struct_trait(846 kinds: &KindsSrc,847 node: &mut AstNodeSrc,848 trait_name: &str,849 methods: &[&str],850) {851 let mut to_remove = Vec::new();852 for (i, field) in node.fields.iter().enumerate() {853 let method_name = field.method_name(kinds).to_string();854 if methods.iter().any(|&it| it == method_name) {855 to_remove.push(i);856 }857 }858 if to_remove.len() == methods.len() {859 node.traits.push(trait_name.to_string());860 node.remove_field(to_remove);861 }862}863864fn extract_enum_traits(ast: &mut AstSrc) {865 let enums = ast.enums.clone();866 for enm in &mut ast.enums {867 if enm.name == "Stmt" {868 continue;869 }870 let nodes = &ast.nodes;871872 let mut variant_traits = enm.variants.iter().map(|var| {873 nodes874 .iter()875 .find_map(|node| {876 if &node.name != var {877 return None;878 }879 Some(node.traits.iter().cloned().collect::<BTreeSet<_>>())880 })881 .unwrap_or_else(|| {882 enums883 .iter()884 .find_map(|node| {885 if &node.name != var {886 return None;887 }888 Some(node.traits.iter().cloned().collect::<BTreeSet<_>>())889 })890 .unwrap_or_else(|| {891 panic!("{}", {892 &format!(893 "Could not find a struct `{}` for enum `{}::{}`",894 var, enm.name, var895 )896 })897 })898 })899 });900901 let mut enum_traits = match variant_traits.next() {902 Some(it) => it,903 None => continue,904 };905 for traits in variant_traits {906 enum_traits = enum_traits.intersection(&traits).cloned().collect();907 }908 enm.traits = enum_traits.into_iter().collect();909 }910}911912pub fn escape_token_macro(token: &str) -> TokenStream {913 if "{}[]()$".contains(token) {914 let c = token.chars().next().unwrap();915 quote! { #c }916 } else if token.contains('$') {917 quote! { #token }918 } else {919 let cs = token.chars().map(|c| Punct::new(c, Spacing::Joint));920 quote! { #(#cs)* }921 }922}