1
1
use crate :: error:: { ParseError , ParseErrorKind :: * } ;
2
2
use std:: fmt;
3
+ use std:: hash:: { Hash , Hasher } ;
3
4
use std:: iter;
4
5
use std:: str:: { self , FromStr } ;
5
6
@@ -16,21 +17,41 @@ pub enum CfgExpr {
16
17
#[ derive( Eq , PartialEq , Hash , Ord , PartialOrd , Clone , Debug ) ]
17
18
pub enum Cfg {
18
19
/// A named cfg value, like `unix`.
19
- Name ( String ) ,
20
+ Name ( Ident ) ,
20
21
/// A key/value cfg pair, like `target_os = "linux"`.
21
- KeyPair ( String , String ) ,
22
+ KeyPair ( Ident , String ) ,
23
+ }
24
+
25
+ /// A identifier
26
+ #[ derive( Eq , Ord , PartialOrd , Clone , Debug ) ]
27
+ pub struct Ident {
28
+ /// The identifier
29
+ pub name : String ,
30
+ /// Is this a raw ident: `r#async`
31
+ ///
32
+ /// It's mainly used for display and doesn't take
33
+ /// part in the hash or equality (`foo` == `r#foo`).
34
+ pub raw : bool ,
22
35
}
23
36
24
37
#[ derive( PartialEq ) ]
25
38
enum Token < ' a > {
26
39
LeftParen ,
27
40
RightParen ,
28
- Ident ( & ' a str ) ,
41
+ Ident ( bool , & ' a str ) ,
29
42
Comma ,
30
43
Equals ,
31
44
String ( & ' a str ) ,
32
45
}
33
46
47
+ /// The list of keywords.
48
+ ///
49
+ /// We should consider all the keywords, but some are conditional on
50
+ /// the edition so for now we just consider true/false.
51
+ ///
52
+ /// <https://doc.rust-lang.org/reference/keywords.html>
53
+ pub ( crate ) const KEYWORDS : & [ & str ; 2 ] = & [ "true" , "false" ] ;
54
+
34
55
#[ derive( Clone ) ]
35
56
struct Tokenizer < ' a > {
36
57
s : iter:: Peekable < str:: CharIndices < ' a > > ,
@@ -41,6 +62,45 @@ struct Parser<'a> {
41
62
t : Tokenizer < ' a > ,
42
63
}
43
64
65
+ impl Ident {
66
+ pub fn as_str ( & self ) -> & str {
67
+ & self . name
68
+ }
69
+ }
70
+
71
+ impl Hash for Ident {
72
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
73
+ self . name . hash ( state) ;
74
+ }
75
+ }
76
+
77
+ impl PartialEq < str > for Ident {
78
+ fn eq ( & self , other : & str ) -> bool {
79
+ self . name == other
80
+ }
81
+ }
82
+
83
+ impl PartialEq < & str > for Ident {
84
+ fn eq ( & self , other : & & str ) -> bool {
85
+ self . name == * other
86
+ }
87
+ }
88
+
89
+ impl PartialEq < Ident > for Ident {
90
+ fn eq ( & self , other : & Ident ) -> bool {
91
+ self . name == other. name
92
+ }
93
+ }
94
+
95
+ impl fmt:: Display for Ident {
96
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
97
+ if self . raw {
98
+ f. write_str ( "r#" ) ?;
99
+ }
100
+ f. write_str ( & * self . name )
101
+ }
102
+ }
103
+
44
104
impl FromStr for Cfg {
45
105
type Err = ParseError ;
46
106
@@ -144,7 +204,8 @@ impl<'a> Parser<'a> {
144
204
145
205
fn expr ( & mut self ) -> Result < CfgExpr , ParseError > {
146
206
match self . peek ( ) {
147
- Some ( Ok ( Token :: Ident ( op @ "all" ) ) ) | Some ( Ok ( Token :: Ident ( op @ "any" ) ) ) => {
207
+ Some ( Ok ( Token :: Ident ( false , op @ "all" ) ) )
208
+ | Some ( Ok ( Token :: Ident ( false , op @ "any" ) ) ) => {
148
209
self . t . next ( ) ;
149
210
let mut e = Vec :: new ( ) ;
150
211
self . eat ( & Token :: LeftParen ) ?;
@@ -161,7 +222,7 @@ impl<'a> Parser<'a> {
161
222
Ok ( CfgExpr :: Any ( e) )
162
223
}
163
224
}
164
- Some ( Ok ( Token :: Ident ( "not" ) ) ) => {
225
+ Some ( Ok ( Token :: Ident ( false , "not" ) ) ) => {
165
226
self . t . next ( ) ;
166
227
self . eat ( & Token :: LeftParen ) ?;
167
228
let e = self . expr ( ) ?;
@@ -179,7 +240,7 @@ impl<'a> Parser<'a> {
179
240
180
241
fn cfg ( & mut self ) -> Result < Cfg , ParseError > {
181
242
match self . t . next ( ) {
182
- Some ( Ok ( Token :: Ident ( name) ) ) => {
243
+ Some ( Ok ( Token :: Ident ( raw , name) ) ) => {
183
244
let e = if self . r#try ( & Token :: Equals ) {
184
245
let val = match self . t . next ( ) {
185
246
Some ( Ok ( Token :: String ( s) ) ) => s,
@@ -197,9 +258,18 @@ impl<'a> Parser<'a> {
197
258
return Err ( ParseError :: new ( self . t . orig , IncompleteExpr ( "a string" ) ) )
198
259
}
199
260
} ;
200
- Cfg :: KeyPair ( name. to_string ( ) , val. to_string ( ) )
261
+ Cfg :: KeyPair (
262
+ Ident {
263
+ name : name. to_string ( ) ,
264
+ raw,
265
+ } ,
266
+ val. to_string ( ) ,
267
+ )
201
268
} else {
202
- Cfg :: Name ( name. to_string ( ) )
269
+ Cfg :: Name ( Ident {
270
+ name : name. to_string ( ) ,
271
+ raw,
272
+ } )
203
273
} ;
204
274
Ok ( e)
205
275
}
@@ -279,14 +349,44 @@ impl<'a> Iterator for Tokenizer<'a> {
279
349
return Some ( Err ( ParseError :: new ( self . orig , UnterminatedString ) ) ) ;
280
350
}
281
351
Some ( ( start, ch) ) if is_ident_start ( ch) => {
352
+ let ( start, raw) = if ch == 'r' {
353
+ if let Some ( & ( _pos, '#' ) ) = self . s . peek ( ) {
354
+ // starts with `r#` is a raw ident
355
+ self . s . next ( ) ;
356
+ if let Some ( ( start, ch) ) = self . s . next ( ) {
357
+ if is_ident_start ( ch) {
358
+ ( start, true )
359
+ } else {
360
+ // not a starting ident character
361
+ return Some ( Err ( ParseError :: new (
362
+ self . orig ,
363
+ UnexpectedChar ( ch) ,
364
+ ) ) ) ;
365
+ }
366
+ } else {
367
+ // not followed by a ident, error out
368
+ return Some ( Err ( ParseError :: new (
369
+ self . orig ,
370
+ IncompleteExpr ( "identifier" ) ,
371
+ ) ) ) ;
372
+ }
373
+ } else {
374
+ // starts with `r` but not does continue with `#`
375
+ // cannot be a raw ident
376
+ ( start, false )
377
+ }
378
+ } else {
379
+ // do not start with `r`, cannot be a raw ident
380
+ ( start, false )
381
+ } ;
282
382
while let Some ( & ( end, ch) ) = self . s . peek ( ) {
283
383
if !is_ident_rest ( ch) {
284
- return Some ( Ok ( Token :: Ident ( & self . orig [ start..end] ) ) ) ;
384
+ return Some ( Ok ( Token :: Ident ( raw , & self . orig [ start..end] ) ) ) ;
285
385
} else {
286
386
self . s . next ( ) ;
287
387
}
288
388
}
289
- return Some ( Ok ( Token :: Ident ( & self . orig [ start..] ) ) ) ;
389
+ return Some ( Ok ( Token :: Ident ( raw , & self . orig [ start..] ) ) ) ;
290
390
}
291
391
Some ( ( _, ch) ) => {
292
392
return Some ( Err ( ParseError :: new ( self . orig , UnexpectedChar ( ch) ) ) ) ;
0 commit comments