Mercurial > genshi > mirror
annotate markup/eval.py @ 144:d1ce85a7f296 trunk
* Coalesce adjacent text events that the parsers would produce when text crossed the buffer boundaries. Fixes #26.
* Fix handling of character and entity references in the HTML parser
author | cmlenz |
---|---|
date | Fri, 11 Aug 2006 16:34:35 +0000 |
parents | 8ad716b4180d |
children | 47bbd9d2a5af |
rev | line source |
---|---|
1 | 1 # -*- coding: utf-8 -*- |
2 # | |
66
59eb24184e9c
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
59eb24184e9c
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
59eb24184e9c
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
1b874f032bde
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 |
1b874f032bde
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
2ad83f1d337c
* 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
d60486018004
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
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
67 __slots__ = ['source', 'code'] |
1 | 68 |
81
d60486018004
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 |
134
d681d2c3cd8d
* 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
|
75 self.code = _compile(self, filename, lineno) |
1 | 76 |
77 def __repr__(self): | |
78 return '<Expression "%s">' % self.source | |
79 | |
120 | 80 def evaluate(self, data, nocall=False): |
81
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
81 """Evaluate the expression against the given data dictionary. |
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
82 |
d60486018004
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
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
86 @return: the result of the evaluation |
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
87 """ |
118
c392d38694d9
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, |
c392d38694d9
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, |
c392d38694d9
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, |
c392d38694d9
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
c835e81c50af
When an expression evaluates to a callable, it is called implicitly.
cmlenz
parents:
88
diff
changeset
|
93 retval = retval() |
c835e81c50af
When an expression evaluates to a callable, it is called implicitly.
cmlenz
parents:
88
diff
changeset
|
94 return retval |
30
bcdbb7e5e4e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
95 |
87
1b874f032bde
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 |
134
d681d2c3cd8d
* 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
|
97 def _compile(expr, filename=None, lineno=-1): |
138 | 98 tree = ExpressionASTTransformer().visit(parse(expr.source, 'eval')) |
116 | 99 if isinstance(filename, unicode): |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
100 # unicode file names not allowed for code objects |
116 | 101 filename = filename.encode('utf-8', 'replace') |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
102 elif not filename: |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
103 filename = '<string>' |
132
dc42cb3c02dc
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
104 tree.filename = filename |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
105 if lineno <= 0: |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
106 lineno = 1 |
87
1b874f032bde
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
|
107 |
116 | 108 gen = ExpressionCodeGenerator(tree) |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
109 gen.optimized = True |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
110 code = gen.getCode() |
87
1b874f032bde
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
|
111 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
112 # We'd like to just set co_firstlineno, but it's readonly. So we need to |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
113 # clone the code object while adjusting the line number |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
114 return new.code(0, code.co_nlocals, code.co_stacksize, |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
115 code.co_flags | 0x0040, code.co_code, code.co_consts, |
134
d681d2c3cd8d
* 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
|
116 code.co_names, code.co_varnames, filename, repr(expr), |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
117 lineno, code.co_lnotab, (), ()) |
116 | 118 |
132
dc42cb3c02dc
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
119 def _lookup_name(data, name, locals_=None): |
dc42cb3c02dc
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
120 val = None |
dc42cb3c02dc
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
121 if locals_: |
dc42cb3c02dc
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
122 val = locals_.get(name) |
dc42cb3c02dc
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
123 if val is None: |
dc42cb3c02dc
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
124 val = data.get(name) |
116 | 125 if val is None: |
126 val = getattr(__builtin__, name, None) | |
127 return val | |
128 | |
118
c392d38694d9
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
|
129 def _lookup_attr(data, obj, key): |
116 | 130 if hasattr(obj, key): |
131 return getattr(obj, key) | |
132 try: | |
133 return obj[key] | |
134 except (KeyError, TypeError): | |
135 return None | |
136 | |
137 def _lookup_item(data, obj, key): | |
138 if len(key) == 1: | |
139 key = key[0] | |
140 try: | |
141 return obj[key] | |
142 except (KeyError, IndexError, TypeError), e: | |
143 if isinstance(key, basestring): | |
144 try: | |
145 return getattr(obj, key) | |
146 except (AttributeError, TypeError), e: | |
147 pass | |
87
1b874f032bde
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 |
138 | 149 |
87
1b874f032bde
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 class ASTTransformer(object): |
1b874f032bde
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 """General purpose base class for AST transformations. |
1b874f032bde
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 |
1b874f032bde
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 Every visitor method can be overridden to return an AST node that has been |
1b874f032bde
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 altered or replaced in some way. |
1b874f032bde
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 """ |
1b874f032bde
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 _visitors = {} |
1b874f032bde
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 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
158 def visit(self, node, *args, **kwargs): |
87
1b874f032bde
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 = self._visitors.get(node.__class__) |
1b874f032bde
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 if not v: |
1b874f032bde
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 = getattr(self, 'visit%s' % node.__class__.__name__) |
1b874f032bde
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 self._visitors[node.__class__] = v |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
163 return v(node, *args, **kwargs) |
87
1b874f032bde
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 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
165 def visitExpression(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
166 node.node = self.visit(node.node, *args, **kwargs) |
87
1b874f032bde
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 return node |
1b874f032bde
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 |
1b874f032bde
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 # Functions & Accessors |
1b874f032bde
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 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
171 def visitCallFunc(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
172 node.node = self.visit(node.node, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
173 node.args = map(lambda x: self.visit(x, *args, **kwargs), node.args) |
87
1b874f032bde
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
|
174 if node.star_args: |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
175 node.star_args = map(lambda x: self.visit(x, *args, **kwargs), |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
176 node.star_args) |
87
1b874f032bde
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
|
177 if node.dstar_args: |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
178 node.dstart_args = map(lambda x: self.visit(x, *args, **kwargs), |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
179 node.dstar_args) |
87
1b874f032bde
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
|
180 return node |
30
bcdbb7e5e4e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
181 |
118
c392d38694d9
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 def visitLambda(self, node, *args, **kwargs): |
c392d38694d9
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 node.code = self.visit(node.code, *args, **kwargs) |
c392d38694d9
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 node.filename = '<string>' # workaround for bug in pycodegen |
c392d38694d9
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 return node |
c392d38694d9
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 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
187 def visitGetattr(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
188 node.expr = self.visit(node.expr, *args, **kwargs) |
87
1b874f032bde
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
|
189 return node |
30
bcdbb7e5e4e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
190 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
191 def visitSubscript(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
192 node.expr = self.visit(node.expr, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
193 node.subs = map(lambda x: self.visit(x, *args, **kwargs), node.subs) |
87
1b874f032bde
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 return node |
30
bcdbb7e5e4e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
195 |
87
1b874f032bde
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 # Operators |
1b874f032bde
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
|
197 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
198 def _visitBoolOp(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
199 node.nodes = map(lambda x: self.visit(x, *args, **kwargs), node.nodes) |
87
1b874f032bde
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 return node |
1b874f032bde
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
|
201 visitAnd = visitOr = visitBitand = visitBitor = _visitBoolOp |
1b874f032bde
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 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
203 def _visitBinOp(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
204 node.left = self.visit(node.left, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
205 node.right = self.visit(node.right, *args, **kwargs) |
87
1b874f032bde
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 return node |
1b874f032bde
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 visitAdd = visitSub = _visitBinOp |
1b874f032bde
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 visitDiv = visitFloorDiv = visitMod = visitMul = visitPower = _visitBinOp |
1b874f032bde
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 visitLeftShift = visitRightShift = _visitBinOp |
1b874f032bde
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 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
211 def visitCompare(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
212 node.expr = self.visit(node.expr, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
213 node.ops = map(lambda (op, n): (op, self.visit(n, *args, **kwargs)), |
87
1b874f032bde
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 node.ops) |
1b874f032bde
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
|
215 return node |
1b874f032bde
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 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
217 def _visitUnaryOp(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
218 node.expr = self.visit(node.expr, *args, **kwargs) |
87
1b874f032bde
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
|
219 return node |
1b874f032bde
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 visitUnaryAdd = visitUnarySub = visitNot = visitInvert = _visitUnaryOp |
98
44af12832c5a
Bugfix in `builder` module: attribute values need to be converted to strings when generating streams.
cmlenz
parents:
90
diff
changeset
|
221 visitBackquote = _visitUnaryOp |
87
1b874f032bde
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
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
223 # Identifiers, Literals and Comprehensions |
87
1b874f032bde
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
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
225 def _visitDefault(self, node, *args, **kwargs): |
87
1b874f032bde
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 return node |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
227 visitAssName = visitAssTuple = _visitDefault |
102 | 228 visitConst = visitName = _visitDefault |
229 | |
230 def visitKeyword(self, node, *args, **kwargs): | |
231 node.expr = self.visit(node.expr, *args, **kwargs) | |
232 return node | |
87
1b874f032bde
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
|
233 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
234 def visitDict(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
235 node.items = map(lambda (k, v): (self.visit(k, *args, **kwargs), |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
236 self.visit(v, *args, **kwargs)), |
87
1b874f032bde
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 node.items) |
1b874f032bde
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
|
238 return node |
1b874f032bde
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 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
240 def visitTuple(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
241 node.nodes = map(lambda n: self.visit(n, *args, **kwargs), node.nodes) |
87
1b874f032bde
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
|
242 return node |
1b874f032bde
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
|
243 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
244 def visitList(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
245 node.nodes = map(lambda n: self.visit(n, *args, **kwargs), node.nodes) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
246 return node |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
247 |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
248 def visitListComp(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
249 node.expr = self.visit(node.expr, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
250 node.quals = map(lambda x: self.visit(x, *args, **kwargs), node.quals) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
251 return node |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
252 |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
253 def visitListCompFor(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
254 node.assign = self.visit(node.assign, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
255 node.list = self.visit(node.list, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
256 node.ifs = map(lambda x: self.visit(x, *args, **kwargs), node.ifs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
257 return node |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
258 |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
259 def visitListCompIf(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
260 node.test = self.visit(node.test, *args, **kwargs) |
87
1b874f032bde
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 return node |
1b874f032bde
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 |
1b874f032bde
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 |
1b874f032bde
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 class ExpressionASTTransformer(ASTTransformer): |
112 | 265 """Concrete AST transformer that implements the AST transformations needed |
266 for template expressions. | |
87
1b874f032bde
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
|
267 """ |
1b874f032bde
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
|
268 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
269 def visitGetattr(self, node, locals_=False): |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
270 return ast.CallFunc(ast.Name('_lookup_attr'), [ |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
271 ast.Name('data'), self.visit(node.expr, locals_=locals_), |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
272 ast.Const(node.attrname) |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
273 ]) |
30
bcdbb7e5e4e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
274 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
275 def visitLambda(self, node, locals_=False): |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
276 node.code = self.visit(node.code, locals_=True) |
118
c392d38694d9
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 node.filename = '<string>' # workaround for bug in pycodegen |
c392d38694d9
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
|
278 return node |
c392d38694d9
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 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
280 def visitListComp(self, node, locals_=False): |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
281 node.expr = self.visit(node.expr, locals_=True) |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
282 node.quals = map(lambda x: self.visit(x, locals_=True), node.quals) |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
283 return node |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
284 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
285 def visitName(self, node, locals_=False): |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
286 func_args = [ast.Name('data'), ast.Const(node.name)] |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
287 if locals_: |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
288 func_args.append(ast.CallFunc(ast.Name('locals'), [])) |
116 | 289 return ast.CallFunc(ast.Name('_lookup_name'), func_args) |
81
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
290 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
291 def visitSubscript(self, node, locals_=False): |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
292 return ast.CallFunc(ast.Name('_lookup_item'), [ |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
293 ast.Name('data'), self.visit(node.expr, locals_=locals_), |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
294 ast.Tuple(map(lambda x: self.visit(x, locals_=locals_), node.subs)) |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
295 ]) |