Allow defclass to have properties/method with built-in names

To allow classes to have methods that match built-in names, yet, still
disallow them outside of defclass, keep an internal state whether
builtins are allowed in the current context.

By default, this is false. But defclass will set it to True when it
compiles its body, and set it back to the previous value when it's done
with that. We need to set back to the previous value to allow nested
defclasses to work properly.

This closes #783.

Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This commit is contained in:
Gergely Nagy 2015-08-11 14:03:09 +02:00
parent 9bff606ee9
commit b92049d119
2 changed files with 16 additions and 2 deletions

View File

@ -370,6 +370,7 @@ def checkargs(exact=None, min=None, max=None, even=None, multiple=None):
class HyASTCompiler(object): class HyASTCompiler(object):
def __init__(self, module_name): def __init__(self, module_name):
self.allow_builtins = False
self.anon_fn_count = 0 self.anon_fn_count = 0
self.anon_var_count = 0 self.anon_var_count = 0
self.imports = defaultdict(set) self.imports = defaultdict(set)
@ -2005,7 +2006,8 @@ class HyASTCompiler(object):
start_line, start_column): start_line, start_column):
str_name = "%s" % name str_name = "%s" % name
if _is_hy_builtin(str_name, self.module_name): if _is_hy_builtin(str_name, self.module_name) and \
not self.allow_builtins:
raise HyTypeError(name, raise HyTypeError(name,
"Can't assign to a builtin: `%s'" % str_name) "Can't assign to a builtin: `%s'" % str_name)
@ -2275,6 +2277,8 @@ class HyASTCompiler(object):
docstring.start_column) docstring.start_column)
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)
@ -2287,6 +2291,8 @@ class HyASTCompiler(object):
for expression in expressions: for expression in expressions:
body += self.compile(macroexpand(expression, self.module_name)) body += self.compile(macroexpand(expression, self.module_name))
self.allow_builtins = allow_builtins
if not body.stmts: if not body.stmts:
body += ast.Pass(lineno=expressions.start_line, body += ast.Pass(lineno=expressions.start_line,
col_offset=expressions.start_column) col_offset=expressions.start_column)

View File

@ -554,6 +554,14 @@ def test_defn():
def test_setv_builtins(): def test_setv_builtins():
"""Ensure that assigning to a builtin fails""" """Ensure that assigning to a builtin fails, unless in a class"""
cant_compile("(setv nil 42)") cant_compile("(setv nil 42)")
cant_compile("(defn get [&rest args] 42)") cant_compile("(defn get [&rest args] 42)")
can_compile("(defclass A [] (defn get [self] 42))")
can_compile("""
(defclass A []
(defn get [self] 42)
(defclass B []
(defn get [self] 42))
(defn if [self] 0))
""")