1 use proc_macro::TokenStream;
4 braced, parse_macro_input,
6 use syn::parse::{Result, Parse, ParseStream};
8 use std::collections::HashSet;
11 #[allow(non_camel_case_types)]
13 syn::custom_keyword!(Keywords);
14 syn::custom_keyword!(Symbols);
22 impl Parse for Keyword {
23 fn parse(input: ParseStream<'_>) -> Result<Self> {
24 let name = input.parse()?;
25 input.parse::<Token![:]>()?;
26 let value = input.parse()?;
27 input.parse::<Token![,]>()?;
38 value: Option<LitStr>,
41 impl Parse for Symbol {
42 fn parse(input: ParseStream<'_>) -> Result<Self> {
43 let name = input.parse()?;
44 let value = match input.parse::<Token![:]>() {
45 Ok(_) => Some(input.parse()?),
48 input.parse::<Token![,]>()?;
57 /// A type used to greedily parse another type until the input is empty.
58 struct List<T>(Vec<T>);
60 impl<T: Parse> Parse for List<T> {
61 fn parse(input: ParseStream<'_>) -> Result<Self> {
62 let mut list = Vec::new();
63 while !input.is_empty() {
64 list.push(input.parse()?);
71 keywords: List<Keyword>,
72 symbols: List<Symbol>,
75 impl Parse for Input {
76 fn parse(input: ParseStream<'_>) -> Result<Self> {
77 input.parse::<kw::Keywords>()?;
79 braced!(content in input);
80 let keywords = content.parse()?;
82 input.parse::<kw::Symbols>()?;
84 braced!(content in input);
85 let symbols = content.parse()?;
94 pub fn symbols(input: TokenStream) -> TokenStream {
95 let input = parse_macro_input!(input as Input);
97 let mut keyword_stream = quote! {};
98 let mut symbols_stream = quote! {};
99 let mut digits_stream = quote! {};
100 let mut prefill_stream = quote! {};
101 let mut counter = 0u32;
102 let mut keys = HashSet::<String>::new();
104 let mut check_dup = |str: &str| {
105 if !keys.insert(str.to_string()) {
106 panic!("Symbol `{}` is duplicated", str);
110 // Generate the listed keywords.
111 for keyword in &input.keywords.0 {
112 let name = &keyword.name;
113 let value = &keyword.value;
114 check_dup(&value.value());
115 prefill_stream.extend(quote! {
118 keyword_stream.extend(quote! {
119 pub const #name: Symbol = Symbol::new(#counter);
124 // Generate the listed symbols.
125 for symbol in &input.symbols.0 {
126 let name = &symbol.name;
127 let value = match &symbol.value {
128 Some(value) => value.value(),
129 None => name.to_string(),
132 prefill_stream.extend(quote! {
135 symbols_stream.extend(quote! {
136 pub const #name: Symbol = Symbol::new(#counter);
141 // Generate symbols for the strings "0", "1", ..., "9".
143 let n = n.to_string();
145 prefill_stream.extend(quote! {
148 digits_stream.extend(quote! {
149 Symbol::new(#counter),
154 let tt = TokenStream::from(quote! {
155 macro_rules! keywords {
161 macro_rules! symbols {
165 pub const digits_array: &[Symbol; 10] = &[
172 pub fn fresh() -> Self {
180 // To see the generated code generated, uncomment this line, recompile, and
181 // run the resulting output through `rustfmt`.
182 //eprintln!("{}", tt);