From 3b7c25ce5b0b2bada6a45036a6455ed916b0b8e6 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 27 Jul 2014 15:11:02 -0700 Subject: [PATCH 1/5] syntax: add some more extension helper methods --- src/libsyntax/ext/build.rs | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 7d683382589b9..6c9e113f41a4c 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -170,6 +170,13 @@ pub trait AstBuilder { subpats: Vec>) -> Gc; fn pat_struct(&self, span: Span, path: ast::Path, field_pats: Vec ) -> Gc; + fn pat_tuple(&self, span: Span, pats: Vec>) -> Gc; + + fn pat_some(&self, span: Span, pat: Gc) -> Gc; + fn pat_none(&self, span: Span) -> Gc; + + fn pat_ok(&self, span: Span, pat: Gc) -> Gc; + fn pat_err(&self, span: Span, pat: Gc) -> Gc; fn arm(&self, span: Span, pats: Vec> , expr: Gc) -> 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, then: Gc, els: Option>) -> Gc; + fn expr_loop(&self, span: Span, block: P) -> Gc; fn lambda_fn_decl(&self, span: Span, fn_decl: P, blk: P) -> Gc; @@ -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 { + let pat = ast::PatTup(pats); + self.pat(span, pat) + } + + fn pat_some(&self, span: Span, pat: Gc) -> Gc { + 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 { + 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) -> Gc { + 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) -> Gc { + 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> , expr: Gc) -> 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) -> Gc { + self.expr(span, ast::ExprLoop(block, None)) + } + fn lambda_fn_decl(&self, span: Span, fn_decl: P, blk: P) -> Gc { self.expr(span, ast::ExprFnBlock(fn_decl, blk)) From 4d472ff1be571cc20d89ddc97d22c9903b6c3aa8 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 27 Jul 2014 15:11:42 -0700 Subject: [PATCH 2/5] syntax: allow quasiquoter to inline `Vec`s --- src/libsyntax/ext/quote.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index a7ede6f742d9f..5e15d6179bb54 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -144,6 +144,7 @@ pub mod rt { impl_to_source!(Generics, generics_to_string) impl_to_source!(Gc, item_to_string) impl_to_source!(Gc, method_to_string) + impl_to_source!(Gc, stmt_to_string) impl_to_source!(Gc, expr_to_string) impl_to_source!(Gc, pat_to_string) impl_to_source_slice!(ast::Ty, ", ") @@ -244,6 +245,7 @@ pub mod rt { impl_to_tokens!(ast::Ty) impl_to_tokens_lifetime!(&'a [ast::Ty]) impl_to_tokens!(Generics) + impl_to_tokens!(Gc) impl_to_tokens!(Gc) impl_to_tokens!(ast::Block) impl_to_tokens!(ast::Arg) From a46463d17920b99411337f20fc0e7edc72230c0b Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 27 Jul 2014 15:23:01 -0700 Subject: [PATCH 3/5] syntax: promote a comment on PatEnum into a docstring --- src/libsyntax/ast.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f05d17569f68d..4a59ada441fdb 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>), - PatEnum(Path, Option>>), /* "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>>), + PatStruct(Path, Vec, bool), PatTup(Vec>), PatBox(Gc), From 1200ad0f06fc1ecc9a5ccf320e704c95786dbfe3 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 27 Jul 2014 18:05:07 -0700 Subject: [PATCH 4/5] Fix a bug pretty printing `match { 5i } { _ => { } }` This also always puts a trailing comma on the last non-block expr. --- src/libsyntax/ext/quote.rs | 2 + src/libsyntax/print/pprust.rs | 99 +++++++++++----------- src/test/pretty/match-block-expr.rs | 16 ++++ src/test/pretty/match-naked-expr-medium.rs | 2 +- src/test/pretty/match-naked-expr.rs | 2 +- 5 files changed, 71 insertions(+), 50 deletions(-) create mode 100644 src/test/pretty/match-block-expr.rs diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 5e15d6179bb54..8f236cebcf471 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -147,6 +147,7 @@ pub mod rt { impl_to_source!(Gc, stmt_to_string) impl_to_source!(Gc, expr_to_string) impl_to_source!(Gc, pat_to_string) + impl_to_source!(ast::Arm, arm_to_string) impl_to_source_slice!(ast::Ty, ", ") impl_to_source_slice!(Gc, "\n\n") @@ -240,6 +241,7 @@ pub mod rt { impl_to_tokens!(ast::Ident) impl_to_tokens!(Gc) impl_to_tokens!(Gc) + impl_to_tokens!(ast::Arm) impl_to_tokens!(Gc) impl_to_tokens_lifetime!(&'a [Gc]) impl_to_tokens!(ast::Ty) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ac8355651916e..4ab9d1b486a34 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_, diff --git a/src/test/pretty/match-block-expr.rs b/src/test/pretty/match-block-expr.rs new file mode 100644 index 0000000000000..44771a29bb4fd --- /dev/null +++ b/src/test/pretty/match-block-expr.rs @@ -0,0 +1,16 @@ +// Copyright 2012 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. + +// pp-exact + +fn main() { + let x = match { 5i } { 1 => 5i, 2 => 6, _ => 7, }; + assert_eq!(x , 7); +} diff --git a/src/test/pretty/match-naked-expr-medium.rs b/src/test/pretty/match-naked-expr-medium.rs index c03ad49947892..d2f8157ef6213 100644 --- a/src/test/pretty/match-naked-expr-medium.rs +++ b/src/test/pretty/match-naked-expr-medium.rs @@ -19,6 +19,6 @@ fn main() { "long".to_string(), "string".to_string()], None => ["none".to_string(), "a".to_string(), "a".to_string(), - "a".to_string(), "a".to_string()] + "a".to_string(), "a".to_string()], }; } diff --git a/src/test/pretty/match-naked-expr.rs b/src/test/pretty/match-naked-expr.rs index 67c389f7e1f08..6b4f579f9c51c 100644 --- a/src/test/pretty/match-naked-expr.rs +++ b/src/test/pretty/match-naked-expr.rs @@ -15,6 +15,6 @@ fn main() { let _y = match x { Some(_) => "some(_)".to_string(), - None => "none".to_string() + None => "none".to_string(), }; } From e841a88b9298b0d1fef93192d8e163b44645fc73 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Mon, 28 Jul 2014 17:32:51 -0700 Subject: [PATCH 5/5] syntax: add support for quoting arms --- src/libsyntax/ext/base.rs | 3 ++ src/libsyntax/ext/quote.rs | 8 +++ src/libsyntax/parse/parser.rs | 54 ++++++++++--------- .../graphviz-flowgraph/f07.dot-expected.dot | 4 +- .../graphviz-flowgraph/f13.dot-expected.dot | 4 +- src/test/run-pass-fulldeps/qquote.rs | 2 + src/test/run-pass-fulldeps/quote-tokens.rs | 1 + 7 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a66d6839ab074..d00406e07b77d 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/quote.rs b/src/libsyntax/ext/quote.rs index 8f236cebcf471..dcfb019812774 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -349,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 { + 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 878994369d0d4..945a643d2b478 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 = 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 { return self.parse_expr_res(UNRESTRICTED); diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot index f0907d8d708f2..2b7088fbc33ff 100644 --- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot @@ -6,7 +6,7 @@ digraph block { N4[label="expr 777i"]; N5[label="expr 7777i"]; N6[label="expr [7i, 77i, 777i, 7777i]"]; - N7[label="expr match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y }"]; + N7[label="expr match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, }"]; N8[label="(dummy_node)"]; N9[label="local x"]; N10[label="local y"]; @@ -15,7 +15,7 @@ digraph block { N13[label="expr x"]; N14[label="expr y"]; N15[label="expr x + y"]; - N16[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y }; }"]; + N16[label="block { match [7i, 77i, 777i, 7777i] { [x, y, ..] => x + y, }; }"]; N0 -> N2; N2 -> N3; N3 -> N4; diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot index dbfa4dd6fe92c..5d1d1253b2238 100644 --- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot @@ -7,7 +7,7 @@ digraph block { N5[label="local x"]; N6[label="local _y"]; N7[label="expr x"]; - N8[label="expr match x { E13a => _y = 1, E13b(v) => _y = v + 1 }"]; + N8[label="expr match x { E13a => _y = 1, E13b(v) => _y = v + 1, }"]; N9[label="(dummy_node)"]; N10[label="local E13a"]; N11[label="expr 1"]; @@ -21,7 +21,7 @@ digraph block { N19[label="expr v + 1"]; N20[label="expr _y"]; N21[label="expr _y = v + 1"]; - N22[label="block {\l let x = E13b(13);\l let _y;\l match x { E13a => _y = 1, E13b(v) => _y = v + 1 }\l}\l"]; + N22[label="block {\l let x = E13b(13);\l let _y;\l match x { E13a => _y = 1, E13b(v) => _y = v + 1, }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index 36b525c134b99..a5cf8e46b7e43 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -72,6 +72,8 @@ fn main() { let pat = quote_pat!(cx, Some(_)); check_pp(ext_cx, pat, pprust::print_pat, "Some(_)".to_string()); + let arm = quote_arm!(cx, (ref x, ref y) => (x, y)); + check_pp(ext_cx, arm, pprust::print_stmt, "(ref x, ref y) = (x, y)".to_string()); } fn check_pp(cx: fake_ext_ctxt, diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index 11c3dfb2241f7..60b8f09bb3ded 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -26,6 +26,7 @@ fn syntax_extension(cx: &ExtCtxt) { let _b: Option> = quote_item!(cx, static foo : int = $e_toks; ); let _c: Gc = quote_pat!(cx, (x, 1 .. 4, *) ); let _d: Gc = quote_stmt!(cx, let x = $a; ); + let _d: syntax::ast::Arm = quote_arm!(cx, (ref x, ref y) = (x, y) ); let _e: Gc = quote_expr!(cx, match foo { $p_toks => 10 } ); let _f: Gc = quote_expr!(cx, ());