Merge pull request #1585 from Kodiologist/empty-bodies
Allow `while` and `for` with empty bodies
This commit is contained in:
commit
51416424e2
1
NEWS.rst
1
NEWS.rst
@ -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
|
||||||
------------------------------
|
------------------------------
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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"""
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user