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