diff options
| author | Austin Bonander <austin.bonander@gmail.com> | 2017-08-01 18:05:08 -0700 |
|---|---|---|
| committer | Austin Bonander <austin.bonander@gmail.com> | 2017-10-05 17:00:55 -0700 |
| commit | 7be36d2a6d8855c4ca8ef7ae469f9aac8bf6e63b (patch) | |
| tree | b02699f2441b596ff5d4e0279ac65576a2a090f8 /src/libproc_macro | |
| parent | c6884b12d9298f1e0af919cb9458a0d80acb3b0a (diff) | |
| download | rust-7be36d2a6d8855c4ca8ef7ae469f9aac8bf6e63b.tar.gz rust-7be36d2a6d8855c4ca8ef7ae469f9aac8bf6e63b.zip | |
`proc_macro::Span` API improvements
Diffstat (limited to 'src/libproc_macro')
| -rw-r--r-- | src/libproc_macro/lib.rs | 131 |
1 files changed, 128 insertions, 3 deletions
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 2c540c8de8f..e6307f10c13 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -50,6 +50,7 @@ mod diagnostic; pub use diagnostic::{Diagnostic, Level}; use std::{ascii, fmt, iter}; +use std::rc::Rc; use std::str::FromStr; use syntax::ast; @@ -58,7 +59,7 @@ use syntax::parse::{self, token}; use syntax::symbol::Symbol; use syntax::tokenstream; use syntax_pos::DUMMY_SP; -use syntax_pos::SyntaxContext; +use syntax_pos::{FileMap, Pos, SyntaxContext}; use syntax_pos::hygiene::Mark; /// The main type provided by this crate, representing an abstract stream of @@ -173,7 +174,7 @@ impl TokenStream { /// A region of source code, along with macro expansion information. #[unstable(feature = "proc_macro", issue = "38356")] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Span(syntax_pos::Span); #[unstable(feature = "proc_macro", issue = "38356")] @@ -211,12 +212,132 @@ impl Span { ::__internal::with_sess(|(_, mark)| Span(mark.expn_info().unwrap().call_site)) } + /// The original source file into which this span points. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn source_file(&self) -> SourceFile { + SourceFile { + filemap: __internal::lookup_char_pos(self.0.lo()).file, + } + } + + /// Get the starting line/column in the source file for this span. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn start(&self) -> LineColumn { + let loc = __internal::lookup_char_pos(self.0.lo()); + LineColumn { + line: loc.line, + column: loc.col.to_usize() + } + } + + /// Get the ending line/column in the source file for this span. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn end(&self) -> LineColumn { + let loc = __internal::lookup_char_pos(self.0.hi()); + LineColumn { + line: loc.line, + column: loc.col.to_usize() + } + } + + /// Create a new span encompassing `self` and `other`. + /// + /// Returns `None` if `self` and `other` are from different files. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn join(&self, other: Span) -> Option<Span> { + let self_loc = __internal::lookup_char_pos(self.0.lo()); + let other_loc = __internal::lookup_char_pos(self.0.lo()); + + if self_loc.file.name != other_loc.file.name { return None } + + Some(Span(self.0.to(other.0))) + } + diagnostic_method!(error, Level::Error); diagnostic_method!(warning, Level::Warning); diagnostic_method!(note, Level::Note); diagnostic_method!(help, Level::Help); } +/// A line-column pair representing the start or end of a `Span`. +#[unstable(feature = "proc_macro", issue = "38356")] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct LineColumn { + /// The 1-indexed line in the source file on which the span starts or ends (inclusive). + line: usize, + /// The 0-indexed column (in UTF-8 characters) in the source file on which + /// the span starts or ends (inclusive). + column: usize +} + +/// The source file of a given `Span`. +#[unstable(feature = "proc_macro", issue = "38356")] +#[derive(Clone)] +pub struct SourceFile { + filemap: Rc<FileMap>, +} + +impl SourceFile { + /// Get the path to this source file as a string. + /// + /// ### Note + /// If the code span associated with this `SourceFile` was generated by an external macro, this + /// may not be an actual path on the filesystem. Use [`is_real`] to check. + /// + /// Also note that even if `is_real` returns `true`, if `-Z remap-path-prefix-*` was passed on + /// the command line, the path as given may not actually be valid. + /// + /// [`is_real`]: #method.is_real + # [unstable(feature = "proc_macro", issue = "38356")] + pub fn as_str(&self) -> &str { + &self.filemap.name + } + + /// Returns `true` if this source file is a real source file, and not generated by an external + /// macro's expansion. + # [unstable(feature = "proc_macro", issue = "38356")] + pub fn is_real(&self) -> bool { + // This is a hack until intercrate spans are implemented and we can have real source files + // for spans generated in external macros. + // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368 + self.filemap.is_real_file() + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl AsRef<str> for SourceFile { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl fmt::Debug for SourceFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SourceFile") + .field("path", &self.as_str()) + .field("is_real", &self.is_real()) + .finish() + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl PartialEq for SourceFile { + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.filemap, &other.filemap) + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl Eq for SourceFile {} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl PartialEq<str> for SourceFile { + fn eq(&self, other: &str) -> bool { + self.as_ref() == other + } +} + /// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`). #[unstable(feature = "proc_macro", issue = "38356")] #[derive(Clone, Debug)] @@ -618,10 +739,14 @@ pub mod __internal { use syntax::parse::{self, ParseSess}; use syntax::parse::token::{self, Token}; use syntax::tokenstream; - use syntax_pos::DUMMY_SP; + use syntax_pos::{BytePos, Loc, DUMMY_SP}; use super::{TokenStream, LexError}; + pub fn lookup_char_pos(pos: BytePos) -> Loc { + with_sess(|(sess, _)| sess.codemap().lookup_char_pos(pos)) + } + pub fn new_token_stream(item: P<ast::Item>) -> TokenStream { let token = Token::interpolated(token::NtItem(item)); TokenStream(tokenstream::TokenTree::Token(DUMMY_SP, token).into()) |
