def macroexpand(tree, compiler, once=False): """Expand the toplevel macros for the `tree`. Load the macros from the given `compiler.module_name`, then expand the (top-level) macros in `tree` until we no longer can. """ load_macros(compiler.module_name) while True: if not isinstance(tree, HyExpression) or tree == []: break fn = tree[0] if fn in ("quote", "quasiquote") or not isinstance(fn, HySymbol): break fn = mangle(fn) m = _hy_macros[compiler.module_name].get(fn) or _hy_macros[None].get( fn) if not m: break opts = {} if m._hy_macro_pass_compiler: opts['compiler'] = compiler try: m_copy = make_empty_fn_copy(m) m_copy(compiler.module_name, *tree[1:], **opts) except TypeError as e: msg = "expanding `" + str(tree[0]) + "': " msg += str(e).replace("<lambda>()", "", 1).strip() raise HyMacroExpansionError(tree, msg) try: obj = m(compiler.module_name, *tree[1:], **opts) except HyTypeError as e: if e.expression is None: e.expression = tree raise except Exception as e: msg = "expanding `" + str(tree[0]) + "': " + repr(e) raise HyMacroExpansionError(tree, msg) tree = replace_hy_obj(obj, tree) if once: break tree = wrap_value(tree) return tree
def macro_exceptions(module, macro_tree, compiler=None): try: yield except HyLanguageError as e: # These are user-level Hy errors occurring in the macro. # We want to pass them up to the user. reraise(type(e), e, sys.exc_info()[2]) except Exception as e: if compiler: filename = compiler.filename source = compiler.source else: filename = None source = None exc_msg = ' '.join( traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])) msg = "expanding macro {}\n ".format(str(macro_tree[0])) msg += exc_msg reraise(HyMacroExpansionError, HyMacroExpansionError(msg, macro_tree, filename, source), sys.exc_info()[2])
def macroexpand_1(tree, module_name): """Expand the toplevel macro from `tree` once, in the context of `module_name`.""" if isinstance(tree, HyExpression): if tree == []: return tree fn = tree[0] if fn in ("quote", "quasiquote"): return tree ntree = HyExpression(tree[:]) ntree.replace(tree) if isinstance(fn, HyString): m = _hy_macros[module_name].get(fn) if m is None: m = _hy_macros[None].get(fn) if m is not None: try: obj = _wrap_value(m(*ntree[1:])) except HyTypeError as e: if e.expression is None: e.expression = tree raise except Exception as e: msg = "expanding `" + str(tree[0]) + "': " + repr(e) raise HyMacroExpansionError(tree, msg) obj.replace(tree) return obj return ntree return tree
def macroexpand_1(tree, compiler): """Expand the toplevel macro from `tree` once, in the context of `module_name`.""" if isinstance(tree, HyExpression): if tree == []: return tree fn = tree[0] if fn in ("quote", "quasiquote"): return tree ntree = HyExpression(tree[:]) ntree.replace(tree) opts = {} if isinstance(fn, HySymbol): fn = mangle(str_type(fn)) m = _hy_macros[compiler.module_name].get(fn) if m is None: m = _hy_macros[None].get(fn) if m is not None: if m._hy_macro_pass_compiler: opts['compiler'] = compiler try: m_copy = make_empty_fn_copy(m) m_copy(compiler.module_name, *ntree[1:], **opts) except TypeError as e: msg = "expanding `" + str(tree[0]) + "': " msg += str(e).replace("<lambda>()", "", 1).strip() raise HyMacroExpansionError(tree, msg) try: obj = m(compiler.module_name, *ntree[1:], **opts) except HyTypeError as e: if e.expression is None: e.expression = tree raise except Exception as e: msg = "expanding `" + str(tree[0]) + "': " + repr(e) raise HyMacroExpansionError(tree, msg) replace_hy_obj(obj, tree) return obj return ntree return tree
def __exit__(self, exc_type, exc_value, exc_traceback): if exc_type is None: return True elif not issubclass(exc_type, HyLanguageError): if self.compiler: filename = self.compiler.filename source = self.compiler.source else: filename = None source = None exc_msg = " ".join( traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])) msg = "expanding macro {}\n ".format(str(self.macro_tree[0])) msg += exc_msg raise HyMacroExpansionError(msg, self.macro_tree, filename, source) else: return False
def macroexpand(tree, module, compiler=None, once=False): """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. `HyExpression` resulting from macro expansions are assigned the module in which the macro function is defined (determined using `inspect.getmodule`). If the resulting `HyExpression` 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 `HyExpression` 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. Parameters ---------- tree: HyObject or list Hy AST tree. module: str or types.ModuleType Module used to determine the local namespace for macros. compiler: HyASTCompiler, optional The compiler object passed to expanded macros. once: boolean, optional Only expand the first macro in `tree`. Returns ------ out: HyObject Returns a mutated tree with macros expanded. """ if not inspect.ismodule(module): module = importlib.import_module(module) assert not compiler or compiler.module == module while True: if not isinstance(tree, HyExpression) or tree == []: break fn = tree[0] if fn in ("quote", "quasiquote") or not isinstance(fn, HySymbol): break fn = mangle(fn) expr_modules = ( ([] if not hasattr(tree, 'module') else [tree.module]) + [module]) # Choose the first namespace with the macro. m = next((mod.__macros__[fn] for mod in expr_modules if fn in mod.__macros__), None) if not m: break opts = {} if m._hy_macro_pass_compiler: if compiler is None: from hy.compiler import HyASTCompiler compiler = HyASTCompiler(module) opts['compiler'] = compiler try: m_copy = make_empty_fn_copy(m) m_copy(module.__name__, *tree[1:], **opts) except TypeError as e: msg = "expanding `" + str(tree[0]) + "': " msg += str(e).replace("<lambda>()", "", 1).strip() raise HyMacroExpansionError(tree, msg) try: obj = m(module.__name__, *tree[1:], **opts) except HyTypeError as e: if e.expression is None: e.expression = tree raise except Exception as e: msg = "expanding `" + str(tree[0]) + "': " + repr(e) raise HyMacroExpansionError(tree, msg) if isinstance(obj, HyExpression): obj.module = inspect.getmodule(m) tree = replace_hy_obj(obj, tree) if once: break tree = wrap_value(tree) return tree