From f4d281e7dbff45858068c36568e44aaab980e3f3 Mon Sep 17 00:00:00 2001 From: Mike Bayer <mike_mp@zzzcomputing.com> Date: Wed, 14 Mar 2007 00:13:25 +0000 Subject: [PATCH] - AST expression generation - added in just about everything expression-wise from the AST module [ticket:26] --- CHANGES | 4 ++++ lib/mako/ast.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ test/ast.py | 5 +++-- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index f79576f..5936f1b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +0.1.5 +- AST expression generation - added in just about everything + expression-wise from the AST module [ticket:26] + 0.1.4 - got defs-within-defs to be cacheable - fixes to code parsing/whitespace adjusting where plain python comments diff --git a/lib/mako/ast.py b/lib/mako/ast.py index 129a726..bea587d 100644 --- a/lib/mako/ast.py +++ b/lib/mako/ast.py @@ -222,12 +222,30 @@ class ExpressionGenerator(object): self.buf.write(" %s " % op) self.visit(node.right, *args) self.buf.write(")") + def booleanop(self, op, node, *args): + self.visit(node.nodes[0]) + for n in node.nodes[1:]: + self.buf.write(" " + op + " ") + self.visit(n, *args) def visitConst(self, node, *args): self.buf.write(repr(node.value)) + def visitAssName(self, node, *args): + # TODO: figure out OP_ASSIGN, other OP_s + self.buf.write(node.name) def visitName(self, node, *args): self.buf.write(node.name) def visitMul(self, node, *args): self.operator("*", node, *args) + def visitAnd(self, node, *args): + self.booleanop("and", node, *args) + def visitOr(self, node, *args): + self.booleanop("or", node, *args) + def visitBitand(self, node, *args): + self.booleanop("&", node, *args) + def visitBitor(self, node, *args): + self.booleanop("|", node, *args) + def visitBitxor(self, node, *args): + self.booleanop("^", node, *args) def visitAdd(self, node, *args): self.operator("+", node, *args) def visitGetattr(self, node, *args): @@ -235,13 +253,24 @@ class ExpressionGenerator(object): self.buf.write(".%s" % node.attrname) def visitSub(self, node, *args): self.operator("-", node, *args) + def visitNot(self, node, *args): + self.buf.write("not ") + self.visit(node.expr) def visitDiv(self, node, *args): self.operator("/", node, *args) + def visitFloorDiv(self, node, *args): + self.operator("//", node, *args) def visitSubscript(self, node, *args): self.visit(node.expr) self.buf.write("[") [self.visit(x) for x in node.subs] self.buf.write("]") + def visitUnarySub(self, node, *args): + self.buf.write("-") + self.visit(node.expr) + def visitUnaryAdd(self, node, *args): + self.buf.write("-") + self.visit(node.expr) def visitSlice(self, node, *args): self.visit(node.expr) self.buf.write("[") @@ -261,6 +290,14 @@ class ExpressionGenerator(object): if i<len(c) -2: self.buf.write(", ") self.buf.write("}") + def visitTuple(self, node): + self.buf.write("(") + c = node.getChildren() + for i in range(0, len(c)): + self.visit(c[i]) + if i<len(c) - 1: + self.buf.write(", ") + self.buf.write(")") def visitList(self, node): self.buf.write("[") c = node.getChildren() @@ -269,6 +306,28 @@ class ExpressionGenerator(object): if i<len(c) - 1: self.buf.write(", ") self.buf.write("]") + def visitListComp(self, node): + self.buf.write("[") + self.visit(node.expr) + self.buf.write(" ") + for n in node.quals: + self.visit(n) + self.buf.write("]") + def visitListCompFor(self, node): + self.buf.write(" for ") + self.visit(node.assign) + self.buf.write(" in ") + self.visit(node.list) + for n in node.ifs: + self.visit(n) + def visitListCompIf(self, node): + self.buf.write(" if ") + self.visit(node.test) + def visitCompare(self, node): + self.visit(node.expr) + for tup in node.ops: + self.buf.write(tup[0]) + self.visit(tup[1]) def visitCallFunc(self, node, *args): self.visit(node.node) self.buf.write("(") diff --git a/test/ast.py b/test/ast.py index 0d6378b..31680a2 100644 --- a/test/ast.py +++ b/test/ast.py @@ -185,11 +185,12 @@ import x as bar newcode = ast.ExpressionGenerator(astnode).value() assert(eval(code, local_dict)) == eval(newcode, local_dict) - for code in ["repr({'x':7,'y':18})", "repr([])", "repr({})", "repr([{3:[]}])", "repr({'x':37*2 + len([6,7,8])})", "repr([1, 2, {}, {'x':'7'}])"]: + for code in ["repr({'x':7,'y':18})", "repr([])", "repr({})", "repr([{3:[]}])", "repr({'x':37*2 + len([6,7,8])})", "repr([1, 2, {}, {'x':'7'}])", "repr({'x':-1})", "repr(((1,2,3), (4,5,6)))", "repr(1 and 2 and 3 and 4)", "repr(True and False or 55)", "repr(1 & 2 | 3)", "repr(3//5)", "repr(3^5)", "repr([q.endswith('e') for q in ['one', 'two', 'three']])", "repr([x for x in (5,6,7) if x == 6])", "repr(not False)"]: local_dict={} astnode = parse(code) newcode = ast.ExpressionGenerator(astnode).value() - assert(eval(code, local_dict)) == eval(newcode, local_dict) + print code, newcode + assert(eval(code, local_dict)) == eval(newcode, local_dict), "%s != %s" % (code, newcode) if __name__ == '__main__': unittest.main() -- GitLab