From be673e77e75ece1611cdcf7b1b784ccd53cc9011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Lehel?= Date: Sun, 16 Mar 2014 22:46:04 +0100 Subject: [PATCH] syntax: allow stmt/expr macro invocations to be delimited by []. this is useful for macros like vec! which construct containers --- src/libsyntax/parse/parser.rs | 38 ++++++++------------ src/libsyntax/parse/token.rs | 18 ++++------ src/test/run-pass/vec-macro-with-brackets.rs | 23 ++++++++++++ 3 files changed, 45 insertions(+), 34 deletions(-) create mode 100644 src/test/run-pass/vec-macro-with-brackets.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2d0c4ca488eab..83cc92d48284a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1881,12 +1881,9 @@ impl<'a> Parser<'a> { if self.token == token::NOT { // MACRO INVOCATION expression self.bump(); - match self.token { - token::LPAREN | token::LBRACE => {} - _ => self.fatal("expected open delimiter") - }; - let ket = token::flip_delimiter(&self.token); + let ket = token::close_delimiter_for(&self.token) + .unwrap_or_else(|| self.fatal("expected open delimiter")); self.bump(); let tts = self.parse_seq_to_end(&ket, @@ -2109,8 +2106,8 @@ impl<'a> Parser<'a> { TTTok(p.span, p.bump_and_get()) } - match self.token { - token::EOF => { + match (&self.token, token::close_delimiter_for(&self.token)) { + (&token::EOF, _) => { let open_braces = self.open_braces.clone(); for sp in open_braces.iter() { self.span_note(*sp, "Did you mean to close this delimiter?"); @@ -2119,9 +2116,7 @@ impl<'a> Parser<'a> { // if we give it one self.fatal("this file contains an un-closed delimiter "); } - token::LPAREN | token::LBRACE | token::LBRACKET => { - let close_delim = token::flip_delimiter(&self.token); - + (_, Some(close_delim)) => { // Parse the open delimiter. self.open_braces.push(self.span); let mut result = vec!(parse_any_tt_tok(self)); @@ -2157,13 +2152,12 @@ impl<'a> Parser<'a> { // the interpolation of Matcher's maybe_whole!(self, NtMatchers); let mut name_idx = 0u; - match self.token { - token::LBRACE | token::LPAREN | token::LBRACKET => { - let other_delimiter = token::flip_delimiter(&self.token); + match token::close_delimiter_for(&self.token) { + Some(other_delimiter) => { self.bump(); self.parse_matcher_subseq_upto(&mut name_idx, &other_delimiter) } - _ => self.fatal("expected open delimiter") + None => self.fatal("expected open delimiter") } } @@ -3138,7 +3132,7 @@ impl<'a> Parser<'a> { let pth = self.parse_path(NoTypesAllowed).path; self.bump(); - let id = if self.token == token::LPAREN || self.token == token::LBRACE { + let id = if token::close_delimiter_for(&self.token).is_some() { token::special_idents::invalid // no special identifier } else { self.parse_ident() @@ -3147,10 +3141,9 @@ impl<'a> Parser<'a> { // check that we're pointing at delimiters (need to check // again after the `if`, because of `parse_ident` // consuming more tokens). - let (bra, ket) = match self.token { - token::LPAREN => (token::LPAREN, token::RPAREN), - token::LBRACE => (token::LBRACE, token::RBRACE), - _ => { + let (bra, ket) = match token::close_delimiter_for(&self.token) { + Some(ket) => (self.token.clone(), ket), + None => { // we only expect an ident if we didn't parse one // above. let ident_str = if id == token::special_idents::invalid { @@ -4724,15 +4717,14 @@ impl<'a> Parser<'a> { token::special_idents::invalid // no special identifier }; // eat a matched-delimiter token tree: - let tts = match self.token { - token::LPAREN | token::LBRACE => { - let ket = token::flip_delimiter(&self.token); + let tts = match token::close_delimiter_for(&self.token) { + Some(ket) => { self.bump(); self.parse_seq_to_end(&ket, seq_sep_none(), |p| p.parse_token_tree()) } - _ => self.fatal("expected open delimiter") + None => self.fatal("expected open delimiter") }; // single-variant-enum... : let m = ast::MacInvocTT(pth, tts, EMPTY_CTXT); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 2c5698ddec403..ff1509fe23a76 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -297,21 +297,17 @@ pub fn can_begin_expr(t: &Token) -> bool { } } -/// what's the opposite delimiter? -pub fn flip_delimiter(t: &token::Token) -> token::Token { +/// Returns the matching close delimiter if this is an open delimiter, +/// otherwise `None`. +pub fn close_delimiter_for(t: &Token) -> Option { match *t { - LPAREN => RPAREN, - LBRACE => RBRACE, - LBRACKET => RBRACKET, - RPAREN => LPAREN, - RBRACE => LBRACE, - RBRACKET => LBRACKET, - _ => fail!() + LPAREN => Some(RPAREN), + LBRACE => Some(RBRACE), + LBRACKET => Some(RBRACKET), + _ => None } } - - pub fn is_lit(t: &Token) -> bool { match *t { LIT_CHAR(_) => true, diff --git a/src/test/run-pass/vec-macro-with-brackets.rs b/src/test/run-pass/vec-macro-with-brackets.rs new file mode 100644 index 0000000000000..87b18f841ed28 --- /dev/null +++ b/src/test/run-pass/vec-macro-with-brackets.rs @@ -0,0 +1,23 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(macro_rules)] + +macro_rules! vec [ + ($($e:expr),*) => ({ + let mut _temp = ::std::vec::Vec::new(); + $(_temp.push($e);)* + _temp + }) +] + +pub fn main() { + let my_vec = vec![1, 2, 3, 4, 5]; +}