Skip to content

Commit de3f2d1

Browse files
committed
Enforce the static symbol order.
By making the proc macro abort if any symbols are out of order. The commit also changes the proc macro collect multiple errors (of order or duplicated symbols) and prints them at the end, which is useful if you have multiple errors.
1 parent 8aa18cb commit de3f2d1

File tree

2 files changed

+161
-133
lines changed

2 files changed

+161
-133
lines changed

src/librustc_macros/src/symbols.rs

+24-5
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,29 @@ pub fn symbols(input: TokenStream) -> TokenStream {
8787
let mut prefill_stream = quote! {};
8888
let mut counter = 0u32;
8989
let mut keys = HashSet::<String>::new();
90+
let mut prev_key: Option<String> = None;
91+
let mut errors = Vec::<String>::new();
9092

91-
let mut check_dup = |str: &str| {
93+
let mut check_dup = |str: &str, errors: &mut Vec<String>| {
9294
if !keys.insert(str.to_string()) {
93-
panic!("Symbol `{}` is duplicated", str);
95+
errors.push(format!("Symbol `{}` is duplicated", str));
9496
}
9597
};
9698

99+
let mut check_order = |str: &str, errors: &mut Vec<String>| {
100+
if let Some(ref prev_str) = prev_key {
101+
if str < prev_str {
102+
errors.push(format!("Symbol `{}` must precede `{}`", str, prev_str));
103+
}
104+
}
105+
prev_key = Some(str.to_string());
106+
};
107+
97108
// Generate the listed keywords.
98109
for keyword in &input.keywords.0 {
99110
let name = &keyword.name;
100111
let value = &keyword.value;
101-
check_dup(&value.value());
112+
check_dup(&value.value(), &mut errors);
102113
prefill_stream.extend(quote! {
103114
#value,
104115
});
@@ -116,7 +127,8 @@ pub fn symbols(input: TokenStream) -> TokenStream {
116127
Some(value) => value.value(),
117128
None => name.to_string(),
118129
};
119-
check_dup(&value);
130+
check_dup(&value, &mut errors);
131+
check_order(&name.to_string(), &mut errors);
120132
prefill_stream.extend(quote! {
121133
#value,
122134
});
@@ -131,7 +143,7 @@ pub fn symbols(input: TokenStream) -> TokenStream {
131143
// Generate symbols for the strings "0", "1", ..., "9".
132144
for n in 0..10 {
133145
let n = n.to_string();
134-
check_dup(&n);
146+
check_dup(&n, &mut errors);
135147
prefill_stream.extend(quote! {
136148
#n,
137149
});
@@ -141,6 +153,13 @@ pub fn symbols(input: TokenStream) -> TokenStream {
141153
counter += 1;
142154
}
143155

156+
if !errors.is_empty() {
157+
for error in errors.into_iter() {
158+
eprintln!("error: {}", error)
159+
}
160+
panic!("errors in `Keywords` and/or `Symbols`");
161+
}
162+
144163
let tt = TokenStream::from(quote! {
145164
macro_rules! keywords {
146165
() => {

0 commit comments

Comments
 (0)