1use std::collections::HashMap;
2
3use darling::{FromDeriveInput, FromField, FromMeta, FromVariant};
4use proc_macro2::{Span, TokenStream};
5use quote::{format_ident, quote, quote_spanned};
6use syn::{parse_macro_input, spanned::Spanned, DeriveInput, LitStr, Token};
7
8#[derive(FromField)]
9struct TokenVariantField {
10 ident: Option<syn::Ident>,
11}
12
13struct TokenDisplay {
14 format: String,
15 args: Vec<String>,
16}
17
18impl FromMeta for TokenDisplay {
19 fn from_string(value: &str) -> darling::Result<Self> {
20 Ok(Self {
21 format: value.to_owned(),
22 args: vec![],
23 })
24 }
25
26 fn from_list(items: &[darling::ast::NestedMeta]) -> darling::Result<Self> {
27 Ok(Self {
28 format: String::from_nested_meta(
29 items
30 .first()
31 .ok_or_else(|| darling::Error::custom("missing format string"))?,
32 )?,
33 args: items
34 .iter()
35 .skip(1)
36 .map(String::from_nested_meta)
37 .collect::<Result<Vec<_>, _>>()?,
38 })
39 }
40}
41
42struct TokenAttr {
43 token: String,
44}
45
46impl FromMeta for TokenAttr {
47 fn from_list(items: &[darling::ast::NestedMeta]) -> darling::Result<Self> {
48 Ok(Self {
49 token: String::from_nested_meta(
50 items
51 .first()
52 .ok_or_else(|| darling::Error::custom("missing token literal"))?,
53 )?,
54 })
55 }
56}
57
58enum AsParser {
59 Path(syn::Path),
60 RawString(String),
61}
62
63impl FromMeta for AsParser {
64 fn from_string(value: &str) -> darling::Result<Self> {
65 Ok(Self::RawString(value.to_owned()))
66 }
67
68 fn from_nested_meta(item: &darling::ast::NestedMeta) -> darling::Result<Self> {
69 match item {
70 darling::ast::NestedMeta::Meta(syn::Meta::Path(p)) => Ok(Self::Path(p.to_owned())),
71 _ => Err(darling::Error::unsupported_format("meta")),
72 }
73 }
74
75 fn from_list(items: &[darling::ast::NestedMeta]) -> darling::Result<Self> {
76 if let Some(item) = items.first() {
77 return Self::from_nested_meta(item);
78 }
79
80 Err(darling::Error::unsupported_format("list"))
81 }
82}
83
84#[derive(FromVariant)]
85#[darling(attributes(lang_util), forward_attrs(token))]
86struct TokenVariant {
87 ident: syn::Ident,
88 fields: darling::ast::Fields<TokenVariantField>,
89 attrs: Vec<syn::Attribute>,
90 #[darling(default)]
91 display: Option<TokenDisplay>,
92 #[darling(default, rename = "parser")]
93 as_parser: Option<AsParser>,
94 #[darling(default, rename = "token")]
95 fallback_token: Option<String>,
96 #[darling(multiple, rename = "kind")]
97 kinds: Vec<String>,
98}
99
100struct Token<'s> {
101 base_ident: &'s syn::Ident,
102 variant: &'s TokenVariant,
103 token: TokenAttrTy<'s>,
104 as_parser: Result<String, AsParserError>,
105}
106
107impl<'s> Token<'s> {
108 fn empty_variant_header(&self) -> TokenStream {
109 let variant_name = &self.variant.ident;
110 let variant_header = match &self.variant.fields.style {
111 darling::ast::Style::Tuple => {
112 let fields = self
113 .variant
114 .fields
115 .fields
116 .iter()
117 .map(|_| Token));
118
119 quote! { #variant_name ( #(#fields),* ) }
120 }
121 darling::ast::Style::Struct => {
122 quote! { .. }
123 }
124 darling::ast::Style::Unit => quote! { #variant_name },
125 };
126
127 let base_ident = self.base_ident;
128 quote_spanned! { self.variant.ident.span() => #base_ident :: #variant_header }
129 }
130
131 fn variant_name_arm(&self) -> TokenStream {
132 let variant_header = self.empty_variant_header();
133
134 let body = {
135 let value = &self.variant.ident.to_string();
136 quote_spanned! { self.variant.ident.span() => #value }
137 };
138
139 quote_spanned! {
140 self.variant.ident.span() =>
141 #variant_header => #body
142 }
143 }
144
145 fn parser_token_body(&self) -> TokenStream {
146 match &self.as_parser {
147 Ok(value) => quote_spanned! { self.variant.ident.span() => #value },
148 Err(error) => {
149 let error = error.to_string();
150 quote_spanned! {
151 self.variant.ident.span() =>
152 compile_error!(#error)
153 }
154 }
155 }
156 }
157
158 fn parser_token_arm(&self) -> TokenStream {
159 let variant_header = self.empty_variant_header();
160 let body = self.parser_token_body();
161
162 quote_spanned! {
163 self.variant.ident.span() =>
164 #variant_header => #body
165 }
166 }
167
168 fn kinds_body(&self) -> TokenStream {
169 if self.variant.kinds.is_empty() {
170 if let Some((token, attr)) = &self.token {
171 match token {
172 Ok(value) => {
173 let value = &value.token;
174 quote_spanned! { self.variant.ident.span() => &[#value] }
175 }
176 Err(error) => {
177 let s = format!("invalid token attribute: {}", error);
178 quote_spanned! {
179 attr.span() =>
180 compile_error!(#s)
181 }
182 }
183 }
184 } else {
185 quote_spanned! {
186 self.variant.ident.span() =>
187 compile_error!("cannot determine token kind for this token")
188 }
189 }
190 } else {
191 let kinds = &self.variant.kinds;
192
193 if let Some((Ok(token), _)) = &self.token {
194 let value = &token.token;
195 quote_spanned! { self.variant.ident.span() => &[#(#kinds),*, #value] }
196 } else {
197 quote_spanned! { self.variant.ident.span() => &[#(#kinds),*] }
198 }
199 }
200 }
201
202 fn kinds_arm(&self) -> TokenStream {
203 let variant_header = self.empty_variant_header();
204 let body = self.kinds_body();
205
206 quote_spanned! {
207 self.variant.ident.span() =>
208 #variant_header => #body
209 }
210 }
211
212 fn get_prefixed_fmt(&self, base_fmt: &str) -> String {
213 if self.variant.kinds.is_empty() {
214 format!("`{}`", base_fmt)
215 } else {
216 format!("{} `{}`", self.variant.kinds.last().unwrap(), base_fmt)
217 }
218 }
219
220 fn display_arm_body(&self, declared_fields: &[syn::Ident]) -> TokenStream {
221 match self.variant.fields.style {
222 darling::ast::Style::Tuple => {
223 if let Some(display) = &self.variant.display {
224 let fmt = &display.format;
225
226 let args = if display.args.is_empty() {
228 if declared_fields.len() == 1 && display.format.contains("{}") {
229 let f = &declared_fields[0];
230 vec![quote_spanned! { self.variant.ident.span() => #f }]
231 } else {
232 declared_fields
233 .iter()
234 .enumerate()
235 .filter_map(|(i, df)| {
236 let ph = format!("_{}", i);
237
238 if fmt.contains(&ph) {
239 let ph = format_ident!("{}", ph);
240 Some(quote_spanned! { self.variant.ident.span() => #ph = #df })
241 } else {
242 None
243 }
244 })
245 .collect()
246 }
247 } else {
248 let mut repl = Vec::new();
249 for (i, df) in declared_fields.iter().enumerate() {
250 repl.push((format!("_{}", i), df.to_string()));
251 }
252
253 display
254 .args
255 .iter()
256 .map(|arg| {
257 let mut arg = arg.clone();
258 for (src, dst) in &repl {
259 arg = arg.replace(src, dst);
260 }
261
262 syn::parse_str(&arg).expect("parsing error")
263 })
264 .collect()
265 };
266
267 let fmt = self.get_prefixed_fmt(fmt);
268 return quote_spanned! {
269 self.variant.ident.span() =>
270 write!(f, #fmt, #(#args),*)
271 };
272 } else {
273 if declared_fields.len() == 1 {
275 let v1 = &declared_fields[0];
276 let fmt = self.get_prefixed_fmt("{}");
277 return quote_spanned! {
278 self.variant.ident.span() =>
279 write!(f, #fmt, #v1)
280 };
281 }
282 }
283 }
284 darling::ast::Style::Struct => {
285 return quote_spanned! {
286 self.variant.ident.span() =>
287 compile_error!("struct variants are not supported yet by derive(Token)")
288 };
289 }
290 darling::ast::Style::Unit => {
291 if let Some((token, attr)) = &self.token {
293 return match token {
294 Ok(value) => {
295 let value = &value.token;
296 let fmt = self.get_prefixed_fmt("{}");
297 quote_spanned! { self.variant.ident.span() => write!(f, #fmt, #value) }
298 }
299 Err(error) => {
300 let s = format!("invalid token attribute: {}", error);
301 quote_spanned! {
302 attr.span() =>
303 compile_error!(#s)
304 }
305 }
306 };
307 } else if let Some(display) = &self.variant.display {
308 let value = &display.format;
309 let fmt = self.get_prefixed_fmt("{}");
310 return quote_spanned! { self.variant.ident.span() => write!(f, #fmt, #value) };
311 }
312 }
313 }
314
315 quote_spanned! {
316 self.variant.ident.span() =>
317 compile_error!("missing token or lang_util(display(...)) attributes")
318 }
319 }
320
321 fn display_arm(&self) -> TokenStream {
322 let variant_name = &self.variant.ident;
324 let (variant_header, declared_fields) = match &self.variant.fields.style {
325 darling::ast::Style::Tuple => {
326 let fields: Vec<_> = self
327 .variant
328 .fields
329 .fields
330 .iter()
331 .enumerate()
332 .map(|(i, _field)| format_ident!("value_{}", i))
333 .collect();
334
335 (
336 quote_spanned! { self.variant.ident.span() => #variant_name ( #(#fields),* ) },
337 fields,
338 )
339 }
340 darling::ast::Style::Struct => {
341 let fields: Vec<_> = self
342 .variant
343 .fields
344 .fields
345 .iter()
346 .map(|field| field.ident.as_ref().unwrap().clone())
347 .collect();
348
349 (
350 quote_spanned! { self.variant.ident.span() => #variant_name { #(#fields),* } },
351 fields,
352 )
353 }
354 darling::ast::Style::Unit => (quote! { #variant_name }, vec![]),
355 };
356
357 let body = self.display_arm_body(&declared_fields);
359
360 let base_ident = self.base_ident;
361 quote_spanned! {
362 self.variant.ident.span() =>
363 #base_ident :: #variant_header => { #body }
364 }
365 }
366
367 fn all_tokens_arm(&self) -> TokenStream {
368 let variant_name = self.variant.ident.to_string();
369 let parser_token = self.parser_token_body();
370 let kinds = self.kinds_body();
371
372 quote_spanned! {
373 self.variant.ident.span() =>
374 ::lang_util::token::TokenDescriptor::new(#variant_name, #parser_token, #kinds)
375 }
376 }
377}
378
379type TokenAttrTy<'s> = Option<(darling::Result<TokenAttr>, proc_macro2::Span)>;
380
381fn parse_token_attr(variant: &TokenVariant) -> TokenAttrTy {
382 for attr in variant.attrs.iter() {
384 if attr.path().is_ident("token") {
385 return Some((
386 if let Ok(result) = attr.parse_args::<LitStr>() {
387 Ok(TokenAttr {
388 token: result.value(),
389 })
390 } else {
391 attr.parse_args()
392 .map_err(darling::Error::custom)
393 .and_then(|meta| TokenAttr::from_meta(&meta))
394 },
395 attr.span(),
396 ));
397 }
398 }
399
400 if let Some(fallback) = &variant.fallback_token {
402 return Some((
403 Ok(TokenAttr {
404 token: fallback.clone(),
405 }),
406 proc_macro2::Span::call_site(),
407 ));
408 }
409
410 None
411}
412
413#[derive(Debug)]
414enum AsParserError {
415 MissingDisplayImpl,
416 InvalidAs,
417 InvalidTokenAttribute(String),
418 NoTokenOrAs,
419}
420
421impl std::fmt::Display for AsParserError {
422 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
423 match self {
424 Self::MissingDisplayImpl => write!(f, "in lang_util attribute, `parser = display` specified but not display implementation provided"),
425 Self::InvalidAs => write!(f, "invalid `parser` value, expected display or a literal string"),
426 Self::InvalidTokenAttribute(error) => write!(f, "invalid token attribute: {}", error),
427 Self::NoTokenOrAs => write!(f, "missing token or lang_util(parser = \"...\") attributes"),
428 }
429 }
430}
431
432fn parse_as_parser(variant: &TokenVariant, token: &TokenAttrTy) -> Result<String, AsParserError> {
433 if let Some(as_parser) = &variant.as_parser {
434 match as_parser {
435 AsParser::Path(path) => {
436 if path.get_ident().map(|id| id == "display").unwrap_or(false) {
437 if let Some(display) = &variant.display {
438 Ok(format!("\"{}\"", &display.format))
439 } else {
440 Err(AsParserError::MissingDisplayImpl)
441 }
442 } else {
443 Err(AsParserError::InvalidAs)
444 }
445 }
446 AsParser::RawString(s) => Ok(s.to_owned()),
447 }
448 } else if let Some((token, _)) = &token {
449 match token {
450 Ok(value) => {
451 Ok(format!("\"{}\"", &value.token))
453 }
454 Err(error) => Err(AsParserError::InvalidTokenAttribute(error.to_string())),
455 }
456 } else {
457 Err(AsParserError::NoTokenOrAs)
458 }
459}
460
461impl<'s> From<(&'s syn::Ident, &'s TokenVariant)> for Token<'s> {
462 fn from((base_ident, variant): (&'s syn::Ident, &'s TokenVariant)) -> Self {
463 let token = parse_token_attr(variant);
464 let as_parser = parse_as_parser(variant, &token);
465
466 Self {
467 base_ident,
468 variant,
469 token,
470 as_parser,
471 }
472 }
473}
474
475#[derive(FromDeriveInput)]
476#[darling(attributes(lang_util))]
477struct TokenOpts {
478 ident: syn::Ident,
479 generics: syn::Generics,
480 data: darling::ast::Data<TokenVariant, ()>,
481}
482
483fn display_impl(
484 base_ident: &syn::Ident,
485 enum_name: &TokenStream,
486 variants: &[Token],
487) -> TokenStream {
488 let arms = variants.iter().map(Token::display_arm);
489
490 quote_spanned! {
491 base_ident.span() =>
492 impl ::std::fmt::Display for #enum_name {
493 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
494 match self {
495 #(#arms),*
496 }
497 }
498 }
499 }
500}
501
502fn token_impl(base_ident: &syn::Ident, enum_name: &TokenStream, variants: &[Token]) -> TokenStream {
503 let variant_name_arms = variants.iter().map(Token::variant_name_arm);
504 let parser_token_arms = variants.iter().map(Token::parser_token_arm);
505 let kinds_arms = variants.iter().map(Token::kinds_arm);
506 let all_tokens_arms = variants.iter().map(Token::all_tokens_arm);
507
508 let id = format_ident!("__{}_TOKENS", base_ident.to_string().to_uppercase());
509 let cnt = variants.len();
510
511 quote_spanned! {
512 base_ident.span() =>
513 static #id: [::lang_util::token::TokenDescriptor; #cnt] = [
514 #(#all_tokens_arms),*
515 ];
516
517 impl ::lang_util::token::Token for #enum_name {
518 fn variant_name(&self) -> &'static str {
519 match self {
520 #(#variant_name_arms),*
521 }
522 }
523
524 fn parser_token(&self) -> &'static str {
525 match self {
526 #(#parser_token_arms),*
527 }
528 }
529
530 fn kinds(&self) -> &'static [&'static str] {
531 match self {
532 #(#kinds_arms),*
533 }
534 }
535
536 fn all_tokens() -> &'static [::lang_util::token::TokenDescriptor] {
537 &#id
538 }
539 }
540 }
541}
542
543pub(crate) fn token(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
544 let opts = {
545 let input = parse_macro_input!(input as DeriveInput);
547 match TokenOpts::from_derive_input(&input) {
549 Ok(res) => res,
550 Err(err) => return err.write_errors().into(),
551 }
552 };
553
554 let base_ident = &opts.ident;
555
556 let fields = match &opts.data {
558 darling::ast::Data::Enum(fields) => fields,
559 darling::ast::Data::Struct(_) => {
560 return proc_macro::TokenStream::from(quote_spanned! {
561 opts.ident.span() =>
562 compile_error!("only enums can be used as tokens with derive(Token)")
563 })
564 }
565 };
566
567 let fields: Vec<Token> = fields
569 .iter()
570 .map(|variant| (base_ident, variant).into())
571 .collect();
572
573 let mut decls = Vec::new();
575
576 let mut seen: HashMap<_, &Token> = HashMap::new();
578 for decl in &fields {
579 if let Ok(as_parser) = &decl.as_parser {
580 if let Some(previous) = seen.get(as_parser) {
581 let s = format!(
582 "`{}` parser token already declared by variant {}",
583 as_parser, previous.variant.ident
584 );
585 decls.push(quote_spanned! { decl.variant.ident.span() => compile_error!(#s); });
586 } else {
587 seen.insert(as_parser, decl);
588 }
589 }
590 }
591
592 let enum_name = {
594 let lifetimes: Vec<_> = opts.generics.lifetimes().map(|_| quote! { '_ }).collect();
596
597 if lifetimes.is_empty() {
598 quote! { #base_ident }
599 } else {
600 quote! { #base_ident<#(#lifetimes),*> }
601 }
602 };
603
604 decls.push(display_impl(base_ident, &enum_name, &fields));
605 decls.push(token_impl(base_ident, &enum_name, &fields));
606
607 proc_macro::TokenStream::from(quote_spanned! {
608 opts.ident.span() =>
609 #(#decls)*
610 })
611}