Mercurial > genshi > genshi-test
annotate markup/eval.py @ 133:b9a0031d4bbb
Minor cleanup and performance improvement for the builder module.
author | cmlenz |
---|---|
date | Sun, 06 Aug 2006 17:10:47 +0000 |
parents | 0288dedce3d2 |
children | df44110ca91d |
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 from markup.core import Stream | |
22 | |
23 __all__ = ['Expression'] | |
24 | |
25 | |
26 class Expression(object): | |
27 """Evaluates Python expressions used in templates. | |
28 | |
29 >>> data = dict(test='Foo', items=[1, 2, 3], dict={'some': 'thing'}) | |
30 >>> Expression('test').evaluate(data) | |
31 'Foo' | |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
32 |
1 | 33 >>> Expression('items[0]').evaluate(data) |
34 1 | |
35 >>> Expression('items[-1]').evaluate(data) | |
36 3 | |
37 >>> Expression('dict["some"]').evaluate(data) | |
38 'thing' | |
39 | |
40 Similar to e.g. Javascript, expressions in templates can use the dot | |
41 notation for attribute access to access items in mappings: | |
42 | |
43 >>> Expression('dict.some').evaluate(data) | |
44 'thing' | |
86 | 45 |
1 | 46 This also works the other way around: item access can be used to access |
47 any object attribute (meaning there's no use for `getattr()` in templates): | |
48 | |
49 >>> class MyClass(object): | |
50 ... myattr = 'Bar' | |
51 >>> data = dict(mine=MyClass(), key='myattr') | |
52 >>> Expression('mine.myattr').evaluate(data) | |
53 'Bar' | |
54 >>> Expression('mine["myattr"]').evaluate(data) | |
55 'Bar' | |
56 >>> Expression('mine[key]').evaluate(data) | |
57 'Bar' | |
58 | |
31 | 59 All of the standard Python operators are available to template expressions. |
1 | 60 Built-in functions such as `len()` are also available in template |
61 expressions: | |
62 | |
63 >>> data = dict(items=[1, 2, 3]) | |
64 >>> Expression('len(items)').evaluate(data) | |
65 3 | |
66 """ | |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
67 __slots__ = ['source', 'code'] |
1 | 68 |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
69 def __init__(self, source, filename=None, lineno=-1): |
27 | 70 """Create the expression. |
71 | |
72 @param source: the expression as string | |
73 """ | |
1 | 74 self.source = source |
116 | 75 self.code = _compile(source, filename, lineno) |
1 | 76 |
77 def __repr__(self): | |
78 return '<Expression "%s">' % self.source | |
79 | |
120 | 80 def evaluate(self, data, nocall=False): |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
81 """Evaluate the expression against the given data dictionary. |
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
82 |
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
83 @param data: a mapping containing the data to evaluate against |
120 | 84 @param nocall: if true, the result of the evaluation is not called if |
85 if it is a callable | |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
86 @return: the result of the evaluation |
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
87 """ |
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
|
88 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
|
89 '_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
|
90 '_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
|
91 '_lookup_item': _lookup_item}) |
120 | 92 if not nocall and callable(retval): |
90
242610137d1f
When an expression evaluates to a callable, it is called implicitly.
cmlenz
parents:
88
diff
changeset
|
93 retval = retval() |
242610137d1f
When an expression evaluates to a callable, it is called implicitly.
cmlenz
parents:
88
diff
changeset
|
94 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
|
95 |
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
|
96 |
116 | 97 def _compile(source, filename=None, lineno=-1): |
98 tree = parse(source, 'eval') | |
99 xform = ExpressionASTTransformer() | |
100 tree = xform.visit(tree) | |
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
|
101 |
116 | 102 if isinstance(filename, unicode): |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
103 # unicode file names not allowed for code objects |
116 | 104 filename = filename.encode('utf-8', 'replace') |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
105 elif not filename: |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
106 filename = '<string>' |
132
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
107 tree.filename = filename |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
108 if lineno <= 0: |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
109 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
|
110 |
116 | 111 gen = ExpressionCodeGenerator(tree) |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
112 gen.optimized = True |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
113 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
|
114 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
115 # 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
|
116 # 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
|
117 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
|
118 code.co_flags | 0x0040, code.co_code, code.co_consts, |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
119 code.co_names, code.co_varnames, filename, code.co_name, |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
120 lineno, code.co_lnotab, (), ()) |
116 | 121 |
132
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
122 def _lookup_name(data, name, locals_=None): |
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
123 val = None |
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
124 if locals_: |
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
125 val = locals_.get(name) |
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
126 if val is None: |
0288dedce3d2
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
127 val = data.get(name) |
116 | 128 if val is None: |
129 val = getattr(__builtin__, name, None) | |
130 return val | |
131 | |
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
|
132 def _lookup_attr(data, obj, key): |
116 | 133 if hasattr(obj, key): |
134 return getattr(obj, key) | |
135 try: | |
136 return obj[key] | |
137 except (KeyError, TypeError): | |
138 return None | |
139 | |
140 def _lookup_item(data, obj, key): | |
141 if len(key) == 1: | |
142 key = key[0] | |
143 try: | |
144 return obj[key] | |
145 except (KeyError, IndexError, TypeError), e: | |
146 if isinstance(key, basestring): | |
147 try: | |
148 return getattr(obj, key) | |
149 except (AttributeError, TypeError), e: | |
150 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
|
151 |
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 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
|
153 """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
|
154 |
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 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
|
156 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
|
157 """ |
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 _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
|
159 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
160 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
|
161 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
|
162 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
|
163 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
|
164 self._visitors[node.__class__] = v |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
165 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
|
166 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
167 def visitExpression(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
168 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
|
169 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
|
170 |
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
|
171 # 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
|
172 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
173 def visitCallFunc(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
174 node.node = self.visit(node.node, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
175 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
|
176 if node.star_args: |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
177 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
|
178 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
|
179 if node.dstar_args: |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
180 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
|
181 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
|
182 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
|
183 |
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
|
184 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
|
185 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
|
186 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
|
187 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
|
188 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
189 def visitGetattr(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) |
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
|
191 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
|
192 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
193 def visitSubscript(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
194 node.expr = self.visit(node.expr, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
195 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
|
196 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
|
197 |
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 # 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
|
199 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
200 def _visitBoolOp(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
201 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
|
202 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
|
203 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
|
204 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
205 def _visitBinOp(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
206 node.left = self.visit(node.left, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
207 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
|
208 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
|
209 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
|
210 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
|
211 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
|
212 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
213 def visitCompare(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
214 node.expr = self.visit(node.expr, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
215 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
|
216 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
|
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 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
219 def _visitUnaryOp(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
220 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
|
221 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
|
222 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
|
223 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
|
224 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
225 # 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
|
226 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
227 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
|
228 return node |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
229 visitAssName = visitAssTuple = _visitDefault |
102 | 230 visitConst = visitName = _visitDefault |
231 | |
232 def visitKeyword(self, node, *args, **kwargs): | |
233 node.expr = self.visit(node.expr, *args, **kwargs) | |
234 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
|
235 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
236 def visitDict(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
237 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
|
238 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
|
239 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
|
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 visitTuple(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) |
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
|
244 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
|
245 |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
246 def visitList(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
247 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
|
248 return node |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
249 |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
250 def visitListComp(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
251 node.expr = self.visit(node.expr, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
252 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
|
253 return node |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
254 |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
255 def visitListCompFor(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
256 node.assign = self.visit(node.assign, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
257 node.list = self.visit(node.list, *args, **kwargs) |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
258 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
|
259 return node |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
260 |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
261 def visitListCompIf(self, node, *args, **kwargs): |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
262 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
|
263 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
|
264 |
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 class ExpressionASTTransformer(ASTTransformer): |
112 | 267 """Concrete AST transformer that implements the AST transformations needed |
268 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
|
269 """ |
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
|
270 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
271 def visitGetattr(self, node, locals_=False): |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
272 return ast.CallFunc(ast.Name('_lookup_attr'), [ |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
273 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
|
274 ast.Const(node.attrname) |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
275 ]) |
30
2ee9f28e16e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
276 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
277 def visitLambda(self, node, locals_=False): |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
278 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
|
279 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
|
280 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
|
281 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
282 def visitListComp(self, node, locals_=False): |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
283 node.expr = self.visit(node.expr, locals_=True) |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
284 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
|
285 return node |
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
286 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
287 def visitName(self, node, locals_=False): |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
288 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
|
289 if locals_: |
88
9ecae580dd93
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
290 func_args.append(ast.CallFunc(ast.Name('locals'), [])) |
116 | 291 return ast.CallFunc(ast.Name('_lookup_name'), func_args) |
81
cc034182061e
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
292 |
131
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
293 def visitSubscript(self, node, locals_=False): |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
294 return ast.CallFunc(ast.Name('_lookup_item'), [ |
203f459e7e26
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
295 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
|
296 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
|
297 ]) |