aboutsummaryrefslogtreecommitdiff
path: root/macros/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'macros/src/lib.rs')
-rw-r--r--macros/src/lib.rs56
1 files changed, 40 insertions, 16 deletions
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index a420d56..42f7565 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -8,13 +8,13 @@ use syn::{
8 parse::{Parse, ParseStream, Result as ParseResult}, 8 parse::{Parse, ParseStream, Result as ParseResult},
9 parse_macro_input, 9 parse_macro_input,
10 punctuated::Punctuated, 10 punctuated::Punctuated,
11 Ident, ItemStruct, Lit, Path, Token, 11 Expr, Ident, ItemStruct, Lit, Token,
12}; 12};
13 13
14struct KeyValue { 14struct KeyValue {
15 key: Ident, 15 key: Ident,
16 _eq: Token![=], 16 _eq: Token![=],
17 value: Lit, 17 value: Expr,
18} 18}
19 19
20impl Parse for KeyValue { 20impl Parse for KeyValue {
@@ -27,7 +27,7 @@ impl Parse for KeyValue {
27 } 27 }
28} 28}
29 29
30struct LintMeta(HashMap<Ident, Lit>); 30struct LintMeta(HashMap<Ident, Expr>);
31 31
32impl Parse for LintMeta { 32impl Parse for LintMeta {
33 fn parse(input: ParseStream) -> ParseResult<Self> { 33 fn parse(input: ParseStream) -> ParseResult<Self> {
@@ -54,11 +54,13 @@ fn generate_meta_impl(struct_name: &Ident, meta: &LintMeta) -> TokenStream2 {
54 let name_fn = generate_name_fn(meta); 54 let name_fn = generate_name_fn(meta);
55 let note_fn = generate_note_fn(meta); 55 let note_fn = generate_note_fn(meta);
56 let match_with_fn = generate_match_with_fn(meta); 56 let match_with_fn = generate_match_with_fn(meta);
57 let match_kind = generate_match_kind(meta);
57 quote! { 58 quote! {
58 impl Metadata for #struct_name { 59 impl Metadata for #struct_name {
59 #name_fn 60 #name_fn
60 #note_fn 61 #note_fn
61 #match_with_fn 62 #match_with_fn
63 #match_kind
62 } 64 }
63 } 65 }
64} 66}
@@ -68,11 +70,16 @@ fn generate_name_fn(meta: &LintMeta) -> TokenStream2 {
68 .0 70 .0
69 .get(&format_ident!("name")) 71 .get(&format_ident!("name"))
70 .unwrap_or_else(|| panic!("`name` not present")); 72 .unwrap_or_else(|| panic!("`name` not present"));
71 quote! { 73 if let syn::Expr::Lit(name_lit) = name {
72 fn name(&self) -> &str { 74 if let Lit::Str(name_str) = &name_lit.lit {
73 #name 75 return quote! {
76 fn name(&self) -> &str {
77 #name_str
78 }
79 };
74 } 80 }
75 } 81 }
82 panic!("Invalid value for `name`");
76} 83}
77 84
78fn generate_note_fn(meta: &LintMeta) -> TokenStream2 { 85fn generate_note_fn(meta: &LintMeta) -> TokenStream2 {
@@ -80,11 +87,16 @@ fn generate_note_fn(meta: &LintMeta) -> TokenStream2 {
80 .0 87 .0
81 .get(&format_ident!("note")) 88 .get(&format_ident!("note"))
82 .unwrap_or_else(|| panic!("`note` not present")); 89 .unwrap_or_else(|| panic!("`note` not present"));
83 quote! { 90 if let syn::Expr::Lit(note_lit) = note {
84 fn note(&self) -> &str { 91 if let Lit::Str(note_str) = &note_lit.lit {
85 #note 92 return quote! {
93 fn note(&self) -> &str {
94 #note_str
95 }
96 };
86 } 97 }
87 } 98 }
99 panic!("Invalid value for `note`");
88} 100}
89 101
90fn generate_match_with_fn(meta: &LintMeta) -> TokenStream2 { 102fn generate_match_with_fn(meta: &LintMeta) -> TokenStream2 {
@@ -92,18 +104,30 @@ fn generate_match_with_fn(meta: &LintMeta) -> TokenStream2 {
92 .0 104 .0
93 .get(&format_ident!("match_with")) 105 .get(&format_ident!("match_with"))
94 .unwrap_or_else(|| panic!("`match_with` not present")); 106 .unwrap_or_else(|| panic!("`match_with` not present"));
95 if let Lit::Str(match_with) = match_with_lit { 107 if let syn::Expr::Path(match_path) = match_with_lit {
96 let path: Path = match_with
97 .parse()
98 .ok()
99 .unwrap_or_else(|| panic!("`match_with` does not contain valid path"));
100 quote! { 108 quote! {
101 fn match_with(&self, with: &SyntaxKind) -> bool { 109 fn match_with(&self, with: &SyntaxKind) -> bool {
102 *with == #path 110 #match_path == *with
111 }
112 }
113 } else {
114 panic!("`match_with` has non-path value")
115 }
116}
117
118fn generate_match_kind(meta: &LintMeta) -> TokenStream2 {
119 let match_with_lit = meta
120 .0
121 .get(&format_ident!("match_with"))
122 .unwrap_or_else(|| panic!("`match_with` not present"));
123 if let syn::Expr::Path(match_path) = match_with_lit {
124 quote! {
125 fn match_kind(&self) -> SyntaxKind {
126 #match_path
103 } 127 }
104 } 128 }
105 } else { 129 } else {
106 panic!("`match_with` has non-literal value") 130 panic!("`match_with` has non-path value")
107 } 131 }
108} 132}
109 133