Skip to content

Commit

Permalink
Allow loop/recur nested in catch and finally
Browse files Browse the repository at this point in the history
Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
  • Loading branch information
jarpiain authored and stuarthalloway committed Jun 16, 2012
1 parent 7c9ff0a commit ddc65a9
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 5 deletions.
8 changes: 3 additions & 5 deletions src/jvm/clojure/lang/Compiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -2133,7 +2133,7 @@ public Expr parse(C context, Object frm) {
if(bodyExpr == null)
try {
Var.pushThreadBindings(RT.map(NO_RECUR, true));
bodyExpr = (new BodyExpr.Parser()).parse(context, RT.seq(body));
bodyExpr = (new BodyExpr.Parser()).parse(C.EXPRESSION, RT.seq(body));
} finally {
Var.popThreadBindings();
}
Expand All @@ -2159,7 +2159,7 @@ public Expr parse(C context, Object frm) {
(Symbol) (RT.second(f) instanceof Symbol ? RT.second(f)
: null),
null,false);
Expr handler = (new BodyExpr.Parser()).parse(context, RT.next(RT.next(RT.next(f))));
Expr handler = (new BodyExpr.Parser()).parse(C.EXPRESSION, RT.next(RT.next(RT.next(f))));
catches = catches.cons(new CatchClause(c, lb, handler));
}
finally
Expand Down Expand Up @@ -2188,7 +2188,7 @@ public Expr parse(C context, Object frm) {
try
{
Var.pushThreadBindings(RT.map(NO_RECUR, true));
bodyExpr = (new BodyExpr.Parser()).parse(context, RT.seq(body));
bodyExpr = (new BodyExpr.Parser()).parse(C.EXPRESSION, RT.seq(body));
}
finally
{
Expand Down Expand Up @@ -6144,8 +6144,6 @@ public Expr parse(C context, Object frm) {
IPersistentVector loopLocals = (IPersistentVector) LOOP_LOCALS.deref();
if(context != C.RETURN || loopLocals == null)
throw new UnsupportedOperationException("Can only recur from tail position");
if(IN_CATCH_FINALLY.deref() != null)
throw new UnsupportedOperationException("Cannot recur from catch/finally");
if(NO_RECUR.deref() != null)
throw new UnsupportedOperationException("Cannot recur across try");
PersistentVector args = PersistentVector.EMPTY;
Expand Down
26 changes: 26 additions & 0 deletions test/clojure/test_clojure/compilation.clj
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@
(is (thrown? Compiler$CompilerException
(eval '(loop [x 5]
(try (recur 1)))))))
(testing "don't recur to loop from inside of catch inside of try"
(is (thrown? Compiler$CompilerException
(eval '(loop [x 5]
(try
(catch Exception e
(recur 1))))))))
(testing "don't recur to loop from inside of finally inside of try"
(is (thrown? Compiler$CompilerException
(eval '(loop [x 5]
(try
(finally
(recur 1))))))))
(testing "don't get confused about what the recur is targeting"
(is (thrown? Compiler$CompilerException
(eval '(loop [x 5]
Expand All @@ -71,6 +83,20 @@
(testing "allow loop/recur inside try"
(is (= 0 (eval '(try (loop [x 3]
(if (zero? x) x (recur (dec x)))))))))
(testing "allow loop/recur fully inside catch"
(is (= 3 (eval '(try
(throw (Exception.))
(catch Exception e
(loop [x 0]
(if (< x 3) (recur (inc x)) x))))))))
(testing "allow loop/recur fully inside finally"
(is (= "012" (eval '(with-out-str
(try
:return-val-discarded-because-of-with-out-str
(finally (loop [x 0]
(when (< x 3)
(print x)
(recur (inc x)))))))))))
(testing "allow fn/recur inside try"
(is (= 0 (eval '(try
((fn [x]
Expand Down

0 comments on commit ddc65a9

Please sign in to comment.