Make lists no longer magical for the compiler
This commit is contained in:
parent
f55fcf43bd
commit
4be37b358b
@ -12,7 +12,8 @@ from hy.lex.parser import hy_symbol_mangle
|
||||
|
||||
import hy.macros
|
||||
from hy._compat import (
|
||||
str_type, bytes_type, long_type, PY3, PY34, PY35, raise_empty)
|
||||
str_type, string_types, bytes_type, long_type, PY3, PY34, PY35,
|
||||
raise_empty)
|
||||
from hy.macros import require, macroexpand, tag_macroexpand
|
||||
import hy.importer
|
||||
|
||||
@ -110,6 +111,17 @@ def builds_if(_type, condition):
|
||||
return lambda fn: fn
|
||||
|
||||
|
||||
def spoof_positions(obj):
|
||||
if not hasattr(obj, "start_column"):
|
||||
obj.start_column = 0
|
||||
if not hasattr(obj, "start_line"):
|
||||
obj.start_line = 0
|
||||
if (hasattr(obj, "__iter__") and
|
||||
not isinstance(obj, (string_types, bytes_type))):
|
||||
for x in obj:
|
||||
spoof_positions(x)
|
||||
|
||||
|
||||
class Result(object):
|
||||
"""
|
||||
Smart representation of the result of a hy->AST compilation
|
||||
@ -378,23 +390,23 @@ class HyASTCompiler(object):
|
||||
ret = Result()
|
||||
for module, names in self.imports.items():
|
||||
if None in names:
|
||||
ret += self.compile([
|
||||
HyExpression([
|
||||
e = HyExpression([
|
||||
HySymbol("import"),
|
||||
HySymbol(module),
|
||||
]).replace(expr)
|
||||
])
|
||||
spoof_positions(e)
|
||||
ret += self.compile(e)
|
||||
names = sorted(name for name in names if name)
|
||||
if names:
|
||||
ret += self.compile([
|
||||
HyExpression([
|
||||
e = HyExpression([
|
||||
HySymbol("import"),
|
||||
HyList([
|
||||
HySymbol(module),
|
||||
HyList([HySymbol(name) for name in names])
|
||||
])
|
||||
]).replace(expr)
|
||||
])
|
||||
spoof_positions(e)
|
||||
ret += self.compile(e)
|
||||
self.imports = defaultdict(set)
|
||||
return ret.stmts
|
||||
|
||||
@ -602,12 +614,6 @@ class HyASTCompiler(object):
|
||||
ast.copy_location(new_name, name)
|
||||
return new_name
|
||||
|
||||
@builds(list)
|
||||
def compile_raw_list(self, entries):
|
||||
ret = self._compile_branch(entries)
|
||||
ret += ret.expr_as_stmt()
|
||||
return ret
|
||||
|
||||
def _render_quoted_form(self, form, level):
|
||||
"""
|
||||
Render a quoted form as a new HyExpression.
|
||||
@ -741,6 +747,7 @@ class HyASTCompiler(object):
|
||||
return ret
|
||||
|
||||
@builds("try")
|
||||
@checkargs(min=2)
|
||||
def compile_try_expression(self, expr):
|
||||
expr.pop(0) # try
|
||||
|
||||
@ -2594,21 +2601,17 @@ def hy_compile(tree, module_name, root=ast.Module, get_expr=False):
|
||||
body = []
|
||||
expr = None
|
||||
|
||||
if not (isinstance(tree, HyObject) or type(tree) is list):
|
||||
raise HyCompileError("tree must be a HyObject or a list")
|
||||
if not isinstance(tree, HyObject):
|
||||
raise HyCompileError("tree must be a HyObject")
|
||||
|
||||
if isinstance(tree, HyObject) or tree:
|
||||
compiler = HyASTCompiler(module_name)
|
||||
result = compiler.compile(tree)
|
||||
expr = result.force_expr
|
||||
compiler = HyASTCompiler(module_name)
|
||||
result = compiler.compile(tree)
|
||||
expr = result.force_expr
|
||||
|
||||
if not get_expr:
|
||||
result += result.expr_as_stmt()
|
||||
if not get_expr:
|
||||
result += result.expr_as_stmt()
|
||||
|
||||
# We need to test that the type is *exactly* `list` because we don't
|
||||
# want to do `tree[0]` on HyList or such.
|
||||
spoof_tree = tree[0] if type(tree) is list else tree
|
||||
body = compiler.imports_as_stmts(spoof_tree) + result.stmts
|
||||
body = compiler.imports_as_stmts(tree) + result.stmts
|
||||
|
||||
ret = root(body=body)
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
# license. See the LICENSE.
|
||||
|
||||
from hy.compiler import hy_compile, HyTypeError
|
||||
from hy.models import HyObject, replace_hy_obj
|
||||
from hy.models import HyObject, HyExpression, HySymbol, replace_hy_obj
|
||||
from hy.lex import tokenize, LexException
|
||||
from hy.errors import HyIOError
|
||||
|
||||
@ -32,7 +32,7 @@ def ast_compile(ast, filename, mode):
|
||||
|
||||
def import_buffer_to_hst(buf):
|
||||
"""Import content from buf and return a Hy AST."""
|
||||
return tokenize(buf + "\n")
|
||||
return HyExpression([HySymbol("do")] + tokenize(buf + "\n"))
|
||||
|
||||
|
||||
def import_file_to_hst(fpath):
|
||||
|
@ -7,9 +7,9 @@ from __future__ import unicode_literals
|
||||
from hy import HyString
|
||||
from hy.models import HyObject
|
||||
from hy.compiler import hy_compile
|
||||
from hy.importer import import_buffer_to_hst
|
||||
from hy.errors import HyCompileError, HyTypeError
|
||||
from hy.lex.exceptions import LexException
|
||||
from hy.lex import tokenize
|
||||
from hy._compat import PY3
|
||||
|
||||
import ast
|
||||
@ -25,12 +25,12 @@ def _ast_spotcheck(arg, root, secondary):
|
||||
|
||||
|
||||
def can_compile(expr):
|
||||
return hy_compile(tokenize(expr), "__main__")
|
||||
return hy_compile(import_buffer_to_hst(expr), "__main__")
|
||||
|
||||
|
||||
def cant_compile(expr):
|
||||
try:
|
||||
hy_compile(tokenize(expr), "__main__")
|
||||
hy_compile(import_buffer_to_hst(expr), "__main__")
|
||||
assert False
|
||||
except HyTypeError as e:
|
||||
# Anything that can't be compiled should raise a user friendly
|
||||
@ -252,7 +252,7 @@ def test_ast_require():
|
||||
def test_ast_no_pointless_imports():
|
||||
def contains_import_from(code):
|
||||
return any([isinstance(node, ast.ImportFrom)
|
||||
for node in hy_compile(tokenize(code), "__main__").body])
|
||||
for node in can_compile(code).body])
|
||||
# `reduce` is a builtin in Python 2, but not Python 3.
|
||||
# The version of `map` that returns an iterator is a builtin in
|
||||
# Python 3, but not Python 2.
|
||||
@ -460,7 +460,7 @@ def test_ast_unicode_strings():
|
||||
hy_s.start_line = hy_s.end_line = 0
|
||||
hy_s.start_column = hy_s.end_column = 0
|
||||
|
||||
code = hy_compile([hy_s], "__main__")
|
||||
code = hy_compile(hy_s, "__main__")
|
||||
|
||||
# code == ast.Module(body=[ast.Expr(value=ast.Str(s=xxx))])
|
||||
return code.body[0].value.s
|
||||
@ -471,7 +471,7 @@ def test_ast_unicode_strings():
|
||||
|
||||
|
||||
def test_ast_unicode_vs_bytes():
|
||||
def f(x): return hy_compile(tokenize(x), "__main__").body[0].value.s
|
||||
def f(x): return can_compile(x).body[0].value.s
|
||||
assert f('"hello"') == u"hello"
|
||||
assert type(f('"hello"')) is (str if PY3 else unicode) # noqa
|
||||
assert f('b"hello"') == (eval('b"hello"') if PY3 else "hello")
|
||||
|
Loading…
Reference in New Issue
Block a user