1
+ use std:: borrow:: Cow ;
1
2
use std:: fmt:: Write ;
2
3
use std:: iter:: Peekable ;
3
4
use std:: path:: Path ;
@@ -24,6 +25,7 @@ enum Def<'a> {
24
25
enum Symbol < ' a > {
25
26
Single ( char ) ,
26
27
Multi ( Vec < ( & ' a str , char ) > ) ,
28
+ MultiAlias ( Vec < ( Cow < ' a , str > , char ) > ) ,
27
29
}
28
30
29
31
/// A single line during parsing.
@@ -34,6 +36,7 @@ enum Line<'a> {
34
36
ModuleEnd ,
35
37
Symbol ( & ' a str , Option < char > ) ,
36
38
Variant ( & ' a str , char ) ,
39
+ Alias ( & ' a str , & ' a str , & ' a str , bool ) ,
37
40
}
38
41
39
42
fn main ( ) {
@@ -102,6 +105,23 @@ fn tokenize(line: &str) -> StrResult<Line> {
102
105
}
103
106
let c = decode_char ( tail. ok_or ( "missing char" ) ?) ?;
104
107
Line :: Variant ( rest, c)
108
+ } else if let Some ( alias) = head. strip_prefix ( '@' ) {
109
+ validate_ident ( alias) ?;
110
+ let mut value = tail. ok_or ( "missing value" ) ?;
111
+ let mut deep = false ;
112
+ if let Some ( v) = value. strip_suffix ( ".*" ) {
113
+ deep = true ;
114
+ value = v;
115
+ }
116
+ let ( head, rest) = value. split_once ( '.' ) . unwrap_or ( ( value, "" ) ) ;
117
+ validate_ident ( head) ?;
118
+ if !rest. is_empty ( ) {
119
+ for part in rest. split ( '.' ) {
120
+ validate_ident ( part) ?;
121
+ }
122
+ }
123
+
124
+ Line :: Alias ( alias, head, rest, deep)
105
125
} else {
106
126
validate_ident ( head) ?;
107
127
let c = tail. map ( decode_char) . transpose ( ) ?;
@@ -139,9 +159,13 @@ fn parse<'a>(
139
159
p : & mut Peekable < impl Iterator < Item = StrResult < Line < ' a > > > > ,
140
160
) -> StrResult < Vec < ( & ' a str , Def < ' a > ) > > {
141
161
let mut defs = vec ! [ ] ;
162
+ let mut aliases = vec ! [ ] ;
142
163
loop {
143
164
match p. next ( ) . transpose ( ) ? {
144
165
None | Some ( Line :: ModuleEnd ) => break ,
166
+ Some ( Line :: Alias ( alias, name, variant, deep) ) => {
167
+ aliases. push ( ( alias, name, variant, deep) ) ;
168
+ }
145
169
Some ( Line :: Symbol ( name, c) ) => {
146
170
let mut variants = vec ! [ ] ;
147
171
while let Some ( Line :: Variant ( name, c) ) = p. peek ( ) . cloned ( ) . transpose ( ) ? {
@@ -169,6 +193,83 @@ fn parse<'a>(
169
193
other => return Err ( format ! ( "expected definition, found {other:?}" ) ) ,
170
194
}
171
195
}
196
+ for ( alias, name, variant, deep) in aliases {
197
+ let aliased_symbol: & Symbol < ' a > = defs
198
+ . iter ( )
199
+ . filter ( |( n, _) | * n == name)
200
+ . find_map ( |( _, def) | match def {
201
+ Def :: Symbol ( s) => Some ( s) ,
202
+ _ => None ,
203
+ } )
204
+ . ok_or_else ( || format ! ( "alias to nonexistent symbol: {name}" ) ) ?;
205
+
206
+ match aliased_symbol {
207
+ & Symbol :: Single ( c) => {
208
+ if variant != "" {
209
+ return Err ( format ! (
210
+ "alias to nonexistent variant: {name}.{variant}"
211
+ ) ) ;
212
+ }
213
+ defs. push ( ( alias, Def :: Symbol ( Symbol :: Single ( c) ) ) ) ;
214
+ }
215
+ Symbol :: MultiAlias ( _) => {
216
+ return Err ( format ! ( "alias to alias: {name}.{variant}" ) ) ;
217
+ }
218
+ Symbol :: Multi ( variants) => {
219
+ let variants: Vec < ( Cow < ' a , str > , char ) > = variants
220
+ . iter ( )
221
+ . filter_map ( |& ( var, c) | {
222
+ if var == variant {
223
+ Some ( ( Cow :: Borrowed ( "" ) , c) )
224
+ } else if deep {
225
+ var. strip_prefix ( variant) ?
226
+ . strip_prefix ( '.' )
227
+ . map ( |v| ( Cow :: Borrowed ( v) , c) )
228
+ . or_else ( || {
229
+ // might just be in a different order
230
+
231
+ let mut alias_modifs = if variant. is_empty ( ) {
232
+ vec ! [ ]
233
+ } else {
234
+ variant. split ( '.' ) . collect ( )
235
+ } ;
236
+
237
+ let mut new_variant = Cow :: Borrowed ( "" ) ;
238
+ for modif in var. split ( '.' ) {
239
+ if let Some ( i) =
240
+ alias_modifs. iter ( ) . position ( |m| * m == modif)
241
+ {
242
+ alias_modifs. swap_remove ( i) ;
243
+ } else if new_variant. is_empty ( ) {
244
+ new_variant = Cow :: Borrowed ( modif) ;
245
+ } else {
246
+ new_variant = Cow :: Owned ( format ! (
247
+ "{new_variant}.{modif}"
248
+ ) ) ;
249
+ }
250
+ }
251
+ alias_modifs. is_empty ( ) . then_some ( ( new_variant, c) )
252
+ } )
253
+ } else {
254
+ None
255
+ }
256
+ } )
257
+ . collect ( ) ;
258
+ if variants. is_empty ( ) {
259
+ return Err ( format ! (
260
+ "alias to nonexistent variant: {name}.{variant}"
261
+ ) ) ;
262
+ }
263
+ if let [ ( ref s, c) ] = variants[ ..] {
264
+ if s. is_empty ( ) {
265
+ defs. push ( ( alias, Def :: Symbol ( Symbol :: Single ( c) ) ) ) ;
266
+ continue ;
267
+ }
268
+ }
269
+ defs. push ( ( alias, Def :: Symbol ( Symbol :: MultiAlias ( variants) ) ) ) ;
270
+ }
271
+ }
272
+ }
172
273
Ok ( defs)
173
274
}
174
275
@@ -188,6 +289,7 @@ fn encode(buf: &mut String, module: &Module) {
188
289
match symbol {
189
290
Symbol :: Single ( c) => write ! ( buf, "Single({c:?})" ) . unwrap ( ) ,
190
291
Symbol :: Multi ( list) => write ! ( buf, "Multi(&{list:?})" ) . unwrap ( ) ,
292
+ Symbol :: MultiAlias ( list) => write ! ( buf, "Multi(&{list:?})" ) . unwrap ( ) ,
191
293
}
192
294
buf. push_str ( ")" ) ;
193
295
}
0 commit comments