1
+ use crate :: error:: { ParseError , ParseErrorKind :: * } ;
1
2
use std:: fmt;
2
3
use std:: iter;
3
4
use std:: str:: { self , FromStr } ;
4
5
5
- use crate :: util:: CargoResult ;
6
-
7
- #[ derive( Eq , PartialEq , Hash , Ord , PartialOrd , Clone , Debug ) ]
8
- pub enum Cfg {
9
- Name ( String ) ,
10
- KeyPair ( String , String ) ,
11
- }
12
-
6
+ /// A cfg expression.
13
7
#[ derive( Eq , PartialEq , Hash , Ord , PartialOrd , Clone , Debug ) ]
14
8
pub enum CfgExpr {
15
9
Not ( Box < CfgExpr > ) ,
@@ -18,6 +12,15 @@ pub enum CfgExpr {
18
12
Value ( Cfg ) ,
19
13
}
20
14
15
+ /// A cfg value.
16
+ #[ derive( Eq , PartialEq , Hash , Ord , PartialOrd , Clone , Debug ) ]
17
+ pub enum Cfg {
18
+ /// A named cfg value, like `unix`.
19
+ Name ( String ) ,
20
+ /// A key/value cfg pair, like `target_os = "linux"`.
21
+ KeyPair ( String , String ) ,
22
+ }
23
+
21
24
#[ derive( PartialEq ) ]
22
25
enum Token < ' a > {
23
26
LeftParen ,
@@ -28,23 +31,27 @@ enum Token<'a> {
28
31
String ( & ' a str ) ,
29
32
}
30
33
34
+ #[ derive( Clone ) ]
31
35
struct Tokenizer < ' a > {
32
36
s : iter:: Peekable < str:: CharIndices < ' a > > ,
33
37
orig : & ' a str ,
34
38
}
35
39
36
40
struct Parser < ' a > {
37
- t : iter :: Peekable < Tokenizer < ' a > > ,
41
+ t : Tokenizer < ' a > ,
38
42
}
39
43
40
44
impl FromStr for Cfg {
41
- type Err = failure :: Error ;
45
+ type Err = ParseError ;
42
46
43
- fn from_str ( s : & str ) -> CargoResult < Cfg > {
47
+ fn from_str ( s : & str ) -> Result < Cfg , Self :: Err > {
44
48
let mut p = Parser :: new ( s) ;
45
49
let e = p. cfg ( ) ?;
46
- if p. t . next ( ) . is_some ( ) {
47
- failure:: bail!( "malformed cfg value or key/value pair: `{}`" , s)
50
+ if let Some ( rest) = p. rest ( ) {
51
+ return Err ( ParseError :: new (
52
+ p. t . orig ,
53
+ UnterminatedExpression ( rest. to_string ( ) ) ,
54
+ ) ) ;
48
55
}
49
56
Ok ( e)
50
57
}
@@ -85,16 +92,16 @@ impl CfgExpr {
85
92
}
86
93
87
94
impl FromStr for CfgExpr {
88
- type Err = failure :: Error ;
95
+ type Err = ParseError ;
89
96
90
- fn from_str ( s : & str ) -> CargoResult < CfgExpr > {
97
+ fn from_str ( s : & str ) -> Result < CfgExpr , Self :: Err > {
91
98
let mut p = Parser :: new ( s) ;
92
99
let e = p. expr ( ) ?;
93
- if p . t . next ( ) . is_some ( ) {
94
- failure :: bail! (
95
- "can only have one cfg-expression, consider using all() or \
96
- any() explicitly"
97
- )
100
+ if let Some ( rest ) = p . rest ( ) {
101
+ return Err ( ParseError :: new (
102
+ p . t . orig ,
103
+ UnterminatedExpression ( rest . to_string ( ) ) ,
104
+ ) ) ;
98
105
}
99
106
Ok ( e)
100
107
}
@@ -131,14 +138,13 @@ impl<'a> Parser<'a> {
131
138
t : Tokenizer {
132
139
s : s. char_indices ( ) . peekable ( ) ,
133
140
orig : s,
134
- }
135
- . peekable ( ) ,
141
+ } ,
136
142
}
137
143
}
138
144
139
- fn expr ( & mut self ) -> CargoResult < CfgExpr > {
140
- match self . t . peek ( ) {
141
- Some ( & Ok ( Token :: Ident ( op @ "all" ) ) ) | Some ( & Ok ( Token :: Ident ( op @ "any" ) ) ) => {
145
+ fn expr ( & mut self ) -> Result < CfgExpr , ParseError > {
146
+ match self . peek ( ) {
147
+ Some ( Ok ( Token :: Ident ( op @ "all" ) ) ) | Some ( Ok ( Token :: Ident ( op @ "any" ) ) ) => {
142
148
self . t . next ( ) ;
143
149
let mut e = Vec :: new ( ) ;
144
150
self . eat ( & Token :: LeftParen ) ?;
@@ -155,67 +161,108 @@ impl<'a> Parser<'a> {
155
161
Ok ( CfgExpr :: Any ( e) )
156
162
}
157
163
}
158
- Some ( & Ok ( Token :: Ident ( "not" ) ) ) => {
164
+ Some ( Ok ( Token :: Ident ( "not" ) ) ) => {
159
165
self . t . next ( ) ;
160
166
self . eat ( & Token :: LeftParen ) ?;
161
167
let e = self . expr ( ) ?;
162
168
self . eat ( & Token :: RightParen ) ?;
163
169
Ok ( CfgExpr :: Not ( Box :: new ( e) ) )
164
170
}
165
- Some ( & Ok ( ..) ) => self . cfg ( ) . map ( CfgExpr :: Value ) ,
166
- Some ( & Err ( ..) ) => Err ( self . t . next ( ) . unwrap ( ) . err ( ) . unwrap ( ) ) ,
167
- None => failure :: bail! (
168
- "expected start of a cfg expression, \
169
- found nothing"
170
- ) ,
171
+ Some ( Ok ( ..) ) => self . cfg ( ) . map ( CfgExpr :: Value ) ,
172
+ Some ( Err ( ..) ) => Err ( self . t . next ( ) . unwrap ( ) . err ( ) . unwrap ( ) ) ,
173
+ None => Err ( ParseError :: new (
174
+ self . t . orig ,
175
+ IncompleteExpr ( "start of a cfg expression" ) ,
176
+ ) ) ,
171
177
}
172
178
}
173
179
174
- fn cfg ( & mut self ) -> CargoResult < Cfg > {
180
+ fn cfg ( & mut self ) -> Result < Cfg , ParseError > {
175
181
match self . t . next ( ) {
176
182
Some ( Ok ( Token :: Ident ( name) ) ) => {
177
183
let e = if self . r#try ( & Token :: Equals ) {
178
184
let val = match self . t . next ( ) {
179
185
Some ( Ok ( Token :: String ( s) ) ) => s,
180
- Some ( Ok ( t) ) => failure:: bail!( "expected a string, found {}" , t. classify( ) ) ,
186
+ Some ( Ok ( t) ) => {
187
+ return Err ( ParseError :: new (
188
+ self . t . orig ,
189
+ UnexpectedToken {
190
+ expected : "a string" ,
191
+ found : t. classify ( ) ,
192
+ } ,
193
+ ) )
194
+ }
181
195
Some ( Err ( e) ) => return Err ( e) ,
182
- None => failure:: bail!( "expected a string, found nothing" ) ,
196
+ None => {
197
+ return Err ( ParseError :: new ( self . t . orig , IncompleteExpr ( "a string" ) ) )
198
+ }
183
199
} ;
184
200
Cfg :: KeyPair ( name. to_string ( ) , val. to_string ( ) )
185
201
} else {
186
202
Cfg :: Name ( name. to_string ( ) )
187
203
} ;
188
204
Ok ( e)
189
205
}
190
- Some ( Ok ( t) ) => failure:: bail!( "expected identifier, found {}" , t. classify( ) ) ,
206
+ Some ( Ok ( t) ) => Err ( ParseError :: new (
207
+ self . t . orig ,
208
+ UnexpectedToken {
209
+ expected : "identifier" ,
210
+ found : t. classify ( ) ,
211
+ } ,
212
+ ) ) ,
191
213
Some ( Err ( e) ) => Err ( e) ,
192
- None => failure :: bail! ( "expected identifier, found nothing" ) ,
214
+ None => Err ( ParseError :: new ( self . t . orig , IncompleteExpr ( "identifier" ) ) ) ,
193
215
}
194
216
}
195
217
218
+ fn peek ( & mut self ) -> Option < Result < Token < ' a > , ParseError > > {
219
+ self . t . clone ( ) . next ( )
220
+ }
221
+
196
222
fn r#try ( & mut self , token : & Token < ' a > ) -> bool {
197
- match self . t . peek ( ) {
198
- Some ( & Ok ( ref t) ) if token == t => { }
223
+ match self . peek ( ) {
224
+ Some ( Ok ( ref t) ) if token == t => { }
199
225
_ => return false ,
200
226
}
201
227
self . t . next ( ) ;
202
228
true
203
229
}
204
230
205
- fn eat ( & mut self , token : & Token < ' a > ) -> CargoResult < ( ) > {
231
+ fn eat ( & mut self , token : & Token < ' a > ) -> Result < ( ) , ParseError > {
206
232
match self . t . next ( ) {
207
233
Some ( Ok ( ref t) ) if token == t => Ok ( ( ) ) ,
208
- Some ( Ok ( t) ) => failure:: bail!( "expected {}, found {}" , token. classify( ) , t. classify( ) ) ,
234
+ Some ( Ok ( t) ) => Err ( ParseError :: new (
235
+ self . t . orig ,
236
+ UnexpectedToken {
237
+ expected : token. classify ( ) ,
238
+ found : t. classify ( ) ,
239
+ } ,
240
+ ) ) ,
209
241
Some ( Err ( e) ) => Err ( e) ,
210
- None => failure:: bail!( "expected {}, but cfg expr ended" , token. classify( ) ) ,
242
+ None => Err ( ParseError :: new (
243
+ self . t . orig ,
244
+ IncompleteExpr ( token. classify ( ) ) ,
245
+ ) ) ,
246
+ }
247
+ }
248
+
249
+ /// Returns the rest of the input from the current location.
250
+ fn rest ( & self ) -> Option < & str > {
251
+ let mut s = self . t . s . clone ( ) ;
252
+ loop {
253
+ match s. next ( ) {
254
+ Some ( ( _, ' ' ) ) => { }
255
+ Some ( ( start, _ch) ) => return Some ( & self . t . orig [ start..] ) ,
256
+ None => return None ,
257
+ }
211
258
}
212
259
}
213
260
}
214
261
215
262
impl < ' a > Iterator for Tokenizer < ' a > {
216
- type Item = CargoResult < Token < ' a > > ;
263
+ type Item = Result < Token < ' a > , ParseError > ;
217
264
218
- fn next ( & mut self ) -> Option < CargoResult < Token < ' a > > > {
265
+ fn next ( & mut self ) -> Option < Result < Token < ' a > , ParseError > > {
219
266
loop {
220
267
match self . s . next ( ) {
221
268
Some ( ( _, ' ' ) ) => { }
@@ -229,7 +276,7 @@ impl<'a> Iterator for Tokenizer<'a> {
229
276
return Some ( Ok ( Token :: String ( & self . orig [ start + 1 ..end] ) ) ) ;
230
277
}
231
278
}
232
- return Some ( Err ( failure :: format_err! ( "unterminated string in cfg" ) ) ) ;
279
+ return Some ( Err ( ParseError :: new ( self . orig , UnterminatedString ) ) ) ;
233
280
}
234
281
Some ( ( start, ch) ) if is_ident_start ( ch) => {
235
282
while let Some ( & ( end, ch) ) = self . s . peek ( ) {
@@ -242,13 +289,7 @@ impl<'a> Iterator for Tokenizer<'a> {
242
289
return Some ( Ok ( Token :: Ident ( & self . orig [ start..] ) ) ) ;
243
290
}
244
291
Some ( ( _, ch) ) => {
245
- return Some ( Err ( failure:: format_err!(
246
- "unexpected character in \
247
- cfg `{}`, expected parens, \
248
- a comma, an identifier, or \
249
- a string",
250
- ch
251
- ) ) ) ;
292
+ return Some ( Err ( ParseError :: new ( self . orig , UnexpectedChar ( ch) ) ) ) ;
252
293
}
253
294
None => return None ,
254
295
}
@@ -265,7 +306,7 @@ fn is_ident_rest(ch: char) -> bool {
265
306
}
266
307
267
308
impl < ' a > Token < ' a > {
268
- fn classify ( & self ) -> & str {
309
+ fn classify ( & self ) -> & ' static str {
269
310
match * self {
270
311
Token :: LeftParen => "`(`" ,
271
312
Token :: RightParen => "`)`" ,
0 commit comments