1 use proc_macro::TokenStream;
3 use std::collections::HashSet;
5 use syn::parse::{Parse, ParseStream, Result};
6 use syn::{braced, parse_macro_input, Ident, LitStr, Token};
8 #[allow(non_camel_case_types)]
10 syn::custom_keyword!(Keywords);
11 syn::custom_keyword!(Symbols);
19 impl Parse for Keyword {
20 fn parse(input: ParseStream<'_>) -> Result<Self> {
21 let name = input.parse()?;
22 input.parse::<Token![:]>()?;
23 let value = input.parse()?;
24 input.parse::<Token![,]>()?;
26 Ok(Keyword { name, value })
32 value: Option<LitStr>,
35 impl Parse for Symbol {
36 fn parse(input: ParseStream<'_>) -> Result<Self> {
37 let name = input.parse()?;
38 let value = match input.parse::<Token![:]>() {
39 Ok(_) => Some(input.parse()?),
42 input.parse::<Token![,]>()?;
44 Ok(Symbol { name, value })
48 /// A type used to greedily parse another type until the input is empty.
49 struct List<T>(Vec<T>);
51 impl<T: Parse> Parse for List<T> {
52 fn parse(input: ParseStream<'_>) -> Result<Self> {
53 let mut list = Vec::new();
54 while !input.is_empty() {
55 list.push(input.parse()?);
62 keywords: List<Keyword>,
63 symbols: List<Symbol>,
66 impl Parse for Input {
67 fn parse(input: ParseStream<'_>) -> Result<Self> {
68 input.parse::<kw::Keywords>()?;
70 braced!(content in input);
71 let keywords = content.parse()?;
73 input.parse::<kw::Symbols>()?;
75 braced!(content in input);
76 let symbols = content.parse()?;
78 Ok(Input { keywords, symbols })
82 pub fn symbols(input: TokenStream) -> TokenStream {
83 let input = parse_macro_input!(input as Input);
85 let mut keyword_stream = quote! {};
86 let mut symbols_stream = quote! {};
87 let mut digits_stream = quote! {};
88 let mut prefill_stream = quote! {};
89 let mut counter = 0u32;
90 let mut keys = HashSet::<String>::new();
92 let mut check_dup = |str: &str| {
93 if !keys.insert(str.to_string()) {
94 panic!("Symbol `{}` is duplicated", str);
98 // Generate the listed keywords.
99 for keyword in &input.keywords.0 {
100 let name = &keyword.name;
101 let value = &keyword.value;
102 check_dup(&value.value());
103 prefill_stream.extend(quote! {
106 keyword_stream.extend(quote! {
107 pub const #name: Symbol = Symbol::new(#counter);
112 // Generate the listed symbols.
113 for symbol in &input.symbols.0 {
114 let name = &symbol.name;
115 let value = match &symbol.value {
116 Some(value) => value.value(),
117 None => name.to_string(),
120 prefill_stream.extend(quote! {
123 symbols_stream.extend(quote! {
124 pub const #name: Symbol = Symbol::new(#counter);
129 // Generate symbols for the strings "0", "1", ..., "9".
131 let n = n.to_string();
133 prefill_stream.extend(quote! {
136 digits_stream.extend(quote! {
137 Symbol::new(#counter),
142 let tt = TokenStream::from(quote! {
143 macro_rules! keywords {
149 macro_rules! symbols {
153 pub const digits_array: &[Symbol; 10] = &[
160 pub fn fresh() -> Self {
168 // To see the generated code generated, uncomment this line, recompile, and
169 // run the resulting output through `rustfmt`.
170 //eprintln!("{}", tt);