diff options
| author | bors <bors@rust-lang.org> | 2014-07-30 13:01:10 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-07-30 13:01:10 +0000 |
| commit | 3ab170ffc5e45d31eef85db8fd7a3b68764f77c2 (patch) | |
| tree | 8146c564ee7c93820cb78da85b9cd9f1d51cc081 /src/libsyntax | |
| parent | 692077b6431460b96beb0ccf4f38299618d51db2 (diff) | |
| parent | e841a88b9298b0d1fef93192d8e163b44645fc73 (diff) | |
| download | rust-3ab170ffc5e45d31eef85db8fd7a3b68764f77c2.tar.gz rust-3ab170ffc5e45d31eef85db8fd7a3b68764f77c2.zip | |
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`.
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 52 | ||||
| -rw-r--r-- | src/libsyntax/ext/quote.rs | 12 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 54 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 99 |
6 files changed, 151 insertions, 75 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f05d17569f6..4a59ada441f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -334,8 +334,10 @@ pub enum Pat_ { /// records this pattern's NodeId in an auxiliary /// set (of "PatIdents that refer to nullary enums") PatIdent(BindingMode, SpannedIdent, Option<Gc<Pat>>), - PatEnum(Path, Option<Vec<Gc<Pat>>>), /* "none" means a * pattern where - * we don't bind the fields to names */ + + /// "None" means a * pattern where we don't bind the fields to names. + PatEnum(Path, Option<Vec<Gc<Pat>>>), + PatStruct(Path, Vec<FieldPat>, bool), PatTup(Vec<Gc<Pat>>), PatBox(Gc<Pat>), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a66d6839ab0..d00406e07b7 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -382,6 +382,9 @@ fn initial_syntax_expander_table() -> SyntaxEnv { syntax_expanders.insert(intern("quote_pat"), builtin_normal_expander( ext::quote::expand_quote_pat)); + syntax_expanders.insert(intern("quote_arm"), + builtin_normal_expander( + ext::quote::expand_quote_arm)); syntax_expanders.insert(intern("quote_stmt"), builtin_normal_expander( ext::quote::expand_quote_stmt)); diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 7d683382589..6c9e113f41a 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -170,6 +170,13 @@ pub trait AstBuilder { subpats: Vec<Gc<ast::Pat>>) -> Gc<ast::Pat>; fn pat_struct(&self, span: Span, path: ast::Path, field_pats: Vec<ast::FieldPat> ) -> Gc<ast::Pat>; + fn pat_tuple(&self, span: Span, pats: Vec<Gc<ast::Pat>>) -> Gc<ast::Pat>; + + fn pat_some(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat>; + fn pat_none(&self, span: Span) -> Gc<ast::Pat>; + + fn pat_ok(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat>; + fn pat_err(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat>; fn arm(&self, span: Span, pats: Vec<Gc<ast::Pat>> , expr: Gc<ast::Expr>) -> ast::Arm; fn arm_unreachable(&self, span: Span) -> ast::Arm; @@ -178,6 +185,7 @@ pub trait AstBuilder { fn expr_if(&self, span: Span, cond: Gc<ast::Expr>, then: Gc<ast::Expr>, els: Option<Gc<ast::Expr>>) -> Gc<ast::Expr>; + fn expr_loop(&self, span: Span, block: P<ast::Block>) -> Gc<ast::Expr>; fn lambda_fn_decl(&self, span: Span, fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> Gc<ast::Expr>; @@ -777,6 +785,46 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let pat = ast::PatStruct(path, field_pats, false); self.pat(span, pat) } + fn pat_tuple(&self, span: Span, pats: Vec<Gc<ast::Pat>>) -> Gc<ast::Pat> { + let pat = ast::PatTup(pats); + self.pat(span, pat) + } + + fn pat_some(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat> { + let some = vec!( + self.ident_of("std"), + self.ident_of("option"), + self.ident_of("Some")); + let path = self.path_global(span, some); + self.pat_enum(span, path, vec!(pat)) + } + + fn pat_none(&self, span: Span) -> Gc<ast::Pat> { + let some = vec!( + self.ident_of("std"), + self.ident_of("option"), + self.ident_of("None")); + let path = self.path_global(span, some); + self.pat_enum(span, path, vec!()) + } + + fn pat_ok(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat> { + let some = vec!( + self.ident_of("std"), + self.ident_of("result"), + self.ident_of("Ok")); + let path = self.path_global(span, some); + self.pat_enum(span, path, vec!(pat)) + } + + fn pat_err(&self, span: Span, pat: Gc<ast::Pat>) -> Gc<ast::Pat> { + let some = vec!( + self.ident_of("std"), + self.ident_of("result"), + self.ident_of("Err")); + let path = self.path_global(span, some); + self.pat_enum(span, path, vec!(pat)) + } fn arm(&self, _span: Span, pats: Vec<Gc<ast::Pat>> , expr: Gc<ast::Expr>) -> ast::Arm { ast::Arm { @@ -803,6 +851,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(span, ast::ExprIf(cond, self.block_expr(then), els)) } + fn expr_loop(&self, span: Span, block: P<ast::Block>) -> Gc<ast::Expr> { + self.expr(span, ast::ExprLoop(block, None)) + } + fn lambda_fn_decl(&self, span: Span, fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> Gc<ast::Expr> { self.expr(span, ast::ExprFnBlock(fn_decl, blk)) diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index a7ede6f742d..dcfb0198127 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -144,8 +144,10 @@ pub mod rt { impl_to_source!(Generics, generics_to_string) impl_to_source!(Gc<ast::Item>, item_to_string) impl_to_source!(Gc<ast::Method>, method_to_string) + impl_to_source!(Gc<ast::Stmt>, stmt_to_string) impl_to_source!(Gc<ast::Expr>, expr_to_string) impl_to_source!(Gc<ast::Pat>, pat_to_string) + impl_to_source!(ast::Arm, arm_to_string) impl_to_source_slice!(ast::Ty, ", ") impl_to_source_slice!(Gc<ast::Item>, "\n\n") @@ -239,11 +241,13 @@ pub mod rt { impl_to_tokens!(ast::Ident) impl_to_tokens!(Gc<ast::Item>) impl_to_tokens!(Gc<ast::Pat>) + impl_to_tokens!(ast::Arm) impl_to_tokens!(Gc<ast::Method>) impl_to_tokens_lifetime!(&'a [Gc<ast::Item>]) impl_to_tokens!(ast::Ty) impl_to_tokens_lifetime!(&'a [ast::Ty]) impl_to_tokens!(Generics) + impl_to_tokens!(Gc<ast::Stmt>) impl_to_tokens!(Gc<ast::Expr>) impl_to_tokens!(ast::Block) impl_to_tokens!(ast::Arg) @@ -345,6 +349,14 @@ pub fn expand_quote_pat(cx: &mut ExtCtxt, base::MacExpr::new(expanded) } +pub fn expand_quote_arm(cx: &mut ExtCtxt, + sp: Span, + tts: &[ast::TokenTree]) + -> Box<base::MacResult> { + let expanded = expand_parse_call(cx, sp, "parse_arm", vec!(), tts); + base::MacExpr::new(expanded) +} + pub fn expand_quote_ty(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 878994369d0..945a643d2b4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2727,37 +2727,41 @@ impl<'a> Parser<'a> { self.commit_expr_expecting(discriminant, token::LBRACE); let mut arms: Vec<Arm> = Vec::new(); while self.token != token::RBRACE { - let attrs = self.parse_outer_attributes(); - let pats = self.parse_pats(); - let mut guard = None; - if self.eat_keyword(keywords::If) { - guard = Some(self.parse_expr()); - } - self.expect(&token::FAT_ARROW); - let expr = self.parse_expr_res(RESTRICT_STMT_EXPR); - - let require_comma = - !classify::expr_is_simple_block(expr) - && self.token != token::RBRACE; - - if require_comma { - self.commit_expr(expr, &[token::COMMA], &[token::RBRACE]); - } else { - self.eat(&token::COMMA); - } - - arms.push(ast::Arm { - attrs: attrs, - pats: pats, - guard: guard, - body: expr - }); + arms.push(self.parse_arm()); } let hi = self.span.hi; self.bump(); return self.mk_expr(lo, hi, ExprMatch(discriminant, arms)); } + pub fn parse_arm(&mut self) -> Arm { + let attrs = self.parse_outer_attributes(); + let pats = self.parse_pats(); + let mut guard = None; + if self.eat_keyword(keywords::If) { + guard = Some(self.parse_expr()); + } + self.expect(&token::FAT_ARROW); + let expr = self.parse_expr_res(RESTRICT_STMT_EXPR); + + let require_comma = + !classify::expr_is_simple_block(expr) + && self.token != token::RBRACE; + + if require_comma { + self.commit_expr(expr, &[token::COMMA], &[token::RBRACE]); + } else { + self.eat(&token::COMMA); + } + + ast::Arm { + attrs: attrs, + pats: pats, + guard: guard, + body: expr, + } + } + /// Parse an expression pub fn parse_expr(&mut self) -> Gc<Expr> { return self.parse_expr_res(UNRESTRICTED); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ac835565191..4ab9d1b486a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -18,7 +18,6 @@ use attr::{AttrMetaMethods, AttributeMethods}; use codemap::{CodeMap, BytePos}; use codemap; use diagnostic; -use parse::classify::expr_is_simple_block; use parse::token; use parse::lexer::comments; use parse; @@ -151,6 +150,10 @@ pub fn pat_to_string(pat: &ast::Pat) -> String { to_string(|s| s.print_pat(pat)) } +pub fn arm_to_string(arm: &ast::Arm) -> String { + to_string(|s| s.print_arm(arm)) +} + pub fn expr_to_string(e: &ast::Expr) -> String { to_string(|s| s.print_expr(e)) } @@ -1402,53 +1405,8 @@ impl<'a> State<'a> { try!(self.print_expr(&**expr)); try!(space(&mut self.s)); try!(self.bopen()); - let len = arms.len(); - for (i, arm) in arms.iter().enumerate() { - // I have no idea why this check is necessary, but here it - // is :( - if arm.attrs.is_empty() { - try!(space(&mut self.s)); - } - try!(self.cbox(indent_unit)); - try!(self.ibox(0u)); - try!(self.print_outer_attributes(arm.attrs.as_slice())); - let mut first = true; - for p in arm.pats.iter() { - if first { - first = false; - } else { - try!(space(&mut self.s)); - try!(self.word_space("|")); - } - try!(self.print_pat(&**p)); - } - try!(space(&mut self.s)); - match arm.guard { - Some(ref e) => { - try!(self.word_space("if")); - try!(self.print_expr(&**e)); - try!(space(&mut self.s)); - } - None => () - } - try!(self.word_space("=>")); - - match arm.body.node { - ast::ExprBlock(ref blk) => { - // the block will close the pattern's ibox - try!(self.print_block_unclosed_indent(&**blk, - indent_unit)); - } - _ => { - try!(self.end()); // close the ibox for the pattern - try!(self.print_expr(&*arm.body)); - } - } - if !expr_is_simple_block(expr.clone()) - && i < len - 1 { - try!(word(&mut self.s, ",")); - } - try!(self.end()); // close enclosing cbox + for arm in arms.iter() { + try!(self.print_arm(arm)); } try!(self.bclose_(expr.span, indent_unit)); } @@ -1882,6 +1840,51 @@ impl<'a> State<'a> { self.ann.post(self, NodePat(pat)) } + fn print_arm(&mut self, arm: &ast::Arm) -> IoResult<()> { + // I have no idea why this check is necessary, but here it + // is :( + if arm.attrs.is_empty() { + try!(space(&mut self.s)); + } + try!(self.cbox(indent_unit)); + try!(self.ibox(0u)); + try!(self.print_outer_attributes(arm.attrs.as_slice())); + let mut first = true; + for p in arm.pats.iter() { + if first { + first = false; + } else { + try!(space(&mut self.s)); + try!(self.word_space("|")); + } + try!(self.print_pat(&**p)); + } + try!(space(&mut self.s)); + match arm.guard { + Some(ref e) => { + try!(self.word_space("if")); + try!(self.print_expr(&**e)); + try!(space(&mut self.s)); + } + None => () + } + try!(self.word_space("=>")); + + match arm.body.node { + ast::ExprBlock(ref blk) => { + // the block will close the pattern's ibox + try!(self.print_block_unclosed_indent(&**blk, + indent_unit)); + } + _ => { + try!(self.end()); // close the ibox for the pattern + try!(self.print_expr(&*arm.body)); + try!(word(&mut self.s, ",")); + } + } + self.end() // close enclosing cbox + } + // Returns whether it printed anything fn print_explicit_self(&mut self, explicit_self: ast::ExplicitSelf_, |
