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