Skip to content

Commit 17294d9

Browse files
committed
Rollup merge of rust-lang#39118 - jseyfried:token_tree_based_parser, r=nrc
Refactor the parser to consume token trees This is groundwork for efficiently parsing attribute proc macro invocations, bang macro invocations, and `TokenStream`-based attributes and fragment matchers. This improves parsing performance by 8-15% and expansion performance by 0-5% on a sampling of the compiler's crates. r? @nrc
2 parents dd5d85e + 0b9e26f commit 17294d9

File tree

20 files changed

+368
-472
lines changed

20 files changed

+368
-472
lines changed

src/librustc/hir/print.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub use self::AnnNode::*;
1313
use syntax::abi::Abi;
1414
use syntax::ast;
1515
use syntax::codemap::{CodeMap, Spanned};
16+
use syntax::parse::ParseSess;
1617
use syntax::parse::lexer::comments;
1718
use syntax::print::pp::{self, break_offset, word, space, hardbreak};
1819
use syntax::print::pp::{Breaks, eof};
@@ -21,7 +22,6 @@ use syntax::print::pprust::{self as ast_pp, PrintState};
2122
use syntax::ptr::P;
2223
use syntax::symbol::keywords;
2324
use syntax_pos::{self, BytePos};
24-
use errors;
2525

2626
use hir;
2727
use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
@@ -116,16 +116,15 @@ pub const default_columns: usize = 78;
116116
/// it can scan the input text for comments and literals to
117117
/// copy forward.
118118
pub fn print_crate<'a>(cm: &'a CodeMap,
119-
span_diagnostic: &errors::Handler,
119+
sess: &ParseSess,
120120
krate: &hir::Crate,
121121
filename: String,
122122
input: &mut Read,
123123
out: Box<Write + 'a>,
124124
ann: &'a PpAnn,
125125
is_expanded: bool)
126126
-> io::Result<()> {
127-
let mut s = State::new_from_input(cm, span_diagnostic, filename, input,
128-
out, ann, is_expanded);
127+
let mut s = State::new_from_input(cm, sess, filename, input, out, ann, is_expanded);
129128

130129
// When printing the AST, we sometimes need to inject `#[no_std]` here.
131130
// Since you can't compile the HIR, it's not necessary.
@@ -137,16 +136,14 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
137136

138137
impl<'a> State<'a> {
139138
pub fn new_from_input(cm: &'a CodeMap,
140-
span_diagnostic: &errors::Handler,
139+
sess: &ParseSess,
141140
filename: String,
142141
input: &mut Read,
143142
out: Box<Write + 'a>,
144143
ann: &'a PpAnn,
145144
is_expanded: bool)
146145
-> State<'a> {
147-
let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic,
148-
filename,
149-
input);
146+
let (cmnts, lits) = comments::gather_comments_and_literals(sess, filename, input);
150147

151148
State::new(cm,
152149
out,

src/librustc/session/config.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use lint;
2525
use middle::cstore;
2626

2727
use syntax::ast::{self, IntTy, UintTy};
28+
use syntax::parse::token;
2829
use syntax::parse;
2930
use syntax::symbol::Symbol;
3031
use syntax::feature_gate::UnstableFeatures;
@@ -1259,7 +1260,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
12591260

12601261
let meta_item = panictry!(parser.parse_meta_item());
12611262

1262-
if !parser.reader.is_eof() {
1263+
if parser.token != token::Eof {
12631264
early_error(ErrorOutputType::default(), &format!("invalid --cfg argument: {}", s))
12641265
} else if meta_item.is_meta_item_list() {
12651266
let msg =

src/librustc_driver/pretty.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ pub fn print_after_parsing(sess: &Session,
838838
debug!("pretty printing source code {:?}", s);
839839
let sess = annotation.sess();
840840
pprust::print_crate(sess.codemap(),
841-
sess.diagnostic(),
841+
&sess.parse_sess,
842842
krate,
843843
src_name.to_string(),
844844
&mut rdr,
@@ -896,7 +896,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
896896
debug!("pretty printing source code {:?}", s);
897897
let sess = annotation.sess();
898898
pprust::print_crate(sess.codemap(),
899-
sess.diagnostic(),
899+
&sess.parse_sess,
900900
krate,
901901
src_name.to_string(),
902902
&mut rdr,
@@ -920,7 +920,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
920920
debug!("pretty printing source code {:?}", s);
921921
let sess = annotation.sess();
922922
pprust_hir::print_crate(sess.codemap(),
923-
sess.diagnostic(),
923+
&sess.parse_sess,
924924
krate,
925925
src_name.to_string(),
926926
&mut rdr,
@@ -945,7 +945,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
945945
let sess = annotation.sess();
946946
let ast_map = annotation.ast_map().expect("--unpretty missing HIR map");
947947
let mut pp_state = pprust_hir::State::new_from_input(sess.codemap(),
948-
sess.diagnostic(),
948+
&sess.parse_sess,
949949
src_name.to_string(),
950950
&mut rdr,
951951
box out,

src/librustc_metadata/cstore_impl.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use rustc_back::PanicStrategy;
2929

3030
use syntax::ast;
3131
use syntax::attr;
32-
use syntax::parse::new_parser_from_source_str;
32+
use syntax::parse::filemap_to_tts;
3333
use syntax::symbol::Symbol;
3434
use syntax_pos::{mk_sp, Span};
3535
use rustc::hir::svh::Svh;
@@ -399,19 +399,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
399399
let (name, def) = data.get_macro(id.index);
400400
let source_name = format!("<{} macros>", name);
401401

402-
// NB: Don't use parse_tts_from_source_str because it parses with quote_depth > 0.
403-
let mut parser = new_parser_from_source_str(&sess.parse_sess, source_name, def.body);
404-
405-
let lo = parser.span.lo;
406-
let body = match parser.parse_all_token_trees() {
407-
Ok(body) => body,
408-
Err(mut err) => {
409-
err.emit();
410-
sess.abort_if_errors();
411-
unreachable!();
412-
}
413-
};
414-
let local_span = mk_sp(lo, parser.prev_span.hi);
402+
let filemap = sess.parse_sess.codemap().new_filemap(source_name, None, def.body);
403+
let local_span = mk_sp(filemap.start_pos, filemap.end_pos);
404+
let body = filemap_to_tts(&sess.parse_sess, filemap);
415405

416406
// Mark the attrs as used
417407
let attrs = data.get_item_attrs(id.index);

src/librustc_save_analysis/span_utils.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ use std::env;
1717
use std::path::Path;
1818

1919
use syntax::ast;
20-
use syntax::parse::lexer::{self, Reader, StringReader};
20+
use syntax::parse::filemap_to_tts;
21+
use syntax::parse::lexer::{self, StringReader};
2122
use syntax::parse::token::{self, Token};
22-
use syntax::parse::parser::Parser;
2323
use syntax::symbol::keywords;
2424
use syntax::tokenstream::TokenTree;
2525
use syntax_pos::*;
@@ -85,14 +85,13 @@ impl<'a> SpanUtils<'a> {
8585
let filemap = self.sess
8686
.codemap()
8787
.new_filemap(String::from("<anon-dxr>"), None, self.snippet(span));
88-
let s = self.sess;
89-
lexer::StringReader::new(s.diagnostic(), filemap)
88+
lexer::StringReader::new(&self.sess.parse_sess, filemap)
9089
}
9190

9291
fn span_to_tts(&self, span: Span) -> Vec<TokenTree> {
93-
let srdr = self.retokenise_span(span);
94-
let mut p = Parser::new(&self.sess.parse_sess, Box::new(srdr), None, false);
95-
p.parse_all_token_trees().expect("Couldn't re-parse span")
92+
let filename = String::from("<anon-dxr>");
93+
let filemap = self.sess.codemap().new_filemap(filename, None, self.snippet(span));
94+
filemap_to_tts(&self.sess.parse_sess, filemap)
9695
}
9796

9897
// Re-parses a path and returns the span for the last identifier in the path

src/librustdoc/html/highlight.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use std::io;
2727
use std::io::prelude::*;
2828

2929
use syntax::codemap::CodeMap;
30-
use syntax::parse::lexer::{self, Reader, TokenAndSpan};
30+
use syntax::parse::lexer::{self, TokenAndSpan};
3131
use syntax::parse::token;
3232
use syntax::parse;
3333
use syntax_pos::Span;
@@ -42,8 +42,7 @@ pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>
4242
let mut out = Vec::new();
4343
write_header(class, id, &mut out).unwrap();
4444

45-
let mut classifier = Classifier::new(lexer::StringReader::new(&sess.span_diagnostic, fm),
46-
sess.codemap());
45+
let mut classifier = Classifier::new(lexer::StringReader::new(&sess, fm), sess.codemap());
4746
if let Err(_) = classifier.write_source(&mut out) {
4847
return format!("<pre>{}</pre>", src);
4948
}
@@ -63,8 +62,7 @@ pub fn render_inner_with_highlighting(src: &str) -> io::Result<String> {
6362
let fm = sess.codemap().new_filemap("<stdin>".to_string(), None, src.to_string());
6463

6564
let mut out = Vec::new();
66-
let mut classifier = Classifier::new(lexer::StringReader::new(&sess.span_diagnostic, fm),
67-
sess.codemap());
65+
let mut classifier = Classifier::new(lexer::StringReader::new(&sess, fm), sess.codemap());
6866
classifier.write_source(&mut out)?;
6967

7068
Ok(String::from_utf8_lossy(&out).into_owned())
@@ -185,10 +183,10 @@ impl<'a> Classifier<'a> {
185183
Ok(tas) => tas,
186184
Err(_) => {
187185
self.lexer.emit_fatal_errors();
188-
self.lexer.span_diagnostic.struct_warn("Backing out of syntax highlighting")
189-
.note("You probably did not intend to render this \
190-
as a rust code-block")
191-
.emit();
186+
self.lexer.sess.span_diagnostic
187+
.struct_warn("Backing out of syntax highlighting")
188+
.note("You probably did not intend to render this as a rust code-block")
189+
.emit();
192190
return Err(io::Error::new(io::ErrorKind::Other, ""));
193191
}
194192
};

src/libsyntax/ext/base.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -615,9 +615,7 @@ impl<'a> ExtCtxt<'a> {
615615

616616
pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree])
617617
-> parser::Parser<'a> {
618-
let mut parser = parse::tts_to_parser(self.parse_sess, tts.to_vec());
619-
parser.allow_interpolated_tts = false; // FIXME(jseyfried) `quote!` can't handle these yet
620-
parser
618+
parse::tts_to_parser(self.parse_sess, tts.to_vec())
621619
}
622620
pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() }
623621
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }

src/libsyntax/ext/expand.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use ext::base::*;
2121
use feature_gate::{self, Features};
2222
use fold;
2323
use fold::*;
24-
use parse::{ParseSess, DirectoryOwnership, PResult, lexer};
24+
use parse::{ParseSess, DirectoryOwnership, PResult, filemap_to_tts};
2525
use parse::parser::Parser;
2626
use parse::token;
2727
use print::pprust;
@@ -669,12 +669,8 @@ fn tts_for_attr_args(attr: &ast::Attribute, parse_sess: &ParseSess) -> Vec<Token
669669
}
670670

671671
fn string_to_tts(text: String, parse_sess: &ParseSess) -> Vec<TokenTree> {
672-
let filemap = parse_sess.codemap()
673-
.new_filemap(String::from("<macro expansion>"), None, text);
674-
675-
let lexer = lexer::StringReader::new(&parse_sess.span_diagnostic, filemap);
676-
let mut parser = Parser::new(parse_sess, Box::new(lexer), None, false);
677-
panictry!(parser.parse_all_token_trees())
672+
let filename = String::from("<macro expansion>");
673+
filemap_to_tts(parse_sess, parse_sess.codemap().new_filemap(filename, None, text))
678674
}
679675

680676
impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {

src/libsyntax/ext/tt/macro_parser.rs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ use ast::Ident;
8282
use syntax_pos::{self, BytePos, mk_sp, Span};
8383
use codemap::Spanned;
8484
use errors::FatalError;
85-
use parse::lexer::*; //resolve bug?
8685
use parse::{Directory, ParseSess};
8786
use parse::parser::{PathStyle, Parser};
8887
use parse::token::{DocComment, MatchNt, SubstNt};
@@ -407,9 +406,9 @@ fn inner_parse_loop(cur_eis: &mut SmallVector<Box<MatcherPos>>,
407406
Success(())
408407
}
409408

410-
pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree], directory: Option<Directory>)
409+
pub fn parse(sess: &ParseSess, tts: Vec<TokenTree>, ms: &[TokenTree], directory: Option<Directory>)
411410
-> NamedParseResult {
412-
let mut parser = Parser::new(sess, Box::new(rdr), directory, true);
411+
let mut parser = Parser::new(sess, tts, directory, true);
413412
let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo));
414413
let mut next_eis = Vec::new(); // or proceed normally
415414

@@ -481,23 +480,8 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
481480
match name {
482481
"tt" => {
483482
p.quote_depth += 1; //but in theory, non-quoted tts might be useful
484-
let mut tt = panictry!(p.parse_token_tree());
483+
let tt = panictry!(p.parse_token_tree());
485484
p.quote_depth -= 1;
486-
while let TokenTree::Token(sp, token::Interpolated(nt)) = tt {
487-
if let token::NtTT(..) = *nt {
488-
match Rc::try_unwrap(nt) {
489-
Ok(token::NtTT(sub_tt)) => tt = sub_tt,
490-
Ok(_) => unreachable!(),
491-
Err(nt_rc) => match *nt_rc {
492-
token::NtTT(ref sub_tt) => tt = sub_tt.clone(),
493-
_ => unreachable!(),
494-
},
495-
}
496-
} else {
497-
tt = TokenTree::Token(sp, token::Interpolated(nt.clone()));
498-
break
499-
}
500-
}
501485
return token::NtTT(tt);
502486
}
503487
_ => {}
@@ -527,7 +511,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
527511
"ident" => match p.token {
528512
token::Ident(sn) => {
529513
p.bump();
530-
token::NtIdent(Spanned::<Ident>{node: sn, span: p.span})
514+
token::NtIdent(Spanned::<Ident>{node: sn, span: p.prev_span})
531515
}
532516
_ => {
533517
let token_str = pprust::token_to_string(&p.token);

src/libsyntax/ext/tt/macro_rules.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use ext::expand::{Expansion, ExpansionKind};
1616
use ext::tt::macro_parser::{Success, Error, Failure};
1717
use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
1818
use ext::tt::macro_parser::{parse, parse_failure_msg};
19+
use ext::tt::transcribe::transcribe;
1920
use parse::{Directory, ParseSess};
20-
use parse::lexer::new_tt_reader;
2121
use parse::parser::Parser;
2222
use parse::token::{self, NtTT, Token};
2323
use parse::token::Token::*;
@@ -113,13 +113,12 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
113113
_ => cx.span_bug(sp, "malformed macro rhs"),
114114
};
115115
// rhs has holes ( `$id` and `$(...)` that need filled)
116-
let trncbr =
117-
new_tt_reader(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs);
116+
let tts = transcribe(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs);
118117
let directory = Directory {
119118
path: cx.current_expansion.module.directory.clone(),
120119
ownership: cx.current_expansion.directory_ownership,
121120
};
122-
let mut p = Parser::new(cx.parse_sess(), Box::new(trncbr), Some(directory), false);
121+
let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), false);
123122
p.root_module_name = cx.current_expansion.module.mod_path.last()
124123
.map(|id| (*id.name.as_str()).to_owned());
125124

@@ -187,10 +186,8 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
187186
})),
188187
];
189188

190-
// Parse the macro_rules! invocation (`none` is for no interpolations):
191-
let arg_reader = new_tt_reader(&sess.span_diagnostic, None, def.body.clone());
192-
193-
let argument_map = match parse(sess, arg_reader, &argument_gram, None) {
189+
// Parse the macro_rules! invocation
190+
let argument_map = match parse(sess, def.body.clone(), &argument_gram, None) {
194191
Success(m) => m,
195192
Failure(sp, tok) => {
196193
let s = parse_failure_msg(tok);

0 commit comments

Comments
 (0)