Skip to content

Commit a5428cb

Browse files
authored
Allow deprecating variants (#86)
1 parent 2a5d8df commit a5428cb

File tree

3 files changed

+78
-29
lines changed

3 files changed

+78
-29
lines changed

build.rs

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::fmt::Write;
2+
use std::iter;
23
use std::iter::Peekable;
34
use std::path::Path;
45

@@ -31,10 +32,10 @@ enum Def<'a> {
3132
Module(Module<'a>),
3233
}
3334

34-
/// A symbol, either a leaf or with modifiers.
35+
/// A symbol, either a leaf or with modifiers with optional deprecation.
3536
enum Symbol<'a> {
3637
Single(char),
37-
Multi(Vec<(ModifierSet<&'a str>, char)>),
38+
Multi(Vec<(ModifierSet<&'a str>, char, Option<&'a str>)>),
3839
}
3940

4041
/// A single line during parsing.
@@ -46,6 +47,15 @@ enum Line<'a> {
4647
ModuleEnd,
4748
Symbol(&'a str, Option<char>),
4849
Variant(ModifierSet<&'a str>, char),
50+
Eof,
51+
}
52+
53+
#[derive(Debug, Copy, Clone)]
54+
enum Declaration<'a> {
55+
ModuleStart(&'a str, Option<&'a str>),
56+
ModuleEnd,
57+
Symbol(&'a str, Option<char>, Option<&'a str>),
58+
Variant(ModifierSet<&'a str>, char, Option<&'a str>),
4959
}
5060

5161
fn main() {
@@ -66,11 +76,43 @@ fn process(buf: &mut String, file: &Path, name: &str, desc: &str) {
6676

6777
let text = std::fs::read_to_string(file).unwrap();
6878
let mut line_nr = 0;
79+
let mut deprecation = None;
6980
let mut iter = text
7081
.lines()
7182
.inspect(|_| line_nr += 1)
7283
.map(tokenize)
73-
.filter(|line| !matches!(line, Ok(Line::Blank)))
84+
.chain(iter::once(Ok(Line::Eof)))
85+
.filter_map(|line| match line {
86+
Err(message) => Some(Err(message)),
87+
Ok(Line::Blank) => None,
88+
Ok(Line::Deprecated(message)) => {
89+
if deprecation.is_some() {
90+
Some(Err(String::from("duplicate `@deprecated:`")))
91+
} else {
92+
deprecation = Some(message);
93+
None
94+
}
95+
}
96+
Ok(Line::ModuleStart(name)) => {
97+
Some(Ok(Declaration::ModuleStart(name, deprecation.take())))
98+
}
99+
Ok(Line::ModuleEnd) => {
100+
if deprecation.is_some() {
101+
Some(Err(String::from("dangling `@deprecated:`")))
102+
} else {
103+
Some(Ok(Declaration::ModuleEnd))
104+
}
105+
}
106+
Ok(Line::Symbol(name, c)) => {
107+
Some(Ok(Declaration::Symbol(name, c, deprecation.take())))
108+
}
109+
Ok(Line::Variant(modifiers, c)) => {
110+
Some(Ok(Declaration::Variant(modifiers, c, deprecation.take())))
111+
}
112+
Ok(Line::Eof) => {
113+
deprecation.map(|_| Err(String::from("dangling `@deprecated:`")))
114+
}
115+
})
74116
.peekable();
75117

76118
let module = match parse(&mut iter) {
@@ -150,29 +192,26 @@ fn decode_char(text: &str) -> StrResult<char> {
150192

151193
/// Turns a stream of lines into a list of definitions.
152194
fn parse<'a>(
153-
p: &mut Peekable<impl Iterator<Item = StrResult<Line<'a>>>>,
195+
p: &mut Peekable<impl Iterator<Item = StrResult<Declaration<'a>>>>,
154196
) -> StrResult<Vec<(&'a str, Binding<'a>)>> {
155197
let mut defs = vec![];
156-
let mut deprecation = None;
157198
loop {
158199
match p.next().transpose()? {
159-
None | Some(Line::ModuleEnd) => {
160-
if let Some(message) = deprecation {
161-
return Err(format!("dangling `@deprecated: {}`", message));
162-
}
200+
None | Some(Declaration::ModuleEnd) => {
163201
break;
164202
}
165-
Some(Line::Deprecated(message)) => deprecation = Some(message),
166-
Some(Line::Symbol(name, c)) => {
203+
Some(Declaration::Symbol(name, c, deprecation)) => {
167204
let mut variants = vec![];
168-
while let Some(Line::Variant(name, c)) = p.peek().cloned().transpose()? {
169-
variants.push((name, c));
205+
while let Some(Declaration::Variant(name, c, deprecation)) =
206+
p.peek().cloned().transpose()?
207+
{
208+
variants.push((name, c, deprecation));
170209
p.next();
171210
}
172211

173212
let symbol = if !variants.is_empty() {
174213
if let Some(c) = c {
175-
variants.insert(0, (ModifierSet::default(), c));
214+
variants.insert(0, (ModifierSet::default(), c, None));
176215
}
177216
Symbol::Multi(variants)
178217
} else {
@@ -181,9 +220,8 @@ fn parse<'a>(
181220
};
182221

183222
defs.push((name, Binding { def: Def::Symbol(symbol), deprecation }));
184-
deprecation = None;
185223
}
186-
Some(Line::ModuleStart(name)) => {
224+
Some(Declaration::ModuleStart(name, deprecation)) => {
187225
let module_defs = parse(p)?;
188226
defs.push((
189227
name,
@@ -192,7 +230,6 @@ fn parse<'a>(
192230
deprecation,
193231
},
194232
));
195-
deprecation = None;
196233
}
197234
other => return Err(format!("expected definition, found {other:?}")),
198235
}

src/lib.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,44 +55,56 @@ pub enum Def {
5555
Module(Module),
5656
}
5757

58-
/// A symbol, either a leaf or with modifiers.
58+
/// A symbol, either a leaf or with modifiers and optional deprecation.
5959
#[derive(Debug, Copy, Clone)]
6060
pub enum Symbol {
6161
/// A symbol without modifiers.
6262
Single(char),
6363
/// A symbol with named modifiers. The symbol defaults to its first variant.
64-
Multi(&'static [(ModifierSet<&'static str>, char)]),
64+
Multi(&'static [(ModifierSet<&'static str>, char, Option<&'static str>)]),
6565
}
6666

6767
impl Symbol {
68-
/// Get the symbol's character for a given set of modifiers.
69-
pub fn get(&self, modifs: ModifierSet<&str>) -> Option<char> {
68+
/// Get the symbol's character for a given set of modifiers, alongside an optional deprecation
69+
/// message.
70+
pub fn get(&self, modifs: ModifierSet<&str>) -> Option<(char, Option<&str>)> {
7071
match self {
71-
Self::Single(c) => modifs.is_empty().then_some(*c),
72-
Self::Multi(list) => modifs.best_match_in(list.iter().copied()),
72+
Self::Single(c) => modifs.is_empty().then_some((*c, None)),
73+
Self::Multi(list) => {
74+
modifs.best_match_in(list.iter().copied().map(|(m, c, d)| (m, (c, d))))
75+
}
7376
}
7477
}
7578

7679
/// The characters that are covered by this symbol.
77-
pub fn variants(&self) -> impl Iterator<Item = (ModifierSet<&str>, char)> {
80+
///
81+
/// Each variant is represented by a tuple `(modifiers, character, deprecation)`.
82+
pub fn variants(
83+
&self,
84+
) -> impl Iterator<Item = (ModifierSet<&str>, char, Option<&str>)> {
7885
enum Variants {
7986
Single(std::iter::Once<char>),
80-
Multi(std::slice::Iter<'static, (ModifierSet<&'static str>, char)>),
87+
Multi(
88+
std::slice::Iter<
89+
'static,
90+
(ModifierSet<&'static str>, char, Option<&'static str>),
91+
>,
92+
),
8193
}
8294
let mut iter = match self {
8395
Self::Single(c) => Variants::Single(std::iter::once(*c)),
8496
Self::Multi(sl) => Variants::Multi(sl.iter()),
8597
};
8698
std::iter::from_fn(move || match &mut iter {
87-
Variants::Single(iter) => Some((ModifierSet::default(), iter.next()?)),
99+
Variants::Single(iter) => Some((ModifierSet::default(), iter.next()?, None)),
88100
Variants::Multi(iter) => iter.next().copied(),
89101
})
90102
}
91103

92104
/// Possible modifiers for this symbol.
93105
pub fn modifiers(&self) -> impl Iterator<Item = &str> + '_ {
94106
self.variants()
95-
.flat_map(|(m, _)| m.into_iter())
107+
.flat_map(|(m, _, _)| m.into_iter())
96108
.collect::<std::collections::BTreeSet<_>>()
97109
.into_iter()
98110
}

src/modules/sym.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ angle ∠
8787
.spheric ∢
8888
.spheric.rev ⦠
8989
.spheric.t ⦡
90-
// Deprecated.
90+
@deprecated: `angle.spheric.top` is deprecated, use `angle.spheric.t` instead
9191
.spheric.top ⦡
9292
ceil
9393
.l ⌈
@@ -481,7 +481,7 @@ integral ∫
481481
.double ∬
482482
.quad ⨌
483483
.inter ⨙
484-
// Deprecated.
484+
@deprecated: `integral.sect` is deprecated, use `integral.inter` instead
485485
.sect ⨙
486486
.slash ⨏
487487
.square ⨖

0 commit comments

Comments
 (0)