Mercurial > genshi > mirror
comparison markup/eval.py @ 116:c77c113846d6 trunk
Merged [135:138/branches/experimental/cspeedups].
author | cmlenz |
---|---|
date | Tue, 01 Aug 2006 17:06:03 +0000 |
parents | 5f9af749341c |
children | c392d38694d9 |
comparison
equal
deleted
inserted
replaced
115:e92fb402ee04 | 116:c77c113846d6 |
---|---|
69 """Create the expression. | 69 """Create the expression. |
70 | 70 |
71 @param source: the expression as string | 71 @param source: the expression as string |
72 """ | 72 """ |
73 self.source = source | 73 self.source = source |
74 self.code = self._compile(source, filename, lineno) | 74 self.code = _compile(source, filename, lineno) |
75 | 75 |
76 def __repr__(self): | 76 def __repr__(self): |
77 return '<Expression "%s">' % self.source | 77 return '<Expression "%s">' % self.source |
78 | 78 |
79 def evaluate(self, data): | 79 def evaluate(self, data): |
85 retval = eval(self.code) | 85 retval = eval(self.code) |
86 if callable(retval): | 86 if callable(retval): |
87 retval = retval() | 87 retval = retval() |
88 return retval | 88 return retval |
89 | 89 |
90 def _compile(self, source, filename, lineno): | 90 |
91 tree = parse(self.source, 'eval') | 91 def _compile(source, filename=None, lineno=-1): |
92 xform = ExpressionASTTransformer() | 92 tree = parse(source, 'eval') |
93 tree = xform.visit(tree) | 93 xform = ExpressionASTTransformer() |
94 | 94 tree = xform.visit(tree) |
95 if isinstance(filename, unicode): | 95 |
96 # pycodegen doesn't like unicode in the filename | 96 if isinstance(filename, unicode): |
97 filename = filename.encode('utf-8', 'replace') | 97 # pycodegen doesn't like unicode in the filename |
98 tree.filename = filename or '<string>' | 98 filename = filename.encode('utf-8', 'replace') |
99 | 99 tree.filename = filename or '<string>' |
100 gen = ExpressionCodeGenerator(tree) | 100 |
101 if lineno >= 0: | 101 gen = ExpressionCodeGenerator(tree) |
102 gen.emit('SET_LINENO', lineno) | 102 if lineno >= 0: |
103 | 103 gen.emit('SET_LINENO', lineno) |
104 return gen.getCode() | 104 |
105 | 105 return gen.getCode() |
106 def _lookup_name(data, name, locals=None): | 106 |
107 val = data.get(name) | 107 def _lookup_name(data, name, locals=None): |
108 if val is None and locals: | 108 val = data.get(name) |
109 val = locals.get(name) | 109 if val is None and locals: |
110 if val is None: | 110 val = locals.get(name) |
111 val = getattr(__builtin__, name, None) | 111 if val is None: |
112 return val | 112 val = getattr(__builtin__, name, None) |
113 _lookup_name = staticmethod(_lookup_name) | 113 return val |
114 | 114 |
115 def _lookup_attribute(data, obj, key): | 115 def _lookup_attribute(data, obj, key): |
116 if hasattr(obj, key): | 116 if hasattr(obj, key): |
117 return getattr(obj, key) | 117 return getattr(obj, key) |
118 try: | 118 try: |
119 return obj[key] | 119 return obj[key] |
120 except (KeyError, TypeError): | 120 except (KeyError, TypeError): |
121 return None | 121 return None |
122 _lookup_attribute = staticmethod(_lookup_attribute) | 122 |
123 | 123 def _lookup_item(data, obj, key): |
124 def _lookup_item(data, obj, key): | 124 if len(key) == 1: |
125 if len(key) == 1: | 125 key = key[0] |
126 key = key[0] | 126 try: |
127 try: | 127 return obj[key] |
128 return obj[key] | 128 except (KeyError, IndexError, TypeError), e: |
129 except (KeyError, IndexError, TypeError), e: | 129 pass |
130 pass | 130 if isinstance(key, basestring): |
131 if isinstance(key, basestring): | 131 try: |
132 try: | 132 return getattr(obj, key) |
133 return getattr(obj, key) | 133 except (AttributeError, TypeError), e: |
134 except (AttributeError, TypeError), e: | 134 pass |
135 pass | |
136 _lookup_item = staticmethod(_lookup_item) | |
137 | |
138 | 135 |
139 class ASTTransformer(object): | 136 class ASTTransformer(object): |
140 """General purpose base class for AST transformations. | 137 """General purpose base class for AST transformations. |
141 | 138 |
142 Every visitor method can be overridden to return an AST node that has been | 139 Every visitor method can be overridden to return an AST node that has been |
249 """Concrete AST transformer that implements the AST transformations needed | 246 """Concrete AST transformer that implements the AST transformations needed |
250 for template expressions. | 247 for template expressions. |
251 """ | 248 """ |
252 | 249 |
253 def visitGetattr(self, node, *args, **kwargs): | 250 def visitGetattr(self, node, *args, **kwargs): |
254 return ast.CallFunc( | 251 return ast.CallFunc(ast.Name('_lookup_attribute'), |
255 ast.Getattr(ast.Name('self'), '_lookup_attribute'), | |
256 [ast.Name('data'), self.visit(node.expr, *args, **kwargs), | 252 [ast.Name('data'), self.visit(node.expr, *args, **kwargs), |
257 ast.Const(node.attrname)] | 253 ast.Const(node.attrname)] |
258 ) | 254 ) |
259 | 255 |
260 def visitListComp(self, node, *args, **kwargs): | 256 def visitListComp(self, node, *args, **kwargs): |
267 | 263 |
268 def visitName(self, node, *args, **kwargs): | 264 def visitName(self, node, *args, **kwargs): |
269 func_args = [ast.Name('data'), ast.Const(node.name)] | 265 func_args = [ast.Name('data'), ast.Const(node.name)] |
270 if kwargs.get('lookup_locals'): | 266 if kwargs.get('lookup_locals'): |
271 func_args.append(ast.CallFunc(ast.Name('locals'), [])) | 267 func_args.append(ast.CallFunc(ast.Name('locals'), [])) |
272 return ast.CallFunc( | 268 return ast.CallFunc(ast.Name('_lookup_name'), func_args) |
273 ast.Getattr(ast.Name('self'), '_lookup_name'), func_args | |
274 ) | |
275 return node | 269 return node |
276 | 270 |
277 def visitSubscript(self, node, *args, **kwargs): | 271 def visitSubscript(self, node, *args, **kwargs): |
278 return ast.CallFunc( | 272 return ast.CallFunc(ast.Name('_lookup_item'), |
279 ast.Getattr(ast.Name('self'), '_lookup_item'), | |
280 [ast.Name('data'), self.visit(node.expr, *args, **kwargs), | 273 [ast.Name('data'), self.visit(node.expr, *args, **kwargs), |
281 ast.Tuple(map(self.visit, node.subs, *args, **kwargs))] | 274 ast.Tuple(map(self.visit, node.subs, *args, **kwargs))] |
282 ) | 275 ) |