def for_macro(*tree): ret = None # for [x iter y iter] ... # -> # foreach x iter # foreach y iter # ... tree = HyExpression(tree).replace(tree[0]) it = iter(tree.pop(0)) blocks = list(zip(it, it)) # List for Python 3.x degenerating. key, val = blocks.pop(0) ret = HyExpression([HySymbol("foreach"), HyList([key, val])]) root = ret ret.replace(tree) for key, val in blocks: # x, [1, 2, 3, 4] nret = HyExpression([HySymbol("foreach"), HyList([key, val])]) nret.replace(key) ret.append(nret) ret = nret [ret.append(x) for x in tree] # we really need ~@ return root
def test_list_add(): """Check that adding two HyLists generates a HyList""" a = HyList([1, 2, 3]) b = HyList([3, 4, 5]) c = a + b assert c == [1, 2, 3, 3, 4, 5] assert c.__class__ == HyList
def test_list_slice(): """Check that slicing a HyList produces a HyList""" a = HyList([1, 2, 3, 4]) sl1 = a[1:] sl5 = a[5:] assert type(sl1) == HyList assert sl1 == HyList([2, 3, 4]) assert type(sl5) == HyList assert sl5 == HyList([])
def test_preprocessor_expression(): """ Test inner macro expantion """ obj = process(tokenize('(test (test "one" "two"))')[0]) assert type(obj) == HyList assert type(obj[0]) == HyList assert obj[0] == HyList([HyString("one"), HyString("two")]) obj = HyList([HyString("one"), HyString("two")]) obj = tokenize('(shill ["one" "two"])')[0][1] assert obj == process(obj)
def process(tree): if isinstance(tree, HyExpression): fn = tree[0] ntree = HyExpression([fn] + [process(x) for x in tree[1:]]) ntree.replace(tree) if isinstance(fn, HyString): if fn in _hy_macros: m = _hy_macros[fn] obj = m(ntree) obj.replace(tree) return obj ntree.replace(tree) return ntree if isinstance(tree, HyDict): obj = HyDict(dict((process(x), process(tree[x])) for x in tree)) obj.replace(tree) return obj if isinstance(tree, HyList): obj = HyList([process(x) for x in tree]) # NOQA # flake8 thinks we're redefining from 52. obj.replace(tree) return obj if isinstance(tree, list): return [process(x) for x in tree] return tree
def test_compiler_yield_return(self): """ Check that the compiler correctly generates return statements for a generator function. In Python versions prior to 3.3, the return statement in a generator can't take a value, so the final expression should not generate a return statement. From 3.3 onwards a return value should be generated. """ ret = self.c.compile_function_def( self._make_expression(HySymbol("fn"), HyList(), HyExpression([HySymbol("yield"), HyInteger(2)]), HyExpression([HySymbol("+"), HyInteger(1), HyInteger(1)]))) self.assertEqual(len(ret.stmts), 1) stmt = ret.stmts[0] self.assertIsInstance(stmt, ast.FunctionDef) body = stmt.body self.assertEquals(len(body), 2) self.assertIsInstance(body[0], ast.Expr) self.assertIsInstance(body[0].value, ast.Yield) if PY33: # From 3.3+, the final statement becomes a return value self.assertIsInstance(body[1], ast.Return) self.assertIsInstance(body[1].value, ast.BinOp) else: # In earlier versions, the expression is not returned self.assertIsInstance(body[1], ast.Expr) self.assertIsInstance(body[1].value, ast.BinOp)
def hy_compile(tree, root=None): " Compile a HyObject tree into a Python AST tree. " compiler = HyASTCompiler() tlo = root if root is None: tlo = ast.Module _ast = compiler.compile(tree) if type(_ast) == list: _ast = compiler._mangle_branch(_ast, 0, 0) if hasattr(sys, "subversion"): implementation = sys.subversion[0].lower() elif hasattr(sys, "implementation"): implementation = sys.implementation.name.lower() imports = [] for package in compiler.imports: imported = set() syms = compiler.imports[package] for entry, form in syms: if entry in imported: continue replace = form if implementation != "cpython": # using form causes pypy to blow up; let's conditionally # add this for cpython, since it won't go through and make # sure the AST makes sense. Muhahaha. - PRT replace = tree[0] imported.add(entry) imports.append( HyExpression([ HySymbol("import"), HyList([HySymbol(package), HyList([HySymbol(entry)])]) ]).replace(replace)) _ast = compiler.compile(imports) + _ast ret = tlo(body=_ast) return ret
def visit(self, tree): if isinstance(tree, HyExpression) and tree != []: call = tree[0] if call == "if" and self.should_hoist(): # If we've got a hoistable if statement fn = HyExpression( [HyExpression([HySymbol("fn"), HyList([]), tree])]) fn.replace(tree) return fn
def test_cons_list(): """Check that cons of something and a list gets tokenized as a list""" entry = tokenize("(a . [])")[0] assert entry == HyList([HySymbol("a")]) assert type(entry) == HyList entry = tokenize("(a . ())")[0] assert entry == HyExpression([HySymbol("a")]) assert type(entry) == HyExpression entry = tokenize("(a b . {})")[0] assert entry == HyDict([HySymbol("a"), HySymbol("b")]) assert type(entry) == HyDict
def let_macro(variables, *body): expr = HyExpression([HySymbol("fn"), HyList([])]) for var in variables: if isinstance(var, list): expr.append(HyExpression([HySymbol("setf"), var[0], var[1]])) else: expr.append(HyExpression([HySymbol("setf"), var, HySymbol("None")])) return HyExpression([expr + list(body)])
def _render_quoted_form(self, form): name = form.__class__.__name__ self.imports["hy"].append((name, form)) if isinstance(form, HyList): return HyExpression([ HySymbol(name), HyList([self._render_quoted_form(x) for x in form]) ]).replace(form) elif isinstance(form, HySymbol): return HyExpression([HySymbol(name), HyString(form)]).replace(form) return HyExpression([HySymbol(name), form]).replace(form)
def test_preprocessor_expression(): """ Test that macro expansion doesn't recurse""" obj = macroexpand(tokenize('(test (test "one" "two"))')[0], __name__) assert type(obj) == HyList assert type(obj[0]) == HyExpression assert obj[0] == HyExpression([HySymbol("test"), HyString("one"), HyString("two")]) obj = HyList([HyString("one"), HyString("two")]) obj = tokenize('(shill ["one" "two"])')[0][1] assert obj == macroexpand(obj, '')
def process(tree): if isinstance(tree, HyExpression): fn = tree[0] ntree = HyExpression([fn] + [process(x) for x in tree[1:]]) if isinstance(fn, HyString): if fn in _hy_macros: m = _hy_macros[fn] obj = m(ntree) obj.replace(tree) return obj ntree.replace(tree) return ntree if isinstance(tree, HyList): obj = HyList([process(x) for x in tree]) obj.replace(tree) return obj if isinstance(tree, list): return [process(x) for x in tree] return tree
def test_fn_compiler_empty_function(self): ret = self.c.compile_function_def(self._make_expression( "fn", HyList())) self.assertEqual(ret.imports, {}) self.assertEqual(len(ret.stmts), 1) stmt = ret.stmts[0] self.assertIsInstance(stmt, ast.FunctionDef) self.assertIsInstance(stmt.args, ast.arguments) self.assertEqual(stmt.args.vararg, None) self.assertEqual(stmt.args.kwarg, None) self.assertEqual(stmt.args.defaults, []) self.assertEqual(stmt.decorator_list, []) self.assertEqual(len(stmt.body), 1) self.assertIsInstance(stmt.body[0], ast.Pass) self.assertIsInstance(ret.expr, ast.Name)
def let_macro(tree): tree.pop(0) # "let" variables = tree.pop(0) # tree is now the body expr = HyExpression([HySymbol("fn"), HyList([])]) for var in variables: if isinstance(var, list): expr.append(HyExpression([HySymbol("setf"), var[0], var[1]])) else: expr.append(HyExpression([HySymbol("setf"), var, HySymbol("None")])) for stmt in tree: expr.append(stmt) return HyExpression([expr])
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 compile_catch_expression(self, expr): catch = expr.pop(0) # catch try: exceptions = expr.pop(0) except IndexError: exceptions = HyList() # exceptions catch should be either: # [[list of exceptions]] # or # [variable [list of exceptions]] # or # [variable exception] # or # [exception] # or # [] if not isinstance(exceptions, HyList): raise HyTypeError(exceptions, "`%s' exceptions list is not a list" % catch) if len(exceptions) > 2: raise HyTypeError(exceptions, "`%s' exceptions list is too long" % catch) # [variable [list of exceptions]] # let's pop variable and use it as name if len(exceptions) == 2: name = exceptions.pop(0) if sys.version_info[0] >= 3: # Python3 features a change where the Exception handler # moved the name from a Name() to a pure Python String type. # # We'll just make sure it's a pure "string", and let it work # it's magic. name = ast_str(name) else: # Python2 requires an ast.Name, set to ctx Store. name = self._storeize(self.compile(name)) else: name = None try: exceptions_list = exceptions.pop(0) except IndexError: exceptions_list = [] if isinstance(exceptions_list, list): if len(exceptions_list): # [FooBar BarFoo] → catch Foobar and BarFoo exceptions _type = ast.Tuple( elts=[self.compile(x) for x in exceptions_list], lineno=expr.start_line, col_offset=expr.start_column, ctx=ast.Load()) else: # [] → all exceptions catched _type = None elif isinstance(exceptions_list, HySymbol): _type = self.compile(exceptions_list) else: raise HyTypeError(exceptions, "`%s' needs a valid exception list" % catch) body = self._code_branch([self.compile(x) for x in expr], expr.start_line, expr.start_column) return ast.ExceptHandler(lineno=expr.start_line, col_offset=expr.start_column, type=_type, name=name, body=body)
def test_preprocessor_simple(): """ Test basic macro expansion """ obj = macroexpand(tokenize('(test "one" "two")')[0], __name__) assert obj == HyList(["one", "two"]) assert type(obj) == HyList
def tmac(*tree): """ Turn an expression into a list """ return HyList(tree)
def t_empty_list(p): return HyList([])
def compile_catch_expression(self, expr): catch = expr.pop(0) # catch try: exceptions = expr.pop(0) except IndexError: exceptions = HyList() # exceptions catch should be either: # [[list of exceptions]] # or # [variable [list of exceptions]] # or # [variable exception] # or # [exception] # or # [] if not isinstance(exceptions, HyList): raise HyTypeError(exceptions, "`%s' exceptions list is not a list" % catch) if len(exceptions) > 2: raise HyTypeError(exceptions, "`%s' exceptions list is too long" % catch) # [variable [list of exceptions]] # let's pop variable and use it as name if len(exceptions) == 2: name = exceptions.pop(0) if sys.version_info[0] >= 3: # Python3 features a change where the Exception handler # moved the name from a Name() to a pure Python String type. # # We'll just make sure it's a pure "string", and let it work # it's magic. name = ast_str(name) else: # Python2 requires an ast.Name, set to ctx Store. name = self._storeize(self.compile(name)) else: name = None try: exceptions_list = exceptions.pop(0) except IndexError: exceptions_list = [] if isinstance(exceptions_list, list): if len(exceptions_list): # [FooBar BarFoo] → catch Foobar and BarFoo exceptions _type = ast.Tuple(elts=[self.compile(x) for x in exceptions_list], lineno=expr.start_line, col_offset=expr.start_column, ctx=ast.Load()) else: # [] → all exceptions catched _type = None elif isinstance(exceptions_list, HySymbol): _type = self.compile(exceptions_list) else: raise HyTypeError(exceptions, "`%s' needs a valid exception list" % catch) body = self._code_branch([self.compile(x) for x in expr], expr.start_line, expr.start_column) return ast.ExceptHandler( lineno=expr.start_line, col_offset=expr.start_column, type=_type, name=name, body=body)
readers = _hy_reader[source_module] reader_refs = _hy_reader[target_module] for name, reader in readers.items(): reader_refs[name] = reader # type -> wrapping function mapping for _wrap_value _wrappers = { int: HyInteger, bool: lambda x: HySymbol("True") if x else HySymbol("False"), float: HyFloat, complex: HyComplex, str_type: HyString, dict: lambda d: HyDict(_wrap_value(x) for x in sum(d.items(), ())), list: lambda l: HyList(_wrap_value(x) for x in l), tuple: lambda t: HyList(_wrap_value(x) for x in t), type(None): lambda foo: HySymbol("None"), HyExpression: lambda e: HyExpression(_wrap_value(x) for x in e), } if sys.version_info[0] < 3: # do not add long on python3 _wrappers[long_type] = HyInteger def _wrap_value(x): """Wrap `x` into the corresponding Hy type. This allows a macro to return an unquoted expression transparently. """
def t_list(p): return HyList(p[1])
def get_route_macro(*tree): return router(tree, rkwargs=HyList([HyString("GET")]))
def post_route_macro(*tree): return router(tree, rkwargs=HyList([HyString("POST")]))
def test_list_add(): a = HyList([1, 2, 3]) b = HyList([3, 4, 5]) c = a + b assert c == [1, 2, 3, 3, 4, 5] assert c.__class__ == HyList
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 _wrap_value(x): wrapper = _wrappers.get(type(x)) if wrapper is None: return x else: return wrapper(x) _wrappers = { int: HyInteger, bool: lambda x: HySymbol("True") if x else HySymbol("False"), float: HyFloat, complex: HyComplex, str_type: HyString, dict: lambda d: HyDict(_wrap_value(x) for x in sum(d.items(), ())), list: lambda l: HyList(_wrap_value(x) for x in l) } def process(tree, module_name): if isinstance(tree, HyExpression): fn = tree[0] if fn in ("quote", "quasiquote"): return tree ntree = HyExpression([fn] + [process(x, module_name) for x in tree[1:]]) ntree.replace(tree) if isinstance(fn, HyString): m = _hy_macros[module_name].get(fn) if m is None: