Skip to content

Commit 3ab170f

Browse files
committed
auto merge of #16037 : erickt/rust/quote_arm, r=acrichto
This adds support for `quote_arm!(cx, $pat => $expr)`, and `macro_rules!(($a:arm) => (...))`. It also fixes a bug in pretty printing, where this would generate invalid code: ``` match { 5i } { 1 => 2, _ => 3, } ``` It would generate this code: ``` match { 5i } { 1 => 2 _ => 3 } ``` Finally, it adds a couple helper methods to `ExtCtxt`.
2 parents 692077b + e841a88 commit 3ab170f

File tree

13 files changed

+176
-81
lines changed

13 files changed

+176
-81
lines changed

src/libsyntax/ast.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,10 @@ pub enum Pat_ {
334334
/// records this pattern's NodeId in an auxiliary
335335
/// set (of "PatIdents that refer to nullary enums")
336336
PatIdent(BindingMode, SpannedIdent, Option<Gc<Pat>>),
337-
PatEnum(Path, Option<Vec<Gc<Pat>>>), /* "none" means a * pattern where
338-
* we don't bind the fields to names */
337+
338+
/// "None" means a * pattern where we don't bind the fields to names.
339+
PatEnum(Path, Option<Vec<Gc<Pat>>>),
340+
339341
PatStruct(Path, Vec<FieldPat>, bool),
340342
PatTup(Vec<Gc<Pat>>),
341343
PatBox(Gc<Pat>),

src/libsyntax/ext/base.rs

+3
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,9 @@ fn initial_syntax_expander_table() -> SyntaxEnv {
382382
syntax_expanders.insert(intern("quote_pat"),
383383
builtin_normal_expander(
384384
ext::quote::expand_quote_pat));
385+
syntax_expanders.insert(intern("quote_arm"),
386+
builtin_normal_expander(
387+
ext::quote::expand_quote_arm));
385388
syntax_expanders.insert(intern("quote_stmt"),
386389
builtin_normal_expander(
387390
ext::quote::expand_quote_stmt));

src/libsyntax/ext/build.rs

+52
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,13 @@ pub trait AstBuilder {
170170
subpats: Vec<Gc<ast::Pat>>) -> Gc<ast::Pat>;
171171
fn pat_struct(&self, span: Span,
172172
path: ast::Path, field_pats: Vec<ast::FieldPat> ) -> Gc<ast::Pat>;
173+
fn pat_tuple(&self, span: Span, pats: Vec<Gc<ast::Pat>>) -> Gc<ast::Pat>;
174+
175+
fn pat_some(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat>;
176+
fn pat_none(&self, span: Span) -> Gc<ast::Pat>;
177+
178+
fn pat_ok(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat>;
179+
fn pat_err(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat>;
173180

174181
fn arm(&self, span: Span, pats: Vec<Gc<ast::Pat>> , expr: Gc<ast::Expr>) -> ast::Arm;
175182
fn arm_unreachable(&self, span: Span) -> ast::Arm;
@@ -178,6 +185,7 @@ pub trait AstBuilder {
178185
fn expr_if(&self, span: Span,
179186
cond: Gc<ast::Expr>, then: Gc<ast::Expr>,
180187
els: Option<Gc<ast::Expr>>) -> Gc<ast::Expr>;
188+
fn expr_loop(&self, span: Span, block: P<ast::Block>) -> Gc<ast::Expr>;
181189

182190
fn lambda_fn_decl(&self, span: Span,
183191
fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> Gc<ast::Expr>;
@@ -777,6 +785,46 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
777785
let pat = ast::PatStruct(path, field_pats, false);
778786
self.pat(span, pat)
779787
}
788+
fn pat_tuple(&self, span: Span, pats: Vec<Gc<ast::Pat>>) -> Gc<ast::Pat> {
789+
let pat = ast::PatTup(pats);
790+
self.pat(span, pat)
791+
}
792+
793+
fn pat_some(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat> {
794+
let some = vec!(
795+
self.ident_of("std"),
796+
self.ident_of("option"),
797+
self.ident_of("Some"));
798+
let path = self.path_global(span, some);
799+
self.pat_enum(span, path, vec!(pat))
800+
}
801+
802+
fn pat_none(&self, span: Span) -> Gc<ast::Pat> {
803+
let some = vec!(
804+
self.ident_of("std"),
805+
self.ident_of("option"),
806+
self.ident_of("None"));
807+
let path = self.path_global(span, some);
808+
self.pat_enum(span, path, vec!())
809+
}
810+
811+
fn pat_ok(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat> {
812+
let some = vec!(
813+
self.ident_of("std"),
814+
self.ident_of("result"),
815+
self.ident_of("Ok"));
816+
let path = self.path_global(span, some);
817+
self.pat_enum(span, path, vec!(pat))
818+
}
819+
820+
fn pat_err(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat> {
821+
let some = vec!(
822+
self.ident_of("std"),
823+
self.ident_of("result"),
824+
self.ident_of("Err"));
825+
let path = self.path_global(span, some);
826+
self.pat_enum(span, path, vec!(pat))
827+
}
780828

781829
fn arm(&self, _span: Span, pats: Vec<Gc<ast::Pat>> , expr: Gc<ast::Expr>) -> ast::Arm {
782830
ast::Arm {
@@ -803,6 +851,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
803851
self.expr(span, ast::ExprIf(cond, self.block_expr(then), els))
804852
}
805853

854+
fn expr_loop(&self, span: Span, block: P<ast::Block>) -> Gc<ast::Expr> {
855+
self.expr(span, ast::ExprLoop(block, None))
856+
}
857+
806858
fn lambda_fn_decl(&self, span: Span,
807859
fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> Gc<ast::Expr> {
808860
self.expr(span, ast::ExprFnBlock(fn_decl, blk))

src/libsyntax/ext/quote.rs

+12
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,10 @@ pub mod rt {
144144
impl_to_source!(Generics, generics_to_string)
145145
impl_to_source!(Gc<ast::Item>, item_to_string)
146146
impl_to_source!(Gc<ast::Method>, method_to_string)
147+
impl_to_source!(Gc<ast::Stmt>, stmt_to_string)
147148
impl_to_source!(Gc<ast::Expr>, expr_to_string)
148149
impl_to_source!(Gc<ast::Pat>, pat_to_string)
150+
impl_to_source!(ast::Arm, arm_to_string)
149151
impl_to_source_slice!(ast::Ty, ", ")
150152
impl_to_source_slice!(Gc<ast::Item>, "\n\n")
151153

@@ -239,11 +241,13 @@ pub mod rt {
239241
impl_to_tokens!(ast::Ident)
240242
impl_to_tokens!(Gc<ast::Item>)
241243
impl_to_tokens!(Gc<ast::Pat>)
244+
impl_to_tokens!(ast::Arm)
242245
impl_to_tokens!(Gc<ast::Method>)
243246
impl_to_tokens_lifetime!(&'a [Gc<ast::Item>])
244247
impl_to_tokens!(ast::Ty)
245248
impl_to_tokens_lifetime!(&'a [ast::Ty])
246249
impl_to_tokens!(Generics)
250+
impl_to_tokens!(Gc<ast::Stmt>)
247251
impl_to_tokens!(Gc<ast::Expr>)
248252
impl_to_tokens!(ast::Block)
249253
impl_to_tokens!(ast::Arg)
@@ -345,6 +349,14 @@ pub fn expand_quote_pat(cx: &mut ExtCtxt,
345349
base::MacExpr::new(expanded)
346350
}
347351

352+
pub fn expand_quote_arm(cx: &mut ExtCtxt,
353+
sp: Span,
354+
tts: &[ast::TokenTree])
355+
-> Box<base::MacResult> {
356+
let expanded = expand_parse_call(cx, sp, "parse_arm", vec!(), tts);
357+
base::MacExpr::new(expanded)
358+
}
359+
348360
pub fn expand_quote_ty(cx: &mut ExtCtxt,
349361
sp: Span,
350362
tts: &[ast::TokenTree])

src/libsyntax/parse/parser.rs

+29-25
Original file line numberDiff line numberDiff line change
@@ -2727,37 +2727,41 @@ impl<'a> Parser<'a> {
27272727
self.commit_expr_expecting(discriminant, token::LBRACE);
27282728
let mut arms: Vec<Arm> = Vec::new();
27292729
while self.token != token::RBRACE {
2730-
let attrs = self.parse_outer_attributes();
2731-
let pats = self.parse_pats();
2732-
let mut guard = None;
2733-
if self.eat_keyword(keywords::If) {
2734-
guard = Some(self.parse_expr());
2735-
}
2736-
self.expect(&token::FAT_ARROW);
2737-
let expr = self.parse_expr_res(RESTRICT_STMT_EXPR);
2738-
2739-
let require_comma =
2740-
!classify::expr_is_simple_block(expr)
2741-
&& self.token != token::RBRACE;
2742-
2743-
if require_comma {
2744-
self.commit_expr(expr, &[token::COMMA], &[token::RBRACE]);
2745-
} else {
2746-
self.eat(&token::COMMA);
2747-
}
2748-
2749-
arms.push(ast::Arm {
2750-
attrs: attrs,
2751-
pats: pats,
2752-
guard: guard,
2753-
body: expr
2754-
});
2730+
arms.push(self.parse_arm());
27552731
}
27562732
let hi = self.span.hi;
27572733
self.bump();
27582734
return self.mk_expr(lo, hi, ExprMatch(discriminant, arms));
27592735
}
27602736

2737+
pub fn parse_arm(&mut self) -> Arm {
2738+
let attrs = self.parse_outer_attributes();
2739+
let pats = self.parse_pats();
2740+
let mut guard = None;
2741+
if self.eat_keyword(keywords::If) {
2742+
guard = Some(self.parse_expr());
2743+
}
2744+
self.expect(&token::FAT_ARROW);
2745+
let expr = self.parse_expr_res(RESTRICT_STMT_EXPR);
2746+
2747+
let require_comma =
2748+
!classify::expr_is_simple_block(expr)
2749+
&& self.token != token::RBRACE;
2750+
2751+
if require_comma {
2752+
self.commit_expr(expr, &[token::COMMA], &[token::RBRACE]);
2753+
} else {
2754+
self.eat(&token::COMMA);
2755+
}
2756+
2757+
ast::Arm {
2758+
attrs: attrs,
2759+
pats: pats,
2760+
guard: guard,
2761+
body: expr,
2762+
}
2763+
}
2764+
27612765
/// Parse an expression
27622766
pub fn parse_expr(&mut self) -> Gc<Expr> {
27632767
return self.parse_expr_res(UNRESTRICTED);

src/libsyntax/print/pprust.rs

+51-48
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use attr::{AttrMetaMethods, AttributeMethods};
1818
use codemap::{CodeMap, BytePos};
1919
use codemap;
2020
use diagnostic;
21-
use parse::classify::expr_is_simple_block;
2221
use parse::token;
2322
use parse::lexer::comments;
2423
use parse;
@@ -151,6 +150,10 @@ pub fn pat_to_string(pat: &ast::Pat) -> String {
151150
to_string(|s| s.print_pat(pat))
152151
}
153152

153+
pub fn arm_to_string(arm: &ast::Arm) -> String {
154+
to_string(|s| s.print_arm(arm))
155+
}
156+
154157
pub fn expr_to_string(e: &ast::Expr) -> String {
155158
to_string(|s| s.print_expr(e))
156159
}
@@ -1402,53 +1405,8 @@ impl<'a> State<'a> {
14021405
try!(self.print_expr(&**expr));
14031406
try!(space(&mut self.s));
14041407
try!(self.bopen());
1405-
let len = arms.len();
1406-
for (i, arm) in arms.iter().enumerate() {
1407-
// I have no idea why this check is necessary, but here it
1408-
// is :(
1409-
if arm.attrs.is_empty() {
1410-
try!(space(&mut self.s));
1411-
}
1412-
try!(self.cbox(indent_unit));
1413-
try!(self.ibox(0u));
1414-
try!(self.print_outer_attributes(arm.attrs.as_slice()));
1415-
let mut first = true;
1416-
for p in arm.pats.iter() {
1417-
if first {
1418-
first = false;
1419-
} else {
1420-
try!(space(&mut self.s));
1421-
try!(self.word_space("|"));
1422-
}
1423-
try!(self.print_pat(&**p));
1424-
}
1425-
try!(space(&mut self.s));
1426-
match arm.guard {
1427-
Some(ref e) => {
1428-
try!(self.word_space("if"));
1429-
try!(self.print_expr(&**e));
1430-
try!(space(&mut self.s));
1431-
}
1432-
None => ()
1433-
}
1434-
try!(self.word_space("=>"));
1435-
1436-
match arm.body.node {
1437-
ast::ExprBlock(ref blk) => {
1438-
// the block will close the pattern's ibox
1439-
try!(self.print_block_unclosed_indent(&**blk,
1440-
indent_unit));
1441-
}
1442-
_ => {
1443-
try!(self.end()); // close the ibox for the pattern
1444-
try!(self.print_expr(&*arm.body));
1445-
}
1446-
}
1447-
if !expr_is_simple_block(expr.clone())
1448-
&& i < len - 1 {
1449-
try!(word(&mut self.s, ","));
1450-
}
1451-
try!(self.end()); // close enclosing cbox
1408+
for arm in arms.iter() {
1409+
try!(self.print_arm(arm));
14521410
}
14531411
try!(self.bclose_(expr.span, indent_unit));
14541412
}
@@ -1882,6 +1840,51 @@ impl<'a> State<'a> {
18821840
self.ann.post(self, NodePat(pat))
18831841
}
18841842

1843+
fn print_arm(&mut self, arm: &ast::Arm) -> IoResult<()> {
1844+
// I have no idea why this check is necessary, but here it
1845+
// is :(
1846+
if arm.attrs.is_empty() {
1847+
try!(space(&mut self.s));
1848+
}
1849+
try!(self.cbox(indent_unit));
1850+
try!(self.ibox(0u));
1851+
try!(self.print_outer_attributes(arm.attrs.as_slice()));
1852+
let mut first = true;
1853+
for p in arm.pats.iter() {
1854+
if first {
1855+
first = false;
1856+
} else {
1857+
try!(space(&mut self.s));
1858+
try!(self.word_space("|"));
1859+
}
1860+
try!(self.print_pat(&**p));
1861+
}
1862+
try!(space(&mut self.s));
1863+
match arm.guard {
1864+
Some(ref e) => {
1865+
try!(self.word_space("if"));
1866+
try!(self.print_expr(&**e));
1867+
try!(space(&mut self.s));
1868+
}
1869+
None => ()
1870+
}
1871+
try!(self.word_space("=>"));
1872+
1873+
match arm.body.node {
1874+
ast::ExprBlock(ref blk) => {
1875+
// the block will close the pattern's ibox
1876+
try!(self.print_block_unclosed_indent(&**blk,
1877+
indent_unit));
1878+
}
1879+
_ => {
1880+
try!(self.end()); // close the ibox for the pattern
1881+
try!(self.print_expr(&*arm.body));
1882+
try!(word(&mut self.s, ","));
1883+
}
1884+
}
1885+
self.end() // close enclosing cbox
1886+
}
1887+
18851888
// Returns whether it printed anything
18861889
fn print_explicit_self(&mut self,
18871890
explicit_self: ast::ExplicitSelf_,

src/test/pretty/match-block-expr.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// pp-exact
12+
13+
fn main() {
14+
let x = match { 5i } { 1 => 5i, 2 => 6, _ => 7, };
15+
assert_eq!(x , 7);
16+
}

src/test/pretty/match-naked-expr-medium.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ fn main() {
1919
"long".to_string(), "string".to_string()],
2020
None =>
2121
["none".to_string(), "a".to_string(), "a".to_string(),
22-
"a".to_string(), "a".to_string()]
22+
"a".to_string(), "a".to_string()],
2323
};
2424
}

src/test/pretty/match-naked-expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ fn main() {
1515
let _y =
1616
match x {
1717
Some(_) => "some(_)".to_string(),
18-
None => "none".to_string()
18+
None => "none".to_string(),
1919
};
2020
}

src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ digraph block {
66
N4[label="expr 777i"];
77
N5[label="expr 7777i"];
88
N6[label="expr [7i, 77i, 777i, 7777i]"];
9-
N7[label="expr match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y }"];
9+
N7[label="expr match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, }"];
1010
N8[label="(dummy_node)"];
1111
N9[label="local x"];
1212
N10[label="local y"];
@@ -15,7 +15,7 @@ digraph block {
1515
N13[label="expr x"];
1616
N14[label="expr y"];
1717
N15[label="expr x + y"];
18-
N16[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y }; }"];
18+
N16[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, }; }"];
1919
N0 -> N2;
2020
N2 -> N3;
2121
N3 -> N4;

0 commit comments

Comments
 (0)