Support parsing catch expressions.
Fixes #109
diff --git a/tests/test_expr.rs b/tests/test_expr.rs
new file mode 100644
index 0000000..dca8603
--- /dev/null
+++ b/tests/test_expr.rs
@@ -0,0 +1,136 @@
+extern crate syn;
+use syn::*;
+
+macro_rules! assert_let {
+ ($p:pat = $e:expr) => {
+ assert_let!($p = $e; {})
+ };
+
+ ($p:pat = $e:expr; $body:block) => {
+ if let $p = $e
+ $body
+ else {
+ panic!("Expected to match {} but got {:?}", stringify!($p), $e)
+ }
+ };
+}
+
+#[test]
+#[cfg(feature = "full")]
+fn test_catch_expr() {
+ // Taken from tests/rust/src/test/run-pass/catch-expr.rs
+ let raw = r#"
+ struct catch {}
+
+ pub fn main() {
+ let catch_result = do catch {
+ let x = 5;
+ x
+ };
+ assert_eq!(catch_result, 5);
+
+ let mut catch = true;
+ while catch { catch = false; }
+ assert_eq!(catch, false);
+
+ catch = if catch { false } else { true };
+ assert_eq!(catch, true);
+
+ match catch {
+ _ => {}
+ };
+
+ let catch_err = do catch {
+ Err(22)?;
+ Ok(1)
+ };
+ assert_eq!(catch_err, Err(22));
+
+ let catch_okay: Result<i32, i32> = do catch {
+ if false { Err(25)?; }
+ Ok::<(), i32>(())?;
+ Ok(28)
+ };
+ assert_eq!(catch_okay, Ok(28));
+
+ let catch_from_loop: Result<i32, i32> = do catch {
+ for i in 0..10 {
+ if i < 5 { Ok::<i32, i32>(i)?; } else { Err(i)?; }
+ }
+ Ok(22)
+ };
+ assert_eq!(catch_from_loop, Err(5));
+
+ let cfg_init;
+ let _res: Result<(), ()> = do catch {
+ cfg_init = 5;
+ Ok(())
+ };
+ assert_eq!(cfg_init, 5);
+
+ let cfg_init_2;
+ let _res: Result<(), ()> = do catch {
+ cfg_init_2 = 6;
+ Err(())?;
+ Ok(())
+ };
+ assert_eq!(cfg_init_2, 6);
+
+ let my_string = "test".to_string();
+ let res: Result<&str, ()> = do catch {
+ Ok(&my_string)
+ };
+ assert_eq!(res, Ok("test"));
+ }
+ "#;
+
+ let actual = parse_crate(raw).unwrap();
+
+ assert_eq!(&actual.items[0].ident, "catch");
+
+ assert_let!(ItemKind::Struct(..) = actual.items[0].node);
+
+ assert_let!(Item { node: ItemKind::Fn(_, _, _, _, _, ref body), .. } = actual.items[1]; {
+ assert_let!(Stmt::Local(ref local) = body.stmts[0]; {
+ assert_let!(Local { init: Some(ref init_expr), .. } = **local; {
+ assert_let!(Expr { node: ExprKind::Catch(..), .. } = **init_expr);
+ });
+ });
+
+ assert_let!(Stmt::Local(ref local) = body.stmts[2]; {
+ assert_let!(Pat::Ident(BindingMode::ByValue(Mutability::Mutable), ref ident, None) = *local.pat; {
+ assert_eq!(ident, "catch");
+ });
+ });
+
+ assert_let!(Stmt::Expr(ref expr) = body.stmts[3]; {
+ assert_let!(Expr { node: ExprKind::While(ref loop_expr, _, None), .. } = **expr; {
+ assert_let!(Expr { node: ExprKind::Path(None, ref loop_var), .. } = **loop_expr; {
+ assert_eq!(*loop_var, "catch".into());
+ });
+ });
+ });
+
+ assert_let!(Stmt::Semi(ref expr) = body.stmts[5]; {
+ assert_let!(Expr { node: ExprKind::Assign(ref left, ref right), .. } = **expr; {
+ assert_let!(Expr { node: ExprKind::Path(None, ref loop_var), .. } = **left; {
+ assert_eq!(*loop_var, "catch".into());
+ });
+
+ assert_let!(Expr { node: ExprKind::If(ref if_expr, _, _), .. } = **right; {
+ assert_let!(Expr { node: ExprKind::Path(None, ref if_var), .. } = **if_expr; {
+ assert_eq!(*if_var, "catch".into());
+ });
+ });
+ });
+ });
+
+ assert_let!(Stmt::Semi(ref expr) = body.stmts[7]; {
+ assert_let!(Expr { node: ExprKind::Match(ref match_expr, _), .. } = **expr; {
+ assert_let!(Expr { node: ExprKind::Path(None, ref match_var), .. } = **match_expr; {
+ assert_eq!(*match_var, "catch".into());
+ });
+ });
+ });
+ });
+}