@@ -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