annotate markup/eval.py @ 86:5d98c4259d68

Accidentially left some doctests disabled.
author cmlenz
date Mon, 17 Jul 2006 09:01:08 +0000
parents c82c002d4c32
children c6f07b7cd3ea
rev   line source
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
1 # -*- coding: utf-8 -*-
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
2 #
66
822089ae65ce Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents: 42
diff changeset
3 # Copyright (C) 2006 Edgewall Software
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
4 # All rights reserved.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
5 #
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
6 # This software is licensed as described in the file COPYING, which
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
7 # you should have received as part of this distribution. The terms
66
822089ae65ce Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents: 42
diff changeset
8 # are also available at http://markup.edgewall.org/wiki/License.
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
9 #
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
10 # This software consists of voluntary contributions made by many
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
11 # individuals. For the exact contribution history, see the revision
66
822089ae65ce Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents: 42
diff changeset
12 # history and logs, available at http://markup.edgewall.org/log/.
27
b8456279c444 * Fix the boilerplate in the Python source files.
cmlenz
parents: 16
diff changeset
13
b8456279c444 * Fix the boilerplate in the Python source files.
cmlenz
parents: 16
diff changeset
14 """Support for "safe" evaluation of Python expressions."""
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
15
32
3b8c41bbf83d A couple more operators supported in expressions.
cmlenz
parents: 31
diff changeset
16 from __future__ import division
3b8c41bbf83d A couple more operators supported in expressions.
cmlenz
parents: 31
diff changeset
17
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
18 import __builtin__
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
19 from compiler import parse, pycodegen
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
20
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
21 from markup.core import Stream
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
22
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
23 __all__ = ['Expression']
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
24
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
25
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
26 class Expression(object):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
27 """Evaluates Python expressions used in templates.
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
28
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
29 >>> data = dict(test='Foo', items=[1, 2, 3], dict={'some': 'thing'})
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
30 >>> Expression('test').evaluate(data)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
31 'Foo'
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
32
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
33 >>> Expression('items[0]').evaluate(data)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
34 1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
35 >>> Expression('items[-1]').evaluate(data)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
36 3
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
37 >>> Expression('dict["some"]').evaluate(data)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
38 'thing'
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
39
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
40 Similar to e.g. Javascript, expressions in templates can use the dot
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
41 notation for attribute access to access items in mappings:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
42
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
43 >>> Expression('dict.some').evaluate(data)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
44 'thing'
86
5d98c4259d68 Accidentially left some doctests disabled.
cmlenz
parents: 82
diff changeset
45
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
46 This also works the other way around: item access can be used to access
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
47 any object attribute (meaning there's no use for `getattr()` in templates):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
48
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
49 >>> class MyClass(object):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
50 ... myattr = 'Bar'
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
51 >>> data = dict(mine=MyClass(), key='myattr')
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
52 >>> Expression('mine.myattr').evaluate(data)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
53 'Bar'
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
54 >>> Expression('mine["myattr"]').evaluate(data)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
55 'Bar'
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
56 >>> Expression('mine[key]').evaluate(data)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
57 'Bar'
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
58
31
9a958398bed9 * More test cases for expression evaluation.
cmlenz
parents: 30
diff changeset
59 All of the standard Python operators are available to template expressions.
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
60 Built-in functions such as `len()` are also available in template
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
61 expressions:
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
62
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
63 >>> data = dict(items=[1, 2, 3])
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
64 >>> Expression('len(items)').evaluate(data)
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
65 3
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
66 """
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
67 __slots__ = ['source', 'code']
69
e9a3930f8823 A couple of minor performance improvements.
cmlenz
parents: 66
diff changeset
68 _visitors = {}
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
69
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
70 def __init__(self, source, filename=None, lineno=-1):
27
b8456279c444 * Fix the boilerplate in the Python source files.
cmlenz
parents: 16
diff changeset
71 """Create the expression.
b8456279c444 * Fix the boilerplate in the Python source files.
cmlenz
parents: 16
diff changeset
72
b8456279c444 * Fix the boilerplate in the Python source files.
cmlenz
parents: 16
diff changeset
73 @param source: the expression as string
b8456279c444 * Fix the boilerplate in the Python source files.
cmlenz
parents: 16
diff changeset
74 """
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
75 self.source = source
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
76
86
5d98c4259d68 Accidentially left some doctests disabled.
cmlenz
parents: 82
diff changeset
77 ast = parse(self.source, 'eval')
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
78 if isinstance(filename, unicode):
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
79 # pycodegen doesn't like unicode in the filename
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
80 filename = filename.encode('utf-8', 'replace')
86
5d98c4259d68 Accidentially left some doctests disabled.
cmlenz
parents: 82
diff changeset
81 ast.filename = filename or '<string>'
5d98c4259d68 Accidentially left some doctests disabled.
cmlenz
parents: 82
diff changeset
82 gen = TemplateExpressionCodeGenerator(ast)
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
83 if lineno >= 0:
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
84 gen.emit('SET_LINENO', lineno)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
85 self.code = gen.getCode()
1
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
86
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
87 def __repr__(self):
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
88 return '<Expression "%s">' % self.source
821114ec4f69 Initial import.
cmlenz
parents:
diff changeset
89
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
90 def evaluate(self, data):
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
91 """Evaluate the expression against the given data dictionary.
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
92
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
93 @param data: a mapping containing the data to evaluate against
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
94 @return: the result of the evaluation
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
95 """
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
96 return eval(self.code)
30
2ee9f28e16e5 Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents: 27
diff changeset
97
2ee9f28e16e5 Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents: 27
diff changeset
98
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
99 class TemplateExpressionCodeGenerator(pycodegen.ExpressionCodeGenerator):
30
2ee9f28e16e5 Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents: 27
diff changeset
100
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
101 def visitGetattr(self, node):
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
102 """Overridden to fallback to item access if the object doesn't have an
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
103 attribute.
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
104
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
105 Also, if either method fails, this returns `None` instead of raising an
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
106 `AttributeError`.
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
107 """
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
108 # check whether the object has the request attribute
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
109 self.visit(node.expr)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
110 self.emit('STORE_NAME', 'obj')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
111 self.emit('LOAD_GLOBAL', 'hasattr')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
112 self.emit('LOAD_NAME', 'obj')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
113 self.emit('LOAD_CONST', node.attrname)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
114 self.emit('CALL_FUNCTION', 2)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
115 else_ = self.newBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
116 self.emit('JUMP_IF_FALSE', else_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
117 self.emit('POP_TOP')
30
2ee9f28e16e5 Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents: 27
diff changeset
118
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
119 # hasattr returned True, so return the attribute value
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
120 self.emit('LOAD_NAME', 'obj')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
121 self.emit('LOAD_ATTR', node.attrname)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
122 self.emit('STORE_NAME', 'val')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
123 return_ = self.newBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
124 self.emit('JUMP_FORWARD', return_)
30
2ee9f28e16e5 Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents: 27
diff changeset
125
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
126 # hasattr returned False, so try item access
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
127 self.startBlock(else_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
128 try_ = self.newBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
129 except_ = self.newBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
130 self.emit('SETUP_EXCEPT', except_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
131 self.nextBlock(try_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
132 self.setups.push((pycodegen.EXCEPT, try_))
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
133 self.emit('LOAD_NAME', 'obj')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
134 self.emit('LOAD_CONST', node.attrname)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
135 self.emit('BINARY_SUBSCR')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
136 self.emit('STORE_NAME', 'val')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
137 self.emit('POP_BLOCK')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
138 self.setups.pop()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
139 self.emit('JUMP_FORWARD', return_)
30
2ee9f28e16e5 Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents: 27
diff changeset
140
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
141 # exception handler: just return `None`
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
142 self.startBlock(except_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
143 self.emit('DUP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
144 self.emit('LOAD_GLOBAL', 'KeyError')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
145 self.emit('LOAD_GLOBAL', 'TypeError')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
146 self.emit('BUILD_TUPLE', 2)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
147 self.emit('COMPARE_OP', 'exception match')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
148 next = self.newBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
149 self.emit('JUMP_IF_FALSE', next)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
150 self.nextBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
151 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
152 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
153 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
154 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
155 self.emit('LOAD_CONST', None) # exception handler body
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
156 self.emit('STORE_NAME', 'val')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
157 self.emit('JUMP_FORWARD', return_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
158 self.nextBlock(next)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
159 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
160 self.emit('END_FINALLY')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
161
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
162 # return
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
163 self.nextBlock(return_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
164 self.emit('LOAD_NAME', 'val')
30
2ee9f28e16e5 Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents: 27
diff changeset
165
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
166 def visitName(self, node):
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
167 """Overridden to lookup names in the context data instead of in
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
168 locals/globals.
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
169
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
170 If a name is not found in the context data, we fall back to Python
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
171 builtins.
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
172 """
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
173 next = self.newBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
174 end = self.newBlock()
30
2ee9f28e16e5 Experimental support for using the new native AST in Python 2.5 instead of the `compiler` package.
cmlenz
parents: 27
diff changeset
175
81
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
176 # default: lookup in context data
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
177 self.loadName('data')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
178 self.emit('LOAD_ATTR', 'get')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
179 self.emit('LOAD_CONST', node.name)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
180 self.emit('CALL_FUNCTION', 1)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
181 self.emit('STORE_NAME', 'val')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
182
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
183 # test whether the value "is None"
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
184 self.emit('LOAD_NAME', 'val')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
185 self.emit('LOAD_CONST', None)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
186 self.emit('COMPARE_OP', 'is')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
187 self.emit('JUMP_IF_FALSE', next)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
188 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
189
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
190 # if it is, fallback to builtins
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
191 self.emit('LOAD_GLOBAL', 'getattr')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
192 self.emit('LOAD_GLOBAL', '__builtin__')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
193 self.emit('LOAD_CONST', node.name)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
194 self.emit('LOAD_CONST', None)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
195 self.emit('CALL_FUNCTION', 3)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
196 self.emit('STORE_NAME', 'val')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
197 self.emit('JUMP_FORWARD', end)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
198
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
199 self.nextBlock(next)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
200 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
201
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
202 self.nextBlock(end)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
203 self.emit('LOAD_NAME', 'val')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
204
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
205 def visitSubscript(self, node, aug_flag=None):
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
206 """Overridden to fallback to attribute access if the object doesn't
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
207 have an item (or doesn't even support item access).
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
208
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
209 If either method fails, this returns `None` instead of raising an
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
210 `IndexError`, `KeyError`, or `TypeError`.
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
211 """
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
212 self.visit(node.expr)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
213 self.emit('STORE_NAME', 'obj')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
214
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
215 if len(node.subs) > 1:
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
216 # For non-scalar subscripts, use the default method
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
217 # FIXME: this should catch exceptions
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
218 self.emit('LOAD_NAME', 'obj')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
219 for sub in node.subs:
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
220 self.visit(sub)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
221 self.emit('BUILD_TUPLE', len(node.subs))
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
222 self.emit('BINARY_SUBSCR')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
223
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
224 else:
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
225 # For a scalar subscript, fallback to attribute access
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
226 # FIXME: Would be nice if we could limit this to string subscripts
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
227 try_ = self.newBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
228 except_ = self.newBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
229 return_ = self.newBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
230 self.emit('SETUP_EXCEPT', except_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
231 self.nextBlock(try_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
232 self.setups.push((pycodegen.EXCEPT, try_))
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
233 self.emit('LOAD_NAME', 'obj')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
234 self.visit(node.subs[0])
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
235 self.emit('BINARY_SUBSCR')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
236 self.emit('STORE_NAME', 'val')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
237 self.emit('POP_BLOCK')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
238 self.setups.pop()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
239 self.emit('JUMP_FORWARD', return_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
240
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
241 self.startBlock(except_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
242 self.emit('DUP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
243 self.emit('LOAD_GLOBAL', 'KeyError')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
244 self.emit('LOAD_GLOBAL', 'IndexError')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
245 self.emit('LOAD_GLOBAL', 'TypeError')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
246 self.emit('BUILD_TUPLE', 3)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
247 self.emit('COMPARE_OP', 'exception match')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
248 next = self.newBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
249 self.emit('JUMP_IF_FALSE', next)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
250 self.nextBlock()
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
251 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
252 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
253 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
254 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
255 self.emit('LOAD_GLOBAL', 'getattr') # exception handler body
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
256 self.emit('LOAD_NAME', 'obj')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
257 self.visit(node.subs[0])
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
258 self.emit('LOAD_CONST', None)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
259 self.emit('CALL_FUNCTION', 3)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
260 self.emit('STORE_NAME', 'val')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
261 self.emit('JUMP_FORWARD', return_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
262 self.nextBlock(next)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
263 self.emit('POP_TOP')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
264 self.emit('END_FINALLY')
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
265
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
266 # return
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
267 self.nextBlock(return_)
cc034182061e Template expressions are now compiled to Python bytecode.
cmlenz
parents: 69
diff changeset
268 self.emit('LOAD_NAME', 'val')
Copyright (C) 2012-2017 Edgewall Software