def trace_walk(tree, ctx, stop, **kw): if isinstance(tree, expr) and \ tree._fields != () and \ type(tree) is not Num and \ type(tree) is not Str and \ type(tree) is not Name: try: literal_eval(tree) stop() return tree except ValueError: txt = ctx(tree) trace_walk.walk_children(tree, ctx) wrapped = q(wrap(log, u(txt), ast%tree)) stop() return wrapped elif isinstance(tree, stmt): txt = ctx(tree) trace_walk.walk_children(tree , ctx) with q as code: log(u(txt)) stop() return [code, tree]
def trace_walk(tree, ctx, stop, **kw): if isinstance(tree, expr) and \ tree._fields != () and \ type(tree) is not Num and \ type(tree) is not Str and \ type(tree) is not Name: try: literal_eval(tree) stop() return tree except ValueError: txt = ctx(tree) trace_walk.walk_children(tree, ctx) wrapped = q(wrap(log, u(txt), ast % tree)) stop() return wrapped elif isinstance(tree, stmt): txt = ctx(tree) trace_walk.walk_children(tree, ctx) with q as code: log(u(txt)) stop() return [code, tree]
def test_quote_unquote_block(self): a = 10 b = ["a", "b", "c"] c = [] with q as code: c.append(a) c.append(u(a)) c.extend(u(b)) exec(unparse_ast(code)) assert(c == [10, 10, 'a', 'b', 'c']) c = [] a, b = None, None exec(unparse_ast(code)) assert(c == [None, 10, 'a', 'b', 'c'])
def test_quote_unquote(self): x = 1 y = 2 a = q(u(x + y)) assert(eval(unparse_ast(a)) == 3) x = 0 y = 0 assert(eval(unparse_ast(a)) == 3)
def test_structured(self): a = [1, 2, "omg"] b = ["wtf", "bbq"] data1 = q([x for x in u(a + b)]) assert(eval(unparse_ast(data1)) == [1, 2, "omg", "wtf", "bbq"]) b = [] assert(eval(unparse_ast(data1)) == [1, 2, "omg", "wtf", "bbq"])
def show_expanded(tree, expand_macros, **kw): new_tree = [] for stmt in tree: new_stmt = expand_macros(stmt) with q as code: log(u(unparse_ast(new_stmt))) new_tree.append(code) new_tree.append(new_stmt) return new_tree
def test_simple(self): a = 10 b = 2 data1 = q(1 + u(a + b)) data2 = q(1 + (a + b)) assert eval(unparse_ast(data1)) == 13 assert eval(unparse_ast(data2)) == 13 a = 1 assert eval(unparse_ast(data1)) == 13 assert eval(unparse_ast(data2)) == 4
def s(tree, **kw): captured = [] new_string = "" chunks = re.split("{(.*?)}", tree.s) for i in range(0, len(chunks)): if i % 2 == 0: new_string += chunks[i] else: new_string += "%s" captured += [chunks[i]] result = q(u(new_string) % tuple(ast_list(map(parse_expr, captured)))) return result
def _PegWalker(tree, ctx, stop, collect, **kw): if type(tree) is Str: stop() return q(Parser.Raw(ast(tree))) if type(tree) is BinOp and type(tree.op) is RShift: tree.left, b_left = _PegWalker.recurse_real(tree.left) tree.right = q(lambda bindings: ast(tree.right)) tree.right.args.args = map(f(Name(id=_)), flatten(b_left)) stop() return tree if type(tree) is BinOp and type(tree.op) is FloorDiv: tree.left, b_left = _PegWalker.recurse_real(tree.left) stop() collect(b_left) return tree if type(tree) is Tuple: result = q(Parser.Seq([])) result.args[0].elts = tree.elts all_bindings = [] for i, elt in enumerate(tree.elts): result.args[0].elts[i], bindings = _PegWalker.recurse_real( tree.elts[i]) all_bindings.append(bindings) stop() collect(all_bindings) return result if type(tree) is Compare and type(tree.ops[0]) is Is: left_tree, bindings = _PegWalker.recurse_real(tree.left) new_tree = q(ast(left_tree).bind_to(u(tree.comparators[0].id))) stop() collect(bindings + [tree.comparators[0].id]) return new_tree
def _PegWalker(tree, ctx, stop, collect, **kw): if type(tree) is Str: stop() return q(Parser.Raw(ast(tree))) if type(tree) is BinOp and type(tree.op) is RShift: tree.left, b_left = _PegWalker.recurse_real(tree.left) tree.right = q(lambda bindings: ast(tree.right)) tree.right.args.args = map(f(Name(id = _)), flatten(b_left)) stop() return tree if type(tree) is BinOp and type(tree.op) is FloorDiv: tree.left, b_left = _PegWalker.recurse_real(tree.left) stop() collect(b_left) return tree if type(tree) is Tuple: result = q(Parser.Seq([])) result.args[0].elts = tree.elts all_bindings = [] for i, elt in enumerate(tree.elts): result.args[0].elts[i], bindings = _PegWalker.recurse_real(tree.elts[i]) all_bindings.append(bindings) stop() collect(all_bindings) return result if type(tree) is Compare and type(tree.ops[0]) is Is: left_tree, bindings = _PegWalker.recurse_real(tree.left) new_tree = q(ast(left_tree).bind_to(u(tree.comparators[0].id))) stop() collect(bindings + [tree.comparators[0].id]) return new_tree
def show_expanded(tree, expand_macros, **kw): expanded_tree = expand_macros(tree) new_tree = q(wrap_simple(log, u(unparse_ast(expanded_tree)), ast(expanded_tree))) return new_tree
def log(tree, exact_src, **kw): new_tree = q(wrap(log, u(exact_src(tree)), ast(tree))) return new_tree
def pyjs(tree, **kw): javascript = pjs.converter.Converter("").convert_node(tree, Scope()) return q((ast(tree), u(javascript)))
# (f, a1, ..., an) --> f(a1, ..., an) posargs = [x for x in data if not iskwargs(x)] # TODO: tag *args and **kwargs in a kw() as invalid, too (currently just ignored) invalids = list(flatmap(lambda x: x.args, filter(iskwargs, data))) if invalids: assert False, "kw(...) may only specify named args" kwargs = flatmap(lambda x: x.keywords, filter(iskwargs, data)) kwargs = list(rev(uniqify(rev(kwargs), key=lambda x: x.arg))) # latest wins, but keep original ordering return Call(func=op, args=posargs, keywords=list(kwargs)) # This is a first-pass macro. Any nested macros should get clean standard Python, # not having to worry about tuples possibly denoting function calls. yield transform.recurse(block_body, quotelevel=0) # note the exported "q" is ours, but the q we use in this module is a macro. class q: """[syntax] Quote operator. Only meaningful in a tuple in a prefix block.""" def __repr__(self): # in case one of these ends up somewhere at runtime return "<quote>" q = q() class u: """[syntax] Unquote operator. Only meaningful in a tuple in a prefix block.""" def __repr__(self): # in case one of these ends up somewhere at runtime return "<unquote>" u = u() # not a @macro_stub; it only raises a run-time error on foo[...], not foo(...) def kw(**kwargs): """[syntax] Pass-named-args operator. Only meaningful in a tuple in a prefix block.""" raise RuntimeError("kw only meaningful inside a tuple in a prefix block")
def show_expanded(tree, expand_macros, **kw): expanded_tree = expand_macros(tree) new_tree = q( wrap_simple(log, u(unparse_ast(expanded_tree)), ast(expanded_tree))) return new_tree
def expand(tree, **kw): addition = 10 return q(lambda x: x * ast(tree) + u(addition))