@@ -50,6 +50,7 @@ mod diagnostic;
50
50
pub use diagnostic:: { Diagnostic , Level } ;
51
51
52
52
use std:: { ascii, fmt, iter} ;
53
+ use std:: rc:: Rc ;
53
54
use std:: str:: FromStr ;
54
55
55
56
use syntax:: ast;
@@ -58,7 +59,7 @@ use syntax::parse::{self, token};
58
59
use syntax:: symbol:: Symbol ;
59
60
use syntax:: tokenstream;
60
61
use syntax_pos:: DUMMY_SP ;
61
- use syntax_pos:: SyntaxContext ;
62
+ use syntax_pos:: { FileMap , Pos , SyntaxContext } ;
62
63
use syntax_pos:: hygiene:: Mark ;
63
64
64
65
/// The main type provided by this crate, representing an abstract stream of
@@ -173,7 +174,7 @@ impl TokenStream {
173
174
174
175
/// A region of source code, along with macro expansion information.
175
176
#[ unstable( feature = "proc_macro" , issue = "38356" ) ]
176
- #[ derive( Copy , Clone , Debug ) ]
177
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
177
178
pub struct Span ( syntax_pos:: Span ) ;
178
179
179
180
#[ unstable( feature = "proc_macro" , issue = "38356" ) ]
@@ -211,12 +212,132 @@ impl Span {
211
212
:: __internal:: with_sess ( |( _, mark) | Span ( mark. expn_info ( ) . unwrap ( ) . call_site ) )
212
213
}
213
214
215
+ /// The original source file into which this span points.
216
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
217
+ pub fn source_file ( & self ) -> SourceFile {
218
+ SourceFile {
219
+ filemap : __internal:: lookup_char_pos ( self . 0 . lo ( ) ) . file ,
220
+ }
221
+ }
222
+
223
+ /// Get the starting line/column in the source file for this span.
224
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
225
+ pub fn start ( & self ) -> LineColumn {
226
+ let loc = __internal:: lookup_char_pos ( self . 0 . lo ( ) ) ;
227
+ LineColumn {
228
+ line : loc. line ,
229
+ column : loc. col . to_usize ( )
230
+ }
231
+ }
232
+
233
+ /// Get the ending line/column in the source file for this span.
234
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
235
+ pub fn end ( & self ) -> LineColumn {
236
+ let loc = __internal:: lookup_char_pos ( self . 0 . hi ( ) ) ;
237
+ LineColumn {
238
+ line : loc. line ,
239
+ column : loc. col . to_usize ( )
240
+ }
241
+ }
242
+
243
+ /// Create a new span encompassing `self` and `other`.
244
+ ///
245
+ /// Returns `None` if `self` and `other` are from different files.
246
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
247
+ pub fn join ( & self , other : Span ) -> Option < Span > {
248
+ let self_loc = __internal:: lookup_char_pos ( self . 0 . lo ( ) ) ;
249
+ let other_loc = __internal:: lookup_char_pos ( self . 0 . lo ( ) ) ;
250
+
251
+ if self_loc. file . name != other_loc. file . name { return None }
252
+
253
+ Some ( Span ( self . 0 . to ( other. 0 ) ) )
254
+ }
255
+
214
256
diagnostic_method ! ( error, Level :: Error ) ;
215
257
diagnostic_method ! ( warning, Level :: Warning ) ;
216
258
diagnostic_method ! ( note, Level :: Note ) ;
217
259
diagnostic_method ! ( help, Level :: Help ) ;
218
260
}
219
261
262
+ /// A line-column pair representing the start or end of a `Span`.
263
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
264
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
265
+ pub struct LineColumn {
266
+ /// The 1-indexed line in the source file on which the span starts or ends (inclusive).
267
+ line : usize ,
268
+ /// The 0-indexed column (in UTF-8 characters) in the source file on which
269
+ /// the span starts or ends (inclusive).
270
+ column : usize
271
+ }
272
+
273
+ /// The source file of a given `Span`.
274
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
275
+ #[ derive( Clone ) ]
276
+ pub struct SourceFile {
277
+ filemap : Rc < FileMap > ,
278
+ }
279
+
280
+ impl SourceFile {
281
+ /// Get the path to this source file as a string.
282
+ ///
283
+ /// ### Note
284
+ /// If the code span associated with this `SourceFile` was generated by an external macro, this
285
+ /// may not be an actual path on the filesystem. Use [`is_real`] to check.
286
+ ///
287
+ /// Also note that even if `is_real` returns `true`, if `-Z remap-path-prefix-*` was passed on
288
+ /// the command line, the path as given may not actually be valid.
289
+ ///
290
+ /// [`is_real`]: #method.is_real
291
+ # [ unstable( feature = "proc_macro" , issue = "38356" ) ]
292
+ pub fn as_str ( & self ) -> & str {
293
+ & self . filemap . name
294
+ }
295
+
296
+ /// Returns `true` if this source file is a real source file, and not generated by an external
297
+ /// macro's expansion.
298
+ # [ unstable( feature = "proc_macro" , issue = "38356" ) ]
299
+ pub fn is_real ( & self ) -> bool {
300
+ // This is a hack until intercrate spans are implemented and we can have real source files
301
+ // for spans generated in external macros.
302
+ // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368
303
+ self . filemap . is_real_file ( )
304
+ }
305
+ }
306
+
307
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
308
+ impl AsRef < str > for SourceFile {
309
+ fn as_ref ( & self ) -> & str {
310
+ self . as_str ( )
311
+ }
312
+ }
313
+
314
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
315
+ impl fmt:: Debug for SourceFile {
316
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
317
+ f. debug_struct ( "SourceFile" )
318
+ . field ( "path" , & self . as_str ( ) )
319
+ . field ( "is_real" , & self . is_real ( ) )
320
+ . finish ( )
321
+ }
322
+ }
323
+
324
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
325
+ impl PartialEq for SourceFile {
326
+ fn eq ( & self , other : & Self ) -> bool {
327
+ Rc :: ptr_eq ( & self . filemap , & other. filemap )
328
+ }
329
+ }
330
+
331
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
332
+ impl Eq for SourceFile { }
333
+
334
+ #[ unstable( feature = "proc_macro" , issue = "38356" ) ]
335
+ impl PartialEq < str > for SourceFile {
336
+ fn eq ( & self , other : & str ) -> bool {
337
+ self . as_ref ( ) == other
338
+ }
339
+ }
340
+
220
341
/// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
221
342
#[ unstable( feature = "proc_macro" , issue = "38356" ) ]
222
343
#[ derive( Clone , Debug ) ]
@@ -618,10 +739,14 @@ pub mod __internal {
618
739
use syntax:: parse:: { self , ParseSess } ;
619
740
use syntax:: parse:: token:: { self , Token } ;
620
741
use syntax:: tokenstream;
621
- use syntax_pos:: DUMMY_SP ;
742
+ use syntax_pos:: { BytePos , Loc , DUMMY_SP } ;
622
743
623
744
use super :: { TokenStream , LexError } ;
624
745
746
+ pub fn lookup_char_pos ( pos : BytePos ) -> Loc {
747
+ with_sess ( |( sess, _) | sess. codemap ( ) . lookup_char_pos ( pos) )
748
+ }
749
+
625
750
pub fn new_token_stream ( item : P < ast:: Item > ) -> TokenStream {
626
751
let token = Token :: interpolated ( token:: NtItem ( item) ) ;
627
752
TokenStream ( tokenstream:: TokenTree :: Token ( DUMMY_SP , token) . into ( ) )
0 commit comments