diff --git a/CHANGES b/CHANGES index f79576f94b7deb9cfaf26846e2cdaddf1fff20a4..5936f1bc1e962bec507481b1da5f109633705366 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 129a726704a05eaabb1b8b773cbd21f5ca545819..bea587d2d00c89fb13d9add07e32b55a6e9c1a70 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 0d6378b85a5c76e888cee40b9956f02016d9da5a..31680a2b4851103ea6ae964ec525e2b39477bb72 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()