def __new__(cls, car, cdr): if isinstance(cdr, list): # Keep unquotes in the cdr of conses if type(cdr) == HyExpression: if len(cdr) > 0 and type(cdr[0]) == HySymbol: if cdr[0] in ("unquote", "unquote_splice"): return super(HyCons, cls).__new__(cls) return cdr.__class__([wrap_value(car)] + cdr) elif cdr is None: return HyExpression([wrap_value(car)]) else: return super(HyCons, cls).__new__(cls)
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 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 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(wrap_value(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 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 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 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 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, HyString): 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(*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 = wrap_value(m(*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 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_wrap_tuple(): """ Test conversion of tuples.""" wrapped = wrap_value((HyInteger(0), )) assert type(wrapped) == HyList assert type(wrapped[0]) == HyInteger assert wrapped == HyList([HyInteger(0)])
def test_wrap_nested_expr(): """ Test conversion of HyExpressions with embedded non-HyObjects.""" wrapped = wrap_value(HyExpression([0])) assert type(wrapped) == HyExpression assert type(wrapped[0]) == HyInteger assert wrapped == HyExpression([HyInteger(0)])
""" Hy List. Basically just a list. """ def replace(self, other): for x in self: replace_hy_obj(x, other) HyObject.replace(self, other) return self def __add__(self, other): return self.__class__(super(HyList, self).__add__(other)) def __getslice__(self, start, end): return self.__class__(super(HyList, self).__getslice__(start, end)) def __getitem__(self, item): ret = super(HyList, self).__getitem__(item) if isinstance(item, slice): return self.__class__(ret) return ret def __repr__(self): return "[%s]" % (" ".join([repr(x) for x in self])) _wrappers[list] = lambda l: HyList(wrap_value(x) for x in l) _wrappers[tuple] = lambda t: HyList(wrap_value(x) for x in t)
def test_wrap_int(): """ Test conversion of integers.""" wrapped = wrap_value(0) assert type(wrapped) == HyInteger
# copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import _wrappers, wrap_value from hy.models.list import HyList class HySet(HyList): """ Hy set (just a representation of a set) """ def __repr__(self): return "#{%s}" % (" ".join([repr(x) for x in self])) _wrappers[set] = lambda s: HySet(wrap_value(x) for x in s)
def __init__(self, car, cdr): self.car = wrap_value(car) self.cdr = wrap_value(cdr)
# copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import _wrappers, wrap_value from hy.models.list import HyList class HyExpression(HyList): """ Hy S-Expression. Basically just a list. """ def __repr__(self): return "(%s)" % (" ".join([repr(x) for x in self])) _wrappers[HyExpression] = lambda e: HyExpression(wrap_value(x) for x in e)
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
def test_wrap_long_type(): """ Test conversion of integers.""" wrapped = wrap_value(long_type(0)) assert type(wrapped) == HyInteger
def test_wrap_tuple(): """ Test conversion of tuples.""" wrapped = wrap_value((HyInteger(0),)) assert type(wrapped) == HyList assert type(wrapped[0]) == HyInteger assert wrapped == HyList([HyInteger(0)])
def test_wrap_nested_expr(): """ Test conversion of HyExpressions with embedded non-HyObjects.""" wrapped = wrap_value(HyExpression([long_type(0)])) assert type(wrapped) == HyExpression assert type(wrapped[0]) == HyInteger assert wrapped == HyExpression([HyInteger(0)])
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import _wrappers, wrap_value from hy.models.list import HyList class HyDict(HyList): """ HyDict (just a representation of a dict) """ def __repr__(self): return "{%s}" % (" ".join([repr(x) for x in self])) def keys(self): return self[0::2] def values(self): return self[1::2] def items(self): return list(zip(self.keys(), self.values())) _wrappers[dict] = lambda d: HyDict(wrap_value(x) for x in sum(d.items(), ()))