about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-07-30 13:01:10 +0000
committerbors <bors@rust-lang.org>2014-07-30 13:01:10 +0000
commit3ab170ffc5e45d31eef85db8fd7a3b68764f77c2 (patch)
tree8146c564ee7c93820cb78da85b9cd9f1d51cc081 /src/libsyntax
parent692077b6431460b96beb0ccf4f38299618d51db2 (diff)
parente841a88b9298b0d1fef93192d8e163b44645fc73 (diff)
downloadrust-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.rs6
-rw-r--r--src/libsyntax/ext/base.rs3
-rw-r--r--src/libsyntax/ext/build.rs52
-rw-r--r--src/libsyntax/ext/quote.rs12
-rw-r--r--src/libsyntax/parse/parser.rs54
-rw-r--r--src/libsyntax/print/pprust.rs99
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_,