Esempio n. 1
0
            def wrapper(hy_compiler, *args):

                if shadow and any(is_unpack("iterable", x) for x in args):
                    # Try a shadow function call with this name instead.
                    return Expression([Symbol("hy.pyops." + name),
                                       *args]).replace(hy_compiler.this)

                expr = hy_compiler.this
                root = unmangle(expr[0])

                if py_version_required and sys.version_info < py_version_required:
                    raise hy_compiler._syntax_error(
                        expr,
                        "`{}` requires Python {} or later".format(
                            root, ".".join(map(str, py_version_required))),
                    )

                try:
                    parse_tree = pattern.parse(args)
                except NoParseError as e:
                    raise hy_compiler._syntax_error(
                        expr[min(e.state.pos + 1,
                                 len(expr) - 1)],
                        "parse error for pattern macro '{}': {}".format(
                            root, e.msg.replace("<EOF>", "end of form")),
                    )
                return fn(hy_compiler, expr, root, *parse_tree)
Esempio n. 2
0
def require(source_module, target_module, assignments, prefix=""):
    """Load macros from one module into the namespace of another.

    This function is called from the `require` special form in the compiler.

    Parameters
    ----------
    source_module: str or types.ModuleType
        The module from which macros are to be imported.

    target_module: str, types.ModuleType or None
        The module into which the macros will be loaded.  If `None`, then
        the caller's namespace.
        The latter is useful during evaluation of generated AST/bytecode.

    assignments: str or list of tuples of strs
        The string "ALL" or a list of macro name and alias pairs.

    prefix: str, optional ("")
        If nonempty, its value is prepended to the name of each imported macro.
        This allows one to emulate namespaced macros, like
        "mymacromodule.mymacro", which looks like an attribute of a module.

    Returns
    -------
    out: boolean
        Whether or not macros were actually transferred.
    """
    if target_module is None:
        parent_frame = inspect.stack()[1][0]
        target_namespace = parent_frame.f_globals
        target_module = target_namespace.get('__name__', None)
    elif isinstance(target_module, str):
        target_module = importlib.import_module(target_module)
        target_namespace = target_module.__dict__
    elif inspect.ismodule(target_module):
        target_namespace = target_module.__dict__
    else:
        raise HyTypeError(
            '`target_module` is not a recognized type: {}'.format(
                type(target_module)))

    # Let's do a quick check to make sure the source module isn't actually
    # the module being compiled (e.g. when `runpy` executes a module's code
    # in `__main__`).
    # We use the module's underlying filename for this (when they exist), since
    # it's the most "fixed" attribute.
    if _same_modules(source_module, target_module):
        return False

    if not inspect.ismodule(source_module):
        try:
            if source_module.startswith("."):
                source_dirs = source_module.split(".")
                target_dirs = (getattr(target_module, "__name__",
                                       target_module).split("."))
                while (len(source_dirs) > 1 and source_dirs[0] == ""
                       and target_dirs):
                    source_dirs.pop(0)
                    target_dirs.pop()
                package = ".".join(target_dirs + source_dirs[:-1])
            else:
                package = None
            source_module = importlib.import_module(source_module, package)
        except ImportError as e:
            reraise(HyRequireError, HyRequireError(e.args[0]), None)

    source_macros = source_module.__dict__.setdefault('__macros__', {})

    if not source_module.__macros__:
        if assignments != "ALL":
            for name, alias in assignments:
                try:
                    require(f"{source_module.__name__}.{mangle(name)}",
                            target_module,
                            "ALL",
                            prefix=alias)
                except HyRequireError as e:
                    raise HyRequireError(f"Cannot import name '{name}'"
                                         f" from '{source_module.__name__}'"
                                         f" ({source_module.__file__})")
            return True
        else:
            return False

    target_macros = target_namespace.setdefault('__macros__', {})

    if prefix:
        prefix += "."

    if assignments == "ALL":
        name_assigns = [(k, k) for k in source_macros.keys()]
    else:
        name_assigns = assignments

    for name, alias in name_assigns:
        _name = mangle(name)
        alias = mangle('#' + prefix + unmangle(alias)[1:] if unmangle(alias).
                       startswith('#') else prefix + alias)
        if _name in source_module.__macros__:
            target_macros[alias] = source_macros[_name]
        else:
            raise HyRequireError('Could not require name {} from {}'.format(
                _name, source_module))

    return True