1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! A support library for macro authors when defining new macros.
13 //! This library, provided by the standard distribution, provides the types
14 //! consumed in the interfaces of procedurally defined macro definitions.
15 //! Currently the primary use of this crate is to provide the ability to define
16 //! new custom derive modes through `#[proc_macro_derive]`.
18 //! Note that this crate is intentionally very bare-bones currently. The main
19 //! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
20 //! implementations, indicating that it can only go to and come from a string.
21 //! This functionality is intended to be expanded over time as more surface
22 //! area for macro authors is stabilized.
24 //! See [the book](../book/first-edition/procedural-macros.html) for more.
26 #![stable(feature = "proc_macro_lib", since = "1.15.0")]
28 #![deny(missing_docs)]
29 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
30 html_favicon_url
= "https://doc.rust-lang.org/favicon.ico",
31 html_root_url
= "https://doc.rust-lang.org/nightly/",
32 html_playground_url
= "https://play.rust-lang.org/",
33 issue_tracker_base_url
= "https://github.com/rust-lang/rust/issues/",
34 test(no_crate_inject
, attr(deny(warnings
))),
35 test(attr(allow(dead_code
, deprecated
, unused_variables
, unused_mut
))))]
37 #![cfg_attr(stage0, feature(i128_type))]
38 #![feature(rustc_private)]
39 #![feature(staged_api)]
40 #![feature(lang_items)]
41 #![feature(optin_builtin_traits)]
44 extern crate syntax_pos
;
45 extern crate rustc_errors
;
46 extern crate rustc_data_structures
;
50 #[unstable(feature = "proc_macro", issue = "38356")]
51 pub use diagnostic
::{Diagnostic, Level}
;
53 use std
::{ascii, fmt, iter}
;
54 use rustc_data_structures
::sync
::Lrc
;
55 use std
::str::FromStr
;
58 use syntax
::errors
::DiagnosticBuilder
;
59 use syntax
::parse
::{self, token}
;
60 use syntax
::symbol
::Symbol
;
61 use syntax
::tokenstream
;
62 use syntax_pos
::DUMMY_SP
;
63 use syntax_pos
::{FileMap, Pos, SyntaxContext, FileName}
;
64 use syntax_pos
::hygiene
::Mark
;
66 /// The main type provided by this crate, representing an abstract stream of
69 /// This is both the input and output of `#[proc_macro_derive]` definitions.
70 /// Currently it's required to be a list of valid Rust items, but this
71 /// restriction may be lifted in the future.
73 /// The API of this type is intentionally bare-bones, but it'll be expanded over
75 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
76 #[derive(Clone, Debug)]
77 pub struct TokenStream(tokenstream
::TokenStream
);
79 /// Error returned from `TokenStream::from_str`.
80 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
86 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
87 impl FromStr
for TokenStream
{
90 fn from_str(src
: &str) -> Result
<TokenStream
, LexError
> {
91 __internal
::with_sess(|(sess
, mark
)| {
92 let src
= src
.to_string();
93 let name
= FileName
::ProcMacroSourceCode
;
94 let expn_info
= mark
.expn_info().unwrap();
95 let call_site
= expn_info
.call_site
;
96 // notify the expansion info that it is unhygienic
97 let mark
= Mark
::fresh(mark
);
98 mark
.set_expn_info(expn_info
);
99 let span
= call_site
.with_ctxt(SyntaxContext
::empty().apply_mark(mark
));
100 let stream
= parse
::parse_stream_from_source_str(name
, src
, sess
, Some(span
));
101 Ok(__internal
::token_stream_wrap(stream
))
106 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
107 impl fmt
::Display
for TokenStream
{
108 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
113 /// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input.
114 /// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs
115 /// the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`.
117 /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
118 /// To quote `$` itself, use `$$`.
119 #[unstable(feature = "proc_macro", issue = "38356")]
121 macro_rules
! quote { () => {}
}
123 #[unstable(feature = "proc_macro_internals", issue = "27812")]
127 #[unstable(feature = "proc_macro", issue = "38356")]
128 impl From
<TokenTree
> for TokenStream
{
129 fn from(tree
: TokenTree
) -> TokenStream
{
130 TokenStream(tree
.to_internal())
134 #[unstable(feature = "proc_macro", issue = "38356")]
135 impl From
<TokenNode
> for TokenStream
{
136 fn from(kind
: TokenNode
) -> TokenStream
{
137 TokenTree
::from(kind
).into()
141 #[unstable(feature = "proc_macro", issue = "38356")]
142 impl<T
: Into
<TokenStream
>> iter
::FromIterator
<T
> for TokenStream
{
143 fn from_iter
<I
: IntoIterator
<Item
= T
>>(streams
: I
) -> Self {
144 let mut builder
= tokenstream
::TokenStreamBuilder
::new();
145 for stream
in streams
{
146 builder
.push(stream
.into().0);
148 TokenStream(builder
.build())
152 #[unstable(feature = "proc_macro", issue = "38356")]
153 impl IntoIterator
for TokenStream
{
154 type Item
= TokenTree
;
155 type IntoIter
= TokenTreeIter
;
157 fn into_iter(self) -> TokenTreeIter
{
158 TokenTreeIter { cursor: self.0.trees(), stack: Vec::new() }
163 /// Returns an empty `TokenStream`.
164 #[unstable(feature = "proc_macro", issue = "38356")]
165 pub fn empty() -> TokenStream
{
166 TokenStream(tokenstream
::TokenStream
::empty())
169 /// Checks if this `TokenStream` is empty.
170 #[unstable(feature = "proc_macro", issue = "38356")]
171 pub fn is_empty(&self) -> bool
{
176 /// A region of source code, along with macro expansion information.
177 #[unstable(feature = "proc_macro", issue = "38356")]
178 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
179 pub struct Span(syntax_pos
::Span
);
182 /// A span that resolves at the macro definition site.
183 #[unstable(feature = "proc_macro", issue = "38356")]
184 pub fn def_site() -> Span
{
185 ::__internal
::with_sess(|(_
, mark
)| {
186 let call_site
= mark
.expn_info().unwrap().call_site
;
187 Span(call_site
.with_ctxt(SyntaxContext
::empty().apply_mark(mark
)))
192 /// Quote a `Span` into a `TokenStream`.
193 /// This is needed to implement a custom quoter.
194 #[unstable(feature = "proc_macro", issue = "38356")]
195 pub fn quote_span(span
: Span
) -> TokenStream
{
196 quote
::Quote
::quote(span
)
199 macro_rules
! diagnostic_method
{
200 ($name
:ident
, $level
:expr
) => (
201 /// Create a new `Diagnostic` with the given `message` at the span
203 #[unstable(feature = "proc_macro", issue = "38356")]
204 pub fn $name
<T
: Into
<String
>>(self, message
: T
) -> Diagnostic
{
205 Diagnostic
::spanned(self, $level
, message
)
211 /// The span of the invocation of the current procedural macro.
212 #[unstable(feature = "proc_macro", issue = "38356")]
213 pub fn call_site() -> Span
{
214 ::__internal
::with_sess(|(_
, mark
)| Span(mark
.expn_info().unwrap().call_site
))
217 /// The original source file into which this span points.
218 #[unstable(feature = "proc_macro", issue = "38356")]
219 pub fn source_file(&self) -> SourceFile
{
221 filemap
: __internal
::lookup_char_pos(self.0.lo()).file
,
225 /// The `Span` for the tokens in the previous macro expansion from which
226 /// `self` was generated from, if any.
227 #[unstable(feature = "proc_macro", issue = "38356")]
228 pub fn parent(&self) -> Option
<Span
> {
229 self.0.ctxt().outer().expn_info().map(|i
| Span(i
.call_site
))
232 /// The span for the origin source code that `self` was generated from. If
233 /// this `Span` wasn't generated from other macro expansions then the return
234 /// value is the same as `*self`.
235 #[unstable(feature = "proc_macro", issue = "38356")]
236 pub fn source(&self) -> Span
{
237 Span(self.0.source_callsite())
240 /// Get the starting line/column in the source file for this span.
241 #[unstable(feature = "proc_macro", issue = "38356")]
242 pub fn start(&self) -> LineColumn
{
243 let loc
= __internal
::lookup_char_pos(self.0.lo());
246 column
: loc
.col
.to_usize()
250 /// Get the ending line/column in the source file for this span.
251 #[unstable(feature = "proc_macro", issue = "38356")]
252 pub fn end(&self) -> LineColumn
{
253 let loc
= __internal
::lookup_char_pos(self.0.hi());
256 column
: loc
.col
.to_usize()
260 /// Create a new span encompassing `self` and `other`.
262 /// Returns `None` if `self` and `other` are from different files.
263 #[unstable(feature = "proc_macro", issue = "38356")]
264 pub fn join(&self, other
: Span
) -> Option
<Span
> {
265 let self_loc
= __internal
::lookup_char_pos(self.0.lo());
266 let other_loc
= __internal
::lookup_char_pos(other
.0.lo());
268 if self_loc
.file
.name
!= other_loc
.file
.name { return None }
270 Some(Span(self.0.to(other
.0)))
273 /// Creates a new span with the same line/column information as `self` but
274 /// that resolves symbols as though it were at `other`.
275 #[unstable(feature = "proc_macro", issue = "38356")]
276 pub fn resolved_at(&self, other
: Span
) -> Span
{
277 Span(self.0.with_ctxt(other
.0.ctxt()))
280 /// Creates a new span with the same name resolution behavior as `self` but
281 /// with the line/column information of `other`.
282 #[unstable(feature = "proc_macro", issue = "38356")]
283 pub fn located_at(&self, other
: Span
) -> Span
{
284 other
.resolved_at(*self)
287 diagnostic_method
!(error
, Level
::Error
);
288 diagnostic_method
!(warning
, Level
::Warning
);
289 diagnostic_method
!(note
, Level
::Note
);
290 diagnostic_method
!(help
, Level
::Help
);
293 /// A line-column pair representing the start or end of a `Span`.
294 #[unstable(feature = "proc_macro", issue = "38356")]
295 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
296 pub struct LineColumn
{
297 /// The 1-indexed line in the source file on which the span starts or ends (inclusive).
298 #[unstable(feature = "proc_macro", issue = "38356")]
300 /// The 0-indexed column (in UTF-8 characters) in the source file on which
301 /// the span starts or ends (inclusive).
302 #[unstable(feature = "proc_macro", issue = "38356")]
306 /// The source file of a given `Span`.
307 #[unstable(feature = "proc_macro", issue = "38356")]
309 pub struct SourceFile
{
310 filemap
: Lrc
<FileMap
>,
313 #[unstable(feature = "proc_macro", issue = "38356")]
314 impl !Send
for SourceFile {}
315 #[unstable(feature = "proc_macro", issue = "38356")]
316 impl !Sync
for SourceFile {}
319 /// Get the path to this source file.
322 /// If the code span associated with this `SourceFile` was generated by an external macro, this
323 /// may not be an actual path on the filesystem. Use [`is_real`] to check.
325 /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on
326 /// the command line, the path as given may not actually be valid.
328 /// [`is_real`]: #method.is_real
329 # [unstable(feature = "proc_macro", issue = "38356")]
330 pub fn path(&self) -> &FileName
{
334 /// Returns `true` if this source file is a real source file, and not generated by an external
335 /// macro's expansion.
336 # [unstable(feature = "proc_macro", issue = "38356")]
337 pub fn is_real(&self) -> bool
{
338 // This is a hack until intercrate spans are implemented and we can have real source files
339 // for spans generated in external macros.
340 // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368
341 self.filemap
.is_real_file()
345 #[unstable(feature = "proc_macro", issue = "38356")]
346 impl AsRef
<FileName
> for SourceFile
{
347 fn as_ref(&self) -> &FileName
{
352 #[unstable(feature = "proc_macro", issue = "38356")]
353 impl fmt
::Debug
for SourceFile
{
354 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
355 f
.debug_struct("SourceFile")
356 .field("path", self.path())
357 .field("is_real", &self.is_real())
362 #[unstable(feature = "proc_macro", issue = "38356")]
363 impl PartialEq
for SourceFile
{
364 fn eq(&self, other
: &Self) -> bool
{
365 Lrc
::ptr_eq(&self.filemap
, &other
.filemap
)
369 #[unstable(feature = "proc_macro", issue = "38356")]
370 impl Eq
for SourceFile {}
372 #[unstable(feature = "proc_macro", issue = "38356")]
373 impl PartialEq
<FileName
> for SourceFile
{
374 fn eq(&self, other
: &FileName
) -> bool
{
375 self.as_ref() == other
379 /// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`).
380 #[unstable(feature = "proc_macro", issue = "38356")]
381 #[derive(Clone, Debug)]
382 pub struct TokenTree
{
383 /// The `TokenTree`'s span
385 /// Description of the `TokenTree`
389 #[unstable(feature = "proc_macro", issue = "38356")]
390 impl From
<TokenNode
> for TokenTree
{
391 fn from(kind
: TokenNode
) -> TokenTree
{
392 TokenTree { span: Span::def_site(), kind: kind }
396 #[unstable(feature = "proc_macro", issue = "38356")]
397 impl fmt
::Display
for TokenTree
{
398 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
399 TokenStream
::from(self.clone()).fmt(f
)
403 /// Description of a `TokenTree`
404 #[derive(Clone, Debug)]
405 #[unstable(feature = "proc_macro", issue = "38356")]
407 /// A delimited tokenstream.
408 Group(Delimiter
, TokenStream
),
409 /// A unicode identifier.
411 /// A punctuation character (`+`, `,`, `$`, etc.).
413 /// A literal character (`'a'`), string (`"hello"`), or number (`2.3`).
417 /// Describes how a sequence of token trees is delimited.
418 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
419 #[unstable(feature = "proc_macro", issue = "38356")]
427 /// An implicit delimiter, e.g. `$var`, where $var is `...`.
431 /// An interned string.
432 #[derive(Copy, Clone, Debug)]
433 #[unstable(feature = "proc_macro", issue = "38356")]
434 pub struct Term(Symbol
);
437 /// Intern a string into a `Term`.
438 #[unstable(feature = "proc_macro", issue = "38356")]
439 pub fn intern(string
: &str) -> Term
{
440 Term(Symbol
::intern(string
))
443 /// Get a reference to the interned string.
444 #[unstable(feature = "proc_macro", issue = "38356")]
445 pub fn as_str(&self) -> &str {
446 unsafe { &*(&*self.0.as_str() as *const str) }
450 /// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace.
451 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
452 #[unstable(feature = "proc_macro", issue = "38356")]
454 /// e.g. `+` is `Alone` in `+ =`.
456 /// e.g. `+` is `Joint` in `+=`.
460 /// A literal character (`'a'`), string (`"hello"`), or number (`2.3`).
461 #[derive(Clone, Debug)]
462 #[unstable(feature = "proc_macro", issue = "38356")]
463 pub struct Literal(token
::Token
);
465 #[unstable(feature = "proc_macro", issue = "38356")]
466 impl fmt
::Display
for Literal
{
467 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
468 TokenTree { kind: TokenNode::Literal(self.clone()), span: Span(DUMMY_SP) }
.fmt(f
)
472 macro_rules
! int_literals
{
473 ($
($int_kind
:ident
),*) => {$
(
475 #[unstable(feature = "proc_macro", issue = "38356")]
476 pub fn $
int_kind(n
: $int_kind
) -> Literal
{
477 Literal
::typed_integer(n
as i128
, stringify
!($int_kind
))
484 #[unstable(feature = "proc_macro", issue = "38356")]
485 pub fn integer(n
: i128
) -> Literal
{
486 Literal(token
::Literal(token
::Lit
::Integer(Symbol
::intern(&n
.to_string())), None
))
489 int_literals
!(u8, i8, u16, i16, u32, i32, u64, i64, usize, isize);
490 fn typed_integer(n
: i128
, kind
: &'
static str) -> Literal
{
491 Literal(token
::Literal(token
::Lit
::Integer(Symbol
::intern(&n
.to_string())),
492 Some(Symbol
::intern(kind
))))
495 /// Floating point literal.
496 #[unstable(feature = "proc_macro", issue = "38356")]
497 pub fn float(n
: f64) -> Literal
{
499 panic
!("Invalid float literal {}", n
);
501 Literal(token
::Literal(token
::Lit
::Float(Symbol
::intern(&n
.to_string())), None
))
504 /// Floating point literal.
505 #[unstable(feature = "proc_macro", issue = "38356")]
506 pub fn f32(n
: f32) -> Literal
{
508 panic
!("Invalid f32 literal {}", n
);
510 Literal(token
::Literal(token
::Lit
::Float(Symbol
::intern(&n
.to_string())),
511 Some(Symbol
::intern("f32"))))
514 /// Floating point literal.
515 #[unstable(feature = "proc_macro", issue = "38356")]
516 pub fn f64(n
: f64) -> Literal
{
518 panic
!("Invalid f64 literal {}", n
);
520 Literal(token
::Literal(token
::Lit
::Float(Symbol
::intern(&n
.to_string())),
521 Some(Symbol
::intern("f64"))))
525 #[unstable(feature = "proc_macro", issue = "38356")]
526 pub fn string(string
: &str) -> Literal
{
527 let mut escaped
= String
::new();
528 for ch
in string
.chars() {
529 escaped
.extend(ch
.escape_debug());
531 Literal(token
::Literal(token
::Lit
::Str_(Symbol
::intern(&escaped
)), None
))
534 /// Character literal.
535 #[unstable(feature = "proc_macro", issue = "38356")]
536 pub fn character(ch
: char) -> Literal
{
537 let mut escaped
= String
::new();
538 escaped
.extend(ch
.escape_unicode());
539 Literal(token
::Literal(token
::Lit
::Char(Symbol
::intern(&escaped
)), None
))
542 /// Byte string literal.
543 #[unstable(feature = "proc_macro", issue = "38356")]
544 pub fn byte_string(bytes
: &[u8]) -> Literal
{
545 let string
= bytes
.iter().cloned().flat_map(ascii
::escape_default
)
546 .map(Into
::<char>::into
).collect
::<String
>();
547 Literal(token
::Literal(token
::Lit
::ByteStr(Symbol
::intern(&string
)), None
))
551 /// An iterator over `TokenTree`s.
553 #[unstable(feature = "proc_macro", issue = "38356")]
554 pub struct TokenTreeIter
{
555 cursor
: tokenstream
::Cursor
,
556 stack
: Vec
<TokenTree
>,
559 #[unstable(feature = "proc_macro", issue = "38356")]
560 impl Iterator
for TokenTreeIter
{
561 type Item
= TokenTree
;
563 fn next(&mut self) -> Option
<TokenTree
> {
565 let tree
= self.stack
.pop().or_else(|| {
566 let next
= self.cursor
.next_as_stream()?
;
567 Some(TokenTree
::from_internal(next
, &mut self.stack
))
569 if tree
.span
.0 == DUMMY_SP
{
570 if let TokenNode
::Group(Delimiter
::None
, stream
) = tree
.kind
{
571 self.cursor
.insert(stream
.0);
581 fn from_internal(delim
: token
::DelimToken
) -> Delimiter
{
583 token
::Paren
=> Delimiter
::Parenthesis
,
584 token
::Brace
=> Delimiter
::Brace
,
585 token
::Bracket
=> Delimiter
::Bracket
,
586 token
::NoDelim
=> Delimiter
::None
,
590 fn to_internal(self) -> token
::DelimToken
{
592 Delimiter
::Parenthesis
=> token
::Paren
,
593 Delimiter
::Brace
=> token
::Brace
,
594 Delimiter
::Bracket
=> token
::Bracket
,
595 Delimiter
::None
=> token
::NoDelim
,
601 fn from_internal(stream
: tokenstream
::TokenStream
, stack
: &mut Vec
<TokenTree
>)
603 use syntax
::parse
::token
::*;
605 let (tree
, is_joint
) = stream
.as_tree();
606 let (span
, token
) = match tree
{
607 tokenstream
::TokenTree
::Token(span
, token
) => (span
, token
),
608 tokenstream
::TokenTree
::Delimited(span
, delimed
) => {
609 let delimiter
= Delimiter
::from_internal(delimed
.delim
);
612 kind
: TokenNode
::Group(delimiter
, TokenStream(delimed
.tts
.into())),
617 let op_kind
= if is_joint { Spacing::Joint }
else { Spacing::Alone }
;
619 ($e
:expr
) => (TokenTree { span: Span(span), kind: $e }
)
622 ($a
:expr
) => (TokenNode
::Op($a
, op_kind
));
623 ($a
:expr
, $b
:expr
) => ({
624 stack
.push(tt
!(TokenNode
::Op($b
, op_kind
).into()));
625 TokenNode
::Op($a
, Spacing
::Joint
)
627 ($a
:expr
, $b
:expr
, $c
:expr
) => ({
628 stack
.push(tt
!(TokenNode
::Op($c
, op_kind
)));
629 stack
.push(tt
!(TokenNode
::Op($b
, Spacing
::Joint
)));
630 TokenNode
::Op($a
, Spacing
::Joint
)
634 let kind
= match token
{
638 EqEq
=> op
!('
='
, '
='
),
642 AndAnd
=> op
!('
&'
, '
&'
),
643 OrOr
=> op
!('
|'
, '
|'
),
646 BinOp(Plus
) => op
!('
+'
),
647 BinOp(Minus
) => op
!('
-'
),
648 BinOp(Star
) => op
!('
*'
),
649 BinOp(Slash
) => op
!('
/'
),
650 BinOp(Percent
) => op
!('
%'
),
651 BinOp(Caret
) => op
!('
^'),
652 BinOp(And
) => op
!('
&'
),
653 BinOp(Or
) => op
!('
|'
),
654 BinOp(Shl
) => op
!('
<'
, '
<'
),
655 BinOp(Shr
) => op
!('
>'
, '
>'
),
656 BinOpEq(Plus
) => op
!('
+'
, '
='
),
657 BinOpEq(Minus
) => op
!('
-'
, '
='
),
658 BinOpEq(Star
) => op
!('
*'
, '
='
),
659 BinOpEq(Slash
) => op
!('
/'
, '
='
),
660 BinOpEq(Percent
) => op
!('
%'
, '
='
),
661 BinOpEq(Caret
) => op
!('
^', '
='
),
662 BinOpEq(And
) => op
!('
&'
, '
='
),
663 BinOpEq(Or
) => op
!('
|'
, '
='
),
664 BinOpEq(Shl
) => op
!('
<'
, '
<'
, '
='
),
665 BinOpEq(Shr
) => op
!('
>'
, '
>'
, '
='
),
668 DotDot
=> op
!('
.'
, '
.'
),
669 DotDotDot
=> op
!('
.'
, '
.'
, '
.'
),
670 DotDotEq
=> op
!('
.'
, '
.'
, '
='
),
674 ModSep
=> op
!('
:'
, '
:'
),
675 RArrow
=> op
!('
-'
, '
>'
),
676 LArrow
=> op
!('
<'
, '
-'
),
677 FatArrow
=> op
!('
='
, '
>'
),
680 Question
=> op
!('?'
),
682 Ident(ident
, false) | Lifetime(ident
) => TokenNode
::Term(Term(ident
.name
)),
683 Ident(ident
, true) => TokenNode
::Term(Term(Symbol
::intern(&format
!("r#{}", ident
)))),
684 Literal(..) => TokenNode
::Literal(self::Literal(token
)),
687 tt
!(TokenNode
::Term(Term
::intern("doc"))),
689 tt
!(TokenNode
::Literal(self::Literal(Literal(Lit
::Str_(c
), None
)))),
690 ].into_iter().collect();
691 stack
.push(tt
!(TokenNode
::Group(Delimiter
::Bracket
, stream
)));
696 __internal
::with_sess(|(sess
, _
)| {
697 let tts
= token
.interpolated_to_tokenstream(sess
, span
);
698 TokenNode
::Group(Delimiter
::None
, TokenStream(tts
))
702 DotEq
=> op
!('
.'
, '
='
),
703 OpenDelim(..) | CloseDelim(..) => unreachable
!(),
704 Whitespace
| Comment
| Shebang(..) | Eof
=> unreachable
!(),
707 TokenTree { span: Span(span), kind: kind }
710 fn to_internal(self) -> tokenstream
::TokenStream
{
711 use syntax
::parse
::token
::*;
712 use syntax
::tokenstream
::{TokenTree, Delimited}
;
714 let (op
, kind
) = match self.kind
{
715 TokenNode
::Op(op
, kind
) => (op
, kind
),
716 TokenNode
::Group(delimiter
, tokens
) => {
717 return TokenTree
::Delimited(self.span
.0, Delimited
{
718 delim
: delimiter
.to_internal(),
719 tts
: tokens
.0.into
(),
722 TokenNode
::Term(symbol
) => {
723 let ident
= ast
::Ident { name: symbol.0, ctxt: self.span.0.ctxt() }
;
724 let sym_str
= symbol
.0.as_str();
726 if sym_str
.starts_with("'") { Lifetime(ident) }
727 else if sym_str
.starts_with("r#") {
728 let name
= Symbol
::intern(&sym_str
[2..]);
729 let ident
= ast
::Ident { name, ctxt: self.span.0.ctxt() }
;
731 } else { Ident(ident, false) }
;
732 return TokenTree
::Token(self.span
.0, token
).into();
734 TokenNode
::Literal(self::Literal(Literal(Lit
::Integer(ref a
), b
)))
735 if a
.as_str().starts_with("-") =>
737 let minus
= BinOp(BinOpToken
::Minus
);
738 let integer
= Symbol
::intern(&a
.as_str()[1..]);
739 let integer
= Literal(Lit
::Integer(integer
), b
);
740 let a
= TokenTree
::Token(self.span
.0, minus
);
741 let b
= TokenTree
::Token(self.span
.0, integer
);
742 return vec
![a
, b
].into_iter().collect()
744 TokenNode
::Literal(self::Literal(Literal(Lit
::Float(ref a
), b
)))
745 if a
.as_str().starts_with("-") =>
747 let minus
= BinOp(BinOpToken
::Minus
);
748 let float
= Symbol
::intern(&a
.as_str()[1..]);
749 let float
= Literal(Lit
::Float(float
), b
);
750 let a
= TokenTree
::Token(self.span
.0, minus
);
751 let b
= TokenTree
::Token(self.span
.0, float
);
752 return vec
![a
, b
].into_iter().collect()
754 TokenNode
::Literal(token
) => {
755 return TokenTree
::Token(self.span
.0, token
.0).into()
759 let token
= match op
{
769 '
%'
=> BinOp(Percent
),
781 _
=> panic
!("unsupported character {}", op
),
784 let tree
= TokenTree
::Token(self.span
.0, token
);
786 Spacing
::Alone
=> tree
.into(),
787 Spacing
::Joint
=> tree
.joint(),
792 /// Permanently unstable internal implementation details of this crate. This
793 /// should not be used.
795 /// These methods are used by the rest of the compiler to generate instances of
796 /// `TokenStream` to hand to macro definitions, as well as consume the output.
798 /// Note that this module is also intentionally separate from the rest of the
799 /// crate. This allows the `#[unstable]` directive below to naturally apply to
800 /// all of the contents.
801 #[unstable(feature = "proc_macro_internals", issue = "27812")]
804 pub use quote
::{LiteralKind, Quoter, unquote}
;
809 use syntax
::ext
::base
::ExtCtxt
;
810 use syntax
::ext
::hygiene
::Mark
;
812 use syntax
::parse
::{self, ParseSess}
;
813 use syntax
::parse
::token
::{self, Token}
;
814 use syntax
::tokenstream
;
815 use syntax_pos
::{BytePos, Loc, DUMMY_SP}
;
817 use super::{TokenStream, LexError}
;
819 pub fn lookup_char_pos(pos
: BytePos
) -> Loc
{
820 with_sess(|(sess
, _
)| sess
.codemap().lookup_char_pos(pos
))
823 pub fn new_token_stream(item
: P
<ast
::Item
>) -> TokenStream
{
824 let token
= Token
::interpolated(token
::NtItem(item
));
825 TokenStream(tokenstream
::TokenTree
::Token(DUMMY_SP
, token
).into())
828 pub fn token_stream_wrap(inner
: tokenstream
::TokenStream
) -> TokenStream
{
832 pub fn token_stream_parse_items(stream
: TokenStream
) -> Result
<Vec
<P
<ast
::Item
>>, LexError
> {
833 with_sess(move |(sess
, _
)| {
834 let mut parser
= parse
::stream_to_parser(sess
, stream
.0);
835 let mut items
= Vec
::new();
837 while let Some(item
) = try
!(parser
.parse_item().map_err(super::parse_to_lex_err
)) {
845 pub fn token_stream_inner(stream
: TokenStream
) -> tokenstream
::TokenStream
{
850 fn register_custom_derive(&mut self,
852 expand
: fn(TokenStream
) -> TokenStream
,
853 attributes
: &[&'
static str]);
855 fn register_attr_proc_macro(&mut self,
857 expand
: fn(TokenStream
, TokenStream
) -> TokenStream
);
859 fn register_bang_proc_macro(&mut self,
861 expand
: fn(TokenStream
) -> TokenStream
);
864 // Emulate scoped_thread_local!() here essentially
866 static CURRENT_SESS
: Cell
<(*const ParseSess
, Mark
)> =
867 Cell
::new((0 as *const _
, Mark
::root()));
870 pub fn set_sess
<F
, R
>(cx
: &ExtCtxt
, f
: F
) -> R
871 where F
: FnOnce() -> R
873 struct Reset { prev: (*const ParseSess, Mark) }
875 impl Drop
for Reset
{
877 CURRENT_SESS
.with(|p
| p
.set(self.prev
));
881 CURRENT_SESS
.with(|p
| {
882 let _reset
= Reset { prev: p.get() }
;
883 p
.set((cx
.parse_sess
, cx
.current_expansion
.mark
));
888 pub fn in_sess() -> bool
890 let p
= CURRENT_SESS
.with(|p
| p
.get());
894 pub fn with_sess
<F
, R
>(f
: F
) -> R
895 where F
: FnOnce((&ParseSess
, Mark
)) -> R
897 let p
= CURRENT_SESS
.with(|p
| p
.get());
898 assert
!(!p
.0.is_null
(), "proc_macro::__internal::with_sess() called \
899 before set_parse_sess()!");
900 f(unsafe { (&*p.0, p.1) }
)
904 fn parse_to_lex_err(mut err
: DiagnosticBuilder
) -> LexError
{
906 LexError { _inner: () }