11use crate :: parser:: { ParseArg , Parser } ;
2- use proc_macro_error2:: abort;
32use proc_macro2:: { Delimiter , Ident , Literal , Span , TokenStream , TokenTree , token_stream} ;
43use quote:: quote;
54use std:: iter:: Peekable ;
@@ -12,12 +11,12 @@ use std::str::Chars;
1211/// - to escape '$' itself, use "$$"
1312/// - support normal rust character escapes:
1413/// https://doc.rust-lang.org/reference/tokens.html#ascii-escapes
15- pub fn scan_str_lit ( lit : & Literal ) -> TokenStream {
14+ pub fn scan_str_lit ( lit : & Literal ) -> syn :: Result < TokenStream > {
1615 let s = lit. to_string ( ) ;
1716
1817 // If the literal is not a string (e.g., a number literal), treat it as a direct CmdString.
1918 if !s. starts_with ( '\"' ) {
20- return quote ! ( :: cmd_lib:: CmdString :: from( #lit) ) ;
19+ return Ok ( quote ! ( :: cmd_lib:: CmdString :: from( #lit) ) ) ;
2120 }
2221
2322 // Extract the inner string by trimming the surrounding quotes.
@@ -77,7 +76,7 @@ pub fn scan_str_lit(lit: &Literal) -> TokenStream {
7776
7877 // Expect '}' to close the braced interpolation
7978 if chars. next ( ) != Some ( '}' ) {
80- abort ! ( lit. span( ) , "bad substitution: expected '}'" ) ;
79+ bail ! ( lit. span( ) , "bad substitution: expected '} }'" ) ;
8180 }
8281 }
8382
@@ -110,7 +109,7 @@ pub fn scan_str_lit(lit: &Literal) -> TokenStream {
110109
111110 // Append any remaining literal part after the loop finishes.
112111 seal_current_literal_part ( & mut output, & mut current_literal_part) ;
113- output
112+ Ok ( output)
114113}
115114
116115/// Parses a variable name from the character iterator.
@@ -167,14 +166,14 @@ impl Lexer {
167166 }
168167 }
169168
170- pub fn scan ( mut self ) -> Parser < impl Iterator < Item = ParseArg > > {
169+ pub fn scan ( mut self ) -> syn :: Result < Parser < impl Iterator < Item = ParseArg > > > {
171170 while let Some ( item) = self . iter . next ( ) {
172171 match item {
173172 TokenTree :: Group ( _) => {
174- abort ! ( self . iter. span( ) , "grouping is only allowed for variables" ) ;
173+ bail ! ( self . iter. span( ) , "grouping is only allowed for variables" ) ;
175174 }
176175 TokenTree :: Literal ( lit) => {
177- self . scan_literal ( lit) ;
176+ self . scan_literal ( lit) ? ;
178177 }
179178 TokenTree :: Ident ( ident) => {
180179 let s = ident. to_string ( ) ;
@@ -183,17 +182,17 @@ impl Lexer {
183182 TokenTree :: Punct ( punct) => {
184183 let ch = punct. as_char ( ) ;
185184 if ch == ';' {
186- self . add_arg_with_token ( SepToken :: SemiColon , self . iter . span ( ) ) ;
185+ self . add_arg_with_token ( SepToken :: SemiColon , self . iter . span ( ) ) ? ;
187186 } else if ch == '|' {
188- self . scan_pipe ( ) ;
187+ self . scan_pipe ( ) ? ;
189188 } else if ch == '<' {
190- self . set_redirect ( self . iter . span ( ) , RedirectFd :: Stdin ) ;
189+ self . set_redirect ( self . iter . span ( ) , RedirectFd :: Stdin ) ? ;
191190 } else if ch == '>' {
192- self . scan_redirect_out ( 1 ) ;
191+ self . scan_redirect_out ( 1 ) ? ;
193192 } else if ch == '&' {
194- self . scan_ampersand ( ) ;
193+ self . scan_ampersand ( ) ? ;
195194 } else if ch == '$' {
196- self . scan_dollar ( ) ;
195+ self . scan_dollar ( ) ? ;
197196 } else {
198197 let s = ch. to_string ( ) ;
199198 self . extend_last_arg ( quote ! ( #s) ) ;
@@ -202,18 +201,18 @@ impl Lexer {
202201 }
203202
204203 if self . iter . peek_no_gap ( ) . is_none ( ) && !self . last_arg_str . is_empty ( ) {
205- self . add_arg_with_token ( SepToken :: Space , self . iter . span ( ) ) ;
204+ self . add_arg_with_token ( SepToken :: Space , self . iter . span ( ) ) ? ;
206205 }
207206 }
208- self . add_arg_with_token ( SepToken :: Space , self . iter . span ( ) ) ;
209- Parser :: from ( self . args . into_iter ( ) . peekable ( ) )
207+ self . add_arg_with_token ( SepToken :: Space , self . iter . span ( ) ) ? ;
208+ Ok ( Parser :: from ( self . args . into_iter ( ) . peekable ( ) ) )
210209 }
211210
212- fn add_arg_with_token ( & mut self , token : SepToken , token_span : Span ) {
211+ fn add_arg_with_token ( & mut self , token : SepToken , token_span : Span ) -> syn :: Result < ( ) > {
213212 let last_arg_str = & self . last_arg_str ;
214213 if let Some ( ( redirect, span) ) = self . last_redirect . take ( ) {
215214 if last_arg_str. is_empty ( ) {
216- abort ! ( span, "wrong redirection format: missing target" ) ;
215+ bail ! ( span, "wrong redirection format: missing target" ) ;
217216 }
218217
219218 let mut stdouterr = false ;
@@ -239,13 +238,14 @@ impl Lexer {
239238 SepToken :: Space => new_redirect = self . seen_redirect ,
240239 SepToken :: SemiColon => self . args . push ( ParseArg :: Semicolon ) ,
241240 SepToken :: Pipe => {
242- Self :: check_set_redirect ( & mut self . seen_redirect . 1 , "stdout" , token_span) ;
241+ Self :: check_set_redirect ( & mut self . seen_redirect . 1 , "stdout" , token_span) ? ;
243242 self . args . push ( ParseArg :: Pipe ) ;
244243 new_redirect. 0 = true ;
245244 }
246245 }
247246 self . seen_redirect = new_redirect;
248247 self . last_arg_str = TokenStream :: new ( ) ;
248+ Ok ( ( ) )
249249 }
250250
251251 fn extend_last_arg ( & mut self , stream : TokenStream ) {
@@ -255,38 +255,42 @@ impl Lexer {
255255 self . last_arg_str . extend ( quote ! ( . append( #stream) ) ) ;
256256 }
257257
258- fn check_set_redirect ( redirect : & mut bool , name : & str , span : Span ) {
258+ fn check_set_redirect ( redirect : & mut bool , name : & str , span : Span ) -> syn :: Result < ( ) > {
259259 if * redirect {
260- abort ! ( span, "already set {} redirection" , name) ;
260+ bail ! ( span, "already set {} redirection" , name) ;
261261 }
262262 * redirect = true ;
263+ Ok ( ( ) )
263264 }
264265
265- fn set_redirect ( & mut self , span : Span , fd : RedirectFd ) {
266+ fn set_redirect ( & mut self , span : Span , fd : RedirectFd ) -> syn :: Result < ( ) > {
266267 if self . last_redirect . is_some ( ) {
267- abort ! ( span, "wrong double redirection format" ) ;
268+ bail ! ( span, "wrong double redirection format" ) ;
268269 }
269270 match fd {
270- RedirectFd :: Stdin => Self :: check_set_redirect ( & mut self . seen_redirect . 0 , "stdin" , span) ,
271+ RedirectFd :: Stdin => {
272+ Self :: check_set_redirect ( & mut self . seen_redirect . 0 , "stdin" , span) ?
273+ }
271274 RedirectFd :: Stdout { append : _ } => {
272- Self :: check_set_redirect ( & mut self . seen_redirect . 1 , "stdout" , span)
275+ Self :: check_set_redirect ( & mut self . seen_redirect . 1 , "stdout" , span) ?
273276 }
274277 RedirectFd :: Stderr { append : _ } => {
275- Self :: check_set_redirect ( & mut self . seen_redirect . 2 , "stderr" , span)
278+ Self :: check_set_redirect ( & mut self . seen_redirect . 2 , "stderr" , span) ?
276279 }
277280 RedirectFd :: StdoutErr { append : _ } => {
278- Self :: check_set_redirect ( & mut self . seen_redirect . 1 , "stdout" , span) ;
279- Self :: check_set_redirect ( & mut self . seen_redirect . 2 , "stderr" , span) ;
281+ Self :: check_set_redirect ( & mut self . seen_redirect . 1 , "stdout" , span) ? ;
282+ Self :: check_set_redirect ( & mut self . seen_redirect . 2 , "stderr" , span) ? ;
280283 }
281284 }
282285 self . last_redirect = Some ( ( fd, span) ) ;
286+ Ok ( ( ) )
283287 }
284288
285- fn scan_literal ( & mut self , lit : Literal ) {
289+ fn scan_literal ( & mut self , lit : Literal ) -> syn :: Result < ( ) > {
286290 let s = lit. to_string ( ) ;
287291 if s. starts_with ( '\"' ) || s. starts_with ( 'r' ) {
288292 // string literal
289- let ss = scan_str_lit ( & lit) ;
293+ let ss = scan_str_lit ( & lit) ? ;
290294 self . extend_last_arg ( quote ! ( #ss. into_os_string( ) ) ) ;
291295 } else {
292296 let mut is_redirect = false ;
@@ -295,23 +299,24 @@ impl Lexer {
295299 && p. as_char ( ) == '>'
296300 {
297301 self . iter . next ( ) ;
298- self . scan_redirect_out ( if s == "1" { 1 } else { 2 } ) ;
302+ self . scan_redirect_out ( if s == "1" { 1 } else { 2 } ) ? ;
299303 is_redirect = true ;
300304 }
301305 if !is_redirect {
302306 self . extend_last_arg ( quote ! ( #s) ) ;
303307 }
304308 }
309+ Ok ( ( ) )
305310 }
306311
307- fn scan_pipe ( & mut self ) {
312+ fn scan_pipe ( & mut self ) -> syn :: Result < ( ) > {
308313 if let Some ( TokenTree :: Punct ( p) ) = self . iter . peek_no_gap ( )
309314 && p. as_char ( ) == '&'
310315 {
311316 if let Some ( ref redirect) = self . last_redirect {
312- abort ! ( redirect. 1 , "invalid '&': found previous redirect" ) ;
317+ bail ! ( redirect. 1 , "invalid '&': found previous redirect" ) ;
313318 }
314- Self :: check_set_redirect ( & mut self . seen_redirect . 2 , "stderr" , p. span ( ) ) ;
319+ Self :: check_set_redirect ( & mut self . seen_redirect . 2 , "stderr" , p. span ( ) ) ? ;
315320 self . args . push ( ParseArg :: RedirectFd ( 2 , 1 ) ) ;
316321 self . iter . next ( ) ;
317322 }
@@ -320,18 +325,19 @@ impl Lexer {
320325 match self . iter . peek ( ) {
321326 Some ( TokenTree :: Punct ( np) ) => {
322327 if np. as_char ( ) == '|' || np. as_char ( ) == ';' {
323- abort ! ( np. span( ) , "expect new command after '|'" ) ;
328+ bail ! ( np. span( ) , "expect new command after '|'" ) ;
324329 }
325330 }
326331 None => {
327- abort ! ( self . iter. span( ) , "expect new command after '|'" ) ;
332+ bail ! ( self . iter. span( ) , "expect new command after '|'" ) ;
328333 }
329334 _ => { }
330335 }
331- self . add_arg_with_token ( SepToken :: Pipe , self . iter . span ( ) ) ;
336+ self . add_arg_with_token ( SepToken :: Pipe , self . iter . span ( ) ) ?;
337+ Ok ( ( ) )
332338 }
333339
334- fn scan_redirect_out ( & mut self , fd : i32 ) {
340+ fn scan_redirect_out ( & mut self , fd : i32 ) -> syn :: Result < ( ) > {
335341 let append = self . check_append ( ) ;
336342 self . set_redirect (
337343 self . iter . span ( ) ,
@@ -340,68 +346,70 @@ impl Lexer {
340346 } else {
341347 RedirectFd :: Stderr { append }
342348 } ,
343- ) ;
349+ ) ? ;
344350 if let Some ( TokenTree :: Punct ( p) ) = self . iter . peek_no_gap ( )
345351 && p. as_char ( ) == '&'
346352 {
347353 if append {
348- abort ! ( p. span( ) , "raw fd not allowed for append redirection" ) ;
354+ bail ! ( p. span( ) , "raw fd not allowed for append redirection" ) ;
349355 }
350356 self . iter . next ( ) ;
351357 if let Some ( TokenTree :: Literal ( lit) ) = self . iter . peek_no_gap ( ) {
352358 let s = lit. to_string ( ) ;
353359 if s. starts_with ( '\"' ) || s. starts_with ( 'r' ) {
354- abort ! ( lit. span( ) , "invalid literal string after &" ) ;
360+ bail ! ( lit. span( ) , "invalid literal string after &" ) ;
355361 }
356362 if & s == "1" {
357363 self . args . push ( ParseArg :: RedirectFd ( fd, 1 ) ) ;
358364 } else if & s == "2" {
359365 self . args . push ( ParseArg :: RedirectFd ( fd, 2 ) ) ;
360366 } else {
361- abort ! ( lit. span( ) , "Only &1 or &2 is supported" ) ;
367+ bail ! ( lit. span( ) , "Only &1 or &2 is supported" ) ;
362368 }
363369 self . last_redirect = None ;
364370 self . iter . next ( ) ;
365371 } else {
366- abort ! ( self . iter. span( ) , "expect &1 or &2" ) ;
372+ bail ! ( self . iter. span( ) , "expect &1 or &2" ) ;
367373 }
368374 }
375+ Ok ( ( ) )
369376 }
370377
371- fn scan_ampersand ( & mut self ) {
378+ fn scan_ampersand ( & mut self ) -> syn :: Result < ( ) > {
372379 if let Some ( tt) = self . iter . peek_no_gap ( ) {
373380 if let TokenTree :: Punct ( p) = tt {
374381 let span = p. span ( ) ;
375382 if p. as_char ( ) == '>' {
376383 self . iter . next ( ) ;
377384 let append = self . check_append ( ) ;
378- self . set_redirect ( span, RedirectFd :: StdoutErr { append } ) ;
385+ self . set_redirect ( span, RedirectFd :: StdoutErr { append } ) ? ;
379386 } else {
380- abort ! ( span, "invalid punctuation" ) ;
387+ bail ! ( span, "invalid punctuation" ) ;
381388 }
382389 } else {
383- abort ! ( tt. span( ) , "invalid format after '&'" ) ;
390+ bail ! ( tt. span( ) , "invalid format after '&'" ) ;
384391 }
385392 } else if self . last_redirect . is_some ( ) {
386- abort ! (
393+ bail ! (
387394 self . iter. span( ) ,
388395 "wrong redirection format: no spacing permitted before '&'"
389396 ) ;
390397 } else if self . iter . peek ( ) . is_some ( ) {
391- abort ! ( self . iter. span( ) , "invalid spacing after '&'" ) ;
398+ bail ! ( self . iter. span( ) , "invalid spacing after '&'" ) ;
392399 } else {
393- abort ! ( self . iter. span( ) , "invalid '&' at the end" ) ;
400+ bail ! ( self . iter. span( ) , "invalid '&' at the end" ) ;
394401 }
402+ Ok ( ( ) )
395403 }
396404
397- fn scan_dollar ( & mut self ) {
405+ fn scan_dollar ( & mut self ) -> syn :: Result < ( ) > {
398406 let peek_no_gap = self . iter . peek_no_gap ( ) . map ( |tt| tt. to_owned ( ) ) ;
399407 // let peek_no_gap = None;
400408 if let Some ( TokenTree :: Ident ( var) ) = peek_no_gap {
401409 self . extend_last_arg ( quote ! ( #var. as_os_str( ) ) ) ;
402410 } else if let Some ( TokenTree :: Group ( g) ) = peek_no_gap {
403411 if g. delimiter ( ) != Delimiter :: Brace && g. delimiter ( ) != Delimiter :: Bracket {
404- abort ! (
412+ bail ! (
405413 g. span( ) ,
406414 "invalid grouping: found {:?}, only \" brace/bracket\" is allowed" ,
407415 format!( "{:?}" , g. delimiter( ) ) . to_lowercase( )
@@ -412,13 +420,13 @@ impl Lexer {
412420 let span = tt. span ( ) ;
413421 if let TokenTree :: Ident ( ref var) = tt {
414422 if found_var {
415- abort ! ( span, "more than one variable in grouping" ) ;
423+ bail ! ( span, "more than one variable in grouping" ) ;
416424 }
417425 if g. delimiter ( ) == Delimiter :: Brace {
418426 self . extend_last_arg ( quote ! ( #var. as_os_str( ) ) ) ;
419427 } else {
420428 if !self . last_arg_str . is_empty ( ) {
421- abort ! (
429+ bail ! (
422430 span,
423431 "vector variable cannot have content immediately before it"
424432 ) ;
@@ -427,13 +435,14 @@ impl Lexer {
427435 }
428436 found_var = true ;
429437 } else {
430- abort ! ( span, "invalid grouping: extra tokens" ) ;
438+ bail ! ( span, "invalid grouping: extra tokens" ) ;
431439 }
432440 }
433441 } else {
434- abort ! ( self . iter. span( ) , "invalid token after $" ) ;
442+ bail ! ( self . iter. span( ) , "invalid token after $" ) ;
435443 }
436444 self . iter . next ( ) ;
445+ Ok ( ( ) )
437446 }
438447
439448 fn check_append ( & mut self ) -> bool {
0 commit comments