From 6f30a4ee6c35342cc2775d77882ad26fc31ba61e Mon Sep 17 00:00:00 2001 From: Piotr Czarnecki Date: Tue, 7 Oct 2014 00:18:24 +0100 Subject: [PATCH] Remove `Matcher`s --- src/libsyntax/ast.rs | 84 ++++------------------------ src/libsyntax/ext/tt/macro_parser.rs | 26 ++++----- src/libsyntax/ext/tt/macro_rules.rs | 10 +++- src/libsyntax/fold.rs | 2 - src/libsyntax/parse/parser.rs | 64 +-------------------- src/libsyntax/parse/token.rs | 2 - src/libsyntax/print/pprust.rs | 1 - 7 files changed, 33 insertions(+), 156 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 6c71f6d08d2..639b007e7ab 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -641,14 +641,12 @@ pub enum KleeneOp { /// be passed to syntax extensions using a uniform type. /// /// If the syntax extension is an MBE macro, it will attempt to match its -/// LHS "matchers" against the provided token tree, and if it finds a +/// LHS token tree against the provided token tree, and if it finds a /// match, will transcribe the RHS token tree, splicing in any captured -/// `macro_parser::matched_nonterminals` into the `TtNonterminal`s it finds. +/// macro_parser::matched_nonterminals into the `SubstNt`s it finds. /// -/// The RHS of an MBE macro is the only place a `TtNonterminal` or `TtSequence` -/// makes any real sense. You could write them elsewhere but nothing -/// else knows what to do with them, so you'll probably get a syntax -/// error. +/// The RHS of an MBE macro is the only place `SubstNt`s are substituted. +/// Nothing special happens to misnamed or misplaced `SubstNt`s. #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] #[doc="For macro invocations; parsing is delegated to the macro"] pub enum TokenTree { @@ -657,14 +655,19 @@ pub enum TokenTree { /// A delimited sequence of token trees TtDelimited(Span, Rc), - // This only makes sense for right-hand-sides of MBE macros: + // This only makes sense in MBE macros. - /// A Kleene-style repetition sequence with an optional separator. - // FIXME(eddyb) #6308 Use Rc<[TokenTree]> after DST. + /// A kleene-style repetition sequence with a span, a TT forest, + /// an optional separator, and a boolean where true indicates + /// zero or more (..), and false indicates one or more (+). + /// The last member denotes the number of `MATCH_NONTERMINAL`s + /// in the forest. + // FIXME(eddyb) #12938 Use Rc<[TokenTree]> after DST. TtSequence(Span, Rc>, Option<::parse::token::Token>, KleeneOp, uint), } impl TokenTree { + /// For unrolling some tokens or token trees into equivalent sequences. pub fn expand_into_tts(self) -> Rc> { match self { TtToken(sp, token::DocComment(name)) => { @@ -710,69 +713,6 @@ impl TokenTree { } } -// Matchers are nodes defined-by and recognized-by the main rust parser and -// language, but they're only ever found inside syntax-extension invocations; -// indeed, the only thing that ever _activates_ the rules in the rust parser -// for parsing a matcher is a matcher looking for the 'matchers' nonterminal -// itself. Matchers represent a small sub-language for pattern-matching -// token-trees, and are thus primarily used by the macro-defining extension -// itself. -// -// MatchTok -// -------- -// -// A matcher that matches a single token, denoted by the token itself. So -// long as there's no $ involved. -// -// -// MatchSeq -// -------- -// -// A matcher that matches a sequence of sub-matchers, denoted various -// possible ways: -// -// $(M)* zero or more Ms -// $(M)+ one or more Ms -// $(M),+ one or more comma-separated Ms -// $(A B C);* zero or more semi-separated 'A B C' seqs -// -// -// MatchNonterminal -// ----------------- -// -// A matcher that matches one of a few interesting named rust -// nonterminals, such as types, expressions, items, or raw token-trees. A -// black-box matcher on expr, for example, binds an expr to a given ident, -// and that ident can re-occur as an interpolation in the RHS of a -// macro-by-example rule. For example: -// -// $foo:expr => 1 + $foo // interpolate an expr -// $foo:tt => $foo // interpolate a token-tree -// $foo:tt => bar! $foo // only other valid interpolation -// // is in arg position for another -// // macro -// -// As a final, horrifying aside, note that macro-by-example's input is -// also matched by one of these matchers. Holy self-referential! It is matched -// by a MatchSeq, specifically this one: -// -// $( $lhs:matchers => $rhs:tt );+ -// -// If you understand that, you have closed the loop and understand the whole -// macro system. Congratulations. -pub type Matcher = Spanned; - -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] -pub enum Matcher_ { - /// Match one token - MatchTok(token::Token), - /// Match repetitions of a sequence: body, separator, Kleene operator, - /// lo, hi position-in-match-array used: - MatchSeq(Vec, Option, KleeneOp, uint, uint), - /// Parse a Rust NT: name to bind, name of NT, position in match array: - MatchNonterminal(Ident, Ident, uint) -} - pub type Mac = Spanned; /// Represents a macro invocation. The Path indicates which macro diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 022e3a56677..833211f53e7 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -78,7 +78,7 @@ use ast; -use ast::{Matcher, TokenTree, Ident}; +use ast::{TokenTree, Ident}; use ast::{TtDelimited, TtSequence, TtToken}; use codemap::{BytePos, mk_sp}; use codemap; @@ -97,9 +97,8 @@ use std::rc::Rc; use std::collections::HashMap; use std::collections::hash_map::{Vacant, Occupied}; -/* to avoid costly uniqueness checks, we require that `MatchSeq` always has a -nonempty body. */ - +// To avoid costly uniqueness checks, we require that `MatchSeq` always has +// a nonempty body. /// an unzipping of `TokenTree`s #[deriving(Clone)] @@ -157,22 +156,22 @@ pub fn initial_matcher_pos(ms: Rc>, sep: Option, lo: ByteP } } -/// NamedMatch is a pattern-match result for a single ast::MatchNonterminal: +/// NamedMatch is a pattern-match result for a single token::MATCH_NONTERMINAL: /// so it is associated with a single ident in a parse, and all -/// MatchedNonterminal's in the NamedMatch have the same nonterminal type -/// (expr, item, etc). All the leaves in a single NamedMatch correspond to a -/// single matcher_nonterminal in the ast::Matcher that produced it. +/// `MatchedNonterminal`s in the NamedMatch have the same nonterminal type +/// (expr, item, etc). Each leaf in a single NamedMatch corresponds to a +/// single token::MATCH_NONTERMINAL in the TokenTree that produced it. /// /// The in-memory structure of a particular NamedMatch represents the match /// that occurred when a particular subset of a matcher was applied to a /// particular token tree. /// /// The width of each MatchedSeq in the NamedMatch, and the identity of the -/// MatchedNonterminal's, will depend on the token tree it was applied to: each -/// MatchedSeq corresponds to a single MatchSeq in the originating -/// ast::Matcher. The depth of the NamedMatch structure will therefore depend -/// only on the nesting depth of ast::MatchSeq's in the originating -/// ast::Matcher it was derived from. +/// `MatchedNonterminal`s, will depend on the token tree it was applied to: +/// each MatchedSeq corresponds to a single TTSeq in the originating +/// token tree. The depth of the NamedMatch structure will therefore depend +/// only on the nesting depth of `ast::TTSeq`s in the originating +/// token tree it was derived from. pub enum NamedMatch { MatchedSeq(Vec>, codemap::Span), @@ -512,7 +511,6 @@ pub fn parse_nt(p: &mut Parser, name: &str) -> Nonterminal { p.quote_depth -= 1u; res } - "matchers" => token::NtMatchers(p.parse_matchers()), _ => { p.fatal(format!("unsupported builtin nonterminal parser: {}", name).as_slice()) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index cbf34ba5eb3..381e4310d89 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{Ident, Matcher_, Matcher, MatchTok, MatchNonterminal, MatchSeq, TtDelimited}; -use ast::{TtSequence, TtToken}; +use ast::{Ident, TtDelimited, TtSequence, TtToken}; use ast; use codemap::{Span, DUMMY_SP}; use ext::base::{ExtCtxt, MacResult, MacroDef}; @@ -21,7 +20,7 @@ use parse::lexer::new_tt_reader; use parse::parser::Parser; use parse::attr::ParserAttr; use parse::token::{special_idents, gensym_ident}; -use parse::token::{MatchNt, NtMatchers, NtTT}; +use parse::token::{MatchNt, NtTT}; use parse::token; use print; use ptr::P; @@ -207,6 +206,11 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, cx.span_fatal(best_fail_spot, best_fail_msg.as_slice()); } +// Note that macro-by-example's input is also matched against a token tree: +// $( $lhs:tt => $rhs:tt );+ +// +// Holy self-referential! + /// This procedure performs the expansion of the /// macro_rules! macro. It parses the RHS and adds /// an extension to the current context. diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 75fbdb8d8b6..746e1d112c7 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -656,8 +656,6 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)), token::NtPath(box path) => token::NtPath(box fld.fold_path(path)), token::NtTT(tt) => token::NtTT(P(fld.fold_tt(&*tt))), - // it looks to me like we can leave out the matchers: token::NtMatchers(matchers) - _ => nt } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 741014fec89..5a0c7d92fa2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -37,8 +37,8 @@ use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy}; use ast::{LifetimeDef, Lit, Lit_}; use ast::{LitBool, LitChar, LitByte, LitBinary}; use ast::{LitNil, LitStr, LitInt, Local, LocalLet}; -use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, Matcher, MatchNonterminal, MatchNormal}; -use ast::{MatchSeq, MatchTok, Method, MutTy, BiMul, Mutability}; +use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchNormal}; +use ast::{Method, MutTy, BiMul, Mutability}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; @@ -2628,66 +2628,6 @@ impl<'a> Parser<'a> { tts } - pub fn parse_matchers(&mut self) -> Vec { - // unification of Matcher's and TokenTree's would vastly improve - // the interpolation of Matcher's - maybe_whole!(self, NtMatchers); - let mut name_idx = 0u; - let delim = self.expect_open_delim(); - self.parse_matcher_subseq_upto(&mut name_idx, &token::CloseDelim(delim)) - } - - /// This goofy function is necessary to correctly match parens in Matcher's. - /// Otherwise, `$( ( )` would be a valid Matcher, and `$( () )` would be - /// invalid. It's similar to common::parse_seq. - pub fn parse_matcher_subseq_upto(&mut self, - name_idx: &mut uint, - ket: &token::Token) - -> Vec { - let mut ret_val = Vec::new(); - let mut lparens = 0u; - - while self.token != *ket || lparens > 0u { - if self.token == token::OpenDelim(token::Paren) { lparens += 1u; } - if self.token == token::CloseDelim(token::Paren) { lparens -= 1u; } - ret_val.push(self.parse_matcher(name_idx)); - } - - self.bump(); - - return ret_val; - } - - pub fn parse_matcher(&mut self, name_idx: &mut uint) -> Matcher { - let lo = self.span.lo; - - let m = if self.token == token::Dollar { - self.bump(); - if self.token == token::OpenDelim(token::Paren) { - let name_idx_lo = *name_idx; - self.bump(); - let ms = self.parse_matcher_subseq_upto(name_idx, - &token::CloseDelim(token::Paren)); - if ms.len() == 0u { - self.fatal("repetition body must be nonempty"); - } - let (sep, kleene_op) = self.parse_sep_and_kleene_op(); - MatchSeq(ms, sep, kleene_op, name_idx_lo, *name_idx) - } else { - let bound_to = self.parse_ident(); - self.expect(&token::Colon); - let nt_name = self.parse_ident(); - let m = MatchNonterminal(bound_to, nt_name, *name_idx); - *name_idx += 1; - m - } - } else { - MatchTok(self.bump_and_get()) - }; - - return spanned(lo, self.span.hi, m); - } - /// Parse a prefix-operator expr pub fn parse_prefix_expr(&mut self) -> P { let lo = self.span.lo; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 8dd2f8b840f..b0cca5e14de 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -337,7 +337,6 @@ pub enum Nonterminal { NtMeta(P), NtPath(Box), NtTT(P), // needs P'ed to break a circularity - NtMatchers(Vec) } impl fmt::Show for Nonterminal { @@ -353,7 +352,6 @@ impl fmt::Show for Nonterminal { NtMeta(..) => f.pad("NtMeta(..)"), NtPath(..) => f.pad("NtPath(..)"), NtTT(..) => f.pad("NtTT(..)"), - NtMatchers(..) => f.pad("NtMatchers(..)"), } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 12ce81eedca..8ffc2aa3583 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -272,7 +272,6 @@ pub fn token_to_string(tok: &Token) -> String { token::NtPat(..) => "an interpolated pattern".into_string(), token::NtIdent(..) => "an interpolated identifier".into_string(), token::NtTT(..) => "an interpolated tt".into_string(), - token::NtMatchers(..) => "an interpolated matcher sequence".into_string(), } } }