1
- use proc_macro:: Span ;
1
+ use proc_macro:: { TokenTree , Span , TokenStream as TokenStream1 } ;
2
2
use proc_macro2:: TokenStream ;
3
3
use pyo3:: { prelude:: * , types:: PyTraceback , Bound , IntoPyObject , PyErr , PyResult , PyTypeInfo , Python } ;
4
4
use quote:: { quote, quote_spanned} ;
@@ -16,7 +16,7 @@ pub fn compile_error_msg(py: Python, error: PyErr, tokens: TokenStream) -> Token
16
16
let line: Option < usize > = value. getattr ( "lineno" ) . ok ( ) . and_then ( |x| x. extract ( ) . ok ( ) ) ;
17
17
let msg: Option < String > = value. getattr ( "msg" ) . ok ( ) . and_then ( |x| x. extract ( ) . ok ( ) ) ;
18
18
if let ( Some ( line) , Some ( msg) ) = ( line, msg) {
19
- if let Some ( spans) = spans_for_line ( tokens. clone ( ) , line) {
19
+ if let Some ( spans) = spans_for_line ( tokens. clone ( ) . into ( ) , line) {
20
20
return compile_error ( spans, format ! ( "python: {msg}" ) ) ;
21
21
}
22
22
}
@@ -26,7 +26,7 @@ pub fn compile_error_msg(py: Python, error: PyErr, tokens: TokenStream) -> Token
26
26
if let Ok ( ( file, line) ) = get_traceback_info ( tb) {
27
27
if file == Span :: call_site ( ) . file ( ) {
28
28
if let Ok ( msg) = value. str ( ) {
29
- if let Some ( spans) = spans_for_line ( tokens, line) {
29
+ if let Some ( spans) = spans_for_line ( tokens. into ( ) , line) {
30
30
return compile_error ( spans, format ! ( "python: {msg}" ) ) ;
31
31
}
32
32
}
@@ -46,18 +46,28 @@ fn get_traceback_info(tb: &Bound<'_, PyTraceback>) -> PyResult<(String, usize)>
46
46
Ok ( ( file, line) )
47
47
}
48
48
49
- /// Get the first and last span for a specific line of input from a TokenStream.
50
- fn spans_for_line ( input : TokenStream , line : usize ) -> Option < ( Span , Span ) > {
51
- let mut spans = input
52
- . into_iter ( )
53
- . map ( |x| x. span ( ) . unwrap ( ) )
54
- . skip_while ( |span| span. start ( ) . line ( ) < line)
55
- . take_while ( |span| span. start ( ) . line ( ) == line) ;
56
-
57
- let first = spans. next ( ) ?;
58
- let last = spans. last ( ) . unwrap_or ( first) ;
49
+ fn for_all_spans ( input : TokenStream1 , f : & mut impl FnMut ( Span ) ) {
50
+ for token in input {
51
+ match token {
52
+ TokenTree :: Group ( group) => {
53
+ f ( group. span_open ( ) ) ;
54
+ for_all_spans ( group. stream ( ) , f) ;
55
+ f ( group. span_close ( ) ) ;
56
+ }
57
+ _ => f ( token. span ( ) ) ,
58
+ }
59
+ }
60
+ }
59
61
60
- Some ( ( first, last) )
62
+ /// Get the first and last span for a specific line of input from a TokenStream.
63
+ fn spans_for_line ( input : TokenStream1 , line : usize ) -> Option < ( Span , Span ) > {
64
+ let mut spans = None ;
65
+ for_all_spans ( input, & mut |span| {
66
+ if span. start ( ) . line ( ) == line {
67
+ spans. get_or_insert ( ( span, span) ) . 1 = span;
68
+ }
69
+ } ) ;
70
+ spans
61
71
}
62
72
63
73
/// Create a compile_error!{} using two spans that mark the start and end of the error.
0 commit comments