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")]) ]) ] # Duplicate items in a literal set should be okay (and should # be preserved). objs = tokenize("#{1 2 1 1 2 1}") assert objs == [HySet([HyInteger(n) for n in [1, 2, 1, 1, 2, 1]])] assert len(objs[0]) == 6 # https://github.com/hylang/hy/issues/1120 objs = tokenize("#{a 1}") assert objs == [HySet([HySymbol("a"), HyInteger(1)])]
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) obj.replace(tree) return obj return ntree 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 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 = "`" + str(tree[0]) + "' " + " ".join(str(e).split()[1:]) raise HyMacroExpansionError(tree, msg) obj.replace(tree) return obj return ntree return tree
def process(tree, module_name): if isinstance(tree, HyExpression): if tree == []: return tree 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: m = _hy_macros[None].get(fn) if m is not None: obj = _wrap_value(m(*ntree[1:])) obj.replace(tree) return obj ntree.replace(tree) return ntree if isinstance(tree, HyList): obj = tree.__class__([process(x, module_name) for x in tree]) # NOQA # flake8 thinks we're redefining from 52. obj.replace(tree) return obj if isinstance(tree, list): return [process(x, module_name) for x in tree] return tree
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 _make_expression(*args): h = HyExpression(args) h.start_line = 1 h.end_line = 1 h.start_column = 1 h.end_column = 1 return h
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_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 visit(self, tree): if isinstance(tree, HyExpression) and tree != []: call = tree[0] if call == "if" and self.should_hoist(): fn = HyExpression([HyExpression([HySymbol("fn"), HyList([]), tree])]) fn.replace(tree) return fn
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 threading_tail_macro(head, *rest): ret = head for node in rest: if not isinstance(node, HyExpression): nnode = HyExpression([node]) nnode.replace(node) node = nnode node.append(ret) ret = node return ret
def for_macro(tree): tree.pop(0) ret = None # for [x iter y iter] ... # -> # foreach x iter # foreach y iter # ... 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 threading_tail_macro(tree): tree.pop(0) ret = tree.pop(0) for node in tree: if not isinstance(node, HyExpression): nnode = HyExpression([node]) nnode.replace(node) node = nnode node.append(ret) ret = node return ret
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 visit(self, tree): if isinstance(tree, HyExpression) and tree != []: call = tree[0] if call == "fn" and self.should_hoist(): 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 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 let_macro(tree): tree.pop(0) # "let" ret = tree.pop(0) # vars # tree is now the body expr = HyExpression([HySymbol("fn"), HyList([])]) for var in ret: expr.append(HyExpression([HySymbol("setf"), var[0], var[1]])) for stmt in tree: expr.append(stmt) return HyExpression([expr])
def router(tree, rkwargs=None): tree = HyExpression(tree) name = tree.pop(0) path = tree.pop(0) tree.insert(0, HySymbol("fn")) tree = HyExpression([HySymbol("def"), name, tree]) route = HyExpression([HySymbol(".route"), HySymbol("app"), path]) if rkwargs: route = HyExpression([HySymbol("kwapply"), route, HyDict({HyString("methods"): rkwargs})]) return HyExpression([HySymbol("with_decorator"), route, tree])
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 router(tree, rkwargs=None): tree = HyExpression(tree) name = tree.pop(0) path = tree.pop(0) tree.insert(0, HySymbol("fn")) tree = HyExpression([HySymbol("def"), name, tree]) route = HyExpression([HySymbol(".route"), HySymbol("app"), path]) if rkwargs: route = HyExpression([ HySymbol("kwapply"), route, HyDict({HyString("methods"): rkwargs}) ]) return HyExpression([HySymbol("with_decorator"), route, tree])
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 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 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 test_lex_fractions(): """ Make sure that fractions are valid expressions""" objs = tokenize("1/2") assert objs == [ HyExpression([HySymbol("fraction"), HyInteger(1), HyInteger(2)]) ]
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 _make_expression(*args): h = HyExpression(args) h.start_line = 1 h.end_line = 1 h.start_column = 1 h.end_column = 1 return h.replace(h)
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 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 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 compile_expression(self, expression): fn = expression[0] if isinstance(fn, HyString): if fn in _compile_table: return _compile_table[fn](self, expression) if expression[0].startswith("."): return self.compile_dotted_expression(expression) if isinstance(fn, HyKeyword): new_expr = HyExpression(["get", expression[1], fn]) new_expr.start_line = expression.start_line new_expr.start_column = expression.start_column return self.compile_index_expression(new_expr) return ast.Call(func=self.compile(fn), args=[self.compile(x) for x in expression[1:]], keywords=[], starargs=None, kwargs=None, lineno=expression.start_line, col_offset=expression.start_column)
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"})])]
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: m = _hy_macros[None].get(fn) if m is not None: obj = _wrap_value(m(*ntree[1:])) obj.replace(tree) return obj ntree.replace(tree) return ntree if isinstance(tree, HyList): obj = tree.__class__([process(x, module_name) for x in tree]) # NOQA # flake8 thinks we're redefining from 52. obj.replace(tree) return obj if isinstance(tree, list): return [process(x, module_name) for x in tree] return tree
def macroexpand(tree, 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: obj = _wrap_value(m(*ntree[1:])) obj.replace(tree) return obj return ntree return tree
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 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: obj = _wrap_value(m(*ntree[1:])) obj.replace(tree) return obj return ntree return tree
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])