Use a fixed compiler in HyREPL
These changes make `HyREPL` use a single `HyASTCompiler` instance, instead of creating one every time a valid source string is processed. This change avoids the unnecessary re-initiation of the standard library `import` and `require` steps that currently occur within the module tracked by a `HyREPL` instance. Also, one can now pass an existing compiler instance to `hy_repl` and `hy_compiler`. Closes hylang/hy#1698.
This commit is contained in:
parent
fb0220bd52
commit
15c68455ec
@ -20,7 +20,8 @@ import astor.code_gen
|
||||
import hy
|
||||
from hy.lex import hy_parse, mangle
|
||||
from hy.lex.exceptions import LexException, PrematureEndOfInput
|
||||
from hy.compiler import HyTypeError, hy_compile, hy_eval
|
||||
from hy.compiler import HyASTCompiler, hy_compile, hy_eval
|
||||
from hy.errors import HyTypeError
|
||||
from hy.importer import runhy
|
||||
from hy.completer import completion, Completer
|
||||
from hy.macros import macro, require
|
||||
@ -69,6 +70,8 @@ class HyREPL(code.InteractiveConsole, object):
|
||||
# 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:
|
||||
@ -117,7 +120,10 @@ class HyREPL(code.InteractiveConsole, object):
|
||||
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
|
||||
|
@ -1779,18 +1779,38 @@ class HyASTCompiler(object):
|
||||
return ret + asty.Dict(m, keys=keyvalues[::2], values=keyvalues[1::2])
|
||||
|
||||
|
||||
def hy_eval(hytree, locals=None, module=None, ast_callback=None):
|
||||
"""Evaluates a quoted expression and returns the value.
|
||||
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 = calling_module(n=2)
|
||||
|
||||
if not inspect.ismodule(module):
|
||||
raise TypeError('Invalid module type: {}'.format(type(module)))
|
||||
|
||||
return module
|
||||
|
||||
|
||||
def hy_eval(hytree, locals=None, module=None, ast_callback=None,
|
||||
compiler=None):
|
||||
"""Evaluates a quoted expression and returns the value.
|
||||
Examples
|
||||
--------
|
||||
|
||||
=> (eval '(print "Hello World"))
|
||||
"Hello World"
|
||||
|
||||
If you want to evaluate a string, use ``read-str`` to convert it to a
|
||||
form first:
|
||||
|
||||
=> (eval (read-str "(+ 1 1)"))
|
||||
2
|
||||
|
||||
@ -1806,25 +1826,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]
|
||||
@ -1833,7 +1853,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):
|
||||
@ -1856,14 +1877,15 @@ def hy_eval(hytree, locals=None, module=None, ast_callback=None):
|
||||
return eval(ast_compile(expr, "<eval>", "eval"), globals, locals)
|
||||
|
||||
|
||||
def hy_compile(tree, module, root=ast.Module, get_expr=False):
|
||||
"""
|
||||
Compile a Hy tree into a Python AST tree.
|
||||
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.
|
||||
@ -1871,26 +1893,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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user