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