Added Mako report library
[odoo/odoo.git] / bin / mako / pyparser.py
1 # ast.py
2 # Copyright (C) Mako developers
3 #
4 # This module is part of Mako and is released under
5 # the MIT License: http://www.opensource.org/licenses/mit-license.php
6
7 """Handles parsing of Python code.
8
9 Parsing to AST is done via _ast on Python > 2.5, otherwise the compiler
10 module is used.
11 """
12
13 from StringIO import StringIO
14 from mako import exceptions, util
15
16 # words that cannot be assigned to (notably smaller than the total keys in __builtins__)
17 reserved = util.Set(['True', 'False', 'None'])
18
19 try:
20     import _ast
21     util.restore__ast(_ast)
22     import _ast_util
23 except ImportError:
24     _ast = None
25     from compiler import parse as compiler_parse
26     from compiler import visitor
27
28
29 def parse(code, mode='exec', **exception_kwargs):
30     """Parse an expression into AST"""
31     try:
32         if _ast:
33             return _ast_util.parse(code, '<unknown>', mode)
34         else:
35             return compiler_parse(code, mode)
36     except Exception, e:
37         raise exceptions.SyntaxException("(%s) %s (%s)" % (e.__class__.__name__, str(e), repr(code[0:50])), **exception_kwargs)
38
39
40 if _ast:
41     class FindIdentifiers(_ast_util.NodeVisitor):
42         def __init__(self, listener, **exception_kwargs):
43             self.in_function = False
44             self.in_assign_targets = False
45             self.local_ident_stack = {}
46             self.listener = listener
47             self.exception_kwargs = exception_kwargs
48         def _add_declared(self, name):
49             if not self.in_function:
50                 self.listener.declared_identifiers.add(name)
51         def visit_ClassDef(self, node):
52             self._add_declared(node.name)
53         def visit_Assign(self, node):
54             # flip around the visiting of Assign so the expression gets evaluated first, 
55             # in the case of a clause like "x=x+5" (x is undeclared)
56             self.visit(node.value)
57             in_a = self.in_assign_targets
58             self.in_assign_targets = True
59             for n in node.targets:
60                 self.visit(n)
61             self.in_assign_targets = in_a
62         def visit_FunctionDef(self, node):
63             self._add_declared(node.name)
64             # push function state onto stack.  dont log any
65             # more identifiers as "declared" until outside of the function,
66             # but keep logging identifiers as "undeclared".
67             # track argument names in each function header so they arent counted as "undeclared"
68             saved = {}
69             inf = self.in_function
70             self.in_function = True
71             for arg in node.args.args:
72                 if arg.id in self.local_ident_stack:
73                     saved[arg.id] = True
74                 else:
75                     self.local_ident_stack[arg.id] = True
76             for n in node.body:
77                 self.visit(n)
78             self.in_function = inf
79             for arg in node.args.args:
80                 if arg.id not in saved:
81                     del self.local_ident_stack[arg.id]
82         def visit_For(self, node):
83             # flip around visit
84             self.visit(node.iter)
85             self.visit(node.target)
86             for statement in node.body:
87                 self.visit(statement)
88             for statement in node.orelse:
89                 self.visit(statement)
90         def visit_Name(self, node):
91             if isinstance(node.ctx, _ast.Store):
92                 self._add_declared(node.id)
93             if node.id not in reserved and node.id not in self.listener.declared_identifiers and node.id not in self.local_ident_stack:
94                 self.listener.undeclared_identifiers.add(node.id)
95         def visit_Import(self, node):
96             for name in node.names:
97                 if name.asname is not None:
98                     self._add_declared(name.asname)
99                 else:
100                     self._add_declared(name.name.split('.')[0])
101         def visit_ImportFrom(self, node):
102             for name in node.names:
103                 if name.asname is not None:
104                     self._add_declared(name.asname)
105                 else:
106                     if name.name == '*':
107                         raise exceptions.CompileException("'import *' is not supported, since all identifier names must be explicitly declared.  Please use the form 'from <modulename> import <name1>, <name2>, ...' instead.", **self.exception_kwargs)
108                     self._add_declared(name.name)
109
110     class FindTuple(_ast_util.NodeVisitor):
111         def __init__(self, listener, code_factory, **exception_kwargs):
112             self.listener = listener
113             self.exception_kwargs = exception_kwargs
114             self.code_factory = code_factory
115         def visit_Tuple(self, node):
116             for n in node.elts:
117                 p = self.code_factory(n, **self.exception_kwargs)
118                 self.listener.codeargs.append(p)
119                 self.listener.args.append(ExpressionGenerator(n).value())
120                 self.listener.declared_identifiers = self.listener.declared_identifiers.union(p.declared_identifiers)
121                 self.listener.undeclared_identifiers = self.listener.undeclared_identifiers.union(p.undeclared_identifiers)
122
123     class ParseFunc(_ast_util.NodeVisitor):
124         def __init__(self, listener, **exception_kwargs):
125             self.listener = listener
126             self.exception_kwargs = exception_kwargs
127         def visit_FunctionDef(self, node):
128             self.listener.funcname = node.name
129             argnames = [arg.id for arg in node.args.args]
130             if node.args.vararg:
131                 argnames.append(node.args.vararg)
132             if node.args.kwarg:
133                 argnames.append(node.args.kwarg)
134             self.listener.argnames = argnames
135             self.listener.defaults = node.args.defaults # ast
136             self.listener.varargs = node.args.vararg
137             self.listener.kwargs = node.args.kwarg
138
139     class ExpressionGenerator(object):
140         def __init__(self, astnode):
141             self.generator = _ast_util.SourceGenerator(' ' * 4)
142             self.generator.visit(astnode)
143         def value(self):
144             return ''.join(self.generator.result)
145 else:
146     class FindIdentifiers(object):
147         def __init__(self, listener, **exception_kwargs):
148             self.in_function = False
149             self.local_ident_stack = {}
150             self.listener = listener
151             self.exception_kwargs = exception_kwargs
152         def _add_declared(self, name):
153             if not self.in_function:
154                 self.listener.declared_identifiers.add(name)
155         def visitClass(self, node, *args):
156             self._add_declared(node.name)
157         def visitAssName(self, node, *args):
158             self._add_declared(node.name)
159         def visitAssign(self, node, *args):
160             # flip around the visiting of Assign so the expression gets evaluated first, 
161             # in the case of a clause like "x=x+5" (x is undeclared)
162             self.visit(node.expr, *args)
163             for n in node.nodes:
164                 self.visit(n, *args)
165         def visitFunction(self,node, *args):
166             self._add_declared(node.name)
167             # push function state onto stack.  dont log any
168             # more identifiers as "declared" until outside of the function,
169             # but keep logging identifiers as "undeclared".
170             # track argument names in each function header so they arent counted as "undeclared"
171             saved = {}
172             inf = self.in_function
173             self.in_function = True
174             for arg in node.argnames:
175                 if arg in self.local_ident_stack:
176                     saved[arg] = True
177                 else:
178                     self.local_ident_stack[arg] = True
179             for n in node.getChildNodes():
180                 self.visit(n, *args)
181             self.in_function = inf
182             for arg in node.argnames:
183                 if arg not in saved:
184                     del self.local_ident_stack[arg]
185         def visitFor(self, node, *args):
186             # flip around visit
187             self.visit(node.list, *args)
188             self.visit(node.assign, *args)
189             self.visit(node.body, *args)
190         def visitName(self, node, *args):
191             if node.name not in reserved and node.name not in self.listener.declared_identifiers and node.name not in self.local_ident_stack:
192                 self.listener.undeclared_identifiers.add(node.name)
193         def visitImport(self, node, *args):
194             for (mod, alias) in node.names:
195                 if alias is not None:
196                     self._add_declared(alias)
197                 else:
198                     self._add_declared(mod.split('.')[0])
199         def visitFrom(self, node, *args):
200             for (mod, alias) in node.names:
201                 if alias is not None:
202                     self._add_declared(alias)
203                 else:
204                     if mod == '*':
205                         raise exceptions.CompileException("'import *' is not supported, since all identifier names must be explicitly declared.  Please use the form 'from <modulename> import <name1>, <name2>, ...' instead.", **self.exception_kwargs)
206                     self._add_declared(mod)
207         def visit(self, expr):
208             visitor.walk(expr, self) #, walker=walker())
209
210     class FindTuple(object):
211         def __init__(self, listener, code_factory, **exception_kwargs):
212             self.listener = listener
213             self.exception_kwargs = exception_kwargs
214             self.code_factory = code_factory
215         def visitTuple(self, node, *args):
216             for n in node.nodes:
217                 p = self.code_factory(n, **self.exception_kwargs)
218                 self.listener.codeargs.append(p)
219                 self.listener.args.append(ExpressionGenerator(n).value())
220                 self.listener.declared_identifiers = self.listener.declared_identifiers.union(p.declared_identifiers)
221                 self.listener.undeclared_identifiers = self.listener.undeclared_identifiers.union(p.undeclared_identifiers)
222         def visit(self, expr):
223             visitor.walk(expr, self) #, walker=walker())
224
225     class ParseFunc(object):
226         def __init__(self, listener, **exception_kwargs):
227             self.listener = listener
228             self.exception_kwargs = exception_kwargs
229         def visitFunction(self, node, *args):
230             self.listener.funcname = node.name
231             self.listener.argnames = node.argnames
232             self.listener.defaults = node.defaults
233             self.listener.varargs = node.varargs
234             self.listener.kwargs = node.kwargs
235         def visit(self, expr):
236             visitor.walk(expr, self)
237
238     class ExpressionGenerator(object):
239         """given an AST node, generates an equivalent literal Python expression."""
240         def __init__(self, astnode):
241             self.buf = StringIO()
242             visitor.walk(astnode, self) #, walker=walker())
243         def value(self):
244             return self.buf.getvalue()        
245         def operator(self, op, node, *args):
246             self.buf.write("(")
247             self.visit(node.left, *args)
248             self.buf.write(" %s " % op)
249             self.visit(node.right, *args)
250             self.buf.write(")")
251         def booleanop(self, op, node, *args):
252             self.visit(node.nodes[0])
253             for n in node.nodes[1:]:
254                 self.buf.write(" " + op + " ")
255                 self.visit(n, *args)
256         def visitConst(self, node, *args):
257             self.buf.write(repr(node.value))
258         def visitAssName(self, node, *args):
259             # TODO: figure out OP_ASSIGN, other OP_s
260             self.buf.write(node.name)
261         def visitName(self, node, *args):
262             self.buf.write(node.name)
263         def visitMul(self, node, *args):
264             self.operator("*", node, *args)
265         def visitAnd(self, node, *args):
266             self.booleanop("and", node, *args)
267         def visitOr(self, node, *args):
268             self.booleanop("or", node, *args)
269         def visitBitand(self, node, *args):
270             self.booleanop("&", node, *args)
271         def visitBitor(self, node, *args):
272             self.booleanop("|", node, *args)
273         def visitBitxor(self, node, *args):
274             self.booleanop("^", node, *args)
275         def visitAdd(self, node, *args):
276             self.operator("+", node, *args)
277         def visitGetattr(self, node, *args):
278             self.visit(node.expr, *args)
279             self.buf.write(".%s" % node.attrname)
280         def visitSub(self, node, *args):
281             self.operator("-", node, *args)
282         def visitNot(self, node, *args):
283             self.buf.write("not ")
284             self.visit(node.expr)
285         def visitDiv(self, node, *args):
286             self.operator("/", node, *args)
287         def visitFloorDiv(self, node, *args):
288             self.operator("//", node, *args)
289         def visitSubscript(self, node, *args):
290             self.visit(node.expr)
291             self.buf.write("[")
292             [self.visit(x) for x in node.subs]
293             self.buf.write("]")
294         def visitUnarySub(self, node, *args):
295             self.buf.write("-")
296             self.visit(node.expr)
297         def visitUnaryAdd(self, node, *args):
298             self.buf.write("-")
299             self.visit(node.expr)
300         def visitSlice(self, node, *args):
301             self.visit(node.expr)
302             self.buf.write("[")
303             if node.lower is not None:
304                 self.visit(node.lower)
305             self.buf.write(":")
306             if node.upper is not None:
307                 self.visit(node.upper)
308             self.buf.write("]")
309         def visitDict(self, node):
310             self.buf.write("{")
311             c = node.getChildren()
312             for i in range(0, len(c), 2):
313                 self.visit(c[i])
314                 self.buf.write(": ")
315                 self.visit(c[i+1])
316                 if i<len(c) -2:
317                     self.buf.write(", ")
318             self.buf.write("}")
319         def visitTuple(self, node):
320             self.buf.write("(")
321             c = node.getChildren()
322             for i in range(0, len(c)):
323                 self.visit(c[i])
324                 if i<len(c) - 1:
325                     self.buf.write(", ")
326             self.buf.write(")")
327         def visitList(self, node):
328             self.buf.write("[")
329             c = node.getChildren()
330             for i in range(0, len(c)):
331                 self.visit(c[i])
332                 if i<len(c) - 1:
333                     self.buf.write(", ")
334             self.buf.write("]")
335         def visitListComp(self, node):
336             self.buf.write("[")
337             self.visit(node.expr)
338             self.buf.write(" ")
339             for n in node.quals:
340                 self.visit(n)
341             self.buf.write("]")
342         def visitListCompFor(self, node):
343             self.buf.write(" for ")
344             self.visit(node.assign)
345             self.buf.write(" in ")
346             self.visit(node.list)
347             for n in node.ifs:
348                 self.visit(n)
349         def visitListCompIf(self, node):
350             self.buf.write(" if ")
351             self.visit(node.test)
352         def visitCompare(self, node):
353             self.visit(node.expr)
354             for tup in node.ops:
355                 self.buf.write(tup[0])
356                 self.visit(tup[1])
357         def visitCallFunc(self, node, *args):
358             self.visit(node.node)
359             self.buf.write("(")
360             if len(node.args):
361                 self.visit(node.args[0])
362                 for a in node.args[1:]:
363                     self.buf.write(", ")
364                     self.visit(a)
365             self.buf.write(")")
366
367     class walker(visitor.ASTVisitor):
368         def dispatch(self, node, *args):
369             print "Node:", str(node)
370             #print "dir:", dir(node)
371             return visitor.ASTVisitor.dispatch(self, node, *args)