Merge pull request #1700 from brandonwillard/reuse-compiler-instances
Reuse Hy compiler instances
This commit is contained in:
commit
9efd2a9d61
2
NEWS.rst
2
NEWS.rst
@ -9,6 +9,8 @@ Removals
|
|||||||
|
|
||||||
New Features
|
New Features
|
||||||
------------------------------
|
------------------------------
|
||||||
|
* `eval` / `hy_eval` and `hy_compile` now accept an optional `compiler` argument
|
||||||
|
that enables the use of an existing `HyASTCompiler` instance.
|
||||||
* Keyword objects (not just literal keywords) can be called, as
|
* Keyword objects (not just literal keywords) can be called, as
|
||||||
shorthand for `(get obj :key)`, and they accept a default value
|
shorthand for `(get obj :key)`, and they accept a default value
|
||||||
as a second argument.
|
as a second argument.
|
||||||
|
@ -195,7 +195,9 @@ eval
|
|||||||
``eval`` evaluates a quoted expression and returns the value. The optional
|
``eval`` evaluates a quoted expression and returns the value. The optional
|
||||||
second and third arguments specify the dictionary of globals to use and the
|
second and third arguments specify the dictionary of globals to use and the
|
||||||
module name. The globals dictionary defaults to ``(local)`` and the module name
|
module name. The globals dictionary defaults to ``(local)`` and the module name
|
||||||
defaults to the name of the current module.
|
defaults to the name of the current module. An optional fourth keyword parameter,
|
||||||
|
``compiler``, allows one to re-use an existing ``HyASTCompiler`` object for the
|
||||||
|
compilation step.
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
@ -1403,4 +1405,3 @@ are available. Some of their names have been changed:
|
|||||||
- ``dropwhile`` has been changed to ``drop-while``
|
- ``dropwhile`` has been changed to ``drop-while``
|
||||||
|
|
||||||
- ``filterfalse`` has been changed to ``remove``
|
- ``filterfalse`` has been changed to ``remove``
|
||||||
|
|
||||||
|
@ -20,7 +20,8 @@ import astor.code_gen
|
|||||||
import hy
|
import hy
|
||||||
from hy.lex import hy_parse, mangle
|
from hy.lex import hy_parse, mangle
|
||||||
from hy.lex.exceptions import LexException, PrematureEndOfInput
|
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.importer import runhy
|
||||||
from hy.completer import completion, Completer
|
from hy.completer import completion, Completer
|
||||||
from hy.macros import macro, require
|
from hy.macros import macro, require
|
||||||
@ -69,6 +70,8 @@ class HyREPL(code.InteractiveConsole, object):
|
|||||||
# Load cmdline-specific macros.
|
# Load cmdline-specific macros.
|
||||||
require('hy.cmdline', module_name, assignments='ALL')
|
require('hy.cmdline', module_name, assignments='ALL')
|
||||||
|
|
||||||
|
self.hy_compiler = HyASTCompiler(self.module)
|
||||||
|
|
||||||
self.spy = spy
|
self.spy = spy
|
||||||
|
|
||||||
if output_fn is None:
|
if output_fn is None:
|
||||||
@ -117,7 +120,10 @@ class HyREPL(code.InteractiveConsole, object):
|
|||||||
new_ast = ast.Module(main_ast.body +
|
new_ast = ast.Module(main_ast.body +
|
||||||
[ast.Expr(expr_ast.body)])
|
[ast.Expr(expr_ast.body)])
|
||||||
print(astor.to_source(new_ast))
|
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:
|
except HyTypeError as e:
|
||||||
if e.source is None:
|
if e.source is None:
|
||||||
e.source = source
|
e.source = source
|
||||||
|
@ -1779,18 +1779,38 @@ class HyASTCompiler(object):
|
|||||||
return ret + asty.Dict(m, keys=keyvalues[::2], values=keyvalues[1::2])
|
return ret + asty.Dict(m, keys=keyvalues[::2], values=keyvalues[1::2])
|
||||||
|
|
||||||
|
|
||||||
def hy_eval(hytree, locals=None, module=None, ast_callback=None):
|
def get_compiler_module(module=None, compiler=None, calling_frame=False):
|
||||||
"""Evaluates a quoted expression and returns the value.
|
"""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
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
||||||
=> (eval '(print "Hello World"))
|
=> (eval '(print "Hello World"))
|
||||||
"Hello World"
|
"Hello World"
|
||||||
|
|
||||||
If you want to evaluate a string, use ``read-str`` to convert it to a
|
If you want to evaluate a string, use ``read-str`` to convert it to a
|
||||||
form first:
|
form first:
|
||||||
|
|
||||||
=> (eval (read-str "(+ 1 1)"))
|
=> (eval (read-str "(+ 1 1)"))
|
||||||
2
|
2
|
||||||
|
|
||||||
@ -1806,25 +1826,25 @@ def hy_eval(hytree, locals=None, module=None, ast_callback=None):
|
|||||||
module: str or types.ModuleType, optional
|
module: str or types.ModuleType, optional
|
||||||
Module, or name of the module, to which the Hy tree is assigned and
|
Module, or name of the module, to which the Hy tree is assigned and
|
||||||
the global values are taken.
|
the global values are taken.
|
||||||
Defaults to the calling frame's module, if any, and '__eval__'
|
The module associated with `compiler` takes priority over this value.
|
||||||
otherwise.
|
When neither `module` nor `compiler` is specified, the calling frame's
|
||||||
|
module is used.
|
||||||
|
|
||||||
ast_callback: callable, optional
|
ast_callback: callable, optional
|
||||||
A callback that is passed the Hy compiled tree and resulting
|
A callback that is passed the Hy compiled tree and resulting
|
||||||
expression object, in that order, after compilation but before
|
expression object, in that order, after compilation but before
|
||||||
evaluation.
|
evaluation.
|
||||||
|
|
||||||
|
compiler: HyASTCompiler, optional
|
||||||
|
An existing Hy compiler to use for compilation. Also serves as
|
||||||
|
the `module` value when given.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
out : Result of evaluating the Hy compiled tree.
|
out : Result of evaluating the Hy compiled tree.
|
||||||
"""
|
"""
|
||||||
if module is None:
|
|
||||||
module = calling_module()
|
|
||||||
|
|
||||||
if isinstance(module, string_types):
|
module = get_compiler_module(module, compiler, True)
|
||||||
module = importlib.import_module(ast_str(module, piecewise=True))
|
|
||||||
elif not inspect.ismodule(module):
|
|
||||||
raise TypeError('Invalid module type: {}'.format(type(module)))
|
|
||||||
|
|
||||||
if locals is None:
|
if locals is None:
|
||||||
frame = inspect.stack()[1][0]
|
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):
|
if not isinstance(locals, dict):
|
||||||
raise TypeError("Locals must be a dictionary")
|
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...
|
# Spoof the positions in the generated ast...
|
||||||
for node in ast.walk(_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)
|
return eval(ast_compile(expr, "<eval>", "eval"), globals, locals)
|
||||||
|
|
||||||
|
|
||||||
def hy_compile(tree, module, root=ast.Module, get_expr=False):
|
def hy_compile(tree, module=None, root=ast.Module, get_expr=False,
|
||||||
"""
|
compiler=None):
|
||||||
Compile a Hy tree into a Python AST tree.
|
"""Compile a Hy tree into a Python AST tree.
|
||||||
|
|
||||||
Parameters
|
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.
|
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: ast object, optional (ast.Module)
|
||||||
Root object for the Python AST tree.
|
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)
|
get_expr: bool, optional (False)
|
||||||
If true, return a tuple with `(root_obj, last_expression)`.
|
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
|
Returns
|
||||||
-------
|
-------
|
||||||
out : A Python AST tree
|
out : A Python AST tree
|
||||||
"""
|
"""
|
||||||
|
module = get_compiler_module(module, compiler, False)
|
||||||
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)))
|
|
||||||
|
|
||||||
|
|
||||||
tree = wrap_value(tree)
|
tree = wrap_value(tree)
|
||||||
if not isinstance(tree, HyObject):
|
if not isinstance(tree, HyObject):
|
||||||
raise HyCompileError("`tree` must be a HyObject or capable of "
|
raise HyCompileError("`tree` must be a HyObject or capable of "
|
||||||
"being promoted to one")
|
"being promoted to one")
|
||||||
|
|
||||||
compiler = HyASTCompiler(module)
|
compiler = compiler or HyASTCompiler(module)
|
||||||
result = compiler.compile(tree)
|
result = compiler.compile(tree)
|
||||||
expr = result.force_expr
|
expr = result.force_expr
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user