From 6757053cffb585249105fbd76f83a2fe7501219b Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 24 Feb 2014 00:53:59 +1100 Subject: [PATCH] syntax: allow stmt/expr macro invocations to be delimited by {}. This makes using control-flow-y macros like `spawn! { ... }` more fluent and natural. cc #11892. --- src/libsyntax/parse/parser.rs | 26 +++++++++++++++-- .../compile-fail/macro-bad-delimiter-ident.rs | 13 +++++++++ .../macro-mismatched-delim-brace-paren.rs | 15 ++++++++++ .../macro-mismatched-delim-paren-brace.rs | 15 ++++++++++ .../macro-with-braces-in-expr-position.rs | 28 +++++++++++++++++++ 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/macro-bad-delimiter-ident.rs create mode 100644 src/test/compile-fail/macro-mismatched-delim-brace-paren.rs create mode 100644 src/test/compile-fail/macro-mismatched-delim-paren-brace.rs create mode 100644 src/test/run-pass/macro-with-braces-in-expr-position.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dac668da343..cbe371a06a5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3185,15 +3185,35 @@ impl Parser { let pth = self.parse_path(NoTypesAllowed).path; self.bump(); - let id = if self.token == token::LPAREN { + let id = if self.token == token::LPAREN || self.token == token::LBRACE { token::special_idents::invalid // no special identifier } else { self.parse_ident() }; + // 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), + _ => { + // we only expect an ident if we didn't parse one + // above. + let ident_str = if id == token::special_idents::invalid { + "identifier, " + } else { + "" + }; + let tok_str = self.this_token_to_str(); + self.fatal(format!("expected {}`(` or `\\{`, but found `{}`", + ident_str, tok_str)) + } + }; + let tts = self.parse_unspanned_seq( - &token::LPAREN, - &token::RPAREN, + &bra, + &ket, seq_sep_none(), |p| p.parse_token_tree() ); diff --git a/src/test/compile-fail/macro-bad-delimiter-ident.rs b/src/test/compile-fail/macro-bad-delimiter-ident.rs new file mode 100644 index 00000000000..6f3b8bd421f --- /dev/null +++ b/src/test/compile-fail/macro-bad-delimiter-ident.rs @@ -0,0 +1,13 @@ +// 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. + +fn main() { + foo! bar < //~ ERROR expected `(` or `{`, but found `<` +} diff --git a/src/test/compile-fail/macro-mismatched-delim-brace-paren.rs b/src/test/compile-fail/macro-mismatched-delim-brace-paren.rs new file mode 100644 index 00000000000..d03698c1573 --- /dev/null +++ b/src/test/compile-fail/macro-mismatched-delim-brace-paren.rs @@ -0,0 +1,15 @@ +// 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. + +fn main() { + foo! { + bar, "baz", 1, 2.0 + ) //~ ERROR incorrect close delimiter +} diff --git a/src/test/compile-fail/macro-mismatched-delim-paren-brace.rs b/src/test/compile-fail/macro-mismatched-delim-paren-brace.rs new file mode 100644 index 00000000000..d80f93d7ad0 --- /dev/null +++ b/src/test/compile-fail/macro-mismatched-delim-paren-brace.rs @@ -0,0 +1,15 @@ +// 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. + +fn main() { + foo! ( + bar, "baz", 1, 2.0 + } //~ ERROR incorrect close delimiter +} diff --git a/src/test/run-pass/macro-with-braces-in-expr-position.rs b/src/test/run-pass/macro-with-braces-in-expr-position.rs new file mode 100644 index 00000000000..2a368568f8c --- /dev/null +++ b/src/test/run-pass/macro-with-braces-in-expr-position.rs @@ -0,0 +1,28 @@ +// 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! expr (($e: expr) => { $e }) + +macro_rules! spawn { + ($($code: tt)*) => { + expr!(spawn(proc() {$($code)*})) + } +} + +pub fn main() { + spawn! { + info!("stmt"); + }; + let _ = spawn! { + info!("expr"); + }; +}