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:
parent
b8ef9fd9c9
commit
be673e77e7
3 changed files with 45 additions and 34 deletions
|
@ -1881,12 +1881,9 @@ impl<'a> Parser<'a> {
|
||||||
if self.token == token::NOT {
|
if self.token == token::NOT {
|
||||||
// MACRO INVOCATION expression
|
// MACRO INVOCATION expression
|
||||||
self.bump();
|
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();
|
self.bump();
|
||||||
|
|
||||||
let tts = self.parse_seq_to_end(&ket,
|
let tts = self.parse_seq_to_end(&ket,
|
||||||
|
@ -2109,8 +2106,8 @@ impl<'a> Parser<'a> {
|
||||||
TTTok(p.span, p.bump_and_get())
|
TTTok(p.span, p.bump_and_get())
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.token {
|
match (&self.token, token::close_delimiter_for(&self.token)) {
|
||||||
token::EOF => {
|
(&token::EOF, _) => {
|
||||||
let open_braces = self.open_braces.clone();
|
let open_braces = self.open_braces.clone();
|
||||||
for sp in open_braces.iter() {
|
for sp in open_braces.iter() {
|
||||||
self.span_note(*sp, "Did you mean to close this delimiter?");
|
self.span_note(*sp, "Did you mean to close this delimiter?");
|
||||||
|
@ -2119,9 +2116,7 @@ impl<'a> Parser<'a> {
|
||||||
// if we give it one
|
// if we give it one
|
||||||
self.fatal("this file contains an un-closed delimiter ");
|
self.fatal("this file contains an un-closed delimiter ");
|
||||||
}
|
}
|
||||||
token::LPAREN | token::LBRACE | token::LBRACKET => {
|
(_, Some(close_delim)) => {
|
||||||
let close_delim = token::flip_delimiter(&self.token);
|
|
||||||
|
|
||||||
// Parse the open delimiter.
|
// Parse the open delimiter.
|
||||||
self.open_braces.push(self.span);
|
self.open_braces.push(self.span);
|
||||||
let mut result = vec!(parse_any_tt_tok(self));
|
let mut result = vec!(parse_any_tt_tok(self));
|
||||||
|
@ -2157,13 +2152,12 @@ impl<'a> Parser<'a> {
|
||||||
// the interpolation of Matcher's
|
// the interpolation of Matcher's
|
||||||
maybe_whole!(self, NtMatchers);
|
maybe_whole!(self, NtMatchers);
|
||||||
let mut name_idx = 0u;
|
let mut name_idx = 0u;
|
||||||
match self.token {
|
match token::close_delimiter_for(&self.token) {
|
||||||
token::LBRACE | token::LPAREN | token::LBRACKET => {
|
Some(other_delimiter) => {
|
||||||
let other_delimiter = token::flip_delimiter(&self.token);
|
|
||||||
self.bump();
|
self.bump();
|
||||||
self.parse_matcher_subseq_upto(&mut name_idx, &other_delimiter)
|
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;
|
let pth = self.parse_path(NoTypesAllowed).path;
|
||||||
self.bump();
|
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
|
token::special_idents::invalid // no special identifier
|
||||||
} else {
|
} else {
|
||||||
self.parse_ident()
|
self.parse_ident()
|
||||||
|
@ -3147,10 +3141,9 @@ impl<'a> Parser<'a> {
|
||||||
// check that we're pointing at delimiters (need to check
|
// check that we're pointing at delimiters (need to check
|
||||||
// again after the `if`, because of `parse_ident`
|
// again after the `if`, because of `parse_ident`
|
||||||
// consuming more tokens).
|
// consuming more tokens).
|
||||||
let (bra, ket) = match self.token {
|
let (bra, ket) = match token::close_delimiter_for(&self.token) {
|
||||||
token::LPAREN => (token::LPAREN, token::RPAREN),
|
Some(ket) => (self.token.clone(), ket),
|
||||||
token::LBRACE => (token::LBRACE, token::RBRACE),
|
None => {
|
||||||
_ => {
|
|
||||||
// we only expect an ident if we didn't parse one
|
// we only expect an ident if we didn't parse one
|
||||||
// above.
|
// above.
|
||||||
let ident_str = if id == token::special_idents::invalid {
|
let ident_str = if id == token::special_idents::invalid {
|
||||||
|
@ -4724,15 +4717,14 @@ impl<'a> Parser<'a> {
|
||||||
token::special_idents::invalid // no special identifier
|
token::special_idents::invalid // no special identifier
|
||||||
};
|
};
|
||||||
// eat a matched-delimiter token tree:
|
// eat a matched-delimiter token tree:
|
||||||
let tts = match self.token {
|
let tts = match token::close_delimiter_for(&self.token) {
|
||||||
token::LPAREN | token::LBRACE => {
|
Some(ket) => {
|
||||||
let ket = token::flip_delimiter(&self.token);
|
|
||||||
self.bump();
|
self.bump();
|
||||||
self.parse_seq_to_end(&ket,
|
self.parse_seq_to_end(&ket,
|
||||||
seq_sep_none(),
|
seq_sep_none(),
|
||||||
|p| p.parse_token_tree())
|
|p| p.parse_token_tree())
|
||||||
}
|
}
|
||||||
_ => self.fatal("expected open delimiter")
|
None => self.fatal("expected open delimiter")
|
||||||
};
|
};
|
||||||
// single-variant-enum... :
|
// single-variant-enum... :
|
||||||
let m = ast::MacInvocTT(pth, tts, EMPTY_CTXT);
|
let m = ast::MacInvocTT(pth, tts, EMPTY_CTXT);
|
||||||
|
|
|
@ -297,21 +297,17 @@ pub fn can_begin_expr(t: &Token) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// what's the opposite delimiter?
|
/// Returns the matching close delimiter if this is an open delimiter,
|
||||||
pub fn flip_delimiter(t: &token::Token) -> token::Token {
|
/// otherwise `None`.
|
||||||
|
pub fn close_delimiter_for(t: &Token) -> Option<Token> {
|
||||||
match *t {
|
match *t {
|
||||||
LPAREN => RPAREN,
|
LPAREN => Some(RPAREN),
|
||||||
LBRACE => RBRACE,
|
LBRACE => Some(RBRACE),
|
||||||
LBRACKET => RBRACKET,
|
LBRACKET => Some(RBRACKET),
|
||||||
RPAREN => LPAREN,
|
_ => None
|
||||||
RBRACE => LBRACE,
|
|
||||||
RBRACKET => LBRACKET,
|
|
||||||
_ => fail!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn is_lit(t: &Token) -> bool {
|
pub fn is_lit(t: &Token) -> bool {
|
||||||
match *t {
|
match *t {
|
||||||
LIT_CHAR(_) => true,
|
LIT_CHAR(_) => true,
|
||||||
|
|
23
src/test/run-pass/vec-macro-with-brackets.rs
Normal file
23
src/test/run-pass/vec-macro-with-brackets.rs
Normal 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];
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue