Add Tracker
to track matching operations
This should allow us to collect detailed information without slowing down the inital hot path.
This commit is contained in:
parent
6c47848c25
commit
2f8a068cb7
3 changed files with 49 additions and 18 deletions
|
@ -52,7 +52,7 @@ impl KleeneToken {
|
||||||
/// A Kleene-style [repetition operator](https://en.wikipedia.org/wiki/Kleene_star)
|
/// A Kleene-style [repetition operator](https://en.wikipedia.org/wiki/Kleene_star)
|
||||||
/// for token sequences.
|
/// for token sequences.
|
||||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
|
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
|
||||||
enum KleeneOp {
|
pub(crate) enum KleeneOp {
|
||||||
/// Kleene star (`*`) for zero or more repetitions
|
/// Kleene star (`*`) for zero or more repetitions
|
||||||
ZeroOrMore,
|
ZeroOrMore,
|
||||||
/// Kleene plus (`+`) for one or more repetitions
|
/// Kleene plus (`+`) for one or more repetitions
|
||||||
|
|
|
@ -70,21 +70,20 @@
|
||||||
//! eof: [a $( a )* a b ·]
|
//! eof: [a $( a )* a b ·]
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use rustc_errors::ErrorGuaranteed;
|
||||||
pub(crate) use NamedMatch::*;
|
pub(crate) use NamedMatch::*;
|
||||||
pub(crate) use ParseResult::*;
|
pub(crate) use ParseResult::*;
|
||||||
use rustc_errors::ErrorGuaranteed;
|
|
||||||
|
|
||||||
use crate::mbe::{KleeneOp, TokenTree};
|
use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree};
|
||||||
|
|
||||||
use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
|
use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
|
||||||
use rustc_lint_defs::pluralize;
|
|
||||||
use rustc_parse::parser::{NtOrTt, Parser};
|
|
||||||
use rustc_span::symbol::MacroRulesNormalizedIdent;
|
|
||||||
use rustc_span::Span;
|
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
use rustc_lint_defs::pluralize;
|
||||||
|
use rustc_parse::parser::{NtOrTt, Parser};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
use rustc_span::symbol::MacroRulesNormalizedIdent;
|
||||||
|
use rustc_span::Span;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
|
|
||||||
|
@ -97,7 +96,8 @@ use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
///
|
///
|
||||||
/// This means a matcher can be represented by `&[MatcherLoc]`, and traversal mostly involves
|
/// This means a matcher can be represented by `&[MatcherLoc]`, and traversal mostly involves
|
||||||
/// simply incrementing the current matcher position index by one.
|
/// simply incrementing the current matcher position index by one.
|
||||||
pub(super) enum MatcherLoc {
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub(crate) enum MatcherLoc {
|
||||||
Token {
|
Token {
|
||||||
token: Token,
|
token: Token,
|
||||||
},
|
},
|
||||||
|
@ -401,17 +401,21 @@ impl TtParser {
|
||||||
///
|
///
|
||||||
/// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept
|
/// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept
|
||||||
/// track of through the mps generated.
|
/// track of through the mps generated.
|
||||||
fn parse_tt_inner(
|
fn parse_tt_inner<'matcher, T: Tracker<'matcher>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
matcher: &[MatcherLoc],
|
matcher: &'matcher [MatcherLoc],
|
||||||
token: &Token,
|
token: &Token,
|
||||||
|
track: &mut T,
|
||||||
) -> Option<NamedParseResult> {
|
) -> Option<NamedParseResult> {
|
||||||
// Matcher positions that would be valid if the macro invocation was over now. Only
|
// Matcher positions that would be valid if the macro invocation was over now. Only
|
||||||
// modified if `token == Eof`.
|
// modified if `token == Eof`.
|
||||||
let mut eof_mps = EofMatcherPositions::None;
|
let mut eof_mps = EofMatcherPositions::None;
|
||||||
|
|
||||||
while let Some(mut mp) = self.cur_mps.pop() {
|
while let Some(mut mp) = self.cur_mps.pop() {
|
||||||
match &matcher[mp.idx] {
|
let matcher_loc = &matcher[mp.idx];
|
||||||
|
track.before_match_loc(self, matcher_loc);
|
||||||
|
|
||||||
|
match matcher_loc {
|
||||||
MatcherLoc::Token { token: t } => {
|
MatcherLoc::Token { token: t } => {
|
||||||
// If it's a doc comment, we just ignore it and move on to the next tt in the
|
// If it's a doc comment, we just ignore it and move on to the next tt in the
|
||||||
// matcher. This is a bug, but #95267 showed that existing programs rely on
|
// matcher. This is a bug, but #95267 showed that existing programs rely on
|
||||||
|
@ -553,10 +557,11 @@ impl TtParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Match the token stream from `parser` against `matcher`.
|
/// Match the token stream from `parser` against `matcher`.
|
||||||
pub(super) fn parse_tt(
|
pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
parser: &mut Cow<'_, Parser<'_>>,
|
parser: &mut Cow<'_, Parser<'_>>,
|
||||||
matcher: &[MatcherLoc],
|
matcher: &'matcher [MatcherLoc],
|
||||||
|
track: &mut T,
|
||||||
) -> NamedParseResult {
|
) -> NamedParseResult {
|
||||||
// A queue of possible matcher positions. We initialize it with the matcher position in
|
// A queue of possible matcher positions. We initialize it with the matcher position in
|
||||||
// which the "dot" is before the first token of the first token tree in `matcher`.
|
// which the "dot" is before the first token of the first token tree in `matcher`.
|
||||||
|
@ -572,7 +577,8 @@ impl TtParser {
|
||||||
|
|
||||||
// Process `cur_mps` until either we have finished the input or we need to get some
|
// Process `cur_mps` until either we have finished the input or we need to get some
|
||||||
// parsing from the black-box parser done.
|
// parsing from the black-box parser done.
|
||||||
if let Some(res) = self.parse_tt_inner(matcher, &parser.token) {
|
let res = self.parse_tt_inner(matcher, &parser.token, track);
|
||||||
|
if let Some(res) = res {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ use std::borrow::Cow;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::{mem, slice};
|
use std::{mem, slice};
|
||||||
|
|
||||||
|
use super::macro_parser::NamedParseResult;
|
||||||
|
|
||||||
pub(crate) struct ParserAnyMacro<'a> {
|
pub(crate) struct ParserAnyMacro<'a> {
|
||||||
parser: Parser<'a>,
|
parser: Parser<'a>,
|
||||||
|
|
||||||
|
@ -205,6 +207,29 @@ fn trace_macros_note(cx_expansions: &mut FxIndexMap<Span, Vec<String>>, sp: Span
|
||||||
cx_expansions.entry(sp).or_default().push(message);
|
cx_expansions.entry(sp).or_default().push(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) trait Tracker<'matcher> {
|
||||||
|
/// This is called before trying to match next MatcherLoc on the current token
|
||||||
|
fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc);
|
||||||
|
|
||||||
|
/// This is called after an arm has been parsed, either successfully or unsuccessfully. When this is called,
|
||||||
|
/// `before_match_loc` was called at least once (with a `MatcherLoc::Eof`)
|
||||||
|
fn after_arm(&mut self, result: &NamedParseResult);
|
||||||
|
|
||||||
|
/// For tracing
|
||||||
|
fn description() -> &'static str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization
|
||||||
|
struct NoopTracker;
|
||||||
|
|
||||||
|
impl<'matcher> Tracker<'matcher> for NoopTracker {
|
||||||
|
fn before_match_loc(&mut self, _: &TtParser, _: &'matcher MatcherLoc) {}
|
||||||
|
fn after_arm(&mut self, _: &NamedParseResult) {}
|
||||||
|
fn description() -> &'static str {
|
||||||
|
"none"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Expands the rules based macro defined by `lhses` and `rhses` for a given
|
/// Expands the rules based macro defined by `lhses` and `rhses` for a given
|
||||||
/// input `arg`.
|
/// input `arg`.
|
||||||
fn expand_macro<'cx>(
|
fn expand_macro<'cx>(
|
||||||
|
@ -262,7 +287,7 @@ fn expand_macro<'cx>(
|
||||||
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
|
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
|
||||||
let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut());
|
let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut());
|
||||||
|
|
||||||
match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs) {
|
match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker) {
|
||||||
Success(named_matches) => {
|
Success(named_matches) => {
|
||||||
// The matcher was `Success(..)`ful.
|
// The matcher was `Success(..)`ful.
|
||||||
// Merge the gated spans from parsing the matcher with the pre-existing ones.
|
// Merge the gated spans from parsing the matcher with the pre-existing ones.
|
||||||
|
@ -354,7 +379,7 @@ fn expand_macro<'cx>(
|
||||||
if let Some((arg, comma_span)) = arg.add_comma() {
|
if let Some((arg, comma_span)) = arg.add_comma() {
|
||||||
for lhs in lhses {
|
for lhs in lhses {
|
||||||
let parser = parser_from_cx(sess, arg.clone());
|
let parser = parser_from_cx(sess, arg.clone());
|
||||||
if let Success(_) = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs) {
|
if let Success(_) = tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker) {
|
||||||
if comma_span.is_dummy() {
|
if comma_span.is_dummy() {
|
||||||
err.note("you might be missing a comma");
|
err.note("you might be missing a comma");
|
||||||
} else {
|
} else {
|
||||||
|
@ -452,7 +477,7 @@ pub fn compile_declarative_macro(
|
||||||
let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
|
let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
|
||||||
let mut tt_parser =
|
let mut tt_parser =
|
||||||
TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro }));
|
TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro }));
|
||||||
let argument_map = match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
|
let argument_map = match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &argument_gram, &mut NoopTracker) {
|
||||||
Success(m) => m,
|
Success(m) => m,
|
||||||
Failure(token, msg) => {
|
Failure(token, msg) => {
|
||||||
let s = parse_failure_msg(&token);
|
let s = parse_failure_msg(&token);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue