mirror of
				https://github.com/sharkdp/bat.git
				synced 2025-10-31 07:04:04 +00:00 
			
		
		
		
	Build script: replace string-based codegen with quote-based codegen
				
					
				
			This commit is contained in:
		| @@ -9,6 +9,8 @@ use anyhow::{anyhow, bail}; | ||||
| use indexmap::IndexMap; | ||||
| use itertools::Itertools; | ||||
| use once_cell::sync::Lazy; | ||||
| use proc_macro2::TokenStream; | ||||
| use quote::{quote, ToTokens, TokenStreamExt}; | ||||
| use regex::Regex; | ||||
| use serde_derive::Deserialize; | ||||
| use serde_with::DeserializeFromStr; | ||||
| @@ -34,13 +36,14 @@ impl FromStr for MappingTarget { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| impl MappingTarget { | ||||
|     fn codegen(&self) -> String { | ||||
|         match self { | ||||
|             Self::MapTo(syntax) => format!(r###"MappingTarget::MapTo(r#"{syntax}"#)"###), | ||||
|             Self::MapToUnknown => "MappingTarget::MapToUnknown".into(), | ||||
|             Self::MapExtensionToUnknown => "MappingTarget::MapExtensionToUnknown".into(), | ||||
|         } | ||||
| impl ToTokens for MappingTarget { | ||||
|     fn to_tokens(&self, tokens: &mut TokenStream) { | ||||
|         let t = match self { | ||||
|             Self::MapTo(syntax) => quote! { MappingTarget::MapTo(#syntax) }, | ||||
|             Self::MapToUnknown => quote! { MappingTarget::MapToUnknown }, | ||||
|             Self::MapExtensionToUnknown => quote! { MappingTarget::MapExtensionToUnknown }, | ||||
|         }; | ||||
|         tokens.append_all(t); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -116,22 +119,17 @@ impl FromStr for Matcher { | ||||
|         Ok(Self(non_empty_segments)) | ||||
|     } | ||||
| } | ||||
| impl Matcher { | ||||
|     fn codegen(&self) -> String { | ||||
|         match self.0.len() { | ||||
|             0 => unreachable!("0-length matcher should never be created"), | ||||
|             // if-let guard would be ideal here | ||||
|             // see: https://github.com/rust-lang/rust/issues/51114 | ||||
|             1 if self.0[0].is_text() => { | ||||
|                 let s = self.0[0].text().unwrap(); | ||||
|                 format!(r###"Lazy::new(|| Some(build_matcher_fixed(r#"{s}"#)))"###) | ||||
| impl ToTokens for Matcher { | ||||
|     fn to_tokens(&self, tokens: &mut TokenStream) { | ||||
|         let t = match self.0.as_slice() { | ||||
|             [] => unreachable!("0-length matcher should never be created"), | ||||
|             [MatcherSegment::Text(text)] => { | ||||
|                 quote! { Lazy::new(|| Some(build_matcher_fixed(#text)))} | ||||
|             } | ||||
|             // parser logic ensures that this case can only happen when there are dynamic segments | ||||
|             _ => { | ||||
|                 let segs = self.0.iter().map(MatcherSegment::codegen).join(", "); | ||||
|                 format!(r###"Lazy::new(|| build_matcher_dynamic(&[{segs}]))"###) | ||||
|             } | ||||
|         } | ||||
|             segs @ [_, ..] => quote! { Lazy::new(|| build_matcher_dynamic(&[ #(#segs),* ]))}, | ||||
|         }; | ||||
|         tokens.append_all(t); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -143,6 +141,15 @@ enum MatcherSegment { | ||||
|     Text(String), | ||||
|     Env(String), | ||||
| } | ||||
| impl ToTokens for MatcherSegment { | ||||
|     fn to_tokens(&self, tokens: &mut TokenStream) { | ||||
|         let t = match self { | ||||
|             Self::Text(text) => quote! { MatcherSegment::Text(#text)}, | ||||
|             Self::Env(env) => quote! {MatcherSegment::Env(#env)}, | ||||
|         }; | ||||
|         tokens.append_all(t); | ||||
|     } | ||||
| } | ||||
| #[allow(dead_code)] | ||||
| impl MatcherSegment { | ||||
|     fn is_text(&self) -> bool { | ||||
| @@ -163,12 +170,6 @@ impl MatcherSegment { | ||||
|             Self::Env(t) => Some(t), | ||||
|         } | ||||
|     } | ||||
|     fn codegen(&self) -> String { | ||||
|         match self { | ||||
|             Self::Text(s) => format!(r###"MatcherSegment::Text(r#"{s}"#)"###), | ||||
|             Self::Env(s) => format!(r###"MatcherSegment::Env(r#"{s}"#)"###), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// A struct that models a single .toml file in /src/syntax_mapping/builtins/. | ||||
| @@ -194,22 +195,19 @@ impl MappingDefModel { | ||||
|  | ||||
| #[derive(Clone, Debug)] | ||||
| struct MappingList(Vec<(Matcher, MappingTarget)>); | ||||
| impl MappingList { | ||||
|     fn codegen(&self) -> String { | ||||
|         let array_items: Vec<_> = self | ||||
| impl ToTokens for MappingList { | ||||
|     fn to_tokens(&self, tokens: &mut TokenStream) { | ||||
|         let len = self.0.len(); | ||||
|         let array_items = self | ||||
|             .0 | ||||
|             .iter() | ||||
|             .map(|(matcher, target)| { | ||||
|                 format!("({m}, {t})", m = matcher.codegen(), t = target.codegen()) | ||||
|             }) | ||||
|             .collect(); | ||||
|         let len = array_items.len(); | ||||
|             .map(|(matcher, target)| quote! { (#matcher, #target) }); | ||||
|  | ||||
|         format!( | ||||
|             "/// Generated by build script from /src/syntax_mapping/builtins/.\n\ | ||||
|             pub(crate) static BUILTIN_MAPPINGS: [(Lazy<Option<GlobMatcher>>, MappingTarget); {len}] = [\n{items}\n];", | ||||
|             items = array_items.join(",\n") | ||||
|         ) | ||||
|         let t = quote! { | ||||
|             /// Generated by build script from /src/syntax_mapping/builtins/. | ||||
|             pub(crate) static BUILTIN_MAPPINGS: [(Lazy<Option<GlobMatcher>>, MappingTarget); #len] = [#(#array_items),*]; | ||||
|         }; | ||||
|         tokens.append_all(t); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -290,11 +288,13 @@ pub fn build_static_mappings() -> anyhow::Result<()> { | ||||
|     println!("cargo:rerun-if-changed=src/syntax_mapping/builtins/"); | ||||
|  | ||||
|     let mappings = read_all_mappings()?; | ||||
|     let rs_src = syn::parse_file(&mappings.to_token_stream().to_string())?; | ||||
|     let rs_src_pretty = prettyplease::unparse(&rs_src); | ||||
|  | ||||
|     let codegen_path = Path::new(&env::var_os("OUT_DIR").ok_or(anyhow!("OUT_DIR is unset"))?) | ||||
|         .join("codegen_static_syntax_mappings.rs"); | ||||
|  | ||||
|     fs::write(codegen_path, mappings.codegen())?; | ||||
|     fs::write(codegen_path, rs_src_pretty)?; | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user