diff --git a/hy/cmdline.py b/hy/cmdline.py index eeb5ccdd5..0cb5d19e8 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -19,7 +19,7 @@ import hy from hy.lex import LexException, PrematureEndOfInput, mangle -from hy.compiler import HyTypeError, hy_compile +from hy.compiler import HyTypeError, HyASTCompiler, hy_compile from hy.importer import hy_eval, hy_parse, runhy from hy.completer import completion, Completer from hy.macros import macro, require @@ -68,6 +68,8 @@ def __init__(self, spy=False, output_fn=None, locals=None, # Load cmdline-specific macros. require('hy.cmdline', module_name, assignments='ALL') + self.hy_compiler = HyASTCompiler(self.module) + self.spy = spy if output_fn is None: @@ -116,7 +118,10 @@ def ast_callback(main_ast, expr_ast): new_ast = ast.Module(main_ast.body + [ast.Expr(expr_ast.body)]) print(astor.to_source(new_ast)) - value = hy_eval(do, self.locals, self.module, ast_callback) + + value = hy_eval(do, self.locals, + ast_callback=ast_callback, + compiler=self.hy_compiler) except HyTypeError as e: if e.source is None: e.source = source diff --git a/hy/compiler.py b/hy/compiler.py index f6cf052d7..4437b065c 100755 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1554,9 +1554,7 @@ def compile_dispatch_tag_macro(self, expr, root, tag, arg): def compile_eval_and_compile(self, expr, root, body): new_expr = HyExpression([HySymbol("do").replace(expr[0])]).replace(expr) - hy.importer.hy_eval(new_expr + body, - self.module.__dict__, - self.module) + hy.importer.hy_eval(new_expr + body, self.module.__dict__, self.module) return (self._compile_branch(body) if ast_str(root) == "eval_and_compile" @@ -1723,14 +1721,37 @@ def compile_dict(self, m): return ret + asty.Dict(m, keys=keyvalues[::2], values=keyvalues[1::2]) -def hy_compile(tree, module, root=ast.Module, get_expr=False): +def get_compiler_module(module=None, compiler=None, calling_frame=False): + """Get a module object from a compiler, given module object, + string name of a module, and (optionally) the calling frame; otherwise, + raise an error.""" + + module = getattr(compiler, 'module', None) or module + + if isinstance(module, string_types): + if module.startswith('<') and module.endswith('>'): + module = types.ModuleType(module) + else: + module = importlib.import_module(ast_str(module, piecewise=True)) + + if calling_frame and not module: + module = hy.importer.calling_module(n=2) + + if not inspect.ismodule(module): + raise TypeError('Invalid module type: {}'.format(type(module))) + + return module + + +def hy_compile(tree, module=None, root=ast.Module, get_expr=False, compiler=None): """ Compile a Hy tree into a Python AST tree. Parameters ---------- - module: str or types.ModuleType + module: str or types.ModuleType, optional Module, or name of the module, in which the Hy tree is evaluated. + The module associated with `compiler` takes priority over this value. root: ast object, optional (ast.Module) Root object for the Python AST tree. @@ -1738,26 +1759,22 @@ def hy_compile(tree, module, root=ast.Module, get_expr=False): get_expr: bool, optional (False) If true, return a tuple with `(root_obj, last_expression)`. + compiler: HyASTCompiler, optional + An existing Hy compiler to use for compilation. Also serves as + the `module` value when given. + Returns ------- out : A Python AST tree """ - - if isinstance(module, string_types): - if module.startswith('<') and module.endswith('>'): - module = types.ModuleType(module) - else: - module = importlib.import_module(ast_str(module, piecewise=True)) - if not inspect.ismodule(module): - raise TypeError('Invalid module type: {}'.format(type(module))) - + module = get_compiler_module(module, compiler, False) tree = wrap_value(tree) if not isinstance(tree, HyObject): raise HyCompileError("`tree` must be a HyObject or capable of " "being promoted to one") - compiler = HyASTCompiler(module) + compiler = compiler or HyASTCompiler(module) result = compiler.compile(tree) expr = result.force_expr diff --git a/hy/importer.py b/hy/importer.py index fdcb0be03..f56a048bc 100644 --- a/hy/importer.py +++ b/hy/importer.py @@ -20,10 +20,10 @@ from contextlib import contextmanager from hy.errors import HyTypeError -from hy.compiler import hy_compile, ast_str +from hy.compiler import hy_compile, get_compiler_module from hy.lex import tokenize, LexException from hy.models import HyExpression, HySymbol -from hy._compat import string_types, PY3 +from hy._compat import PY3 hy_ast_compile_flags = (__future__.CO_FUTURE_DIVISION | @@ -96,7 +96,8 @@ def hy_parse(source): return HyExpression([HySymbol("do")] + tokenize(source + "\n")) -def hy_eval(hytree, locals=None, module=None, ast_callback=None): +def hy_eval(hytree, locals=None, module=None, ast_callback=None, + compiler=None): """Evaluates a quoted expression and returns the value. Examples @@ -123,25 +124,25 @@ def hy_eval(hytree, locals=None, module=None, ast_callback=None): module: str or types.ModuleType, optional Module, or name of the module, to which the Hy tree is assigned and the global values are taken. - Defaults to the calling frame's module, if any, and '__eval__' - otherwise. + The module associated with `compiler` takes priority over this value. + When neither `module` nor `compiler` is specified, the calling frame's + module is used. ast_callback: callable, optional A callback that is passed the Hy compiled tree and resulting expression object, in that order, after compilation but before evaluation. + compiler: HyASTCompiler, optional + An existing Hy compiler to use for compilation. Also serves as + the `module` value when given. + Returns ------- out : Result of evaluating the Hy compiled tree. """ - if module is None: - module = calling_module() - if isinstance(module, string_types): - module = importlib.import_module(ast_str(module, piecewise=True)) - elif not inspect.ismodule(module): - raise TypeError('Invalid module type: {}'.format(type(module))) + module = get_compiler_module(module, compiler, True) if locals is None: frame = inspect.stack()[1][0] @@ -150,7 +151,8 @@ def hy_eval(hytree, locals=None, module=None, ast_callback=None): if not isinstance(locals, dict): raise TypeError("Locals must be a dictionary") - _ast, expr = hy_compile(hytree, module, get_expr=True) + _ast, expr = hy_compile(hytree, module=module, get_expr=True, + compiler=compiler) # Spoof the positions in the generated ast... for node in ast.walk(_ast):