annotate markup/eval.py @ 85:4938c310d904 trunk

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