Beispiel #1
0
def test_recursive_model_detection():
    """Check for self-references:
    https://github.com/hylang/hy/issues/2153
    """
    self_ref_list = [1, 2, 3]
    self_ref_dict = {1: 1, 2: 2}
    self_ref_list[1] = self_ref_list
    self_ref_dict[2] = self_ref_dict

    mutually_ref_list = [1, 2, 3]
    mutually_ref_dict = {1: 1, 2: 2}
    mutually_ref_list[1] = mutually_ref_dict
    mutually_ref_dict[2] = mutually_ref_list

    for structure in [
            self_ref_list,
            self_ref_dict,
            mutually_ref_list,
            mutually_ref_dict,
    ]:
        with pytest.raises(HyWrapperError) as exc:
            as_model(structure)
        assert "Self-referential" in str(exc)
Beispiel #2
0
def test_wrap_nested_expr():
    """ Test conversion of Expressions with embedded non-HyObjects."""
    wrapped = as_model(Expression([0]))
    assert type(wrapped) == Expression
    assert type(wrapped[0]) == Integer
    assert wrapped == Expression([Integer(0)])
Beispiel #3
0
def test_wrap_tuple():
    """ Test conversion of tuples."""
    wrapped = as_model((Integer(0),))
    assert type(wrapped) == List
    assert type(wrapped[0]) == Integer
    assert wrapped == List([Integer(0)])
Beispiel #4
0
def test_wrap_int():
    """ Test conversion of integers."""
    wrapped = as_model(0)
    assert type(wrapped) == Integer
Beispiel #5
0
def hy_compile(
    tree,
    module,
    root=ast.Module,
    get_expr=False,
    compiler=None,
    filename=None,
    source=None,
    import_stdlib=True,
):
    """Compile a hy.models.Object tree into a Python AST Module.

    Args:
        tree (Object): The Hy AST object to compile.
        module (Union[str, types.ModuleType]): Module, or name of the module, in which the Hy tree is evaluated.
            The module associated with `compiler` takes priority over this value.
        root (Type[ast.AST]): Root object for the Python AST tree.
        get_expr (bool): If true, return a tuple with `(root_obj, last_expression)`.
        compiler (Optional[HyASTCompiler]): An existing Hy compiler to use for compilation.  Also serves as
            the `module` value when given.
        filename (Optional[str]): The filename corresponding to the source for `tree`.  This will be
            overridden by the `filename` field of `tree`, if any; otherwise, it
            defaults to "<string>".  When `compiler` is given, its `filename` field
            value is always used.
        source (Optional[str]): A string containing the source code for `tree`.  This will be
            overridden by the `source` field of `tree`, if any; otherwise,
            if `None`, an attempt will be made to obtain it from the module given by
            `module`.  When `compiler` is given, its `source` field value is always
            used.

    Returns:
        ast.AST: A Python AST tree
    """
    module = get_compiler_module(module, compiler, False)

    if isinstance(module, str):
        if module.startswith("<") and module.endswith(">"):
            module = types.ModuleType(module)
        else:
            module = importlib.import_module(mangle(module))

    if not inspect.ismodule(module):
        raise TypeError("Invalid module type: {}".format(type(module)))

    filename = getattr(tree, "filename", filename)
    source = getattr(tree, "source", source)

    tree = as_model(tree)
    if not isinstance(tree, Object):
        raise TypeError(
            "`tree` must be a hy.models.Object or capable of " "being promoted to one"
        )

    compiler = compiler or HyASTCompiler(module, filename=filename, source=source)

    if import_stdlib:
        # Import hy for compile time, but save the compiled AST.
        stdlib_ast = compiler.compile(
            mkexpr("eval-and-compile", mkexpr("import", "hy"))
        )

    with compiler.scope:
        result = compiler.compile(tree)
    expr = result.force_expr

    if not get_expr:
        result += result.expr_as_stmt()

    body = []

    if issubclass(root, ast.Module):
        # Pull out a single docstring and prepend to the resulting body.
        if (
            result.stmts
            and isinstance(result.stmts[0], ast.Expr)
            and isinstance(result.stmts[0].value, ast.Str)
        ):

            body += [result.stmts.pop(0)]

        # Pull out any __future__ imports, since they are required to be at the beginning.
        while (
            result.stmts
            and isinstance(result.stmts[0], ast.ImportFrom)
            and result.stmts[0].module == "__future__"
        ):

            body += [result.stmts.pop(0)]

        # Import hy for runtime.
        if import_stdlib:
            body += stdlib_ast.stmts

    body += result.stmts
    ret = root(body=body, type_ignores=[])

    if get_expr:
        expr = ast.Expression(body=expr)
        ret = (ret, expr)

    return ret
Beispiel #6
0
def macroexpand(tree, module, compiler=None, once=False, result_ok=True):
    """Expand the toplevel macros for the given Hy AST tree.

    Load the macros from the given `module`, then expand the (top-level) macros
    in `tree` until we no longer can.

    `Expression` resulting from macro expansions are assigned the module in
    which the macro function is defined (determined using `inspect.getmodule`).
    If the resulting `Expression` is itself macro expanded, then the namespace
    of the assigned module is checked first for a macro corresponding to the
    expression's head/car symbol.  If the head/car symbol of such a `Expression`
    is not found among the macros of its assigned module's namespace, the
    outer-most namespace--e.g.  the one given by the `module` parameter--is used
    as a fallback.

    Args:
        tree (Union[Object, list]): Hy AST tree.
        module (Union[str, ModuleType]): Module used to determine the local
            namespace for macros.
        compiler (Optional[HyASTCompiler] ): The compiler object passed to
            expanded macros. Defaults to None
        once (bool): Only expand the first macro in `tree`. Defaults to False
        result_ok (bool): Whether or not it's okay to return a compiler `Result` instance.
            Defaults to True.

    Returns:
        Union[Object, Result]: A mutated tree with macros expanded.
    """
    if not inspect.ismodule(module):
        module = importlib.import_module(module)

    assert not compiler or compiler.module == module

    while isinstance(tree, Expression) and tree:

        fn = tree[0]
        if fn in ("quote", "quasiquote") or not isinstance(fn, Symbol):
            break

        fn = mangle(fn)
        expr_modules = ([] if not hasattr(tree, "module") else [tree.module
                                                                ]) + [module]
        expr_modules.append(builtins)

        # Choose the first namespace with the macro.
        m = next(
            (mod.__macros__[fn]
             for mod in expr_modules if fn in getattr(mod, "__macros__", ())),
            None,
        )
        if not m:
            break

        with MacroExceptions(module, tree, compiler):
            if compiler:
                compiler.this = tree
            obj = m(compiler, *tree[1:])
            if isinstance(obj, (hy.compiler.Result, AST)):
                return obj if result_ok else tree

            if isinstance(obj, Expression):
                obj.module = inspect.getmodule(m)

            tree = replace_hy_obj(obj, tree)

        if once:
            break

    tree = as_model(tree)
    return tree
Beispiel #7
0
def test_wrap_tuple():
    wrapped = as_model((Integer(0), ))
    assert type(wrapped) == List
    assert type(wrapped[0]) == Integer
    assert wrapped == List([Integer(0)])
Beispiel #8
0
def test_wrap_int():
    wrapped = as_model(0)
    assert type(wrapped) == Integer