Implement Python 2 exec
The implementation of `hy.core.language.exec` draws code from the `exec_` function in commit f574c7be6ebc80041ef58ca29588f310248ebed4 of the library Six, which is copyright 2010–2017 Benjamin Peterson and licensed under the Expat license.
This commit is contained in:
parent
3dcf91ab39
commit
ecc974de1e
1
NEWS
1
NEWS
@ -23,6 +23,7 @@ Changes from 0.13.0
|
||||
mistaken for shebang lines
|
||||
* Fixed a bug where REPL history wasn't saved if you quit the REPL with
|
||||
`(quit)` or `(exit)`
|
||||
* `exec` now works under Python 2
|
||||
|
||||
Changes from 0.12.1
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
import re, os, sys, time, cgi
|
||||
sys.path.append(os.path.abspath(".."))
|
||||
|
||||
extensions = ['sphinx.ext.intersphinx']
|
||||
|
||||
from get_version import __version__ as hy_version
|
||||
# Read the Docs might dirty its checkout, so strip the dirty flag.
|
||||
hy_version = re.sub('[+.]dirty\Z', '', hy_version)
|
||||
@ -48,3 +50,7 @@ html_show_sphinx = False
|
||||
|
||||
html_context = dict(
|
||||
hy_descriptive_version = hy_descriptive_version)
|
||||
|
||||
intersphinx_mapping = dict(
|
||||
py2 = ('https://docs.python.org/2', None),
|
||||
py = ('https://docs.python.org/3', None))
|
||||
|
@ -281,6 +281,19 @@ otherwise ``False``. Return ``True`` if *coll* is empty.
|
||||
True
|
||||
|
||||
|
||||
.. _exec-fn:
|
||||
|
||||
exec
|
||||
----
|
||||
|
||||
Equivalent to Python 3's built-in function :py:func:`exec`.
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (exec "print(a + b)" {"a" 1} {"b" 2})
|
||||
3
|
||||
|
||||
|
||||
.. _float?-fn:
|
||||
|
||||
float?
|
||||
|
@ -778,6 +778,19 @@ class HyASTCompiler(object):
|
||||
def compile_unpack_mapping(self, expr):
|
||||
raise HyTypeError(expr, "`unpack-mapping` isn't allowed here")
|
||||
|
||||
@builds_if("exec*", not PY3)
|
||||
# Under Python 3, `exec` is a function rather than a statement type, so Hy
|
||||
# doesn't need a special form for it.
|
||||
@checkargs(min=1, max=3)
|
||||
def compile_exec(self, expr):
|
||||
expr.pop(0)
|
||||
return ast.Exec(
|
||||
lineno=expr.start_line,
|
||||
col_offset=expr.start_column,
|
||||
body=self.compile(expr.pop(0)).force_expr,
|
||||
globals=self.compile(expr.pop(0)).force_expr if expr else None,
|
||||
locals=self.compile(expr.pop(0)).force_expr if expr else None)
|
||||
|
||||
@builds("do")
|
||||
def compile_do(self, expression):
|
||||
expression.pop(0)
|
||||
|
@ -117,6 +117,24 @@
|
||||
range range
|
||||
zip zip))
|
||||
|
||||
(if-python2
|
||||
(defn exec [$code &optional $globals $locals]
|
||||
"Execute Python code.
|
||||
|
||||
The parameter names contain weird characters to discourage calling this
|
||||
function with keyword arguments, which isn't supported by Python 3's
|
||||
`exec`."
|
||||
(if
|
||||
(none? $globals) (do
|
||||
(setv frame (._getframe sys (int 1)))
|
||||
(try
|
||||
(setv $globals frame.f_globals $locals frame.f_locals)
|
||||
(finally (del frame))))
|
||||
(none? $locals)
|
||||
(setv $locals $globals))
|
||||
(exec* $code $globals $locals))
|
||||
(def exec exec))
|
||||
|
||||
;; infinite iterators
|
||||
(def
|
||||
count itertools.count
|
||||
@ -461,8 +479,8 @@
|
||||
(def *exports*
|
||||
'[*map accumulate butlast calling-module-name chain coll? combinations
|
||||
comp complement compress cons cons? constantly count cycle dec distinct
|
||||
disassemble drop drop-last drop-while empty? eval even? every? first filter
|
||||
flatten float? fraction gensym group-by identity inc input instance?
|
||||
disassemble drop drop-last drop-while empty? eval even? every? exec first
|
||||
filter flatten float? fraction gensym group-by identity inc input instance?
|
||||
integer integer? integer-char? interleave interpose islice iterable?
|
||||
iterate iterator? juxt keyword keyword? last list* macroexpand
|
||||
macroexpand-1 map merge-with multicombinations name neg? none? nth
|
||||
|
@ -593,3 +593,27 @@ def test_setv_builtins():
|
||||
def test_lots_of_comment_lines():
|
||||
# https://github.com/hylang/hy/issues/1313
|
||||
can_compile(1000 * ";\n")
|
||||
|
||||
|
||||
def test_exec_star():
|
||||
|
||||
code = can_compile('(exec* "print(5)")').body[0]
|
||||
assert type(code) == (ast.Expr if PY3 else ast.Exec)
|
||||
if not PY3:
|
||||
assert code.body.s == "print(5)"
|
||||
assert code.globals is None
|
||||
assert code.locals is None
|
||||
|
||||
code = can_compile('(exec* "print(a)" {"a" 3})').body[0]
|
||||
assert type(code) == (ast.Expr if PY3 else ast.Exec)
|
||||
if not PY3:
|
||||
assert code.body.s == "print(a)"
|
||||
assert code.globals.keys[0].s == "a"
|
||||
assert code.locals is None
|
||||
|
||||
code = can_compile('(exec* "print(a + b)" {"a" "x"} {"b" "y"})').body[0]
|
||||
assert type(code) == (ast.Expr if PY3 else ast.Exec)
|
||||
if not PY3:
|
||||
assert code.body.s == "print(a + b)"
|
||||
assert code.globals.keys[0].s == "a"
|
||||
assert code.locals.keys[0].s == "b"
|
||||
|
@ -170,6 +170,49 @@
|
||||
(assert-false (every? even? [2 4 5]))
|
||||
(assert-true (every? even? [])))
|
||||
|
||||
(setv globalvar 1)
|
||||
(defn test-exec []
|
||||
(setv localvar 1)
|
||||
(setv code "
|
||||
result['localvar in locals'] = 'localvar' in locals()
|
||||
result['localvar in globals'] = 'localvar' in globals()
|
||||
result['globalvar in locals'] = 'globalvar' in locals()
|
||||
result['globalvar in globals'] = 'globalvar' in globals()
|
||||
result['x in locals'] = 'x' in locals()
|
||||
result['x in globals'] = 'x' in globals()
|
||||
result['y in locals'] = 'y' in locals()
|
||||
result['y in globals'] = 'y' in globals()")
|
||||
|
||||
(setv result {})
|
||||
(exec code)
|
||||
(assert-true (get result "localvar in locals"))
|
||||
(assert-false (get result "localvar in globals"))
|
||||
(assert-false (get result "globalvar in locals"))
|
||||
(assert-true (get result "globalvar in globals"))
|
||||
(assert-false (or
|
||||
(get result "x in locals") (get result "x in globals")
|
||||
(get result "y in locals") (get result "y in globals")))
|
||||
|
||||
(setv result {})
|
||||
(exec code {"x" 1 "result" result})
|
||||
(assert-false (or
|
||||
(get result "localvar in locals") (get result "localvar in globals")
|
||||
(get result "globalvar in locals") (get result "globalvar in globals")))
|
||||
(assert-true (and
|
||||
(get result "x in locals") (get result "x in globals")))
|
||||
(assert-false (or
|
||||
(get result "y in locals") (get result "y in globals")))
|
||||
|
||||
(setv result {})
|
||||
(exec code {"x" 1 "result" result} {"y" 1})
|
||||
(assert-false (or
|
||||
(get result "localvar in locals") (get result "localvar in globals")
|
||||
(get result "globalvar in locals") (get result "globalvar in globals")))
|
||||
(assert-false (get result "x in locals"))
|
||||
(assert-true (get result "x in globals"))
|
||||
(assert-true (get result "y in locals"))
|
||||
(assert-false (get result "y in globals")))
|
||||
|
||||
(defn test-filter []
|
||||
"NATIVE: testing the filter function"
|
||||
(setv res (list (filter pos? [ 1 2 3 -4 5])))
|
||||
|
Loading…
Reference in New Issue
Block a user