Mercurial > genshi > mirror
annotate markup/eval.py @ 193:404c02f3156b trunk
Fix for Python 2.3 compatibility in `py:with` directive (regression in [240]).
author | cmlenz |
---|---|
date | Thu, 24 Aug 2006 19:03:24 +0000 |
parents | b64e36bc1100 |
children | c0535b218466 |
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 |
192
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
21 __all__ = ['Expression', 'Undefined'] |
1 | 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
d60486018004
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
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
65 __slots__ = ['source', 'code'] |
1 | 66 |
81
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
67 def __init__(self, source, filename=None, lineno=-1): |
165
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
68 if isinstance(source, basestring): |
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
69 self.source = source |
167
1999291f7a30
Handle non-ASCII characters in expressions. Closes #29. Thanks to Arnar Birgisson for reporting the problem and comping up with a patch!
cmlenz
parents:
165
diff
changeset
|
70 if isinstance(source, unicode): |
1999291f7a30
Handle non-ASCII characters in expressions. Closes #29. Thanks to Arnar Birgisson for reporting the problem and comping up with a patch!
cmlenz
parents:
165
diff
changeset
|
71 source = '\xef\xbb\xbf' + source.encode('utf-8') |
1999291f7a30
Handle non-ASCII characters in expressions. Closes #29. Thanks to Arnar Birgisson for reporting the problem and comping up with a patch!
cmlenz
parents:
165
diff
changeset
|
72 self.code = _compile(parse(source, 'eval'), self.source, |
165
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
73 filename=filename, lineno=lineno) |
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
74 else: |
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
75 assert isinstance(source, ast.Node) |
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
76 self.source = '?' |
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
77 self.code = _compile(ast.Expression(source), filename=filename, |
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
78 lineno=lineno) |
1 | 79 |
80 def __repr__(self): | |
81 return '<Expression "%s">' % self.source | |
82 | |
120 | 83 def evaluate(self, data, nocall=False): |
81
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
84 """Evaluate the expression against the given data dictionary. |
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
85 |
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
86 @param data: a mapping containing the data to evaluate against |
120 | 87 @param nocall: if true, the result of the evaluation is not called if |
88 if it is a callable | |
81
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
89 @return: the result of the evaluation |
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
90 """ |
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
|
91 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
|
92 '_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
|
93 '_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
|
94 '_lookup_item': _lookup_item}) |
120 | 95 if not nocall and callable(retval): |
90
c835e81c50af
When an expression evaluates to a callable, it is called implicitly.
cmlenz
parents:
88
diff
changeset
|
96 retval = retval() |
c835e81c50af
When an expression evaluates to a callable, it is called implicitly.
cmlenz
parents:
88
diff
changeset
|
97 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
|
98 |
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
|
99 |
192
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
100 class Undefined(object): |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
101 """Represents a reference to an undefined variable. |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
102 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
103 Unlike the Python runtime, template expressions can refer to an undefined |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
104 variable without causing a `NameError` to be raised. The result will be an |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
105 instance of the `Undefined´ class, which is treated the same as `False` in |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
106 conditions, and acts as an empty collection in iterations: |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
107 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
108 >>> foo = Undefined('foo') |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
109 >>> bool(foo) |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
110 False |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
111 >>> list(foo) |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
112 [] |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
113 >>> print foo |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
114 undefined |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
115 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
116 However, calling an undefined variable, or trying to access an attribute |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
117 of that variable, will raise an exception that includes the name used to |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
118 reference that undefined variable. |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
119 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
120 >>> foo('bar') |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
121 Traceback (most recent call last): |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
122 ... |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
123 NameError: Variable "foo" is not defined |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
124 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
125 >>> foo.bar |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
126 Traceback (most recent call last): |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
127 ... |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
128 NameError: Variable "foo" is not defined |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
129 """ |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
130 __slots__ = ['name'] |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
131 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
132 def __init__(self, name): |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
133 self.name = name |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
134 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
135 def __call__(self, *args, **kwargs): |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
136 self.throw() |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
137 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
138 def __getattr__(self, name): |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
139 self.throw() |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
140 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
141 def __iter__(self): |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
142 return iter([]) |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
143 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
144 def __nonzero__(self): |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
145 return False |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
146 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
147 def __repr__(self): |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
148 return 'undefined' |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
149 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
150 def throw(self): |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
151 raise NameError('Variable "%s" is not defined' % self.name) |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
152 |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
153 |
165
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
154 def _compile(node, source=None, filename=None, lineno=-1): |
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
155 tree = ExpressionASTTransformer().visit(node) |
116 | 156 if isinstance(filename, unicode): |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
157 # unicode file names not allowed for code objects |
116 | 158 filename = filename.encode('utf-8', 'replace') |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
159 elif not filename: |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
160 filename = '<string>' |
132
dc42cb3c02dc
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
161 tree.filename = filename |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
162 if lineno <= 0: |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
163 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
|
164 |
116 | 165 gen = ExpressionCodeGenerator(tree) |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
166 gen.optimized = True |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
167 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
|
168 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
169 # 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
|
170 # 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
|
171 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
|
172 code.co_flags | 0x0040, code.co_code, code.co_consts, |
165
54a4be707664
Fix handling of keyword arguments in `py:def` directive. Thanks to Christian Boos for reporting the problem and providing the basic patch for this change.
cmlenz
parents:
145
diff
changeset
|
173 code.co_names, code.co_varnames, filename, |
167
1999291f7a30
Handle non-ASCII characters in expressions. Closes #29. Thanks to Arnar Birgisson for reporting the problem and comping up with a patch!
cmlenz
parents:
165
diff
changeset
|
174 '<Expression %s>' % (repr(source).replace("'", '"') or '?'), |
1999291f7a30
Handle non-ASCII characters in expressions. Closes #29. Thanks to Arnar Birgisson for reporting the problem and comping up with a patch!
cmlenz
parents:
165
diff
changeset
|
175 lineno, code.co_lnotab, (), ()) |
116 | 176 |
192
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
177 BUILTINS = __builtin__.__dict__.copy() |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
178 BUILTINS['Undefined'] = Undefined |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
179 |
132
dc42cb3c02dc
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
180 def _lookup_name(data, name, locals_=None): |
192
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
181 val = Undefined |
132
dc42cb3c02dc
Name lookup in expressions: try locals first, then the context.
cmlenz
parents:
131
diff
changeset
|
182 if locals_: |
192
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
183 val = locals_.get(name, val) |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
184 if val is Undefined: |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
185 val = data.get(name, val) |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
186 if val is Undefined: |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
187 val = BUILTINS.get(name, val) |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
188 if val is not Undefined or name == 'Undefined': |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
189 return val |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
190 else: |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
191 return val |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
192 else: |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
193 return val |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
194 return val(name) |
116 | 195 |
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
|
196 def _lookup_attr(data, obj, key): |
192
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
197 if type(obj) is Undefined: |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
198 obj.throw() |
116 | 199 if hasattr(obj, key): |
200 return getattr(obj, key) | |
201 try: | |
202 return obj[key] | |
203 except (KeyError, TypeError): | |
204 return None | |
205 | |
206 def _lookup_item(data, obj, key): | |
192
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
207 if type(obj) is Undefined: |
b64e36bc1100
Expression evaluation now differentiates between undefined variables and variables that are defined but set to `None`.
cmlenz
parents:
180
diff
changeset
|
208 obj.throw() |
116 | 209 if len(key) == 1: |
210 key = key[0] | |
211 try: | |
212 return obj[key] | |
213 except (KeyError, IndexError, TypeError), e: | |
214 if isinstance(key, basestring): | |
215 try: | |
216 return getattr(obj, key) | |
217 except (AttributeError, TypeError), e: | |
218 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
|
219 |
138 | 220 |
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
|
221 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
|
222 """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
|
223 |
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 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
|
225 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
|
226 """ |
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
|
227 _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
|
228 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
229 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
|
230 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
|
231 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
|
232 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
|
233 self._visitors[node.__class__] = v |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
234 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
|
235 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
236 def visitExpression(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
237 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
|
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 |
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
|
240 # 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
|
241 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
242 def visitCallFunc(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
243 node.node = self.visit(node.node, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
244 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
|
245 if node.star_args: |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
246 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
|
247 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
|
248 if node.dstar_args: |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
249 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
|
250 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
|
251 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
|
252 |
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
|
253 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
|
254 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
|
255 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
|
256 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
|
257 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
258 def visitGetattr(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
259 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
|
260 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
|
261 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
262 def visitSubscript(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
263 node.expr = self.visit(node.expr, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
264 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
|
265 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
|
266 |
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 # 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
|
268 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
269 def _visitBoolOp(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
270 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
|
271 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
|
272 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
|
273 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
274 def _visitBinOp(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
275 node.left = self.visit(node.left, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
276 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
|
277 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
|
278 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
|
279 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
|
280 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
|
281 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
282 def visitCompare(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
283 node.expr = self.visit(node.expr, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
284 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
|
285 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
|
286 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
|
287 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
288 def _visitUnaryOp(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
289 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
|
290 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
|
291 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
|
292 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
|
293 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
294 # 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
|
295 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
296 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
|
297 return node |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
298 visitAssName = visitAssTuple = _visitDefault |
102 | 299 visitConst = visitName = _visitDefault |
300 | |
301 def visitKeyword(self, node, *args, **kwargs): | |
302 node.expr = self.visit(node.expr, *args, **kwargs) | |
303 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
|
304 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
305 def visitDict(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
306 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
|
307 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
|
308 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
|
309 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
|
310 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
311 def visitTuple(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
312 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
|
313 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
|
314 |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
315 def visitList(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
316 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
|
317 return node |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
318 |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
319 def visitListComp(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
320 node.expr = self.visit(node.expr, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
321 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
|
322 return node |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
323 |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
324 def visitListCompFor(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
325 node.assign = self.visit(node.assign, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
326 node.list = self.visit(node.list, *args, **kwargs) |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
327 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
|
328 return node |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
329 |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
330 def visitListCompIf(self, node, *args, **kwargs): |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
331 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
|
332 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
|
333 |
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
|
334 |
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
|
335 class ExpressionASTTransformer(ASTTransformer): |
112 | 336 """Concrete AST transformer that implements the AST transformations needed |
337 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
|
338 """ |
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
|
339 |
180
061491fb4ea8
String literals in XPath expressions are assumed to be UTF-8 encoded.
cmlenz
parents:
167
diff
changeset
|
340 def visitConst(self, node, locals_=False): |
061491fb4ea8
String literals in XPath expressions are assumed to be UTF-8 encoded.
cmlenz
parents:
167
diff
changeset
|
341 if isinstance(node.value, str): |
061491fb4ea8
String literals in XPath expressions are assumed to be UTF-8 encoded.
cmlenz
parents:
167
diff
changeset
|
342 return ast.Const(node.value.decode('utf-8')) |
061491fb4ea8
String literals in XPath expressions are assumed to be UTF-8 encoded.
cmlenz
parents:
167
diff
changeset
|
343 return node |
061491fb4ea8
String literals in XPath expressions are assumed to be UTF-8 encoded.
cmlenz
parents:
167
diff
changeset
|
344 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
345 def visitGetattr(self, node, locals_=False): |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
346 return ast.CallFunc(ast.Name('_lookup_attr'), [ |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
347 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
|
348 ast.Const(node.attrname) |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
349 ]) |
30
bcdbb7e5e4e5
Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents:
27
diff
changeset
|
350 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
351 def visitLambda(self, node, locals_=False): |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
352 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
|
353 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
|
354 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
|
355 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
356 def visitListComp(self, node, locals_=False): |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
357 node.expr = self.visit(node.expr, locals_=True) |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
358 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
|
359 return node |
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
360 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
361 def visitName(self, node, locals_=False): |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
362 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
|
363 if locals_: |
88
628ba9ed39ef
Add support for list comprehension in expressions (see #12).
cmlenz
parents:
87
diff
changeset
|
364 func_args.append(ast.CallFunc(ast.Name('locals'), [])) |
116 | 365 return ast.CallFunc(ast.Name('_lookup_name'), func_args) |
81
d60486018004
Template expressions are now compiled to Python bytecode.
cmlenz
parents:
69
diff
changeset
|
366 |
131
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
367 def visitSubscript(self, node, locals_=False): |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
368 return ast.CallFunc(ast.Name('_lookup_item'), [ |
2ad83f1d337c
* Support for line numbers in exceptions in expression evaluation (#22).
cmlenz
parents:
120
diff
changeset
|
369 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
|
370 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
|
371 ]) |