diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a6156bfa496b3..580b93eb4c6f3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -609,6 +609,14 @@ impl Delimiter { } } +/// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star) +/// for token sequences. +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub enum KleeneOp { + ZeroOrMore, + OneOrMore, +} + /// When the main rust parser encounters a syntax-extension invocation, it /// parses the arguments to the invocation as a token-tree. This is a very /// loose structure, such that all sorts of different AST-fragments can @@ -633,12 +641,9 @@ pub enum TokenTree { // These only make sense for right-hand-sides of MBE macros: - /// A kleene-style repetition sequence with a span, a `TTForest`, - /// an optional separator, and a boolean where true indicates - /// zero or more (..), and false indicates one or more (+). + /// A Kleene-style repetition sequence with an optional separator. // FIXME(eddyb) #6308 Use Rc<[TokenTree]> after DST. - TtSequence(Span, Rc>, Option<::parse::token::Token>, bool), - + TtSequence(Span, Rc>, Option<::parse::token::Token>, KleeneOp), /// A syntactic variable that will be filled in by macro expansion. TtNonterminal(Span, Ident) } @@ -711,9 +716,9 @@ pub type Matcher = Spanned; pub enum Matcher_ { /// Match one token MatchTok(::parse::token::Token), - /// Match repetitions of a sequence: body, separator, zero ok?, + /// Match repetitions of a sequence: body, separator, Kleene operator, /// lo, hi position-in-match-array used: - MatchSeq(Vec , Option<::parse::token::Token>, bool, uint, uint), + MatchSeq(Vec , Option<::parse::token::Token>, KleeneOp, uint, uint), /// Parse a Rust NT: name to bind, name of NT, position in match array: MatchNonterminal(Ident, Ident, uint) } diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index f2081674fb7c8..cea8cab52654d 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -323,9 +323,9 @@ pub fn parse(sess: &ParseSess, } else { match ei.elts[idx].node.clone() { /* need to descend into sequence */ - MatchSeq(ref matchers, ref sep, zero_ok, + MatchSeq(ref matchers, ref sep, kleene_op, match_idx_lo, match_idx_hi) => { - if zero_ok { + if kleene_op == ast::ZeroOrMore { let mut new_ei = ei.clone(); new_ei.idx += 1u; //we specifically matched zero repeats. diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 8b45cf34e8048..3b51fb380b816 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -232,10 +232,11 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt, ms(MatchSeq(vec!( ms(MatchNonterminal(lhs_nm, special_idents::matchers, 0u)), ms(MatchTok(FAT_ARROW)), - ms(MatchNonterminal(rhs_nm, special_idents::tt, 1u))), Some(SEMI), false, 0u, 2u)), + ms(MatchNonterminal(rhs_nm, special_idents::tt, 1u))), Some(SEMI), + ast::OneOrMore, 0u, 2u)), //to phase into semicolon-termination instead of //semicolon-separation - ms(MatchSeq(vec!(ms(MatchTok(SEMI))), None, true, 2u, 2u))); + ms(MatchSeq(vec!(ms(MatchTok(SEMI))), None, ast::ZeroOrMore, 2u, 2u))); // Parse the macro_rules! invocation (`none` is for no interpolations): diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index fde950e49997c..1bb519f66cd55 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -227,9 +227,9 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { r.stack.last_mut().unwrap().idx += 1; return ret_val; } - TtSequence(sp, tts, sep, zerok) => { + TtSequence(sp, tts, sep, kleene_op) => { // FIXME(pcwalton): Bad copy. - match lockstep_iter_size(&TtSequence(sp, tts.clone(), sep.clone(), zerok), r) { + match lockstep_iter_size(&TtSequence(sp, tts.clone(), sep.clone(), kleene_op), r) { LisUnconstrained => { r.sp_diag.span_fatal( sp.clone(), /* blame macro writer */ @@ -243,7 +243,7 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { } LisConstraint(len, _) => { if len == 0 { - if !zerok { + if kleene_op == ast::OneOrMore { // FIXME #2887 blame invoker r.sp_diag.span_fatal(sp.clone(), "this must repeat at least once"); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f8fa053b7aeab..7bf751c2d5ebf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2497,27 +2497,30 @@ impl<'a> Parser<'a> { return e; } - /// Parse an optional separator followed by a kleene-style + /// Parse an optional separator followed by a Kleene-style /// repetition token (+ or *). - pub fn parse_sep_and_zerok(&mut self) -> (Option, bool) { - fn parse_zerok(parser: &mut Parser) -> Option { + pub fn parse_sep_and_kleene_op(&mut self) -> (Option, ast::KleeneOp) { + fn parse_kleene_op(parser: &mut Parser) -> Option { match parser.token { - token::BINOP(token::STAR) | token::BINOP(token::PLUS) => { - let zerok = parser.token == token::BINOP(token::STAR); + token::BINOP(token::STAR) => { parser.bump(); - Some(zerok) + Some(ast::ZeroOrMore) + }, + token::BINOP(token::PLUS) => { + parser.bump(); + Some(ast::OneOrMore) }, _ => None } }; - match parse_zerok(self) { - Some(zerok) => return (None, zerok), + match parse_kleene_op(self) { + Some(kleene_op) => return (None, kleene_op), None => {} } let separator = self.bump_and_get(); - match parse_zerok(self) { + match parse_kleene_op(self) { Some(zerok) => (Some(separator), zerok), None => self.fatal("expected `*` or `+`") } @@ -2564,11 +2567,11 @@ impl<'a> Parser<'a> { seq_sep_none(), |p| p.parse_token_tree() ); - let (s, z) = p.parse_sep_and_zerok(); + let (sep, repeat) = p.parse_sep_and_kleene_op(); let seq = match seq { Spanned { node, .. } => node, }; - TtSequence(mk_sp(sp.lo, p.span.hi), Rc::new(seq), s, z) + TtSequence(mk_sp(sp.lo, p.span.hi), Rc::new(seq), sep, repeat) } else { TtNonterminal(sp, p.parse_ident()) } @@ -2679,8 +2682,8 @@ impl<'a> Parser<'a> { if ms.len() == 0u { self.fatal("repetition body must be nonempty"); } - let (sep, zerok) = self.parse_sep_and_zerok(); - MatchSeq(ms, sep, zerok, name_idx_lo, *name_idx) + 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); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 97c177b696c01..0a77343547bf8 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1037,20 +1037,23 @@ impl<'a> State<'a> { _ => Ok(()) } } - ast::TtSequence(_, ref tts, ref sep, zerok) => { + ast::TtSequence(_, ref tts, ref separator, kleene_op) => { try!(word(&mut self.s, "$(")); for tt_elt in (*tts).iter() { try!(self.print_tt(tt_elt)); } try!(word(&mut self.s, ")")); - match *sep { + match *separator { Some(ref tk) => { try!(word(&mut self.s, parse::token::to_string(tk).as_slice())); } None => () } - word(&mut self.s, if zerok { "*" } else { "+" }) + match kleene_op { + ast::ZeroOrMore => word(&mut self.s, "*"), + ast::OneOrMore => word(&mut self.s, "+"), + } } ast::TtNonterminal(_, name) => { try!(word(&mut self.s, "$"));