1 use proc_macro::TokenStream;
3 use std::collections::HashSet;
4 use syn::parse::{Parse, ParseStream, Result};
5 use syn::{braced, parse_macro_input, Ident, LitStr, Token};
7 #[allow(non_camel_case_types)]
9 syn::custom_keyword!(Keywords);
10 syn::custom_keyword!(Symbols);
18 impl Parse for Keyword {
19 fn parse(input: ParseStream<'_>) -> Result<Self> {
20 let name = input.parse()?;
21 input.parse::<Token![:]>()?;
22 let value = input.parse()?;
23 input.parse::<Token![,]>()?;
25 Ok(Keyword { name, value })
31 value: Option<LitStr>,
34 impl Parse for Symbol {
35 fn parse(input: ParseStream<'_>) -> Result<Self> {
36 let name = input.parse()?;
37 let value = match input.parse::<Token![:]>() {
38 Ok(_) => Some(input.parse()?),
41 input.parse::<Token![,]>()?;
43 Ok(Symbol { name, value })
47 /// A type used to greedily parse another type until the input is empty.
48 struct List<T>(Vec<T>);
50 impl<T: Parse> Parse for List<T> {
51 fn parse(input: ParseStream<'_>) -> Result<Self> {
52 let mut list = Vec::new();
53 while !input.is_empty() {
54 list.push(input.parse()?);
61 keywords: List<Keyword>,
62 symbols: List<Symbol>,
65 impl Parse for Input {
66 fn parse(input: ParseStream<'_>) -> Result<Self> {
67 input.parse::<kw::Keywords>()?;
69 braced!(content in input);
70 let keywords = content.parse()?;
72 input.parse::<kw::Symbols>()?;
74 braced!(content in input);
75 let symbols = content.parse()?;
77 Ok(Input { keywords, symbols })
81 pub fn symbols(input: TokenStream) -> TokenStream {
82 let input = parse_macro_input!(input as Input);
84 let mut keyword_stream = quote! {};
85 let mut symbols_stream = quote! {};
86 let mut digits_stream = quote! {};
87 let mut prefill_stream = quote! {};
88 let mut counter = 0u32;
89 let mut keys = HashSet::<String>::new();
90 let mut prev_key: Option<String> = None;
91 let mut errors = Vec::<String>::new();
93 let mut check_dup = |str: &str, errors: &mut Vec<String>| {
94 if !keys.insert(str.to_string()) {
95 errors.push(format!("Symbol `{}` is duplicated", str));
99 let mut check_order = |str: &str, errors: &mut Vec<String>| {
100 if let Some(ref prev_str) = prev_key {
102 errors.push(format!("Symbol `{}` must precede `{}`", str, prev_str));
105 prev_key = Some(str.to_string());
108 // Generate the listed keywords.
109 for keyword in &input.keywords.0 {
110 let name = &keyword.name;
111 let value = &keyword.value;
112 check_dup(&value.value(), &mut errors);
113 prefill_stream.extend(quote! {
116 keyword_stream.extend(quote! {
117 #[allow(non_upper_case_globals)]
118 pub const #name: Symbol = Symbol::new(#counter);
123 // Generate the listed symbols.
124 for symbol in &input.symbols.0 {
125 let name = &symbol.name;
126 let value = match &symbol.value {
127 Some(value) => value.value(),
128 None => name.to_string(),
130 check_dup(&value, &mut errors);
131 check_order(&name.to_string(), &mut errors);
132 prefill_stream.extend(quote! {
135 symbols_stream.extend(quote! {
136 #[allow(rustc::default_hash_types)]
137 #[allow(non_upper_case_globals)]
138 pub const #name: Symbol = Symbol::new(#counter);
143 // Generate symbols for the strings "0", "1", ..., "9".
145 let n = n.to_string();
146 check_dup(&n, &mut errors);
147 prefill_stream.extend(quote! {
150 digits_stream.extend(quote! {
151 Symbol::new(#counter),
156 if !errors.is_empty() {
157 for error in errors.into_iter() {
158 eprintln!("error: {}", error)
160 panic!("errors in `Keywords` and/or `Symbols`");
163 let tt = TokenStream::from(quote! {
164 macro_rules! keywords {
170 macro_rules! define_symbols {
174 #[allow(non_upper_case_globals)]
175 pub const digits_array: &[Symbol; 10] = &[
182 pub fn fresh() -> Self {
190 // To see the generated code generated, uncomment this line, recompile, and
191 // run the resulting output through `rustfmt`.
192 //eprintln!("{}", tt);