In order to fix #608, we need to know which symbols can't be assigned.
Python has the keyword.iskeyword method we can leverage for Python keywords, but we also need to address Hy builtins like 'get' or 'slice'. And to make behavior compatible with Python 2 or 3, we also make a special case to prevent assignment to False, True or None as well as the Hy versions: false, true, null, and nil. For non-Hy modules, we also check to make sure the symbol is not part of the compiler. This allows shadow.hy to override "+" but prevents general use from re-defn-ing 'get' or 'do'.
This commit is contained in:
parent
f3ecb96119
commit
16e908d56e
@ -47,6 +47,7 @@ import importlib
|
||||
import codecs
|
||||
import ast
|
||||
import sys
|
||||
import keyword
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
@ -73,6 +74,21 @@ def load_stdlib():
|
||||
_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',
|
||||
'true', 'false', 'nil', 'null']
|
||||
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 = {}
|
||||
|
||||
|
||||
@ -1751,6 +1767,12 @@ class HyASTCompiler(object):
|
||||
|
||||
def _compile_assign(self, name, result,
|
||||
start_line, start_column):
|
||||
|
||||
str_name = "%s" % name
|
||||
if _is_hy_builtin(str_name, self.module_name):
|
||||
raise HyTypeError(name,
|
||||
"Can't assign to a builtin: `%s'" % str_name)
|
||||
|
||||
result = self.compile(result)
|
||||
ld_name = self.compile(name)
|
||||
|
||||
|
@ -28,6 +28,28 @@
|
||||
(setv (get foo 0) 12)
|
||||
(assert (= (get foo 0) 12)))
|
||||
|
||||
(defn test-setv-builtin []
|
||||
"NATIVE: test that setv doesn't work on builtins"
|
||||
(try (eval '(setv False 1))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv True 0))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv None 1))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv false 1))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv true 0))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv nil 1))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv null 1))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(defn defclass [] (print "hello")))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(defn get [] (print "hello")))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(defn lambda [] (print "hello")))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))))
|
||||
|
||||
(defn test-for-loop []
|
||||
"NATIVE: test for loops"
|
||||
|
Loading…
Reference in New Issue
Block a user