Unify illegal special forms

This commit is contained in:
Kodi Arfer 2018-04-21 13:39:49 -07:00
parent 45e8783997
commit 57b5fa49b1
2 changed files with 16 additions and 22 deletions

View File

@ -62,12 +62,6 @@ def load_stdlib():
_stdlib[e] = module _stdlib[e] = module
_compile_table = {}
_decoratables = (ast.FunctionDef, ast.ClassDef)
if PY35:
_decoratables += (ast.AsyncFunctionDef,)
def ast_str(x, piecewise=False): def ast_str(x, piecewise=False):
if piecewise: if piecewise:
return ".".join(ast_str(s) if s else "" for s in x.split(".")) return ".".join(ast_str(s) if s else "" for s in x.split("."))
@ -75,6 +69,17 @@ def ast_str(x, piecewise=False):
return x if PY3 else x.encode('UTF8') return x if PY3 else x.encode('UTF8')
_compile_table = {}
_decoratables = (ast.FunctionDef, ast.ClassDef)
if PY35:
_decoratables += (ast.AsyncFunctionDef,)
# _bad_roots are fake special operators, which are used internally
# by other special forms (e.g., `except` in `try`) but can't be
# used to construct special forms themselves.
_bad_roots = tuple(ast_str(x) for x in (
"unquote", "unquote-splice", "unpack-mapping", "except"))
def builds(*types, **kwargs): def builds(*types, **kwargs):
# A decorator that adds the decorated method to _compile_table for # A decorator that adds the decorated method to _compile_table for
# compiling `types`, but only if kwargs['iff'] (if provided) is # compiling `types`, but only if kwargs['iff'] (if provided) is
@ -433,6 +438,9 @@ class HyASTCompiler(object):
def compile_atom(self, atom_type, atom): def compile_atom(self, atom_type, atom):
if isinstance(atom_type, string_types): if isinstance(atom_type, string_types):
atom_type = ast_str(atom_type) atom_type = ast_str(atom_type)
if atom_type in _bad_roots:
raise HyTypeError(atom, "The special form '{}' "
"is not allowed here".format(atom_type))
if atom_type in _compile_table: if atom_type in _compile_table:
# _compile_table[atom_type] is a method for compiling this # _compile_table[atom_type] is a method for compiling this
# type of atom, so call it. If it has an extra parameter, # type of atom, so call it. If it has an extra parameter,
@ -672,11 +680,6 @@ class HyASTCompiler(object):
ret.add_imports("hy", imports) ret.add_imports("hy", imports)
return ret return ret
@builds("unquote", "unquote-splice")
def compile_unquote(self, expr):
raise HyTypeError(expr,
"`%s' can't be used at the top-level" % expr[0])
@special("unpack-iterable", [FORM]) @special("unpack-iterable", [FORM])
def compile_unpack_iterable(self, expr, root, arg): def compile_unpack_iterable(self, expr, root, arg):
if not PY3: if not PY3:
@ -685,10 +688,6 @@ class HyASTCompiler(object):
ret += asty.Starred(expr, value=ret.force_expr, ctx=ast.Load()) ret += asty.Starred(expr, value=ret.force_expr, ctx=ast.Load())
return ret return ret
@builds("unpack-mapping")
def compile_unpack_mapping(self, expr):
raise HyTypeError(expr, "`unpack-mapping` isn't allowed here")
@special([(not PY3, "exec*")], [FORM, maybe(FORM), maybe(FORM)]) @special([(not PY3, "exec*")], [FORM, maybe(FORM), maybe(FORM)])
# Under Python 3, `exec` is a function rather than a statement type, so Hy # Under Python 3, `exec` is a function rather than a statement type, so Hy
# doesn't need a special form for it. # doesn't need a special form for it.
@ -804,11 +803,6 @@ class HyASTCompiler(object):
expr, body=body, handlers=handlers, orelse=orelse) expr, body=body, handlers=handlers, orelse=orelse)
return handler_results + x + returnable return handler_results + x + returnable
@builds("except")
def magic_internal_form(self, expr):
raise HyTypeError(expr,
"Error: `%s' can't be used like that." % (expr[0]))
def _compile_catch_expression(self, expr, var, exceptions, body): def _compile_catch_expression(self, expr, var, exceptions, body):
# exceptions catch should be either: # exceptions catch should be either:
# [[list of exceptions]] # [[list of exceptions]]

View File

@ -585,11 +585,11 @@ def test_setv_builtins():
def test_top_level_unquote(): def test_top_level_unquote():
with pytest.raises(HyTypeError) as excinfo: with pytest.raises(HyTypeError) as excinfo:
can_compile("(unquote)") can_compile("(unquote)")
assert excinfo.value.message == "`unquote' can't be used at the top-level" assert excinfo.value.message == "The special form 'unquote' is not allowed here"
with pytest.raises(HyTypeError) as excinfo: with pytest.raises(HyTypeError) as excinfo:
can_compile("(unquote-splice)") can_compile("(unquote-splice)")
assert excinfo.value.message == "`unquote-splice' can't be used at the top-level" assert excinfo.value.message == "The special form 'unquote-splice' is not allowed here"
def test_lots_of_comment_lines(): def test_lots_of_comment_lines():