comparison genshi/template/inline.py @ 826:8ebccfa9a9fe experimental-inline

inline branch: Add code block support to the template inliner, and some tweaks/cleanup.
author cmlenz
date Fri, 13 Mar 2009 09:34:50 +0000
parents abb1f1d2f4f3
children eb8aa8690480
comparison
equal deleted inserted replaced
821:abb1f1d2f4f3 826:8ebccfa9a9fe
13 13
14 import imp 14 import imp
15 15
16 from genshi.core import Attrs, Stream, _ensure, START, END, TEXT 16 from genshi.core import Attrs, Stream, _ensure, START, END, TEXT
17 from genshi.template.astutil import _ast 17 from genshi.template.astutil import _ast
18 from genshi.template.base import EXPR, SUB 18 from genshi.template.base import EXEC, EXPR, SUB
19 from genshi.template.directives import * 19 from genshi.template.directives import *
20 20
21 21
22 class CodeWriter(object): 22 class CodeWriter(object):
23 23
43 # First check for a string, otherwise the iterable test below 43 # First check for a string, otherwise the iterable test below
44 # succeeds, and the string will be chopped up into individual 44 # succeeds, and the string will be chopped up into individual
45 # characters 45 # characters
46 if isinstance(obj, basestring): 46 if isinstance(obj, basestring):
47 yield TEXT, obj, pos 47 yield TEXT, obj, pos
48 elif isinstance(obj, (int, float, long)):
49 yield TEXT, unicode(obj), pos
48 elif hasattr(obj, '__iter__'): 50 elif hasattr(obj, '__iter__'):
49 for event in _ensure(obj): 51 for event in _ensure(obj):
50 yield event 52 yield event
51 else: 53 else:
52 yield TEXT, unicode(obj), pos 54 yield TEXT, unicode(obj), pos
53 55
56
54 def _expand_text(obj): 57 def _expand_text(obj):
55 if obj is not None: 58 if obj is not None:
56 if isinstance(obj, basestring): 59 if isinstance(obj, basestring):
57 return [obj] 60 return [obj]
61 elif isinstance(obj, (int, float, long)):
62 return [unicode(result)]
58 elif hasattr(obj, '__iter__'): 63 elif hasattr(obj, '__iter__'):
59 return [e[1] for e in _ensure(obj) if e[0] is TEXT] 64 return [e[1] for e in _ensure(obj) if e[0] is TEXT]
60 else: 65 else:
61 return [unicode(obj)] 66 return [unicode(obj)]
62 return [] 67 return []
68
63 69
64 def _assign(ast): 70 def _assign(ast):
65 buf = [] 71 buf = []
66 def _build(node, indices): 72 def _build(node, indices):
67 if isinstance(node, _ast.Tuple): 73 if isinstance(node, _ast.Tuple):
70 elif isinstance(node, _ast.Name): 76 elif isinstance(node, _ast.Name):
71 buf.append('%r: v%s' % (node.id, ''.join(['[%s]' % i for i in indices]))) 77 buf.append('%r: v%s' % (node.id, ''.join(['[%s]' % i for i in indices])))
72 _build(ast, ()) 78 _build(ast, ())
73 return '{%s}' % ', '.join(buf) 79 return '{%s}' % ', '.join(buf)
74 80
81
75 def inline(template): 82 def inline(template):
76 w = CodeWriter() 83 w = CodeWriter()
77 84
78 yield w('from genshi.core import Attrs, QName') 85 yield w('from genshi.core import Attrs, QName')
79 yield w('from genshi.core import START, START_NS, END, END_NS, DOCTYPE, TEXT') 86 yield w('from genshi.core import START, START_CDATA, START_NS, END, '
87 'END_CDATA, END_NS, DOCTYPE, TEXT')
80 yield w('from genshi.path import Path') 88 yield w('from genshi.path import Path')
81 yield w('from genshi.template.eval import Expression') 89 yield w('from genshi.template.eval import Expression, Suite')
82 yield w('from genshi.template.inline import _expand, _expand_text') 90 yield w('from genshi.template.inline import _expand, _expand_text')
83 yield w() 91 yield w()
84 92
85 def _predecl_vars(stream): 93 def _declare_vars(stream):
86 for kind, data, pos in stream: 94 for kind, data, pos in stream:
87 95
88 if kind is START: 96 if kind is START:
89 tagname, attrs = data 97 tagname, attrs = data
90 yield 'Q', tagname, tagname 98 yield 'Q', tagname, tagname
101 yield 'A', tuple(sattrs), sattrs 109 yield 'A', tuple(sattrs), sattrs
102 110
103 elif kind is EXPR: 111 elif kind is EXPR:
104 yield 'E', data, data 112 yield 'E', data, data
105 113
114 elif kind is EXEC:
115 yield 'S', data, data
116
106 elif kind is SUB: 117 elif kind is SUB:
107 directives, substream = data 118 directives, substream = data
108 for directive in directives: 119 for directive in directives:
109 120
110 if directive.expr: 121 if directive.expr:
115 yield 'E', expr, expr 126 yield 'E', expr, expr
116 127
117 elif hasattr(directive, 'path') and directive.path: 128 elif hasattr(directive, 'path') and directive.path:
118 yield 'P', directive.path, directive.path 129 yield 'P', directive.path, directive.path
119 130
120 for line in _predecl_vars(substream): 131 for line in _declare_vars(substream):
121 yield line 132 yield line
122 133
123 def _predecl_defs(stream): 134 def _declare_functions(stream, names):
124 for kind, data, pos in stream: 135 for kind, data, pos in stream:
125 if kind is SUB: 136 if kind is SUB:
126 directives, substream = data 137 directives, substream = data
127 for idx, directive in enumerate(directives): 138 for idx, directive in enumerate(directives):
128 if isinstance(directive, DefDirective): 139 if isinstance(directive, DefDirective):
129 defs.append(directive.name) 140 names.append(directive.name)
130 yield w('def %s:', directive.signature) 141 yield w('def %s:', directive.signature)
131 w.shift() 142 w.shift()
132 args = ['%r: %s' % (name, name) for name 143 args = ['%r: %s' % (name, name) for name
133 in directive.args] 144 in directive.args]
134 yield w('ctxt.push({%s})', ', '.join(args)) 145 yield w('push({%s})', ', '.join(args))
135 for line in _apply(directives[idx + 1:], substream): 146 for line in _apply(directives[idx + 1:], substream):
136 yield line 147 yield line
137 yield w('ctxt.pop()') 148 yield w('pop()')
138 w.unshift() 149 w.unshift()
139 150
140 # Recursively apply directives 151 # Recursively apply directives
141 def _apply(directives, stream): 152 def _apply(directives, stream):
142 if not directives: 153 if not directives:
154 yield w('# Applying %r', d) 165 yield w('# Applying %r', d)
155 166
156 if isinstance(d, ForDirective): 167 if isinstance(d, ForDirective):
157 yield w('for v in e[%d].evaluate(ctxt):', index['E'][d.expr]) 168 yield w('for v in e[%d].evaluate(ctxt):', index['E'][d.expr])
158 w.shift() 169 w.shift()
159 yield w('ctxt.push(%s)', _assign(d.target)) 170 yield w('push(%s)', _assign(d.target))
160 for line in _apply(rest, stream): 171 for line in _apply(rest, stream):
161 yield line 172 yield line
162 yield w('ctxt.pop()') 173 yield w('pop()')
163 w.unshift() 174 w.unshift()
164 175
165 elif isinstance(d, IfDirective): 176 elif isinstance(d, IfDirective):
166 yield w('if e[%d].evaluate(ctxt):', index['E'][d.expr]) 177 yield w('if e[%d].evaluate(ctxt):', index['E'][d.expr])
167 w.shift() 178 w.shift()
179 for kind, data, pos in stream: 190 for kind, data, pos in stream:
180 191
181 if kind is EXPR: 192 if kind is EXPR:
182 yield w('for evt in _expand(e[%d].evaluate(ctxt), (f, %d, %d)): yield evt', 193 yield w('for evt in _expand(e[%d].evaluate(ctxt), (f, %d, %d)): yield evt',
183 index['E'][data], *pos[1:]) 194 index['E'][data], *pos[1:])
195
196 elif kind is EXEC:
197 yield w('s[%d].execute(ctxt)', index['S'][data])
184 198
185 elif kind is START: 199 elif kind is START:
186 tagname, attrs = data 200 tagname, attrs = data
187 qn = index['Q'][tagname] 201 qn = index['Q'][tagname]
188 202
223 yield w('yield %s, %r, (f, %d, %d)', kind, data, *pos[1:]) 237 yield w('yield %s, %r, (f, %d, %d)', kind, data, *pos[1:])
224 238
225 yield w('_F = %r', template.filename) 239 yield w('_F = %r', template.filename)
226 yield w() 240 yield w()
227 241
228 yield '# predeclare qnames, attributes, and expressions' 242 yield '# Create qnames, attributes, expressions, and suite objects'
229 index, counter, values = {}, {}, {} 243 index, counter, values = {}, {}, {}
230 for prefix, key, value in _predecl_vars(template.stream): 244 for prefix, key, value in _declare_vars(template.stream):
231 if not prefix in counter: 245 if not prefix in counter:
232 counter[prefix] = 0 246 counter[prefix] = 0
233 if key not in index.get(prefix, ()): 247 if key not in index.get(prefix, ()):
234 index.setdefault(prefix, {})[key] = counter[prefix] 248 index.setdefault(prefix, {})[key] = counter[prefix]
235 counter[prefix] += 1 249 counter[prefix] += 1
241 yield w(')') 255 yield w(')')
242 yield w() 256 yield w()
243 257
244 yield w('def generate(ctxt, %s):', 258 yield w('def generate(ctxt, %s):',
245 ', '.join(['f=_F'] + ['%s=_%s' % (n.lower(), n) for n in index])) 259 ', '.join(['f=_F'] + ['%s=_%s' % (n.lower(), n) for n in index]))
260 w.shift()
261 yield w('push = ctxt.push; pop = ctxt.pop')
246 yield w() 262 yield w()
247 w.shift()
248 263
249 # Define macro functions 264 # Define macro functions
250 defs = [] 265 defs = []
251 for line in _predecl_defs(template.stream): 266 for line in _declare_functions(template.stream, names=defs):
252 yield line 267 yield line
253 if defs: 268 if defs:
254 yield w() 269 yield w()
255 yield w('ctxt.push({%s})', ', '.join(['%r: %s' % (n, n) for n in defs])) 270 yield w('push({%s})', ', '.join('%r: %s' % (n, n) for n in defs))
256 yield w() 271 yield w()
257 272
258 ei, pi = [0], [0] 273 ei, pi = [0], [0]
259 for line in _generate(template.stream): 274 for line in _generate(template.stream):
260 yield line 275 yield line
262 277
263 if __name__ == '__main__': 278 if __name__ == '__main__':
264 import timeit 279 import timeit
265 from genshi.template import Context, MarkupTemplate 280 from genshi.template import Context, MarkupTemplate
266 281
267 text = """<!DOCTYPE html 282 text = """<html xmlns="http://www.w3.org/1999/xhtml"
268 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
269 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
270 <html xmlns="http://www.w3.org/1999/xhtml"
271 xmlns:py="http://genshi.edgewall.org/" 283 xmlns:py="http://genshi.edgewall.org/"
272 lang="en"> 284 lang="en">
285 <?python
286 def foo(x):
287 return x*x
288 ?>
273 <body> 289 <body>
274 <h1 py:def="sayhi(name='world')" py:strip=""> 290 <h1 py:def="sayhi(name='world')" py:strip="">
275 Hello, $name! 291 Hello, $name!
276 </h1> 292 </h1>
277 ${sayhi()} 293 ${sayhi()}
291 for idx, line in enumerate(inline(tmpl)): 307 for idx, line in enumerate(inline(tmpl)):
292 print '%3d %s' % (idx + 1, line) 308 print '%3d %s' % (idx + 1, line)
293 309
294 print 310 print
295 print 'Interpreted template:' 311 print 'Interpreted template:'
296 print tmpl.generate(ctxt) 312 print tmpl.generate(ctxt).render('html')
297 313
298 print 314 print
299 print 'Executed module:' 315 print 'Executed module:'
300 module = tmpl.compile() 316 module = tmpl.compile()
301 print Stream(module.generate(ctxt)) 317 print Stream(module.generate(ctxt)).render('html')
302 318
303 print 319 print
304 print 320 print
305 t = timeit.Timer('list(tmpl.generate(**data))', ''' 321 t = timeit.Timer('list(tmpl.generate(**data))', '''
306 from genshi.template import Context, MarkupTemplate 322 from genshi.template import Context, MarkupTemplate
Copyright (C) 2012-2017 Edgewall Software