/// 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 {
/// A delimited sequence of token trees
TtDelimited(Span, Rc<Delimited>),
- // 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<Vec<TokenTree>>, 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<Vec<TokenTree>> {
match self {
TtToken(sp, token::DocComment(name)) => {
}
}
-// 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<Matcher_>;
-
-#[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<Matcher>, Option<token::Token>, 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<Mac_>;
/// Represents a macro invocation. The Path indicates which macro
use ast;
-use ast::{Matcher, TokenTree, Ident};
+use ast::{TokenTree, Ident};
use ast::{TtDelimited, TtSequence, TtToken};
use codemap::{BytePos, mk_sp};
use codemap;
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)]
}
}
-/// 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<Rc<NamedMatch>>, codemap::Span),
p.quote_depth -= 1u;
res
}
- "matchers" => token::NtMatchers(p.parse_matchers()),
_ => {
p.fatal(format!("unsupported builtin nonterminal parser: {}",
name).as_slice())
// 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};
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;
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.
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
}
}
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};
tts
}
- pub fn parse_matchers(&mut self) -> Vec<Matcher> {
- // 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<Matcher> {
- 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<Expr> {
let lo = self.span.lo;
NtMeta(P<ast::MetaItem>),
NtPath(Box<ast::Path>),
NtTT(P<ast::TokenTree>), // needs P'ed to break a circularity
- NtMatchers(Vec<ast::Matcher>)
}
impl fmt::Show for Nonterminal {
NtMeta(..) => f.pad("NtMeta(..)"),
NtPath(..) => f.pad("NtPath(..)"),
NtTT(..) => f.pad("NtTT(..)"),
- NtMatchers(..) => f.pad("NtMatchers(..)"),
}
}
}
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(),
}
}
}