284 lines
9.9 KiB
Rust
284 lines
9.9 KiB
Rust
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
|
// file at the top-level directory of this distribution and at
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
// option. This file may not be copied, modified, or distributed
|
|
// except according to those terms.
|
|
|
|
use {Delimiter, Level, Spacing, Span, __internal};
|
|
use {Group, Ident, Literal, Punct, TokenTree};
|
|
|
|
use rustc_errors as errors;
|
|
use syntax::ast;
|
|
use syntax::parse::lexer::comments;
|
|
use syntax::parse::token;
|
|
use syntax::tokenstream;
|
|
use syntax_pos::symbol::{keywords, Symbol};
|
|
|
|
impl Ident {
|
|
pub(crate) fn new_maybe_raw(string: &str, span: Span, is_raw: bool) -> Ident {
|
|
let sym = Symbol::intern(string);
|
|
if is_raw
|
|
&& (sym == keywords::Underscore.name()
|
|
|| ast::Ident::with_empty_ctxt(sym).is_path_segment_keyword())
|
|
{
|
|
panic!("`{:?}` is not a valid raw identifier", string)
|
|
}
|
|
Ident { sym, span, is_raw }
|
|
}
|
|
}
|
|
|
|
impl Delimiter {
|
|
pub(crate) fn from_internal(delim: token::DelimToken) -> Delimiter {
|
|
match delim {
|
|
token::Paren => Delimiter::Parenthesis,
|
|
token::Brace => Delimiter::Brace,
|
|
token::Bracket => Delimiter::Bracket,
|
|
token::NoDelim => Delimiter::None,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn to_internal(self) -> token::DelimToken {
|
|
match self {
|
|
Delimiter::Parenthesis => token::Paren,
|
|
Delimiter::Brace => token::Brace,
|
|
Delimiter::Bracket => token::Bracket,
|
|
Delimiter::None => token::NoDelim,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TokenTree {
|
|
pub(crate) fn from_internal(
|
|
stream: tokenstream::TokenStream,
|
|
stack: &mut Vec<TokenTree>,
|
|
) -> TokenTree {
|
|
use syntax::parse::token::*;
|
|
|
|
let (tree, is_joint) = stream.as_tree();
|
|
let (span, token) = match tree {
|
|
tokenstream::TokenTree::Token(span, token) => (span, token),
|
|
tokenstream::TokenTree::Delimited(span, delimed) => {
|
|
let delimiter = Delimiter::from_internal(delimed.delim);
|
|
let mut g = Group::new(delimiter, ::TokenStream(delimed.tts.into()));
|
|
g.set_span(Span(span));
|
|
return g.into();
|
|
}
|
|
};
|
|
|
|
let op_kind = if is_joint {
|
|
Spacing::Joint
|
|
} else {
|
|
Spacing::Alone
|
|
};
|
|
macro_rules! tt {
|
|
($e:expr) => {{
|
|
let mut x = TokenTree::from($e);
|
|
x.set_span(Span(span));
|
|
x
|
|
}};
|
|
}
|
|
macro_rules! op {
|
|
($a:expr) => {
|
|
tt!(Punct::new($a, op_kind))
|
|
};
|
|
($a:expr, $b:expr) => {{
|
|
stack.push(tt!(Punct::new($b, op_kind)));
|
|
tt!(Punct::new($a, Spacing::Joint))
|
|
}};
|
|
($a:expr, $b:expr, $c:expr) => {{
|
|
stack.push(tt!(Punct::new($c, op_kind)));
|
|
stack.push(tt!(Punct::new($b, Spacing::Joint)));
|
|
tt!(Punct::new($a, Spacing::Joint))
|
|
}};
|
|
}
|
|
|
|
match token {
|
|
Eq => op!('='),
|
|
Lt => op!('<'),
|
|
Le => op!('<', '='),
|
|
EqEq => op!('=', '='),
|
|
Ne => op!('!', '='),
|
|
Ge => op!('>', '='),
|
|
Gt => op!('>'),
|
|
AndAnd => op!('&', '&'),
|
|
OrOr => op!('|', '|'),
|
|
Not => op!('!'),
|
|
Tilde => op!('~'),
|
|
BinOp(Plus) => op!('+'),
|
|
BinOp(Minus) => op!('-'),
|
|
BinOp(Star) => op!('*'),
|
|
BinOp(Slash) => op!('/'),
|
|
BinOp(Percent) => op!('%'),
|
|
BinOp(Caret) => op!('^'),
|
|
BinOp(And) => op!('&'),
|
|
BinOp(Or) => op!('|'),
|
|
BinOp(Shl) => op!('<', '<'),
|
|
BinOp(Shr) => op!('>', '>'),
|
|
BinOpEq(Plus) => op!('+', '='),
|
|
BinOpEq(Minus) => op!('-', '='),
|
|
BinOpEq(Star) => op!('*', '='),
|
|
BinOpEq(Slash) => op!('/', '='),
|
|
BinOpEq(Percent) => op!('%', '='),
|
|
BinOpEq(Caret) => op!('^', '='),
|
|
BinOpEq(And) => op!('&', '='),
|
|
BinOpEq(Or) => op!('|', '='),
|
|
BinOpEq(Shl) => op!('<', '<', '='),
|
|
BinOpEq(Shr) => op!('>', '>', '='),
|
|
At => op!('@'),
|
|
Dot => op!('.'),
|
|
DotDot => op!('.', '.'),
|
|
DotDotDot => op!('.', '.', '.'),
|
|
DotDotEq => op!('.', '.', '='),
|
|
Comma => op!(','),
|
|
Semi => op!(';'),
|
|
Colon => op!(':'),
|
|
ModSep => op!(':', ':'),
|
|
RArrow => op!('-', '>'),
|
|
LArrow => op!('<', '-'),
|
|
FatArrow => op!('=', '>'),
|
|
Pound => op!('#'),
|
|
Dollar => op!('$'),
|
|
Question => op!('?'),
|
|
SingleQuote => op!('\''),
|
|
|
|
Ident(ident, false) => tt!(self::Ident::new(&ident.as_str(), Span(span))),
|
|
Ident(ident, true) => tt!(self::Ident::new_raw(&ident.as_str(), Span(span))),
|
|
Lifetime(ident) => {
|
|
let ident = ident.without_first_quote();
|
|
stack.push(tt!(self::Ident::new(&ident.as_str(), Span(span))));
|
|
tt!(Punct::new('\'', Spacing::Joint))
|
|
}
|
|
Literal(lit, suffix) => tt!(self::Literal {
|
|
lit,
|
|
suffix,
|
|
span: Span(span)
|
|
}),
|
|
DocComment(c) => {
|
|
let style = comments::doc_comment_style(&c.as_str());
|
|
let stripped = comments::strip_doc_comment_decoration(&c.as_str());
|
|
let stream = vec![
|
|
tt!(self::Ident::new("doc", Span(span))),
|
|
tt!(Punct::new('=', Spacing::Alone)),
|
|
tt!(self::Literal::string(&stripped)),
|
|
].into_iter()
|
|
.collect();
|
|
stack.push(tt!(Group::new(Delimiter::Bracket, stream)));
|
|
if style == ast::AttrStyle::Inner {
|
|
stack.push(tt!(Punct::new('!', Spacing::Alone)));
|
|
}
|
|
tt!(Punct::new('#', Spacing::Alone))
|
|
}
|
|
|
|
Interpolated(_) => __internal::with_sess(|sess, _| {
|
|
let tts = token.interpolated_to_tokenstream(sess, span);
|
|
tt!(Group::new(Delimiter::None, ::TokenStream(tts)))
|
|
}),
|
|
|
|
DotEq => op!('.', '='),
|
|
OpenDelim(..) | CloseDelim(..) => unreachable!(),
|
|
Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn to_internal(self) -> tokenstream::TokenStream {
|
|
use syntax::parse::token::*;
|
|
use syntax::tokenstream::{Delimited, TokenTree};
|
|
|
|
let (ch, kind, span) = match self {
|
|
self::TokenTree::Punct(tt) => (tt.as_char(), tt.spacing(), tt.span()),
|
|
self::TokenTree::Group(tt) => {
|
|
return TokenTree::Delimited(
|
|
tt.span.0,
|
|
Delimited {
|
|
delim: tt.delimiter.to_internal(),
|
|
tts: tt.stream.0.into(),
|
|
},
|
|
).into();
|
|
}
|
|
self::TokenTree::Ident(tt) => {
|
|
let token = Ident(ast::Ident::new(tt.sym, tt.span.0), tt.is_raw);
|
|
return TokenTree::Token(tt.span.0, token).into();
|
|
}
|
|
self::TokenTree::Literal(self::Literal {
|
|
lit: Lit::Integer(ref a),
|
|
suffix,
|
|
span,
|
|
})
|
|
if a.as_str().starts_with("-") =>
|
|
{
|
|
let minus = BinOp(BinOpToken::Minus);
|
|
let integer = Symbol::intern(&a.as_str()[1..]);
|
|
let integer = Literal(Lit::Integer(integer), suffix);
|
|
let a = TokenTree::Token(span.0, minus);
|
|
let b = TokenTree::Token(span.0, integer);
|
|
return vec![a, b].into_iter().collect();
|
|
}
|
|
self::TokenTree::Literal(self::Literal {
|
|
lit: Lit::Float(ref a),
|
|
suffix,
|
|
span,
|
|
})
|
|
if a.as_str().starts_with("-") =>
|
|
{
|
|
let minus = BinOp(BinOpToken::Minus);
|
|
let float = Symbol::intern(&a.as_str()[1..]);
|
|
let float = Literal(Lit::Float(float), suffix);
|
|
let a = TokenTree::Token(span.0, minus);
|
|
let b = TokenTree::Token(span.0, float);
|
|
return vec![a, b].into_iter().collect();
|
|
}
|
|
self::TokenTree::Literal(tt) => {
|
|
let token = Literal(tt.lit, tt.suffix);
|
|
return TokenTree::Token(tt.span.0, token).into();
|
|
}
|
|
};
|
|
|
|
let token = match ch {
|
|
'=' => Eq,
|
|
'<' => Lt,
|
|
'>' => Gt,
|
|
'!' => Not,
|
|
'~' => Tilde,
|
|
'+' => BinOp(Plus),
|
|
'-' => BinOp(Minus),
|
|
'*' => BinOp(Star),
|
|
'/' => BinOp(Slash),
|
|
'%' => BinOp(Percent),
|
|
'^' => BinOp(Caret),
|
|
'&' => BinOp(And),
|
|
'|' => BinOp(Or),
|
|
'@' => At,
|
|
'.' => Dot,
|
|
',' => Comma,
|
|
';' => Semi,
|
|
':' => Colon,
|
|
'#' => Pound,
|
|
'$' => Dollar,
|
|
'?' => Question,
|
|
'\'' => SingleQuote,
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
let tree = TokenTree::Token(span.0, token);
|
|
match kind {
|
|
Spacing::Alone => tree.into(),
|
|
Spacing::Joint => tree.joint(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Level {
|
|
pub(crate) fn to_internal(self) -> errors::Level {
|
|
match self {
|
|
Level::Error => errors::Level::Error,
|
|
Level::Warning => errors::Level::Warning,
|
|
Level::Note => errors::Level::Note,
|
|
Level::Help => errors::Level::Help,
|
|
}
|
|
}
|
|
}
|