Mercurial > genshi > genshi-test
annotate markup/eval.py @ 151:77779d507d40
The convention for an unknown position is `(None, -1, -1)`.
author | cmlenz |
---|---|
date | Tue, 15 Aug 2006 22:03:39 +0000 |
parents | 56d534eb53f9 |
children | 4ed68a904235 |
rev | line source |
---|---|
1 | 1 # -*- coding: utf-8 -*- |
2 # | |
66
822089ae65ce
Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents:
42
diff
changeset
|
3 # Copyright (C) 2006 Edgewall Software |
1 | 4 # All rights reserved. |
5 # | |
6 # This software is licensed as described in the file COPYING, which | |
7 # you should have received as part of this distribution. The terms | |
66
822089ae65ce
Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents:
42
diff
changeset
|
8 # are also available at http://markup.edgewall.org/wiki/License. |
1 | 9 # |
10 # This software consists of voluntary contributions made by many | |
11 # individuals. For the exact contribution history, see the revision | |
66
822089ae65ce
Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents:
42
diff
changeset
|
12 # history and logs, available at http://markup.edgewall.org/log/. |
27 | 13 |
14 """Support for "safe" evaluation of Python expressions.""" | |
1 | 15 |
16 import __builtin__ | |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
17 from compiler import ast, parse |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
18 from compiler.pycodegen import ExpressionCodeGenerator |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
19 import new |
1 | 20 |
21 __all__ = ['Expression'] | |
22 | |
23 | |
24 class Expression(object): | |
25 """Evaluates Python expressions used in templates. | |
26 | |
27 >>> data = dict(test='Foo', items=[1, 2, 3], dict={'some': 'thing'}) | |
28 >>> Expression('test').evaluate(data) | |
29 'Foo' | |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
30 |
1 | 31 >>> Expression('items[0]').evaluate(data) |
32 1 | |
33 >>> Expression('items[-1]').evaluate(data) | |
34 3 | |
35 >>> Expression('dict["some"]').evaluate(data) | |
36 'thing' | |
37 | |
38 Similar to e.g. Javascript, expressions in templates can use the dot | |
39 notation for attribute access to access items in mappings: | |
40 | |
41 >>> Expression('dict.some').evaluate(data) | |
42 'thing' | |
86 | 43 |
1 | 44 This also works the other way around: item access can be used to access |
45 any object attribute (meaning there's no use for `getattr()` in templates): | |
46 | |
47 >>> class MyClass(object): | |
48 ... myattr = 'Bar' | |
49 >>> data = dict(mine=MyClass(), key='myattr') | |
50 >>> Expression('mine.myattr').evaluate(data) | |
51 'Bar' | |
52 >>> Expression('mine["myattr"]').evaluate(data) | |
53 'Bar' | |
54 >>> Expression('mine[key]').evaluate(data) | |
55 'Bar' | |
56 | |
31 | 57 All of the standard Python operators are available to template expressions. |
1 | 58 Built-in functions such as `len()` are also available in template |
59 expressions: | |
60 | |
61 >>> data = dict(items=[1, 2, 3]) | |
62 >>> Expression('len(items)').evaluate(data) | |
63 3 | |
64 """ | |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
65 __slots__ = ['source', 'code'] |
1 | 66 |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
67 def __init__(self, source, filename=None, lineno=-1): |
27 | 68 """Create the expression. |
69 | |
70 @param source: the expression as string | |
71 """ | |
1 | 72 self.source = source |
134
df44110ca91d
* Improve the accuracy of line numbers for text nodes, so that reported errors about syntax or evaluation errors in expressions point to the right line (not quite perfect yet, though).
cmlenz
parents:
133
diff
changeset
|
73 self.code = _compile(self, filename, lineno) |
1 | 74 |
75 def __repr__(self): | |
76 return '<Expression "%s">' % self.source | |
77 | |
120 | 78 def evaluate(self, data, nocall=False): |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
79 """Evaluate the expression against the given data dictionary. |
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
80 |
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
81 @param data: a mapping containing the data to evaluate against |
120 | 82 @param nocall: if true, the result of the evaluation is not called if |
83 if it is a callable | |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
84 @return: the result of the evaluation |
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
85 """ |
118
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
86 retval = eval(self.code, {'data': data, |
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
87 '_lookup_name': _lookup_name, |
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
88 '_lookup_attr': _lookup_attr, |
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
89 '_lookup_item': _lookup_item}) |
120 | 90 if not nocall and callable(retval): |
90
242610137d1f
When an expression evaluates to a callable, it is called implicitly.
cmlenz
parents:
88
diff
changeset
|
91 retval = retval() |
242610137d1f
When an expression evaluates to a callable, it is called implicitly.
cmlenz
parents:
88
diff
changeset
|
92 return retval |
30
2ee9f28e16e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
93 |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
94 |
134
df44110ca91d
* Improve the accuracy of line numbers for text nodes, so that reported errors about syntax or evaluation errors in expressions point to the right line (not quite perfect yet, though).
cmlenz
parents:
133
diff
changeset
|
95 def _compile(expr, filename=None, lineno=-1): |
138 | 96 tree = ExpressionASTTransformer().visit(parse(expr.source, 'eval')) |
116 | 97 if isinstance(filename, unicode): |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
98 # unicode file names not allowed for code objects |
116 | 99 filename = filename.encode('utf-8', 'replace') |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
100 elif not filename: |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
101 filename = '<string>' |
132
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
102 tree.filename = filename |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
103 if lineno <= 0: |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
104 lineno = 1 |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
105 |
116 | 106 gen = ExpressionCodeGenerator(tree) |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
107 gen.optimized = True |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
108 code = gen.getCode() |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
109 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
110 # We'd like to just set co_firstlineno, but it's readonly. So we need to |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
111 # clone the code object while adjusting the line number |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
112 return new.code(0, code.co_nlocals, code.co_stacksize, |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
113 code.co_flags | 0x0040, code.co_code, code.co_consts, |
134
df44110ca91d
* Improve the accuracy of line numbers for text nodes, so that reported errors about syntax or evaluation errors in expressions point to the right line (not quite perfect yet, though).
cmlenz
parents:
133
diff
changeset
|
114 code.co_names, code.co_varnames, filename, repr(expr), |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
115 lineno, code.co_lnotab, (), ()) |
116 | 116 |
132
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
117 def _lookup_name(data, name, locals_=None): |
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
118 val = None |
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
119 if locals_: |
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
120 val = locals_.get(name) |
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
121 if val is None: |
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
122 val = data.get(name) |
116 | 123 if val is None: |
124 val = getattr(__builtin__, name, None) | |
125 return val | |
126 | |
118
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
127 def _lookup_attr(data, obj, key): |
116 | 128 if hasattr(obj, key): |
129 return getattr(obj, key) | |
130 try: | |
131 return obj[key] | |
132 except (KeyError, TypeError): | |
133 return None | |
134 | |
135 def _lookup_item(data, obj, key): | |
136 if len(key) == 1: | |
137 key = key[0] | |
138 try: | |
139 return obj[key] | |
140 except (KeyError, IndexError, TypeError), e: | |
141 if isinstance(key, basestring): | |
142 try: | |
143 return getattr(obj, key) | |
144 except (AttributeError, TypeError), e: | |
145 pass | |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
146 |
138 | 147 |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
148 class ASTTransformer(object): |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
149 """General purpose base class for AST transformations. |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
150 |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
151 Every visitor method can be overridden to return an AST node that has been |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
152 altered or replaced in some way. |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
153 """ |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
154 _visitors = {} |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
155 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
156 def visit(self, node, *args, **kwargs): |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
157 v = self._visitors.get(node.__class__) |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
158 if not v: |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
159 v = getattr(self, 'visit%s' % node.__class__.__name__) |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
160 self._visitors[node.__class__] = v |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
161 return v(node, *args, **kwargs) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
162 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
163 def visitExpression(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
164 node.node = self.visit(node.node, *args, **kwargs) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
165 return node |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
166 |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
167 # Functions & Accessors |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
168 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
169 def visitCallFunc(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
170 node.node = self.visit(node.node, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
171 node.args = map(lambda x: self.visit(x, *args, **kwargs), node.args) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
172 if node.star_args: |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
173 node.star_args = map(lambda x: self.visit(x, *args, **kwargs), |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
174 node.star_args) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
175 if node.dstar_args: |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
176 node.dstart_args = map(lambda x: self.visit(x, *args, **kwargs), |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
177 node.dstar_args) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
178 return node |
30
2ee9f28e16e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
179 |
118
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
180 def visitLambda(self, node, *args, **kwargs): |
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
181 node.code = self.visit(node.code, *args, **kwargs) |
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
182 node.filename = '<string>' # workaround for bug in pycodegen |
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
183 return node |
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
184 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
185 def visitGetattr(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
186 node.expr = self.visit(node.expr, *args, **kwargs) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
187 return node |
30
2ee9f28e16e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
188 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
189 def visitSubscript(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
190 node.expr = self.visit(node.expr, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
191 node.subs = map(lambda x: self.visit(x, *args, **kwargs), node.subs) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
192 return node |
30
2ee9f28e16e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
193 |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
194 # Operators |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
195 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
196 def _visitBoolOp(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
197 node.nodes = map(lambda x: self.visit(x, *args, **kwargs), node.nodes) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
198 return node |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
199 visitAnd = visitOr = visitBitand = visitBitor = _visitBoolOp |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
200 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
201 def _visitBinOp(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
202 node.left = self.visit(node.left, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
203 node.right = self.visit(node.right, *args, **kwargs) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
204 return node |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
205 visitAdd = visitSub = _visitBinOp |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
206 visitDiv = visitFloorDiv = visitMod = visitMul = visitPower = _visitBinOp |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
207 visitLeftShift = visitRightShift = _visitBinOp |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
208 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
209 def visitCompare(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
210 node.expr = self.visit(node.expr, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
211 node.ops = map(lambda (op, n): (op, self.visit(n, *args, **kwargs)), |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
212 node.ops) |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
213 return node |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
214 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
215 def _visitUnaryOp(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
216 node.expr = self.visit(node.expr, *args, **kwargs) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
217 return node |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
218 visitUnaryAdd = visitUnarySub = visitNot = visitInvert = _visitUnaryOp |
98
bc73d3ab823f
Bugfix in `builder` module: attribute values need to be converted to strings when generating streams.
cmlenz
parents:
90
diff
changeset
|
219 visitBackquote = _visitUnaryOp |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
220 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
221 # Identifiers, Literals and Comprehensions |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
222 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
223 def _visitDefault(self, node, *args, **kwargs): |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
224 return node |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
225 visitAssName = visitAssTuple = _visitDefault |
102 | 226 visitConst = visitName = _visitDefault |
227 | |
228 def visitKeyword(self, node, *args, **kwargs): | |
229 node.expr = self.visit(node.expr, *args, **kwargs) | |
230 return node | |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
231 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
232 def visitDict(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
233 node.items = map(lambda (k, v): (self.visit(k, *args, **kwargs), |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
234 self.visit(v, *args, **kwargs)), |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
235 node.items) |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
236 return node |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
237 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
238 def visitTuple(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
239 node.nodes = map(lambda n: self.visit(n, *args, **kwargs), node.nodes) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
240 return node |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
241 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
242 def visitList(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
243 node.nodes = map(lambda n: self.visit(n, *args, **kwargs), node.nodes) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
244 return node |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
245 |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
246 def visitListComp(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
247 node.expr = self.visit(node.expr, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
248 node.quals = map(lambda x: self.visit(x, *args, **kwargs), node.quals) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
249 return node |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
250 |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
251 def visitListCompFor(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
252 node.assign = self.visit(node.assign, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
253 node.list = self.visit(node.list, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
254 node.ifs = map(lambda x: self.visit(x, *args, **kwargs), node.ifs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
255 return node |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
256 |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
257 def visitListCompIf(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
258 node.test = self.visit(node.test, *args, **kwargs) |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
259 return node |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
260 |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
261 |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
262 class ExpressionASTTransformer(ASTTransformer): |
112 | 263 """Concrete AST transformer that implements the AST transformations needed |
264 for template expressions. | |
87
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
265 """ |
c6f07b7cd3ea
Fix some problems in expression evaluation by transforming the AST and compiling that to bytecode, instead of generating bytecode directly. Invalidates #13.
cmlenz
parents:
86
diff
changeset
|
266 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
267 def visitGetattr(self, node, locals_=False): |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
268 return ast.CallFunc(ast.Name('_lookup_attr'), [ |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
269 ast.Name('data'), self.visit(node.expr, locals_=locals_), |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
270 ast.Const(node.attrname) |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
271 ]) |
30
2ee9f28e16e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
272 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
273 def visitLambda(self, node, locals_=False): |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
274 node.code = self.visit(node.code, locals_=True) |
118
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
275 node.filename = '<string>' # workaround for bug in pycodegen |
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
276 return node |
226613431921
Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
cmlenz
parents:
116
diff
changeset
|
277 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
278 def visitListComp(self, node, locals_=False): |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
279 node.expr = self.visit(node.expr, locals_=True) |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
280 node.quals = map(lambda x: self.visit(x, locals_=True), node.quals) |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
281 return node |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
282 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
283 def visitName(self, node, locals_=False): |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
284 func_args = [ast.Name('data'), ast.Const(node.name)] |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
285 if locals_: |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
286 func_args.append(ast.CallFunc(ast.Name('locals'), [])) |
116 | 287 return ast.CallFunc(ast.Name('_lookup_name'), func_args) |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
288 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
289 def visitSubscript(self, node, locals_=False): |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
290 return ast.CallFunc(ast.Name('_lookup_item'), [ |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
291 ast.Name('data'), self.visit(node.expr, locals_=locals_), |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
292 ast.Tuple(map(lambda x: self.visit(x, locals_=locals_), node.subs)) |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
293 ]) |