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) replace_hy_obj(obj, tree) return obj return ntree return tree
def hy_eval(hytree, namespace, module_name): foo = HyObject() foo.start_line = 0 foo.end_line = 0 foo.start_column = 0 foo.end_column = 0 replace_hy_obj(hytree, foo) if not isinstance(module_name, string_types): raise HyTypeError(foo, "Module name must be a string") _ast, expr = hy_compile(hytree, module_name, get_expr=True) # Spoof the positions in the generated ast... for node in ast.walk(_ast): node.lineno = 1 node.col_offset = 1 for node in ast.walk(expr): node.lineno = 1 node.col_offset = 1 if not isinstance(namespace, dict): raise HyTypeError(foo, "Globals must be a dictionary") # Two-step eval: eval() the body of the exec call eval(ast_compile(_ast, "<eval_body>", "exec"), namespace) # Then eval the expression context and return that return eval(ast_compile(expr, "<eval>", "eval"), namespace)
def __compile_code(self, code_string): hytree = hy.lex.tokenize(code_string) module_name = '__main__' foo = HyObject() foo.start_line = 0 foo.end_line = 0 foo.start_column = 0 foo.end_column = 0 replace_hy_obj(hytree, foo) if not isinstance(module_name, string_types): raise HyTypeError(foo, "Module name must be a string") _ast, expr = hy_compile(hytree, module_name, get_expr=True) # Spoof the positions in the generated ast... for node in ast.walk(_ast): node.lineno = 1 node.col_offset = 1 for node in ast.walk(expr): node.lineno = 1 node.col_offset = 1 return _ast, expr
def hy_eval(hytree, namespace, module_name, ast_callback=None): foo = HyObject() foo.start_line = 0 foo.end_line = 0 foo.start_column = 0 foo.end_column = 0 replace_hy_obj(hytree, foo) if not isinstance(module_name, string_types): raise HyTypeError(foo, "Module name must be a string") _ast, expr = hy_compile(hytree, module_name, get_expr=True) # Spoof the positions in the generated ast... for node in ast.walk(_ast): node.lineno = 1 node.col_offset = 1 for node in ast.walk(expr): node.lineno = 1 node.col_offset = 1 if ast_callback: ast_callback(_ast, expr) if not isinstance(namespace, dict): raise HyTypeError(foo, "Globals must be a dictionary") # Two-step eval: eval() the body of the exec call eval(ast_compile(_ast, "<eval_body>", "exec"), namespace) # Then eval the expression context and return that return eval(ast_compile(expr, "<eval>", "eval"), namespace)
def replace(self, other): if self.car is not None: replace_hy_obj(self.car, other) if self.cdr is not None: replace_hy_obj(self.cdr, other) HyObject.replace(self, other)
def hy_eval(hytree, namespace=None, module_name=None, ast_callback=None): """``eval`` evaluates a quoted expression and returns the value. The optional 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 defaults to the name of the current module. => (eval '(print "Hello World")) "Hello World" If you want to evaluate a string, use ``read-str`` to convert it to a form first: => (eval (read-str "(+ 1 1)")) 2""" if namespace is None: frame = inspect.stack()[1][0] namespace = inspect.getargvalues(frame).locals if module_name is None: m = inspect.getmodule(inspect.stack()[1][0]) module_name = '__eval__' if m is None else m.__name__ foo = HyObject() foo.start_line = 0 foo.end_line = 0 foo.start_column = 0 foo.end_column = 0 replace_hy_obj(hytree, foo) if not isinstance(module_name, string_types): raise HyTypeError(foo, "Module name must be a string") _ast, expr = hy_compile(hytree, module_name, get_expr=True) # Spoof the positions in the generated ast... for node in ast.walk(_ast): node.lineno = 1 node.col_offset = 1 for node in ast.walk(expr): node.lineno = 1 node.col_offset = 1 if ast_callback: ast_callback(_ast, expr) if not isinstance(namespace, dict): raise HyTypeError(foo, "Globals must be a dictionary") # Two-step eval: eval() the body of the exec call eval(ast_compile(_ast, "<eval_body>", "exec"), namespace) # Then eval the expression context and return that return eval(ast_compile(expr, "<eval>", "eval"), namespace)
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 reader_macroexpand(char, tree, module_name): """Expand the reader macro "char" with argument `tree`.""" load_macros(module_name) reader_macro = _hy_reader[module_name].get(char) if reader_macro is None: try: reader_macro = _hy_reader[None][char] except KeyError: raise HyTypeError(char, "`{0}' is not a defined reader macro.".format(char)) expr = reader_macro(tree) return replace_hy_obj(wrap_value(expr), tree)
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 hy_eval(hytree, namespace, module_name): foo = HyObject() foo.start_line = 0 foo.end_line = 0 foo.start_column = 0 foo.end_column = 0 replace_hy_obj(hytree, foo) _ast, expr = hy_compile(hytree, module_name, get_expr=True) # Spoof the positions in the generated ast... for node in ast.walk(_ast): node.lineno = 1 node.col_offset = 1 for node in ast.walk(expr): node.lineno = 1 node.col_offset = 1 # Two-step eval: eval() the body of the exec call eval(ast_compile(_ast, "<eval_body>", "exec"), namespace) # Then eval the expression context and return that return eval(ast_compile(expr, "<eval>", "eval"), namespace)
def tag_macroexpand(tag, tree, compiler): """Expand the tag macro "tag" with argument `tree`.""" load_macros(compiler.module_name) tag_macro = _hy_tag[compiler.module_name].get(tag) if tag_macro is None: try: tag_macro = _hy_tag[None][tag] except KeyError: raise HyTypeError(tag, "`{0}' is not a defined tag macro.".format(tag)) expr = tag_macro(tree) return replace_hy_obj(expr, tree)
def sharp_macroexpand(char, tree, compiler): """Expand the sharp macro "char" with argument `tree`.""" load_macros(compiler.module_name) sharp_macro = _hy_sharp[compiler.module_name].get(char) if sharp_macro is None: try: sharp_macro = _hy_sharp[None][char] except KeyError: raise HyTypeError( char, "`{0}' is not a defined sharp macro.".format(char)) expr = sharp_macro(tree) return replace_hy_obj(wrap_value(expr), tree)
def reader_macroexpand(char, tree, module_name): """Expand the reader macro "char" with argument `tree`.""" load_macros(module_name) reader_macro = _hy_reader[module_name].get(char) if reader_macro is None: try: reader_macro = _hy_reader[None][char] except KeyError: raise HyTypeError( char, "`{0}' is not a defined reader macro.".format(char)) expr = reader_macro(tree) return replace_hy_obj(wrap_value(expr), tree)
def macroexpand(tree, compiler, once=False): """Expand the toplevel macros for the `tree`. Load the macros from the given `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 sharp_macroexpand(char, tree, compiler): """Expand the sharp macro "char" with argument `tree`.""" load_macros(compiler.module_name) sharp_macro = _hy_sharp[compiler.module_name].get(char) if sharp_macro is None: try: sharp_macro = _hy_sharp[None][char] except KeyError: raise HyTypeError( char, "`{0}' is not a defined sharp macro.".format(char) ) expr = sharp_macro(tree) return replace_hy_obj(wrap_value(expr), tree)
def tag_macroexpand(tag, tree, compiler): """Expand the tag macro "tag" with argument `tree`.""" load_macros(compiler.module_name) tag_macro = _hy_tag[compiler.module_name].get(tag) if tag_macro is None: try: tag_macro = _hy_tag[None][tag] except KeyError: raise HyTypeError( tag, "`{0}' is not a defined tag macro.".format(tag) ) expr = tag_macro(tree) return replace_hy_obj(expr, tree)
def tag_macroexpand(tag, tree, module): """Expand the tag macro `tag` with argument `tree`.""" if not inspect.ismodule(module): module = importlib.import_module(module) expr_modules = (([] if not hasattr(tree, 'module') else [tree.module]) + [module]) # Choose the first namespace with the macro. tag_macro = next((mod.__tags__[tag] for mod in expr_modules if tag in mod.__tags__), None) if tag_macro is None: raise HyTypeError(tag, "'{0}' is not a defined tag macro.".format(tag)) expr = tag_macro(tree) if isinstance(expr, HyExpression): expr.module = inspect.getmodule(tag_macro) return replace_hy_obj(expr, tree)
def tag_macroexpand(tag, tree, module): """Expand the tag macro `tag` with argument `tree`.""" if not inspect.ismodule(module): module = importlib.import_module(module) expr_modules = (([] if not hasattr(tree, 'module') else [tree.module]) + [module]) # Choose the first namespace with the macro. tag_macro = next((mod.__tags__[tag] for mod in expr_modules if tag in mod.__tags__), None) if tag_macro is None: raise HyTypeError("`{0}' is not a defined tag macro.".format(tag), None, tag, None) expr = tag_macro(tree) if isinstance(expr, HyExpression): expr.module = inspect.getmodule(tag_macro) return replace_hy_obj(expr, tree)
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 isinstance(tree, HyExpression) and tree: 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 with macro_exceptions(module, tree, compiler): obj = m(module.__name__, *tree[1:], **opts) if isinstance(obj, HyExpression): obj.module = inspect.getmodule(m) tree = replace_hy_obj(obj, tree) if once: break tree = wrap_value(tree) return tree
def test_replace_tuple(): """ Test replacing tuples.""" replaced = replace_hy_obj((0, ), HyInteger(13)) assert type(replaced) == HyList assert type(replaced[0]) == HyInteger assert replaced == HyList([HyInteger(0)])
def test_replace_string_type(): """Test replacing python string""" replaced = replace_hy_obj("foo", HyString("bar")) assert replaced == HyString("foo")
def test_replace_int(): """ Test replacing integers.""" replaced = replace_hy_obj(0, HyInteger(13)) assert replaced == HyInteger(0)
def test_replace_tuple(): replaced = replace_hy_obj((0, ), Integer(13)) assert type(replaced) == List assert type(replaced[0]) == Integer assert replaced == List([Integer(0)])
def replace(self, other): for x in self: replace_hy_obj(x, other) HyObject.replace(self, other) return self
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
def test_replace_int(): replaced = replace_hy_obj(0, Integer(13)) assert replaced == Integer(0)
def test_replace_string_type(): """Test replacing python string""" replaced = replace_hy_obj(str_type("foo"), HyString("bar")) assert replaced == HyString("foo")
def test_replace_str(): replaced = replace_hy_obj("foo", String("bar")) assert replaced == String("foo")
def test_replace_long_type(): """ Test replacing integers.""" replaced = replace_hy_obj(long_type(0), HyInteger(13)) assert replaced == HyInteger(0)
def test_replace_tuple(): """ Test replacing tuples.""" replaced = replace_hy_obj((long_type(0), ), HyInteger(13)) assert type(replaced) == HyList assert type(replaced[0]) == HyInteger assert replaced == HyList([HyInteger(0)])
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 with macro_exceptions(module, tree, compiler): obj = m(module.__name__, *tree[1:], **opts) if isinstance(obj, HyExpression): obj.module = inspect.getmodule(m) tree = replace_hy_obj(obj, tree) if once: break tree = wrap_value(tree) return tree