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!(Other);
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 impl Parse for Symbol {
39 fn parse(input: ParseStream<'_>) -> Result<Self> {
40 let ident: Ident = input.parse()?;
41 input.parse::<Token![,]>()?;
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::Other>()?;
74 braced!(content in input);
75 let symbols = content.parse()?;
84 pub fn symbols(input: TokenStream) -> TokenStream {
85 let input = parse_macro_input!(input as Input);
87 let mut keyword_stream = quote! {};
88 let mut symbols_stream = quote! {};
89 let mut prefill_stream = quote! {};
90 let mut from_str_stream = quote! {};
91 let mut counter = 0u32;
92 let mut keys = HashSet::<String>::new();
94 let mut check_dup = |str: &str| {
95 if !keys.insert(str.to_string()) {
96 panic!("Symbol `{}` is duplicated", str);
100 for keyword in &input.keywords.0 {
101 let name = &keyword.name;
102 let value = &keyword.value;
103 check_dup(&value.value());
104 prefill_stream.extend(quote! {
107 keyword_stream.extend(quote! {
108 pub const #name: Keyword = Keyword {
109 ident: Ident::with_empty_ctxt(super::Symbol::new(#counter))
112 from_str_stream.extend(quote! {
118 for symbol in &input.symbols.0 {
119 let value = &symbol.0;
120 let value_str = value.to_string();
121 check_dup(&value_str);
122 prefill_stream.extend(quote! {
125 symbols_stream.extend(quote! {
126 pub const #value: Symbol = Symbol::new(#counter);
131 TokenStream::from(quote! {
132 macro_rules! keywords {
136 impl std::str::FromStr for Keyword {
139 fn from_str(s: &str) -> Result<Self, ()> {
149 macro_rules! symbols {
156 pub fn fresh() -> Self {