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 t_identifier(p): obj = p[0].value try: return HyInteger(obj) except ValueError: pass if '/' in obj: try: lhs, rhs = obj.split('/') return HyExpression( [HySymbol('fraction'), HyInteger(lhs), HyInteger(rhs)]) except ValueError: pass try: return HyFloat(obj) except ValueError: pass if obj != 'j': try: return HyComplex(obj) except ValueError: pass if obj.startswith(":"): return HyKeyword(obj) obj = ".".join([hy_symbol_mangle(part) for part in obj.split(".")]) return HySymbol(obj)
def compile_eval(self, expr): expr.pop(0) self.imports["hy.importer"].append(("hy_eval", expr)) return self.compile( HyExpression([HySymbol("hy_eval")] + expr + [HyExpression([HySymbol("locals")])]).replace(expr))
def unless_macro(test, *body): return HyExpression([ HySymbol('if'), test, HySymbol('None'), HyExpression([HySymbol("do")] + list(body)), ])
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 test_dotted_list(): """Check that dotted lists get tokenized correctly""" entry = tokenize("(a b c . (d . e))")[0] assert entry == HyCons( HySymbol("a"), HyCons(HySymbol("b"), HyCons(HySymbol("c"), HyCons(HySymbol("d"), HySymbol("e")))))
def test_lex_expression_complex(): """ Make sure expressions can produce complex """ objs = tokenize("(foo 2.j)") assert objs == [HyExpression([HySymbol("foo"), HyComplex(2.j)])] objs = tokenize("(foo -0.5j)") assert objs == [HyExpression([HySymbol("foo"), HyComplex(-0.5j)])] objs = tokenize("(foo 1.e7j)") assert objs == [HyExpression([HySymbol("foo"), HyComplex(1.e7j)])]
def test_lex_expression_float(): """ Make sure expressions can produce floats """ objs = tokenize("(foo 2.)") assert objs == [HyExpression([HySymbol("foo"), HyFloat(2.)])] objs = tokenize("(foo -0.5)") assert objs == [HyExpression([HySymbol("foo"), HyFloat(-0.5)])] objs = tokenize("(foo 1.e7)") assert objs == [HyExpression([HySymbol("foo"), HyFloat(1.e7)])]
def test_lex_mangling_star(): """Ensure that mangling starred identifiers works according to plan""" entry = tokenize("*foo*") assert entry == [HySymbol("FOO")] entry = tokenize("*") assert entry == [HySymbol("*")] entry = tokenize("*foo") assert entry == [HySymbol("*foo")]
def t_identifier(p): obj = p[0].value try: return HyInteger(obj) except ValueError: pass if '/' in obj: try: lhs, rhs = obj.split('/') return HyExpression( [HySymbol('fraction'), HyInteger(lhs), HyInteger(rhs)]) except ValueError: pass try: return HyFloat(obj) except ValueError: pass if obj != 'j': try: return HyComplex(obj) except ValueError: pass table = { "true": "True", "false": "False", "nil": "None", "null": "None", } if obj in table: return HySymbol(table[obj]) if obj.startswith(":"): return HyKeyword(obj) def mangle(p): if p.startswith("*") and p.endswith("*") and p not in ("*", "**"): p = p[1:-1].upper() if "-" in p and p != "-": p = p.replace("-", "_") if p.endswith("?") and p != "?": p = "is_%s" % (p[:-1]) return p obj = ".".join([mangle(part) for part in obj.split(".")]) return HySymbol(obj)
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 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 cond_macro(*tree): it = iter(tree) test, branch = next(it) root = HyExpression([HySymbol("if"), test, branch]) ret = root for (test, branch) in it: n = HyExpression([HySymbol("if"), test, branch]) ret.append(n) ret = n return root
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 visit(self, tree): """ Visit all the nodes in the Hy code tree. """ if isinstance(tree, HyExpression) and tree != []: call = tree[0] if call == "fn" and self.should_hoist(): # if we have a Function and we should hoist it -- new_name = HySymbol(self.unique_name()) new_name.replace(tree) fn_def = HyExpression([HySymbol("def"), new_name, tree]) fn_def.replace(tree) self.hoist(fn_def) return new_name
def test_dicts(): """ Ensure that we can tokenize a dict. """ objs = tokenize("{foo bar bar baz}") assert objs == [HyDict(["foo", "bar", "bar", "baz"])] objs = tokenize("(bar {foo bar bar baz})") assert objs == [HyExpression([HySymbol("bar"), HyDict(["foo", "bar", "bar", "baz"])])] objs = tokenize("{(foo bar) (baz quux)}") assert objs == [HyDict([ HyExpression([HySymbol("foo"), HySymbol("bar")]), HyExpression([HySymbol("baz"), HySymbol("quux")]) ])]
def _resolve_atom(obj): """ Resolve a bare atom into one of the following (in order): - Integer - LambdaListKeyword - Float - Complex - Symbol """ try: return HyInteger(obj) except ValueError: pass if obj.startswith("&"): return HyLambdaListKeyword(obj) try: return HyFloat(obj) except ValueError: pass if obj != "j": try: return HyComplex(obj) except ValueError: pass table = { "true": "True", "false": "False", "null": "None", } if obj in table: return HySymbol(table[obj]) if obj.startswith(":"): return HyKeyword(obj) if obj.startswith("*") and obj.endswith("*") and obj not in ("*", "**"): obj = obj[1:-1].upper() if "-" in obj and obj != "-": obj = obj.replace("-", "_") return HySymbol(obj)
def compile_for_expression(self, expression): with self.is_returnable(False): expression.pop(0) # for name, iterable = expression.pop(0) target = self._storeize(self.compile_symbol(name)) orelse = [] # (foreach [] body (else …)) if expression and expression[-1][0] == HySymbol("else"): else_expr = expression.pop() if len(else_expr) > 2: raise HyTypeError( else_expr, "`else' statement in `foreach' is too long") elif len(else_expr) == 2: orelse = self._code_branch(self.compile(else_expr[1]), else_expr[1].start_line, else_expr[1].start_column) ret = ast.For(lineno=expression.start_line, col_offset=expression.start_column, target=target, iter=self.compile(iterable), body=self._code_branch( [self.compile(x) for x in expression], expression.start_line, expression.start_column), orelse=orelse) return ret
def test_complex(): """Ensure we tokenize complex numbers properly""" # This is a regression test for #143 entry = tokenize("(1j)")[0][0] assert entry == HyComplex("1.0j") entry = tokenize("(j)")[0][0] assert entry == HySymbol("j")
def rest_macro(tree): tree.pop(0) # "first" ret = tree.pop(0) # the list # assert tree is empty return HyExpression([HySymbol('slice'), ret, HyInteger(1)])
def drop_macro(tree): tree.pop(0) # "drop" n = tree.pop(0) ret = tree.pop(0) return HyExpression([HySymbol('slice'), ret, HyInteger(n)])
def ideas_macro(): return HyExpression([ HySymbol('print'), HyString(""" => (import [sh [figlet]]) => (figlet "Hi, Hy!") _ _ _ _ _ _ | | | (_) | | | |_ _| | | |_| | | | |_| | | | | | | _ | |_ | _ | |_| |_| |_| |_|_( ) |_| |_|\__, (_) |/ |___/ ;;; string things (.join ", " ["what" "the" "heck"]) ;;; this one plays with command line bits (import [sh [cat grep]]) (-> (cat "/usr/share/dict/words") (grep "-E" "bro$")) ;;; filtering a list w/ a lambda (filter (lambda [x] (= (% x 2) 0)) (range 0 10)) ;;; swaggin' functional bits (Python rulez) (max (map (lambda [x] (len x)) ["hi" "my" "name" "is" "paul"])) """) ])
def test_sets(): """ Ensure that we can tokenize a set. """ objs = tokenize("#{1 2}") assert objs == [HySet([HyInteger(1), HyInteger(2)])] objs = tokenize("(bar #{foo bar baz})") assert objs == [ HyExpression([HySymbol("bar"), HySet(["foo", "bar", "baz"])]) ] objs = tokenize("#{(foo bar) (baz quux)}") assert objs == [ HySet([ HyExpression([HySymbol("foo"), HySymbol("bar")]), HyExpression([HySymbol("baz"), HySymbol("quux")]) ]) ]
def test_lex_fractions(): """ Make sure that fractions are valid expressions""" objs = tokenize("1/2") assert objs == [ HyExpression([HySymbol("fraction"), HyInteger(1), HyInteger(2)]) ]
def take_macro(tree): tree.pop(0) # "take" n = tree.pop(0) ret = tree.pop(0) return HyExpression([HySymbol('slice'), ret, HyInteger(0), HyInteger(n)])
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 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 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 t_identifier(p): obj = p[0].value try: return HyInteger(obj) except ValueError: pass try: return HyFloat(obj) except ValueError: pass if obj != 'j': try: return HyComplex(obj) except ValueError: pass table = { "true": "True", "false": "False", "null": "None", } if obj in table: return HySymbol(table[obj]) if obj.startswith(":"): return HyKeyword(obj) if obj.startswith("&"): return HyLambdaListKeyword(obj) if obj.startswith("*") and obj.endswith("*") and obj not in ("*", "**"): obj = obj[1:-1].upper() if "-" in obj and obj != "-": obj = obj.replace("-", "_") return HySymbol(obj)
def test_compiler_bare_names(self): """ Check that the compiler doesn't drop bare names from code branches """ ret = self.c.compile( self._make_expression(HySymbol("do"), HySymbol("a"), HySymbol("b"), HySymbol("c"))) # We expect two statements and a final expr. self.assertEqual(len(ret.stmts), 2) stmt = ret.stmts[0] self.assertIsInstance(stmt, ast.Expr) self.assertIsInstance(stmt.value, ast.Name) self.assertEqual(stmt.value.id, "a") stmt = ret.stmts[1] self.assertIsInstance(stmt, ast.Expr) self.assertIsInstance(stmt.value, ast.Name) self.assertEqual(stmt.value.id, "b") expr = ret.expr self.assertIsInstance(expr, ast.Name) self.assertEqual(expr.id, "c")