@@ -50,6 +50,7 @@ mod diagnostic;
5050pub use diagnostic:: { Diagnostic , Level } ;
5151
5252use std:: { ascii, fmt, iter} ;
53+ use std:: rc:: Rc ;
5354use std:: str:: FromStr ;
5455
5556use syntax:: ast;
@@ -58,7 +59,7 @@ use syntax::parse::{self, token};
5859use syntax:: symbol:: Symbol ;
5960use syntax:: tokenstream;
6061use syntax_pos:: DUMMY_SP ;
61- use syntax_pos:: SyntaxContext ;
62+ use syntax_pos:: { FileMap , Pos , SyntaxContext } ;
6263use syntax_pos:: hygiene:: Mark ;
6364
6465/// The main type provided by this crate, representing an abstract stream of
@@ -173,7 +174,7 @@ impl TokenStream {
173174
174175/// A region of source code, along with macro expansion information.
175176#[ unstable( feature = "proc_macro" , issue = "38356" ) ]
176- #[ derive( Copy , Clone , Debug ) ]
177+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
177178pub struct Span ( syntax_pos:: Span ) ;
178179
179180#[ unstable( feature = "proc_macro" , issue = "38356" ) ]
@@ -211,12 +212,132 @@ impl Span {
211212 :: __internal:: with_sess ( |( _, mark) | Span ( mark. expn_info ( ) . unwrap ( ) . call_site ) )
212213 }
213214
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+
214256 diagnostic_method ! ( error, Level :: Error ) ;
215257 diagnostic_method ! ( warning, Level :: Warning ) ;
216258 diagnostic_method ! ( note, Level :: Note ) ;
217259 diagnostic_method ! ( help, Level :: Help ) ;
218260}
219261
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+
220341/// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
221342#[ unstable( feature = "proc_macro" , issue = "38356" ) ]
222343#[ derive( Clone , Debug ) ]
@@ -618,10 +739,14 @@ pub mod __internal {
618739 use syntax:: parse:: { self , ParseSess } ;
619740 use syntax:: parse:: token:: { self , Token } ;
620741 use syntax:: tokenstream;
621- use syntax_pos:: DUMMY_SP ;
742+ use syntax_pos:: { BytePos , Loc , DUMMY_SP } ;
622743
623744 use super :: { TokenStream , LexError } ;
624745
746+ pub fn lookup_char_pos ( pos : BytePos ) -> Loc {
747+ with_sess ( |( sess, _) | sess. codemap ( ) . lookup_char_pos ( pos) )
748+ }
749+
625750 pub fn new_token_stream ( item : P < ast:: Item > ) -> TokenStream {
626751 let token = Token :: interpolated ( token:: NtItem ( item) ) ;
627752 TokenStream ( tokenstream:: TokenTree :: Token ( DUMMY_SP , token) . into ( ) )
0 commit comments