Merge pull request #1585 from Kodiologist/empty-bodies

Allow `while` and `for` with empty bodies
This commit is contained in:
Kodi Arfer 2018-04-29 20:05:08 -07:00 committed by GitHub
commit 51416424e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 19 deletions

View File

@ -39,6 +39,7 @@ New Features
* `defclass` in Python 3 now supports specifying metaclasses and other * `defclass` in Python 3 now supports specifying metaclasses and other
keyword arguments keyword arguments
* Added a command-line option `-E` per CPython * Added a command-line option `-E` per CPython
* `while` and `for` are allowed to have empty bodies
Bug Fixes Bug Fixes
------------------------------ ------------------------------

View File

@ -1820,7 +1820,7 @@ class HyASTCompiler(object):
ret += node(expression, ret += node(expression,
target=target, target=target,
iter=ret.force_expr, iter=ret.force_expr,
body=body.stmts, body=body.stmts or [asty.Pass(expression)],
orelse=orel.stmts) orelse=orel.stmts)
ret.contains_yield = body.contains_yield ret.contains_yield = body.contains_yield
@ -1828,7 +1828,7 @@ class HyASTCompiler(object):
return ret return ret
@builds("while") @builds("while")
@checkargs(min=2) @checkargs(min=1)
def compile_while_expression(self, expr): def compile_while_expression(self, expr):
expr.pop(0) # "while" expr.pop(0) # "while"
cond = expr.pop(0) cond = expr.pop(0)
@ -1867,7 +1867,8 @@ class HyASTCompiler(object):
ret = cond_compiled + asty.While( ret = cond_compiled + asty.While(
expr, test=cond_compiled.force_expr, expr, test=cond_compiled.force_expr,
body=body.stmts, orelse=orel.stmts) body=body.stmts or [asty.Pass(expr)],
orelse=orel.stmts)
ret.contains_yield = body.contains_yield ret.contains_yield = body.contains_yield
return ret return ret

View File

@ -110,15 +110,11 @@ used as the result."
(defn _for [node args body] (defn _for [node args body]
(setv body (list body)) (setv body (list body))
(if (empty? body) (setv belse (if (and body (isinstance (get body -1) HyExpression) (= (get body -1 0) "else"))
(macro-error None "`for' requires a body to evaluate"))
(setv lst (get body -1))
(setv belse (if (and (isinstance lst HyExpression) (= (get lst 0) "else"))
[(body.pop)] [(body.pop)]
[])) []))
(if (if
(odd? (len args)) (macro-error args "`for' requires an even number of args.") (odd? (len args)) (macro-error args "`for' requires an even number of args.")
(empty? body) (macro-error None "`for' requires a body to evaluate")
(empty? args) `(do ~@body ~@belse) (empty? args) `(do ~@body ~@belse)
(= (len args) 2) `(~node [~@args] (do ~@body) ~@belse) (= (len args) 2) `(~node [~@args] (do ~@body) ~@belse)
(do (do

View File

@ -97,7 +97,6 @@ def test_ast_invalid_unary_op():
def test_ast_bad_while(): def test_ast_bad_while():
"Make sure AST can't compile invalid while" "Make sure AST can't compile invalid while"
cant_compile("(while)") cant_compile("(while)")
cant_compile("(while (True))")
def test_ast_good_do(): def test_ast_good_do():
@ -535,14 +534,6 @@ def test_for_compile_error():
can_compile("(fn [] (for [x] x))") can_compile("(fn [] (for [x] x))")
assert excinfo.value.message == "`for' requires an even number of args." assert excinfo.value.message == "`for' requires an even number of args."
with pytest.raises(HyTypeError) as excinfo:
can_compile("(fn [] (for [x xx]))")
assert excinfo.value.message == "`for' requires a body to evaluate"
with pytest.raises(HyTypeError) as excinfo:
can_compile("(fn [] (for [x xx] (else 1)))")
assert excinfo.value.message == "`for' requires a body to evaluate"
def test_attribute_access(): def test_attribute_access():
"""Ensure attribute access compiles correctly""" """Ensure attribute access compiles correctly"""

View File

@ -232,7 +232,15 @@
(assert (= (list ((fn [] (for [x [[1] [2 3]] y x] (yield y))))) (assert (= (list ((fn [] (for [x [[1] [2 3]] y x] (yield y)))))
(list-comp y [x [[1] [2 3]] y x]))) (list-comp y [x [[1] [2 3]] y x])))
(assert (= (list ((fn [] (for [x [[1] [2 3]] y x z (range 5)] (yield z))))) (assert (= (list ((fn [] (for [x [[1] [2 3]] y x z (range 5)] (yield z)))))
(list-comp z [x [[1] [2 3]] y x z (range 5)])))) (list-comp z [x [[1] [2 3]] y x z (range 5)])))
(setv l [])
(defn f []
(for [x [4 9 2]]
(.append l (* 10 x))
(yield x)))
(for [_ (f)])
(assert (= l [40 90 20])))
(defn test-nasty-for-nesting [] (defn test-nasty-for-nesting []
@ -283,7 +291,21 @@
(setv fact (* fact count)) (setv fact (* fact count))
(setv count (- count 1))) (setv count (- count 1)))
(assert (= count 0)) (assert (= count 0))
(assert (= fact 120))) (assert (= fact 120))
(setv l [])
(defn f []
(.append l 1)
(len l))
(while (!= (f) 4))
(assert (= l [1 1 1 1]))
(setv l [])
(defn f []
(.append l 1)
(len l))
(while (!= (f) 4) (do))
(assert (= l [1 1 1 1])))
(defn test-while-loop-else [] (defn test-while-loop-else []
(setv count 5) (setv count 5)