syntax: allow stmt/expr macro invocations to be delimited by [].

this is useful for macros like vec! which construct containers
This commit is contained in:
Gábor Lehel 2014-03-16 22:46:04 +01:00 committed by Sean McArthur
parent b8ef9fd9c9
commit be673e77e7
3 changed files with 45 additions and 34 deletions

View File

@ -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);

View File

@ -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<Token> {
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,

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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];
}