Mangle names that coincide with Python keywords
This commit is contained in:
parent
52edad28e2
commit
d252bb0e94
@ -18,7 +18,7 @@ except ImportError:
|
|||||||
(x >> 8) & 0xff,
|
(x >> 8) & 0xff,
|
||||||
(x >> 16) & 0xff,
|
(x >> 16) & 0xff,
|
||||||
(x >> 24) & 0xff]))
|
(x >> 24) & 0xff]))
|
||||||
import sys
|
import sys, keyword
|
||||||
|
|
||||||
PY3 = sys.version_info[0] >= 3
|
PY3 = sys.version_info[0] >= 3
|
||||||
PY35 = sys.version_info >= (3, 5)
|
PY35 = sys.version_info >= (3, 5)
|
||||||
@ -37,15 +37,22 @@ else:
|
|||||||
raise t(*args)
|
raise t(*args)
|
||||||
|
|
||||||
def isidentifier(x):
|
def isidentifier(x):
|
||||||
|
if x in ('True', 'False', 'None', 'print'):
|
||||||
|
# `print` is special-cased here because Python 2's
|
||||||
|
# keyword.iskeyword will count it as a keyword, but we
|
||||||
|
# use the __future__ feature print_function, which makes
|
||||||
|
# it a non-keyword.
|
||||||
|
return True
|
||||||
|
if keyword.iskeyword(x):
|
||||||
|
return False
|
||||||
if PY3:
|
if PY3:
|
||||||
return x.isidentifier()
|
return x.isidentifier()
|
||||||
else:
|
if x.rstrip() != x:
|
||||||
if x.rstrip() != x:
|
return False
|
||||||
return False
|
import tokenize as T
|
||||||
import tokenize as T
|
from StringIO import StringIO
|
||||||
from StringIO import StringIO
|
try:
|
||||||
try:
|
tokens = list(T.generate_tokens(StringIO(x).readline))
|
||||||
tokens = list(T.generate_tokens(StringIO(x).readline))
|
except T.TokenError:
|
||||||
except T.TokenError:
|
return False
|
||||||
return False
|
return len(tokens) == 2 and tokens[0][0] == T.NAME
|
||||||
return len(tokens) == 2 and tokens[0][0] == T.NAME
|
|
||||||
|
@ -61,20 +61,6 @@ def load_stdlib():
|
|||||||
_stdlib[e] = module
|
_stdlib[e] = module
|
||||||
|
|
||||||
|
|
||||||
# True, False and None included here since they
|
|
||||||
# are assignable in Python 2.* but become
|
|
||||||
# keywords in Python 3.*
|
|
||||||
def _is_hy_builtin(name, module_name):
|
|
||||||
extras = ['True', 'False', 'None']
|
|
||||||
if name in extras or keyword.iskeyword(name):
|
|
||||||
return True
|
|
||||||
# for non-Hy modules, check for pre-existing name in
|
|
||||||
# _compile_table
|
|
||||||
if not module_name.startswith("hy."):
|
|
||||||
return name in _compile_table
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
_compile_table = {}
|
_compile_table = {}
|
||||||
_decoratables = (ast.FunctionDef, ast.ClassDef)
|
_decoratables = (ast.FunctionDef, ast.ClassDef)
|
||||||
if PY35:
|
if PY35:
|
||||||
@ -386,7 +372,6 @@ def ends_with_else(expr):
|
|||||||
class HyASTCompiler(object):
|
class HyASTCompiler(object):
|
||||||
|
|
||||||
def __init__(self, module_name):
|
def __init__(self, module_name):
|
||||||
self.allow_builtins = module_name.startswith("hy.core")
|
|
||||||
self.anon_var_count = 0
|
self.anon_var_count = 0
|
||||||
self.imports = defaultdict(set)
|
self.imports = defaultdict(set)
|
||||||
self.module_name = module_name
|
self.module_name = module_name
|
||||||
@ -1803,10 +1788,11 @@ class HyASTCompiler(object):
|
|||||||
def _compile_assign(self, name, result):
|
def _compile_assign(self, name, result):
|
||||||
|
|
||||||
str_name = "%s" % name
|
str_name = "%s" % name
|
||||||
if (_is_hy_builtin(str_name, self.module_name) and
|
if str_name in (["None"] + (["True", "False"] if PY3 else [])):
|
||||||
not self.allow_builtins):
|
# Python 2 allows assigning to True and False, although
|
||||||
|
# this is rarely wise.
|
||||||
raise HyTypeError(name,
|
raise HyTypeError(name,
|
||||||
"Can't assign to a builtin: `%s'" % str_name)
|
"Can't assign to `%s'" % str_name)
|
||||||
|
|
||||||
result = self.compile(result)
|
result = self.compile(result)
|
||||||
ld_name = self.compile(name)
|
ld_name = self.compile(name)
|
||||||
@ -2082,8 +2068,6 @@ class HyASTCompiler(object):
|
|||||||
body += self._compile_assign(symb, docstring)
|
body += self._compile_assign(symb, docstring)
|
||||||
body += body.expr_as_stmt()
|
body += body.expr_as_stmt()
|
||||||
|
|
||||||
allow_builtins = self.allow_builtins
|
|
||||||
self.allow_builtins = True
|
|
||||||
if expressions and isinstance(expressions[0], HyList) \
|
if expressions and isinstance(expressions[0], HyList) \
|
||||||
and not isinstance(expressions[0], HyExpression):
|
and not isinstance(expressions[0], HyExpression):
|
||||||
expr = expressions.pop(0)
|
expr = expressions.pop(0)
|
||||||
@ -2095,8 +2079,6 @@ class HyASTCompiler(object):
|
|||||||
for expression in expressions:
|
for expression in expressions:
|
||||||
body += self.compile(rewire_init(macroexpand(expression, self)))
|
body += self.compile(rewire_init(macroexpand(expression, self)))
|
||||||
|
|
||||||
self.allow_builtins = allow_builtins
|
|
||||||
|
|
||||||
if not body.stmts:
|
if not body.stmts:
|
||||||
body += asty.Pass(expressions)
|
body += asty.Pass(expressions)
|
||||||
|
|
||||||
|
@ -596,13 +596,11 @@ def test_invalid_list_comprehension():
|
|||||||
|
|
||||||
def test_bad_setv():
|
def test_bad_setv():
|
||||||
"""Ensure setv handles error cases"""
|
"""Ensure setv handles error cases"""
|
||||||
cant_compile("(setv if* 1)")
|
|
||||||
cant_compile("(setv (a b) [1 2])")
|
cant_compile("(setv (a b) [1 2])")
|
||||||
|
|
||||||
|
|
||||||
def test_defn():
|
def test_defn():
|
||||||
"""Ensure that defn works correctly in various corner cases"""
|
"""Ensure that defn works correctly in various corner cases"""
|
||||||
cant_compile("(defn if* [] 1)")
|
|
||||||
cant_compile("(defn \"hy\" [] 1)")
|
cant_compile("(defn \"hy\" [] 1)")
|
||||||
cant_compile("(defn :hy [] 1)")
|
cant_compile("(defn :hy [] 1)")
|
||||||
can_compile("(defn &hy [] 1)")
|
can_compile("(defn &hy [] 1)")
|
||||||
@ -611,7 +609,6 @@ def test_defn():
|
|||||||
def test_setv_builtins():
|
def test_setv_builtins():
|
||||||
"""Ensure that assigning to a builtin fails, unless in a class"""
|
"""Ensure that assigning to a builtin fails, unless in a class"""
|
||||||
cant_compile("(setv None 42)")
|
cant_compile("(setv None 42)")
|
||||||
cant_compile("(defn get [&rest args] 42)")
|
|
||||||
can_compile("(defclass A [] (defn get [self] 42))")
|
can_compile("(defclass A [] (defn get [self] 42))")
|
||||||
can_compile("""
|
can_compile("""
|
||||||
(defclass A []
|
(defclass A []
|
||||||
|
@ -65,19 +65,19 @@
|
|||||||
|
|
||||||
|
|
||||||
(defn test-setv-builtin []
|
(defn test-setv-builtin []
|
||||||
"NATIVE: test that setv doesn't work on builtins"
|
"NATIVE: test that setv doesn't work on names Python can't assign to
|
||||||
(try (eval '(setv False 1))
|
and that we can't mangle"
|
||||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
|
||||||
(try (eval '(setv True 0))
|
|
||||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
|
||||||
(try (eval '(setv None 1))
|
(try (eval '(setv None 1))
|
||||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
(except [e [TypeError]] (assert (in "Can't assign to" (str e)))))
|
||||||
(try (eval '(defn defclass [] (print "hello")))
|
(try (eval '(defn None [] (print "hello")))
|
||||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
(except [e [TypeError]] (assert (in "Can't assign to" (str e)))))
|
||||||
(try (eval '(defn get [] (print "hello")))
|
(when PY3
|
||||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
(try (eval '(setv False 1))
|
||||||
(try (eval '(defn fn [] (print "hello")))
|
(except [e [TypeError]] (assert (in "Can't assign to" (str e)))))
|
||||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))))
|
(try (eval '(setv True 0))
|
||||||
|
(except [e [TypeError]] (assert (in "Can't assign to" (str e)))))
|
||||||
|
(try (eval '(defn True [] (print "hello")))
|
||||||
|
(except [e [TypeError]] (assert (in "Can't assign to" (str e)))))))
|
||||||
|
|
||||||
|
|
||||||
(defn test-setv-pairs []
|
(defn test-setv-pairs []
|
||||||
@ -223,14 +223,14 @@
|
|||||||
|
|
||||||
; don't be fooled by constructs that look like else
|
; don't be fooled by constructs that look like else
|
||||||
(setv s "")
|
(setv s "")
|
||||||
(setv (get (globals) "else") True)
|
(setv else True)
|
||||||
(for [x "abcde"]
|
(for [x "abcde"]
|
||||||
(+= s x)
|
(+= s x)
|
||||||
[else (+= s "_")])
|
[else (+= s "_")])
|
||||||
(assert (= s "a_b_c_d_e_"))
|
(assert (= s "a_b_c_d_e_"))
|
||||||
|
|
||||||
(setv s "")
|
(setv s "")
|
||||||
(setv (get (globals) "else") True)
|
(setv else True)
|
||||||
(with [(pytest.raises TypeError)]
|
(with [(pytest.raises TypeError)]
|
||||||
(for [x "abcde"]
|
(for [x "abcde"]
|
||||||
(+= s x)
|
(+= s x)
|
||||||
@ -329,7 +329,7 @@
|
|||||||
; don't be fooled by constructs that look like else clauses
|
; don't be fooled by constructs that look like else clauses
|
||||||
(setv x 2)
|
(setv x 2)
|
||||||
(setv a [])
|
(setv a [])
|
||||||
(setv (get (globals) "else") True)
|
(setv else True)
|
||||||
(while x
|
(while x
|
||||||
(.append a x)
|
(.append a x)
|
||||||
(-= x 1)
|
(-= x 1)
|
||||||
|
@ -115,6 +115,20 @@
|
|||||||
(assert (= x "aabb")))
|
(assert (= x "aabb")))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-python-keyword []
|
||||||
|
(setv if 3)
|
||||||
|
(assert (= if 3))
|
||||||
|
(assert (= hyx_if 3)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-operator []
|
||||||
|
(setv + 3)
|
||||||
|
(assert (= + 3))
|
||||||
|
(if PY3
|
||||||
|
(assert (= hyx_Δplus_signΔ 3))
|
||||||
|
(assert (= hyx_Xplus_signX 3))))
|
||||||
|
|
||||||
|
|
||||||
(defn test-late-mangling []
|
(defn test-late-mangling []
|
||||||
; Mangling should only happen during compilation.
|
; Mangling should only happen during compilation.
|
||||||
(assert (!= 'foo? 'is_foo))
|
(assert (!= 'foo? 'is_foo))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user