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