• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use proc_macro2::{Span, TokenStream};
2 use quote::ToTokens;
3 use syn::parse::{Parse, ParseStream};
4 use syn::{Attribute, Error, Expr, Fields, Result, Stmt, Token, Visibility};
5 
6 use crate::emit::Kind;
7 
8 pub struct Nothing;
9 
10 impl Parse for Nothing {
parse(_input: ParseStream) -> Result<Self>11     fn parse(_input: ParseStream) -> Result<Self> {
12         Ok(Nothing)
13     }
14 }
15 
16 pub enum Input {
17     Enum(syn::ItemEnum),
18     Match(syn::ExprMatch),
19     Struct(syn::ItemStruct),
20     Let(syn::ExprMatch),
21 }
22 
23 impl Input {
kind(&self) -> Kind24     pub fn kind(&self) -> Kind {
25         match self {
26             Input::Enum(_) => Kind::Enum,
27             Input::Match(_) => Kind::Match,
28             Input::Struct(_) => Kind::Struct,
29             Input::Let(_) => Kind::Let,
30         }
31     }
32 }
33 
34 impl Parse for Input {
parse(input: ParseStream) -> Result<Self>35     fn parse(input: ParseStream) -> Result<Self> {
36         let ahead = input.fork();
37         let _ = ahead.call(Attribute::parse_outer)?;
38 
39         if ahead.peek(Token![match]) {
40             let expr = match input.parse()? {
41                 Expr::Match(expr) => expr,
42                 _ => unreachable!("expected match"),
43             };
44             return Ok(Input::Match(expr));
45         }
46 
47         if ahead.peek(Token![let]) {
48             let stmt = match input.parse()? {
49                 Stmt::Local(stmt) => stmt,
50                 _ => unreachable!("expected let"),
51             };
52             let init = match stmt.init {
53                 Some((_, init)) => *init,
54                 None => return Err(unexpected()),
55             };
56             let expr = match init {
57                 Expr::Match(expr) => expr,
58                 _ => return Err(unexpected()),
59             };
60             return Ok(Input::Let(expr));
61         }
62 
63         let _: Visibility = ahead.parse()?;
64         if ahead.peek(Token![enum]) {
65             return input.parse().map(Input::Enum);
66         } else if ahead.peek(Token![struct]) {
67             let input: syn::ItemStruct = input.parse()?;
68             if let Fields::Named(_) = &input.fields {
69                 return Ok(Input::Struct(input));
70             }
71         }
72 
73         Err(unexpected())
74     }
75 }
76 
77 impl ToTokens for Input {
to_tokens(&self, tokens: &mut TokenStream)78     fn to_tokens(&self, tokens: &mut TokenStream) {
79         match self {
80             Input::Enum(item) => item.to_tokens(tokens),
81             Input::Struct(item) => item.to_tokens(tokens),
82             Input::Match(expr) | Input::Let(expr) => expr.to_tokens(tokens),
83         }
84     }
85 }
86 
unexpected() -> Error87 fn unexpected() -> Error {
88     let span = Span::call_site();
89     let msg = "expected enum, struct, or match expression";
90     Error::new(span, msg)
91 }
92