Skip to content

Commit 0672cf9

Browse files
authored
Make it possible to deprecate symbols and modules (#19)
1 parent e43cb08 commit 0672cf9

File tree

2 files changed

+64
-22
lines changed

2 files changed

+64
-22
lines changed

build.rs

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@ use std::path::Path;
55
type StrResult<T> = Result<T, String>;
66

77
/// A module of definitions.
8-
struct Module<'a>(Vec<(&'a str, Def<'a>)>);
8+
struct Module<'a>(Vec<(&'a str, Binding<'a>)>);
99

1010
impl<'a> Module<'a> {
11-
fn new(mut list: Vec<(&'a str, Def<'a>)>) -> Self {
11+
fn new(mut list: Vec<(&'a str, Binding<'a>)>) -> Self {
1212
list.sort_by_key(|&(name, _)| name);
1313
Self(list)
1414
}
1515
}
1616

17+
/// A definition bound in a module, with metadata.
18+
struct Binding<'a> {
19+
def: Def<'a>,
20+
deprecation: Option<&'a str>,
21+
}
22+
1723
/// A definition in a module.
1824
enum Def<'a> {
1925
Symbol(Symbol<'a>),
@@ -30,6 +36,7 @@ enum Symbol<'a> {
3036
#[derive(Debug, Copy, Clone)]
3137
enum Line<'a> {
3238
Blank,
39+
Deprecated(&'a str),
3340
ModuleStart(&'a str),
3441
ModuleEnd,
3542
Symbol(&'a str, Option<char>),
@@ -91,7 +98,9 @@ fn tokenize(line: &str) -> StrResult<Line> {
9198
None => (line, None),
9299
};
93100

94-
Ok(if tail == Some("{") {
101+
Ok(if head == "@deprecated:" {
102+
Line::Deprecated(tail.ok_or("missing deprecation message")?.trim())
103+
} else if tail == Some("{") {
95104
validate_ident(head)?;
96105
Line::ModuleStart(head)
97106
} else if head == "}" && tail.is_none() {
@@ -137,11 +146,18 @@ fn decode_char(text: &str) -> StrResult<char> {
137146
/// Turns a stream of lines into a list of definitions.
138147
fn parse<'a>(
139148
p: &mut Peekable<impl Iterator<Item = StrResult<Line<'a>>>>,
140-
) -> StrResult<Vec<(&'a str, Def<'a>)>> {
149+
) -> StrResult<Vec<(&'a str, Binding<'a>)>> {
141150
let mut defs = vec![];
151+
let mut deprecation = None;
142152
loop {
143153
match p.next().transpose()? {
144-
None | Some(Line::ModuleEnd) => break,
154+
None | Some(Line::ModuleEnd) => {
155+
if let Some(message) = deprecation {
156+
return Err(format!("dangling `@deprecated: {}`", message));
157+
}
158+
break;
159+
}
160+
Some(Line::Deprecated(message)) => deprecation = Some(message),
145161
Some(Line::Symbol(name, c)) => {
146162
let mut variants = vec![];
147163
while let Some(Line::Variant(name, c)) = p.peek().cloned().transpose()? {
@@ -159,11 +175,19 @@ fn parse<'a>(
159175
Symbol::Single(c)
160176
};
161177

162-
defs.push((name, Def::Symbol(symbol)));
178+
defs.push((name, Binding { def: Def::Symbol(symbol), deprecation }));
179+
deprecation = None;
163180
}
164181
Some(Line::ModuleStart(name)) => {
165182
let module_defs = parse(p)?;
166-
defs.push((name, Def::Module(Module::new(module_defs))));
183+
defs.push((
184+
name,
185+
Binding {
186+
def: Def::Module(Module::new(module_defs)),
187+
deprecation,
188+
},
189+
));
190+
deprecation = None;
167191
}
168192
other => return Err(format!("expected definition, found {other:?}")),
169193
}
@@ -174,9 +198,9 @@ fn parse<'a>(
174198
/// Encodes a `Module` into Rust code.
175199
fn encode(buf: &mut String, module: &Module) {
176200
buf.push_str("Module(&[");
177-
for (name, def) in &module.0 {
178-
write!(buf, "({name:?},").unwrap();
179-
match def {
201+
for (name, entry) in &module.0 {
202+
write!(buf, "({name:?}, Binding {{ def: ").unwrap();
203+
match &entry.def {
180204
Def::Module(module) => {
181205
buf.push_str("Def::Module(");
182206
encode(buf, module);
@@ -191,7 +215,7 @@ fn encode(buf: &mut String, module: &Module) {
191215
buf.push_str(")");
192216
}
193217
}
194-
buf.push_str("),");
218+
write!(buf, ", deprecation: {:?} }}),", entry.deprecation).unwrap();
195219
}
196220
buf.push_str("])");
197221
}

src/lib.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,42 @@ Human-friendly notation for Unicode symbols.
33
*/
44

55
/// A module of definitions.
6-
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
7-
pub struct Module(&'static [(&'static str, Def)]);
6+
#[derive(Debug, Copy, Clone)]
7+
pub struct Module(&'static [(&'static str, Binding)]);
88

99
impl Module {
10-
/// Try to get a definition from the module.
11-
pub fn get(&self, name: &str) -> Option<Def> {
10+
/// Try to get a bound definition in the module.
11+
pub fn get(&self, name: &str) -> Option<Binding> {
1212
self.0
1313
.binary_search_by_key(&name, |(k, _)| k)
1414
.ok()
1515
.map(|i| self.0[i].1)
1616
}
1717

1818
/// Iterate over the module's definition.
19-
pub fn iter(&self) -> impl Iterator<Item = (&'static str, Def)> {
19+
pub fn iter(&self) -> impl Iterator<Item = (&'static str, Binding)> {
2020
self.0.iter().copied()
2121
}
2222
}
2323

24+
/// A definition bound in a module, with metadata.
25+
#[derive(Debug, Copy, Clone)]
26+
pub struct Binding {
27+
/// The bound definition.
28+
pub def: Def,
29+
/// A deprecation message for the definition, if it is deprecated.
30+
pub deprecation: Option<&'static str>,
31+
}
32+
33+
impl Binding {
34+
/// Create a new bound definition.
35+
pub const fn new(definition: Def) -> Self {
36+
Self { def: definition, deprecation: None }
37+
}
38+
}
39+
2440
/// A definition in a module.
25-
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
41+
#[derive(Debug, Copy, Clone)]
2642
pub enum Def {
2743
/// A symbol, potentially with modifiers.
2844
Symbol(Symbol),
@@ -31,7 +47,7 @@ pub enum Def {
3147
}
3248

3349
/// A symbol, either a leaf or with modifiers.
34-
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
50+
#[derive(Debug, Copy, Clone)]
3551
pub enum Symbol {
3652
/// A symbol without modifiers.
3753
Single(char),
@@ -40,8 +56,10 @@ pub enum Symbol {
4056
}
4157

4258
/// A module that contains the other top-level modules.
43-
pub const ROOT: Module =
44-
Module(&[("emoji", Def::Module(EMOJI)), ("sym", Def::Module(SYM))]);
59+
pub const ROOT: Module = Module(&[
60+
("emoji", Binding::new(Def::Module(EMOJI))),
61+
("sym", Binding::new(Def::Module(SYM))),
62+
]);
4563

4664
include!(concat!(env!("OUT_DIR"), "/out.rs"));
4765

@@ -54,8 +72,8 @@ mod test {
5472
fn assert_sorted_recursively(root: Module) {
5573
assert!(root.0.is_sorted_by_key(|(k, _)| k));
5674

57-
for (_, def) in root.iter() {
58-
if let Def::Module(module) = def {
75+
for (_, entry) in root.iter() {
76+
if let Def::Module(module) = entry.def {
5977
assert_sorted_recursively(module)
6078
}
6179
}

0 commit comments

Comments
 (0)