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);