Add a KleeneOp enum for clarity

This commit is contained in:
Brendan Zabarauskas 2014-10-23 11:24:20 +11:00
parent 34dacb80ce
commit 94d6eee335
6 changed files with 42 additions and 30 deletions

View file

@ -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 /// 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 /// 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 /// 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: // These only make sense for right-hand-sides of MBE macros:
/// A kleene-style repetition sequence with a span, a `TTForest`, /// A Kleene-style repetition sequence with an optional separator.
/// an optional separator, and a boolean where true indicates
/// zero or more (..), and false indicates one or more (+).
// FIXME(eddyb) #6308 Use Rc<[TokenTree]> after DST. // FIXME(eddyb) #6308 Use Rc<[TokenTree]> after DST.
TtSequence(Span, Rc<Vec<TokenTree>>, Option<::parse::token::Token>, bool), TtSequence(Span, Rc<Vec<TokenTree>>, Option<::parse::token::Token>, KleeneOp),
/// A syntactic variable that will be filled in by macro expansion. /// A syntactic variable that will be filled in by macro expansion.
TtNonterminal(Span, Ident) TtNonterminal(Span, Ident)
} }
@ -711,9 +716,9 @@ pub type Matcher = Spanned<Matcher_>;
pub enum Matcher_ { pub enum Matcher_ {
/// Match one token /// Match one token
MatchTok(::parse::token::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: /// lo, hi position-in-match-array used:
MatchSeq(Vec<Matcher> , Option<::parse::token::Token>, bool, uint, uint), MatchSeq(Vec<Matcher> , Option<::parse::token::Token>, KleeneOp, uint, uint),
/// Parse a Rust NT: name to bind, name of NT, position in match array: /// Parse a Rust NT: name to bind, name of NT, position in match array:
MatchNonterminal(Ident, Ident, uint) MatchNonterminal(Ident, Ident, uint)
} }

View file

@ -323,9 +323,9 @@ pub fn parse(sess: &ParseSess,
} else { } else {
match ei.elts[idx].node.clone() { match ei.elts[idx].node.clone() {
/* need to descend into sequence */ /* 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) => { match_idx_lo, match_idx_hi) => {
if zero_ok { if kleene_op == ast::ZeroOrMore {
let mut new_ei = ei.clone(); let mut new_ei = ei.clone();
new_ei.idx += 1u; new_ei.idx += 1u;
//we specifically matched zero repeats. //we specifically matched zero repeats.

View file

@ -232,10 +232,11 @@ pub fn add_new_extension<'cx>(cx: &'cx mut ExtCtxt,
ms(MatchSeq(vec!( ms(MatchSeq(vec!(
ms(MatchNonterminal(lhs_nm, special_idents::matchers, 0u)), ms(MatchNonterminal(lhs_nm, special_idents::matchers, 0u)),
ms(MatchTok(FAT_ARROW)), 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 //to phase into semicolon-termination instead of
//semicolon-separation //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): // Parse the macro_rules! invocation (`none` is for no interpolations):

View file

@ -227,9 +227,9 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
r.stack.last_mut().unwrap().idx += 1; r.stack.last_mut().unwrap().idx += 1;
return ret_val; return ret_val;
} }
TtSequence(sp, tts, sep, zerok) => { TtSequence(sp, tts, sep, kleene_op) => {
// FIXME(pcwalton): Bad copy. // 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 => { LisUnconstrained => {
r.sp_diag.span_fatal( r.sp_diag.span_fatal(
sp.clone(), /* blame macro writer */ sp.clone(), /* blame macro writer */
@ -243,7 +243,7 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan {
} }
LisConstraint(len, _) => { LisConstraint(len, _) => {
if len == 0 { if len == 0 {
if !zerok { if kleene_op == ast::OneOrMore {
// FIXME #2887 blame invoker // FIXME #2887 blame invoker
r.sp_diag.span_fatal(sp.clone(), r.sp_diag.span_fatal(sp.clone(),
"this must repeat at least once"); "this must repeat at least once");

View file

@ -2497,27 +2497,30 @@ impl<'a> Parser<'a> {
return e; return e;
} }
/// Parse an optional separator followed by a kleene-style /// Parse an optional separator followed by a Kleene-style
/// repetition token (+ or *). /// repetition token (+ or *).
pub fn parse_sep_and_zerok(&mut self) -> (Option<token::Token>, bool) { pub fn parse_sep_and_kleene_op(&mut self) -> (Option<token::Token>, ast::KleeneOp) {
fn parse_zerok(parser: &mut Parser) -> Option<bool> { fn parse_kleene_op(parser: &mut Parser) -> Option<ast::KleeneOp> {
match parser.token { match parser.token {
token::BINOP(token::STAR) | token::BINOP(token::PLUS) => { token::BINOP(token::STAR) => {
let zerok = parser.token == token::BINOP(token::STAR);
parser.bump(); parser.bump();
Some(zerok) Some(ast::ZeroOrMore)
},
token::BINOP(token::PLUS) => {
parser.bump();
Some(ast::OneOrMore)
}, },
_ => None _ => None
} }
}; };
match parse_zerok(self) { match parse_kleene_op(self) {
Some(zerok) => return (None, zerok), Some(kleene_op) => return (None, kleene_op),
None => {} None => {}
} }
let separator = self.bump_and_get(); let separator = self.bump_and_get();
match parse_zerok(self) { match parse_kleene_op(self) {
Some(zerok) => (Some(separator), zerok), Some(zerok) => (Some(separator), zerok),
None => self.fatal("expected `*` or `+`") None => self.fatal("expected `*` or `+`")
} }
@ -2564,11 +2567,11 @@ impl<'a> Parser<'a> {
seq_sep_none(), seq_sep_none(),
|p| p.parse_token_tree() |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 { let seq = match seq {
Spanned { node, .. } => node, 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 { } else {
TtNonterminal(sp, p.parse_ident()) TtNonterminal(sp, p.parse_ident())
} }
@ -2679,8 +2682,8 @@ impl<'a> Parser<'a> {
if ms.len() == 0u { if ms.len() == 0u {
self.fatal("repetition body must be nonempty"); self.fatal("repetition body must be nonempty");
} }
let (sep, zerok) = self.parse_sep_and_zerok(); let (sep, kleene_op) = self.parse_sep_and_kleene_op();
MatchSeq(ms, sep, zerok, name_idx_lo, *name_idx) MatchSeq(ms, sep, kleene_op, name_idx_lo, *name_idx)
} else { } else {
let bound_to = self.parse_ident(); let bound_to = self.parse_ident();
self.expect(&token::COLON); self.expect(&token::COLON);

View file

@ -1037,20 +1037,23 @@ impl<'a> State<'a> {
_ => Ok(()) _ => Ok(())
} }
} }
ast::TtSequence(_, ref tts, ref sep, zerok) => { ast::TtSequence(_, ref tts, ref separator, kleene_op) => {
try!(word(&mut self.s, "$(")); try!(word(&mut self.s, "$("));
for tt_elt in (*tts).iter() { for tt_elt in (*tts).iter() {
try!(self.print_tt(tt_elt)); try!(self.print_tt(tt_elt));
} }
try!(word(&mut self.s, ")")); try!(word(&mut self.s, ")"));
match *sep { match *separator {
Some(ref tk) => { Some(ref tk) => {
try!(word(&mut self.s, try!(word(&mut self.s,
parse::token::to_string(tk).as_slice())); parse::token::to_string(tk).as_slice()));
} }
None => () 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) => { ast::TtNonterminal(_, name) => {
try!(word(&mut self.s, "$")); try!(word(&mut self.s, "$"));