Unverified Commit 57533951 authored by Jeffrey Schiller's avatar Jeffrey Schiller Committed by GitHub

Modified the “while” macro

Modified the “while” macro to avoid a bug in the Kawa in-line optimizer.

Change-Id: I4247adab9fbf80e2e3396f67c4aac5f4a21fa752
parent 41e45a6f
......@@ -800,25 +800,22 @@
;; Also unhygienic (see comment above about foreach)
;; The structure of this macro is important. If the argument to
;; call-with-current-continuation is a lambda expression, then Kawa
;; attempts to optimize it. This optimization fails spectacularly when
;; the lambda expression is tail-recursive (like ours is). By binding
;; the lambda expression to a variable and then calling via the
;; variable, the optimizer is not invoked and the code produced, while
;; not optmized, is correct.
(define-macro (while condition body . rest)
`(call-with-current-continuation
(lambda (*yail-break*)
(let *yail-loop* ()
(if ,condition
(begin
;; Kawa attempts to be smart by detecting unreachable
;; code and reporting it as an error. This causes an
;; issue here if *yail-break* is determined to be always
;; called within body-form, since *yail-loop* will
;; unreachable. The mixing of `or` and `and` operators
;; below fools the Kawa optimizer so that even in
;; trivial cases it won't flag the call to *yail-loop*
;; as unreachable. It also works around a bug in the
;; tail-recursive optimizer that breaks when the while
;; loop is empty.
(or (and ((lambda () (begin ,body . ,rest))) #f)
(*yail-loop*)))
#!null)))))
`(let ((cont (lambda (*yail-break*)
(let *yail-loop* ()
(if ,condition
(begin (begin ,body . ,rest)
(*yail-loop*))
*the-null-value*)))))
(call-with-current-continuation cont)))
;; Below are hygienic versions of the forrange, foreach and while
;; macros. They are here to be "future aware". A future version of
......
......@@ -253,7 +253,13 @@ public class YailEvalTest extends TestCase {
String schemeString = "(define theList (list)) (define foo 5) (while (< foo 10) " +
"(set! theList (append theList (list foo))) (set! foo (+ foo 1))) theList";
assertEquals("null, (5 6 7 8 9)", scheme.eval(schemeString).toString());
}
public void testYailWhileWithBreak() throws Throwable {
String schemeString = "(define theList (list))(define foo 5)(while (< foo 100)" +
"(set! theList (append theList (list foo)))(set! foo (+ foo 1))" +
"(if (= foo 10) (*yail-break* #f)))theList";
assertEquals("false, (5 6 7 8 9)", scheme.eval(schemeString).toString());
}
public void testYailAnd() throws Throwable {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment