from macropy.core.macros import * from macropy.core.quotes import macros, q, ast, u from macropy.core.hquotes import macros, hq, ast, u, name from macropy.core.cleanup import ast_ctx_fixer macros = Macros() def _(): """Placeholder for a function argument in the `f` macro.""" @macros.expr def f(tree, gen_sym, **kw): """Macro to concisely create function literals; any `_`s within the wrapped expression becomes an argument to the generated function.""" @Walker def underscore_search(tree, collect, **kw): if isinstance(tree, Name) and tree.id == "_": name = gen_sym("_") tree.id = name collect(name) return tree tree, used_names = underscore_search.recurse_collect(tree) new_tree = q[lambda: ast[tree]] new_tree.args.args = [Name(id = x) for x in used_names] return new_tree @macros.expr def lazy(tree, **kw): """Macro to wrap an expression in a lazy memoizing thunk. This can be called via `thing()` to extract the value. The wrapped expression is only evaluated the first time the thunk is called and the result cached for all subsequent evaluations.""" return hq[Lazy(lambda: ast[tree])] def get_interned(store, index, thunk): if store[index] is None: store[index] = [thunk()] return store[index][0] @register(injected_vars) def interned_count(**kw): return [0] @register(injected_vars) def interned_name(gen_sym, **kw): return gen_sym() @register(post_processing) def interned_processing(tree, gen_sym, interned_count, interned_name, **kw): if interned_count[0] != 0: with q as code: name[interned_name] = [None for x in range(u[interned_count[0]])] code = ast_ctx_fixer.recurse(code) code = map(fix_missing_locations, code) tree.body = code + tree.body return tree @macros.expr def interned(tree, interned_name, interned_count, **kw): """Macro to intern the wrapped expression on a per-module basis""" interned_count[0] += 1 return hq[get_interned(name[interned_name], interned_count[0] - 1, lambda: ast[tree])]