Add setx
for assignment expressions
This commit is contained in:
parent
7b3ef423c1
commit
6c74cf1f07
1
NEWS.rst
1
NEWS.rst
@ -12,6 +12,7 @@ New Features
|
||||
* Python 3.8 is now supported.
|
||||
* Format strings with embedded Hy code (e.g., `f"The sum is {(+ x y)}"`)
|
||||
are now supported, even on Pythons earlier than 3.6.
|
||||
* Added a special form `setx` to create Python 3.8 assignment expressions.
|
||||
* New list? function.
|
||||
* New tuple? function.
|
||||
|
||||
|
@ -4,7 +4,7 @@ import importlib
|
||||
import py
|
||||
import pytest
|
||||
import hy
|
||||
from hy._compat import PY3, PY36
|
||||
from hy._compat import PY3, PY36, PY38
|
||||
|
||||
NATIVE_TESTS = os.path.join("", "tests", "native_tests", "")
|
||||
|
||||
@ -13,7 +13,8 @@ _fspath_pyimport = py.path.local.pyimport
|
||||
|
||||
def pytest_ignore_collect(path, config):
|
||||
return (("py3_only" in path.basename and not PY3) or
|
||||
("py36_only" in path.basename and not PY36) or None)
|
||||
("py36_only" in path.basename and not PY36) or
|
||||
("py38_only" in path.basename and not PY38) or None)
|
||||
|
||||
|
||||
def pyimport_patch_mismatch(self, **kwargs):
|
||||
|
@ -412,6 +412,21 @@ They can be used to assign multiple variables at once:
|
||||
=>
|
||||
|
||||
|
||||
``setv`` always returns ``None``.
|
||||
|
||||
|
||||
setx
|
||||
-----
|
||||
|
||||
Whereas ``setv`` creates an assignment statement, ``setx`` creates an assignment expression (see :pep:`572`). It requires Python 3.8 or later. Only one target–value pair is allowed, and the target must be a bare symbol, but the ``setx`` form returns the assigned value instead of ``None``.
|
||||
|
||||
::
|
||||
|
||||
=> (when (> (setx x (+ 1 2)) 0)
|
||||
... (print x "is greater than 0"))
|
||||
3 is greater than 0
|
||||
|
||||
|
||||
defclass
|
||||
--------
|
||||
|
||||
|
@ -15,7 +15,7 @@ from hy.errors import (HyCompileError, HyTypeError, HyLanguageError,
|
||||
from hy.lex import mangle, unmangle, hy_parse, parse_one_thing, LexException
|
||||
|
||||
from hy._compat import (string_types, str_type, bytes_type, long_type, PY3,
|
||||
PY36, reraise)
|
||||
PY36, PY38, reraise)
|
||||
from hy.macros import require, load_macros, macroexpand, tag_macroexpand
|
||||
|
||||
import hy.core
|
||||
@ -1399,15 +1399,16 @@ class HyASTCompiler(object):
|
||||
expr, target=target, value=ret.force_expr, op=op())
|
||||
|
||||
@special("setv", [many(FORM + FORM)])
|
||||
@special((PY38, "setx"), [times(1, 1, SYM + FORM)])
|
||||
def compile_def_expression(self, expr, root, pairs):
|
||||
if not pairs:
|
||||
return asty.Name(expr, id='None', ctx=ast.Load())
|
||||
result = Result()
|
||||
for pair in pairs:
|
||||
result += self._compile_assign(*pair)
|
||||
result += self._compile_assign(root, *pair)
|
||||
return result
|
||||
|
||||
def _compile_assign(self, name, result):
|
||||
def _compile_assign(self, root, name, result):
|
||||
|
||||
str_name = "%s" % name
|
||||
if str_name in (["None"] + (["True", "False"] if PY3 else [])):
|
||||
@ -1427,14 +1428,18 @@ class HyASTCompiler(object):
|
||||
and isinstance(name, HySymbol)
|
||||
and '.' not in name):
|
||||
result.rename(name)
|
||||
# Throw away .expr to ensure that (setv ...) returns None.
|
||||
result.expr = None
|
||||
if root != HySymbol("setx"):
|
||||
# Throw away .expr to ensure that (setv ...) returns None.
|
||||
result.expr = None
|
||||
else:
|
||||
st_name = self._storeize(name, ld_name)
|
||||
result += asty.Assign(
|
||||
node = (asty.NamedExpr
|
||||
if root == HySymbol("setx")
|
||||
else asty.Assign)
|
||||
result += node(
|
||||
name if hasattr(name, "start_line") else result,
|
||||
targets=[st_name],
|
||||
value=result.force_expr)
|
||||
value=result.force_expr,
|
||||
target=st_name, targets=[st_name])
|
||||
|
||||
return result
|
||||
|
||||
|
29
tests/native_tests/py38_only_tests.hy
Normal file
29
tests/native_tests/py38_only_tests.hy
Normal file
@ -0,0 +1,29 @@
|
||||
;; Copyright 2019 the authors.
|
||||
;; This file is part of Hy, which is free software licensed under the Expat
|
||||
;; license. See the LICENSE.
|
||||
|
||||
;; Tests where the emitted code relies on Python ≥3.8.
|
||||
;; conftest.py skips this file when running on Python <3.8.
|
||||
|
||||
(import pytest)
|
||||
|
||||
(defn test-setx []
|
||||
(setx y (+ (setx x (+ "a" "b")) "c"))
|
||||
(assert (= x "ab"))
|
||||
(assert (= y "abc"))
|
||||
|
||||
(setv l [])
|
||||
(for [x [1 2 3]]
|
||||
(when (>= (setx y (+ x 8)) 10)
|
||||
(.append l y)))
|
||||
(assert (= l [10 11]))
|
||||
|
||||
(setv a ["apple" None "banana"])
|
||||
(setv filtered (lfor
|
||||
i (range (len a))
|
||||
:if (is-not (setx v (get a i)) None)
|
||||
v))
|
||||
(assert (= filtered ["apple" "banana"]))
|
||||
(assert (= v "banana"))
|
||||
(with [(pytest.raises NameError)]
|
||||
i))
|
Loading…
Reference in New Issue
Block a user