root/livinglogic.python.xist/src/ll/ul4c.py @ 3716:815e6f979e09

Revision 3716:815e6f979e09, 87.2 KB (checked in by Walter Doerwald <walter@…>, 11 years ago)

Bump file format version.

Line 
1# -*- coding: utf-8 -*-
2
3## Copyright 2009 by LivingLogic AG, Bayreuth/Germany
4## Copyright 2009 by Walter Dörwald
5##
6## All Rights Reserved
7##
8## See ll/__init__.py for the license
9
10
11"""
12:mod:`ll.ul4c` provides templating for XML/HTML as well as any other text-based
13format. A template defines placeholders for data output and basic logic (like
14loops and conditional blocks), that define how the final rendered output will
15look.
16
17:mod:`ll.ul4c` compiles a template to a bytecode format, which makes it possible
18to implement template renderers in multiple programming languages.
19"""
20
21from __future__ import division
22
23__docformat__ = "reStructuredText"
24
25
26import re, datetime, StringIO, locale
27
28from ll import spark, color
29
30
31# Regular expression used for splitting dates
32datesplitter = re.compile("[-T:.]")
33
34
35###
36### Location information
37###
38
39class Location(object):
40    """
41    A :class:`Location` object contains information about the location of a
42    template tag.
43    """
44    __slots__ = ("source", "type", "starttag", "endtag", "startcode", "endcode")
45
46    def __init__(self, source, type, starttag, endtag, startcode, endcode):
47        """
48        Create a new :class:`Location` object. The arguments have the following
49        meaning:
50
51        :var:`source`
52            The complete source string
53
54        :var:`type`
55            The tag type (i.e. ``"for"``, ``"if"``, etc.)
56
57        :var:`starttag`
58            The start position of the start delimiter.
59
60        :var:`endtag`
61            The end position of the end delimiter.
62
63        :var:`startcode`
64            The start position of the tag code.
65
66        :var:`endcode`
67            The end position of the tag code.
68        """
69        self.source = source
70        self.type = type
71        self.starttag = starttag
72        self.endtag = endtag
73        self.startcode = startcode
74        self.endcode = endcode
75
76    @property
77    def code(self):
78        return self.source[self.startcode:self.endcode]
79
80    @property
81    def tag(self):
82        return self.source[self.starttag:self.endtag]
83
84    def __repr__(self):
85        return "<%s.%s %s at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self, id(self))
86
87    def pos(self):
88        lastlinefeed = self.source.rfind("\n", 0, self.starttag)
89        if lastlinefeed >= 0:
90            return (self.source.count("\n", 0, self.starttag)+1, self.starttag-lastlinefeed)
91        else:
92            return (1, self.starttag + 1)
93
94    def __str__(self):
95        (line, col) = self.pos()
96        return "%r at %d (line %d, col %d)" % (self.tag, self.starttag+1, line, col)
97
98
99###
100### Exceptions
101###
102
103class Error(Exception):
104    """
105    Exception class that wraps another exception and provides a location.
106    """
107    def __init__(self, location, cause):
108        self.location = location
109        self.cause = cause
110
111    def __repr__(self):
112        return "<%s.%s in %s at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.location, id(self))
113
114    def __str__(self):
115        path = []
116
117        exc = self
118        while isinstance(exc, Error):
119            if not path or path[-1] is not exc.location:
120                path.append(exc.location)
121            exc = exc.cause
122        name = exc.__class__.__name__
123        module = exc.__class__.__module__
124        if module != "exceptions":
125            name = "%s.%s" % (module, name)
126        return "%s %s %s" % (name, "".join("in %s:" % location for location in path), exc)
127
128
129class LexicalError(Exception):
130    def __init__(self, start, end, input):
131        self.start = start
132        self.end = end
133        self.input = input
134
135    def __str__(self):
136        return "Unmatched input %r" % self.input
137
138
139class SyntaxError(Exception):
140    def __init__(self, token):
141        self.token = token
142
143    def __str__(self):
144        return "Lexical error near %r" % str(self.token)
145
146
147class UnterminatedStringError(Exception):
148    """
149    Exception that is raised by the parser when a string constant is not
150    terminated.
151    """
152    def __str__(self):
153        return "Unterminated string"
154
155
156class BlockError(Exception):
157    """
158    Exception that is raised by the compiler when an illegal block structure is
159    detected (e.g. an ``endif`` without a previous ``if``).
160    """
161
162    def __init__(self, message):
163        self.message = message
164
165    def __str__(self):
166        return self.message
167
168
169class UnknownFunctionError(Exception):
170    """
171    Exception that is raised by the renderer if the function to be executed by
172    the ``callfunc0``, ``callfunc1``, ``callfunc2``, ``callfunc3`` or
173    ``callfunc4`` opcodes is unknown.
174    """
175
176    def __init__(self, funcname):
177        self.funcname = funcname
178
179    def __str__(self):
180        return "function %r unknown" % self.funcname
181
182
183class UnknownMethodError(Exception):
184    """
185    Exception that is raised by the renderer if the method to be executed by the
186    ``callmeth0``, ``callmeth1``, ``callmeth2``  or ``callmeth3`` opcodes is
187    unknown.
188    """
189
190    def __init__(self, methname):
191        self.methname = methname
192
193    def __str__(self):
194        return "method %r unknown" % self.methname
195
196
197class UnknownOpcodeError(Exception):
198    """
199    Exception that is raised when an unknown opcode is encountered by the renderer.
200    """
201
202    def __init__(self, opcode):
203        self.opcode = opcode
204
205    def __str__(self):
206        return "opcode %r unknown" % self.opcode
207
208
209class OutOfRegistersError(Exception):
210    """
211    Exception that is raised by the compiler when there are no more free
212    registers. This might happen with complex expressions in tag code.
213    """
214
215    def __str__(self):
216        return "out of registers"
217
218
219###
220### opcode class
221###
222
223class Opcode(object):
224    """
225    An :class:`Opcode` stores an opcode. An :class:`Opcode` object has the
226    following attributes:
227
228    :attr:`code` : string or :const:`None`
229        The opcode type (see below for a list).
230
231    :attr:`r1`, :attr:`r2`, :attr:`r3`, :attr:`r4`, :attr:`r5` : integer or :const:`None`
232         Register specifications (for the sources or the target of the opcode)
233
234    :attr:`arg` : string or :const:`None`
235        Used if the opcode requires an additional argument (like a variable name
236        or the value of a constant).
237
238    :attr:`location` : :class:`Location` object
239        The location of the tag to which this opcode belongs.
240
241    The following opcode types are available:
242
243    :const:`None`:
244        Print text. The text is available from ``location.code``.
245
246    ``"print"``:
247        Print the content of register :attr:`r1`. (If the object in the register
248        is not a string, it will be converted to a string first.)
249
250    ``"loadnone"``:
251        Load the constant :const:`None` into register :attr:`r1`.
252
253    ``"loadfalse"``:
254        Load the constant :const:`False` into register :attr:`r1`.
255
256    ``"loadtrue"``:
257        Load the constant :const:`True` into register :attr:`r1`.
258
259    ``"loadstr"``:
260        Load the string :attr:`arg` into register :attr:`r1`.
261
262    ``"loadint"``:
263        Load the integer value :attr:`arg` into register :attr:`r1`.
264
265    ``"loadfloat"``:
266        Load the float value :attr:`arg` into register :attr:`r1`.
267
268    ``"loaddate"``:
269        Load the date value :attr:`arg` into register :attr:`r1`. :attr:`arg` must
270        be in ISO format (e.g. ``2008-07-02T11:05:55.460464``).
271
272    ``"loadcolor"``:
273        Load the color value :attr:`arg` into register :attr:`r1`. :attr:`arg` must
274        be in the format ``rrggbbaa``).
275
276    ``"buildlist"``:
277        Load an empty list into register :attr:`r1`.
278
279    ``"builddict"``:
280        Load an empty dictionary into register :attr:`r1`.
281
282    ``"addlist"``
283        Append the object in register :attr:`r2` to the list in register :attr:`r1`.
284   
285    ``"adddict"``
286        Add a new entry to the dictionary in register :attr:`r1`. The object in
287        :attr:`r2` is the key and the object in register :attr:`r3` is the value.
288   
289    ``"updatedict"``
290        Update the dictionary in register :attr:`r1` with the items from the
291        dictionary in :attr:`r2`.
292   
293    ``"loadvar"``:
294        Load the variable named :attr:`arg` into the register :attr:`r1`.
295
296    ``"storevar"``:
297        Store the content of register :attr:`r1` in the variable named :attr:`arg`.
298
299    ``"addvar"``:
300        Add the content of register :attr:`r1` to the variable named :attr:`arg`.
301
302    ``"for"``:
303        Start a loop over the object in the register :attr:`r2` and store the
304        object from each loop iteration in the register :attr:`r1`.
305
306    ``"endfor"``:
307        End the innermost running ``for`` loop.
308
309    ``"break"``:
310        Breaks the innermost running ``for`` loop.
311
312    ``"continue"``:
313        Continues the innermost running ``for`` loop (i.e. jumps back to the
314        start of the loop body).
315
316    ``"if"``:
317        Start a conditional block. If the objects in the register :attr:`r1` is
318        true the block will be executed. The "block" consists of all opcodes after
319        the ``if`` upto the matching ``else`` or ``endif`` opcode.
320
321    ``"else"``:
322        Start the else branch of the previous ``if``.
323
324    ``"endif"``:
325        End a conditional block.
326
327    ``"getattr"``:
328        Get the attribute named :attr:`arg` from the object in register :attr:`r2`
329        and store it in register :attr:`r1`.
330
331    ``"getitem"``:
332        Get an item from the object in register :attr:`r2`. If this object is a
333        list or string the object in register :attr:`r3` will be used as the
334        index. If it is a dictionary :attr:`r3` will be used as the key. The
335        result will be stored in register :attr:`r1`.
336
337    ``"getslice12"``:
338        Get an slice from the object in register :attr:`r2`. The object in
339        register :attr:`r3` (which must be an ``int`` or :const:`None`) specifies
340        the start index, the object in register :attr:`r4` specifies the end index.
341        The result will be stored in register :attr:`r1`.
342
343    ``"getslice1"``:
344        Similar to ``getslice12`` except that the end index is always the length
345        of the object.
346
347    ``"getslice2"``:
348        Similar to ``getslice12`` except that the start index is always 0 and the
349        end index is in register :attr:`r3`.
350
351    ``"not"``:
352        Invert the truth value of the object in register :attr:`r2` and stores the
353        resulting bool in the register :attr:`r1`.
354
355    ``"eq"``:
356        Compare the objects in register :attr:`r2` and :attr:`r3` and store
357        ``True`` in the register :attr:`r1` if they are equal, ``False`` otherwise.
358
359    ``"ne"``:
360        Compare the objects in register :attr:`r2` and :attr:`r3` and store
361        ``False`` in the register :attr:`r1` if they are equal, ``True`` otherwise.
362
363    ``"lt"``:
364        Does a "<" comparison of the objects in register :attr:`r2` and :attr:`r3`
365        and stores the result in register :attr:`r1`.
366
367    ``"le"``:
368        Does a "<=" comparison of the objects in register :attr:`r2` and :attr:`r3`
369        and stores the result in register :attr:`r1`.
370
371    ``"gt"``:
372        Does a ">" comparison of the objects in register :attr:`r2` and :attr:`r3`
373        and stores the result in register :attr:`r1`.
374
375    ``"ge"``:
376        Does a ">=" comparison of the objects in register :attr:`r2` and :attr:`r3`
377        and stores the result in register :attr:`r1`.
378
379    ``"contains"``:
380        Test whether the object in register :attr:`r3` contains the object in
381        register :attr:`r2` (either as a key if :attr:`r3` is a dictionary or as
382        an item if it's a list or as a substring if it's a string) and store
383        ``True`` into the register :attr:`r1` if it does, ``False`` otherwise.
384
385    ``"notcontains"``:
386        Test whether the object in register :attr:`r3` contains the object in
387        register :attr:`r2` (either as a key if :attr:`r3` is a dictionary or as
388        an item if it's a list or as a substring if it's a string) and store
389        ``False`` into the register :attr:`r1` if it does, ``True`` otherwise.
390
391    ``"or"``:
392        Check the truth value of the two objects in registers :attr:`r2` and
393        :attr:`r3` and store :attr:`r2` in the register :attr:`r1` if it is true,
394        :attr:`r3` otherwise).
395
396    ``"and"``:
397        Check the truth value of the two objects in registers :attr:`r2` and
398        :attr:`r3` and store :attr:`r3` in the register :attr:`r1` if :attr:`r2`
399        is true, :attr:`r3` otherwise).
400
401    ``"mod"``:
402        Does a modulo operation: Calculates :attr:`r2` modulo :attr:`r3` and stores
403        the result in register :attr:`r1`.
404
405    ``"callfunc0"``:
406        Call the function named :attr:`arg` without any arguments and store the
407        return value in register :attr:`r1`.
408
409    ``"callfunc1"``:
410        Call the function named :attr:`arg` with the content of register :attr:`r2`
411        as an argument and store the return value in register :attr:`r1`.
412
413    ``"callfunc2"``:
414        Call the function named :attr:`arg` with the contents of register
415        :attr:`r2` and :attr:`r3` as the two arguments and store the return value
416        in register :attr:`r1`.
417
418    ``"callfunc3"``:
419        Call the function named :attr:`arg` with the contents of register
420        :attr:`r2`, :attr:`r3` and :attr:`r4` as the three arguments and store
421        the return value in register :attr:`r1`.
422
423    ``"callfunc4"``:
424        Call the function named :attr:`arg` with the contents of register
425        :attr:`r2`, :attr:`r3`, :attr:`r4` and :attr:`r5` as the four arguments
426        and store the return value in register :attr:`r1`.
427
428    ``"callmeth0"``:
429        Call the method named :attr:`arg` on the object in register :attr:`r2`
430        and store the return value in register :attr:`r1`.
431
432    ``"callmeth1"``:
433        Call the method named :attr:`arg` on the object in register :attr:`r2`
434        using the object in register :attr:`r3` as the only argument and store the
435        return value in register :attr:`r1`.
436
437    ``"callmeth2"``:
438        Call the method named :attr:`arg` on the object in register :attr:`r2`
439        using the objects in register :attr:`r3` and :attr:`r4` as arguments and
440        store the return value in register :attr:`r1`.
441
442    ``"callmeth3"``:
443        Call the method named :attr:`arg` on the object in register :attr:`r2`
444        using the objects in register :attr:`r3`, :attr:`r4` and :attr:`r5` as
445        arguments and store the return value in register :attr:`r1`.
446
447    ``"render"``:
448        Render the template in the attribute :attr:`r1`. The content of register
449        :attr:`r2` (which must be a dictionary) will be passed to the template as
450        the variable dictionary.
451    """
452    __slots__ = ("code", "r1", "r2", "r3", "r4", "r5", "arg", "location", "jump")
453
454    def __init__(self, code, r1=None, r2=None, r3=None, r4=None, r5=None, arg=None, location=None):
455        self.code = code
456        self.r1 = r1
457        self.r2 = r2
458        self.r3 = r3
459        self.r4 = r4
460        self.r5 = r5
461        self.arg = arg
462        self.location = location
463        self.jump = None
464
465    def __repr__(self):
466        v = ["<", self.__class__.__name__, " code=%r" % self.code]
467        for attrname in ("r1", "r2", "r3", "r4", "r5", "arg"):
468            attr = getattr(self, attrname)
469            if attr is not None:
470                v.append(" %s=%r" % (attrname, attr))
471        if self.code is None:
472            v.append(" text=%r" % self.location.code)
473        v.append(" at 0x%x>" % id(self))
474        return "".join(v)
475
476    def __str__(self):
477        if self.code is None:
478            return "print %r" % self.location.code
479        elif self.code == "print":
480            return "print r%r" % self.r1
481        elif self.code == "printx":
482            return "print xmlescape(r%r)" % self.r1
483        elif self.code == "loadnone":
484            return "r%r = None" % self.r1
485        elif self.code == "loadfalse":
486            return "r%r = False" % self.r1
487        elif self.code == "loadtrue":
488            return "r%r = True" % self.r1
489        elif self.code == "loadstr":
490            return "r%r = %r" % (self.r1, self.arg)
491        elif self.code == "loadint":
492            return "r%r = %s" % (self.r1, self.arg)
493        elif self.code == "loadfloat":
494            return "r%r = %s" % (self.r1, self.arg)
495        elif self.code == "loaddate":
496            return "r%r = %s" % (self.r1, self.arg)
497        elif self.code == "loadcolor":
498            return "r%r = #%s" % (self.r1, self.arg)
499        elif self.code == "buildlist":
500            return "r%r = []" % (self.r1)
501        elif self.code == "builddict":
502            return "r%r = {}" % (self.r1)
503        elif self.code == "addlist":
504            return "r%r.append(r%r)" % (self.r1, self.r2)
505        elif self.code == "adddict":
506            return "r%r[r%r] = r%r" % (self.r1, self.r2, self.r3)
507        elif self.code == "updatedict":
508            return "r%r.update(r%r)" % (self.r1, self.r2)
509        elif self.code == "loadvar":
510            return "r%r = vars[%r]" % (self.r1, self.arg)
511        elif self.code == "storevar":
512            return "vars[%r] = r%r" % (self.arg, self.r1)
513        elif self.code == "addvar":
514            return "vars[%r] += r%r" % (self.arg, self.r1)
515        elif self.code == "subvar":
516            return "vars[%r] -= r%r" % (self.arg, self.r1)
517        elif self.code == "mulvar":
518            return "vars[%r] *= r%r" % (self.arg, self.r1)
519        elif self.code == "truedivvar":
520            return "vars[%r] /= r%r" % (self.arg, self.r1)
521        elif self.code == "floordivvar":
522            return "vars[%r] //= r%r" % (self.arg, self.r1)
523        elif self.code == "modvar":
524            return "vars[%r] %%= r%r" % (self.arg, self.r1)
525        elif self.code == "delvar":
526            return "del vars[%r]" % self.arg
527        elif self.code == "for":
528            return "for r%r in r%r" % (self.r1, self.r2)
529        elif self.code == "endfor":
530            return "endfor"
531        elif self.code == "break":
532            return "break"
533        elif self.code == "continue":
534            return "continue"
535        elif self.code == "if":
536            return "if r%r" % self.r1
537        elif self.code == "else":
538            return "else"
539        elif self.code == "endif":
540            return "endif"
541        elif self.code == "getattr":
542            return "r%r = getattr(r%r, %r)" % (self.r1, self.r2, self.arg)
543        elif self.code == "getitem":
544            return "r%r = r%r[r%r]" % (self.r1, self.r2, self.r3)
545        elif self.code == "getslice1":
546            return "r%r = r%r[r%r:]" % (self.r1, self.r2, self.r3)
547        elif self.code == "getslice2":
548            return "r%r = r%r[:r%r]" % (self.r1, self.r2, self.r3)
549        elif self.code == "getslice12":
550            return "r%r = r%r[r%r:r%r]" % (self.r1, self.r2, self.r3, self.r4)
551        elif self.code == "not":
552            return "r%r = not r%r" % (self.r1, self.r2)
553        elif self.code == "eq":
554            return "r%r = r%r == r%r" % (self.r1, self.r2, self.r3)
555        elif self.code == "ne":
556            return "r%r = r%r != r%r" % (self.r1, self.r2, self.r3)
557        elif self.code == "lt":
558            return "r%r = r%r < r%r" % (self.r1, self.r2, self.r3)
559        elif self.code == "le":
560            return "r%r = r%r <= r%r" % (self.r1, self.r2, self.r3)
561        elif self.code == "gt":
562            return "r%r = r%r > r%r" % (self.r1, self.r2, self.r3)
563        elif self.code == "ge":
564            return "r%r = r%r >= r%r" % (self.r1, self.r2, self.r3)
565        elif self.code == "contains":
566            return "r%r = r%r in r%r" % (self.r1, self.r2, self.r3)
567        elif self.code == "notcontains":
568            return "r%r = r%r not in r%r" % (self.r1, self.r2, self.r3)
569        elif self.code == "add":
570            return "r%r = r%r + r%r" % (self.r1, self.r2, self.r3)
571        elif self.code == "sub":
572            return "r%r = r%r - r%r" % (self.r1, self.r2, self.r3)
573        elif self.code == "mul":
574            return "r%r = r%r * r%r" % (self.r1, self.r2, self.r3)
575        elif self.code == "floordiv":
576            return "r%r = r%r // r%r" % (self.r1, self.r2, self.r3)
577        elif self.code == "truediv":
578            return "r%r = r%r / r%r" % (self.r1, self.r2, self.r3)
579        elif self.code == "and":
580            return "r%r = r%r and r%r" % (self.r1, self.r2, self.r3)
581        elif self.code == "or":
582            return "r%r = r%r or r%r" % (self.r1, self.r2, self.r3)
583        elif self.code == "mod":
584            return "r%r = r%r %% r%r" % (self.r1, self.r2, self.r3)
585        elif self.code == "neg":
586            return "r%r = -r%r" % (self.r1, self.r2)
587        elif self.code == "callfunc0":
588            return "r%r = %s()" % (self.r1, self.arg)
589        elif self.code == "callfunc1":
590            return "r%r = %s(r%r)" % (self.r1, self.arg, self.r2)
591        elif self.code == "callfunc2":
592            return "r%r = %s(r%r, r%r)" % (self.r1, self.arg, self.r2, self.r3)
593        elif self.code == "callfunc3":
594            return "r%r = %s(r%r, r%r, r%r)" % (self.r1, self.arg, self.r2, self.r3, self.r4)
595        elif self.code == "callfunc4":
596            return "r%r = %s(r%r, r%r, r%r, r%r)" % (self.r1, self.arg, self.r2, self.r3, self.r4, self.r5)
597        elif self.code == "callmeth0":
598            return "r%r = r%r.%s()" % (self.r1, self.r2, self.arg)
599        elif self.code == "callmeth1":
600            return "r%r = r%r.%s(r%r)" % (self.r1, self.r2, self.arg, self.r3)
601        elif self.code == "callmeth2":
602            return "r%r = r%r.%s(r%r, r%r)" % (self.r1, self.r2, self.arg, self.r3, self.r4)
603        elif self.code == "callmeth3":
604            return "r%r = r%r.%s(r%r, r%r, r%r)" % (self.r1, self.r2, self.arg, self.r3, self.r4, self.r5)
605        elif self.code == "callmethkw":
606            return "r%r = r%r.%s(**r%r)" % (self.r1, self.r2, self.arg, self.r3)
607        elif self.code == "render":
608            return "render r%r(r%r)" % (self.r1, self.r2)
609        else:
610            raise UnknownOpcodeError(self.code)
611
612
613class Template(object):
614    """
615    A template object can be compiled via the class method :meth:`compile` from
616    source. It can be loaded from the compiled format via :meth:`load` (from a
617    stream) or :meth:`loads` (from a string).
618   
619    The compiled format can be generated with the methods :meth:`dump` (which
620    dumps the format to a stream) or :meth:`dumps` (which returns a string with
621    the compiled format).
622
623    Rendering the template can be done with the methods :meth:`render` (which
624    is a generator) or :meth:`renders` (which returns a string).
625    """
626    version = "10"
627
628    def __init__(self):
629        self.startdelim = None
630        self.enddelim = None
631        self.source = None
632        self.opcodes = None
633        # The following is used for converting the opcodes back to executable Python code
634        self._pythonfunction = None
635
636    @classmethod
637    def loads(cls, data):
638        """
639        The class method :meth:`loads` loads the template from string :var:`data`.
640        :var:`data` must contain the template in compiled format.
641        """
642        def _readint(term):
643            i = 0
644            while True:
645                c = stream.read(1)
646                if c.isdigit():
647                    i = 10*i+int(c)
648                elif c == term:
649                    return i
650                else:
651                    raise ValueError("invalid terminator, expected %r, got %r" % (term, c))
652
653        def _readstr(term):
654            i = 0
655            digit = False
656            while True:
657                c = stream.read(1)
658                if c.isdigit():
659                    i = 10*i+int(c)
660                    digit = True
661                elif c == term:
662                    if digit:
663                        break
664                    return None
665                else:
666                    raise ValueError("invalid terminator, expected %r, got %r" % (term, c))
667            s = stream.read(i)
668            if len(s) != i:
669                raise ValueError("short read")
670            return s
671
672        def _readspec():
673            c = stream.read(1)
674            if c == "-":
675                return None
676            elif c.isdigit():
677                return int(c)
678            else:
679                raise ValueError("invalid register spec %r" % c)
680
681        def _readcr():
682            c = stream.read(1)
683            if c != "\n":
684                raise ValueError("invalid linefeed %r" % c)
685
686        self = cls()
687        stream = StringIO.StringIO(data)
688        header = stream.readline()
689        header = header.rstrip()
690        if header != "ul4":
691            raise ValueError("invalid header, expected 'ul4', got %r" % header)
692        version = stream.readline()
693        version = version.rstrip()
694        if version != self.version:
695            raise ValueError("invalid version, expected %r got, %r" % (self.version, version))
696        self.startdelim = _readstr(u"<")
697        _readcr()
698        self.enddelim = _readstr(u">")
699        _readcr()
700        self.source = _readstr('"')
701        self.opcodes = []
702        _readcr()
703        count = _readint(u"#")
704        _readcr()
705        location = None
706        while count:
707            r1 = _readspec()
708            r2 = _readspec()
709            r3 = _readspec()
710            r4 = _readspec()
711            r5 = _readspec()
712            code = _readstr(":")
713            arg = _readstr(".")
714            locspec = stream.read(1)
715            if locspec == u"^":
716                if location is None:
717                    raise ValueError("no previous location")
718            elif locspec == u"*":
719                location = Location(self.source, _readstr("="), _readint("("), _readint(")"), _readint("{"), _readint("}"))
720            else:
721                raise ValueError("invalid location spec %r" % locspec)
722            _readcr()
723            count -= 1
724            self.opcodes.append(Opcode(code, r1, r2, r3, r4, r5, arg, location))
725        return self
726
727    @classmethod
728    def load(cls, stream):
729        """
730        The class method :meth:`load` loads the template from the stream
731        :var:`stream`. The stream must contain the template in compiled format.
732        """
733        return cls.loads(stream.read())
734
735    def iterdump(self):
736        """
737        This generator outputs the template in compiled format.
738        """
739        def _writeint(term, number):
740            yield unicode(number)
741            yield term
742
743        def _writestr(term, string):
744            if string is None:
745                yield term
746            else:
747                yield str(len(string))
748                yield term
749                yield string
750
751        yield "ul4\n%s\n" % self.version
752        for p in _writestr("<", self.startdelim): yield p
753        yield "\n"
754        for p in _writestr(">", self.enddelim): yield p
755        yield "\n"
756        for p in _writestr('"', self.source): yield p
757        yield "\n"
758        for p in _writeint("#", len(self.opcodes)): yield p
759        yield "\n"
760        lastlocation = None
761        for opcode in self.opcodes:
762            yield str(opcode.r1) if opcode.r1 is not None else u"-"
763            yield str(opcode.r2) if opcode.r2 is not None else u"-"
764            yield str(opcode.r3) if opcode.r3 is not None else u"-"
765            yield str(opcode.r4) if opcode.r4 is not None else u"-"
766            yield str(opcode.r5) if opcode.r5 is not None else u"-"
767            for p in _writestr(":", opcode.code): yield p
768            for p in _writestr(".", opcode.arg): yield p
769            if opcode.location is not lastlocation:
770                lastlocation = opcode.location
771                yield u"*"
772                for p in _writestr("=", lastlocation.type): yield p
773                for p in _writeint("(", lastlocation.starttag): yield p
774                for p in _writeint(")", lastlocation.endtag): yield p
775                for p in _writeint("{", lastlocation.startcode): yield p
776                for p in _writeint("}", lastlocation.endcode): yield p
777            else:
778                yield "^"
779            yield "\n"
780
781    def dump(self, stream):
782        """
783        :meth:`dump` dumps the template in compiled format to the stream
784        :var:`stream`.
785        """
786        for part in self.iterdump():
787            stream.write(part)
788
789    def dumps(self):
790        """
791        :meth:`dumps` returns the template in compiled format (as a string).
792        """
793        return "".join(self.iterdump())
794
795    def _pythonsource_dispatch_None(self, opcode):
796        self.lines.append("%syield %r" % (self.indent, opcode.location.code))
797
798    def _pythonsource_dispatch_loadstr(self, opcode):
799        self.lines.append("%sreg%d = %r" % (self.indent, opcode.r1, opcode.arg))
800
801    def _pythonsource_dispatch_loadint(self, opcode):
802        self.lines.append("%sreg%d = %s" % (self.indent, opcode.r1, opcode.arg))
803
804    def _pythonsource_dispatch_loadfloat(self, opcode):
805        self.lines.append("%sreg%d = %s" % (self.indent, opcode.r1, opcode.arg))
806
807    def _pythonsource_dispatch_loadnone(self, opcode):
808        self.lines.append("%sreg%d = None" % (self.indent, opcode.r1))
809
810    def _pythonsource_dispatch_loadfalse(self, opcode):
811        self.lines.append("%sreg%d = False" % (self.indent, opcode.r1))
812
813    def _pythonsource_dispatch_loadtrue(self, opcode):
814        self.lines.append("%sreg%d = True" % (self.indent, opcode.r1))
815
816    def _pythonsource_dispatch_loaddate(self, opcode):
817        self.lines.append("%sreg%d = datetime.datetime(%s)" % (self.indent, opcode.r1, ", ".join(str(int(p)) for p in datesplitter.split(opcode.arg))))
818
819    def _pythonsource_dispatch_loadcolor(self, opcode):
820        self.lines.append("%sreg%d = color.Color(0x%s, 0x%s, 0x%s, 0x%s)" % (self.indent, opcode.r1, opcode.arg[:2], opcode.arg[2:4], opcode.arg[4:6], opcode.arg[6:]))
821
822    def _pythonsource_dispatch_buildlist(self, opcode):
823        self.lines.append("%sreg%d = []" % (self.indent, opcode.r1))
824
825    def _pythonsource_dispatch_builddict(self, opcode):
826        self.lines.append("%sreg%d = {}" % (self.indent, opcode.r1))
827
828    def _pythonsource_dispatch_addlist(self, opcode):
829        self.lines.append("%sreg%d.append(reg%d)" % (self.indent, opcode.r1, opcode.r2))
830
831    def _pythonsource_dispatch_adddict(self, opcode):
832        self.lines.append("%sreg%d[reg%d] = reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
833
834    def _pythonsource_dispatch_updatedict(self, opcode):
835        self.lines.append("%sreg%d.update(reg%d)" % (self.indent, opcode.r1, opcode.r2))
836
837    def _pythonsource_dispatch_loadvar(self, opcode):
838        self.lines.append("%sreg%d = variables[%r]" % (self.indent, opcode.r1, opcode.arg))
839
840    def _pythonsource_dispatch_storevar(self, opcode):
841        self.lines.append("%svariables[%r] = reg%d" % (self.indent, opcode.arg, opcode.r1))
842
843    def _pythonsource_dispatch_addvar(self, opcode):
844        self.lines.append("%svariables[%r] += reg%d" % (self.indent, opcode.arg, opcode.r1))
845
846    def _pythonsource_dispatch_subvar(self, opcode):
847        self.lines.append("%svariables[%r] -= reg%d" % (self.indent, opcode.arg, opcode.r1))
848
849    def _pythonsource_dispatch_mulvar(self, opcode):
850        self.lines.append("%svariables[%r] *= reg%d" % (self.indent, opcode.arg, opcode.r1))
851
852    def _pythonsource_dispatch_truedivvar(self, opcode):
853        self.lines.append("%svariables[%r] /= reg%d" % (self.indent, opcode.arg, opcode.r1))
854
855    def _pythonsource_dispatch_floordivvar(self, opcode):
856        self.lines.append("%svariables[%r] //= reg%d" % (self.indent, opcode.arg, opcode.r1))
857
858    def _pythonsource_dispatch_modvar(self, opcode):
859        self.lines.append("%svariables[%r] %%= reg%d" % (self.indent, opcode.arg, opcode.r1))
860
861    def _pythonsource_dispatch_delvar(self, opcode):
862        self.lines.append("%sdel variables[%r]" % (self.indent, opcode.arg))
863
864    def _pythonsource_dispatch_getattr(self, opcode):
865        self.lines.append("%sreg%d = reg%d[%r]" % (self.indent, opcode.r1, opcode.r2, opcode.arg))
866
867    def _pythonsource_dispatch_getitem(self, opcode):
868        self.lines.append("%sreg%d = reg%d[reg%d]" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
869
870    def _pythonsource_dispatch_getslice12(self, opcode):
871        self.lines.append("%sreg%d = reg%d[reg%d:reg%d]" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
872
873    def _pythonsource_dispatch_getslice1(self, opcode):
874        self.lines.append("%sreg%d = reg%d[reg%d:]" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
875
876    def _pythonsource_dispatch_getslice2(self, opcode):
877        self.lines.append("%sreg%d = reg%d[:reg%d]" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
878
879    def _pythonsource_dispatch_print(self, opcode):
880        self.lines.append("%sif reg%d is not None: yield unicode(reg%d)" % (self.indent, opcode.r1, opcode.r1))
881
882    def _pythonsource_dispatch_printx(self, opcode):
883        self.lines.append("%sif reg%d is not None: yield xmlescape(unicode(reg%d))" % (self.indent, opcode.r1, opcode.r1))
884
885    def _pythonsource_dispatch_for(self, opcode):
886        self.lines.append("%sfor reg%d in reg%d:" % (self.indent, opcode.r1, opcode.r2))
887        self.indent += "\t"
888
889    def _pythonsource_dispatch_endfor(self, opcode):
890        # we don't have to check for empty loops here, as a ``<?for?>`` tag always generates at least one ``storevar`` opcode inside the loop
891        self.indent = self.indent[:-1]
892        self.lines.append("%s# end for" % self.indent)
893
894    def _pythonsource_dispatch_break(self, opcode):
895        self.lines.append("%sbreak" % self.indent)
896
897    def _pythonsource_dispatch_continue(self, opcode):
898        self.lines.append("%scontinue" % self.indent)
899
900    def _pythonsource_dispatch_not(self, opcode):
901        self.lines.append("%sreg%d = not reg%d" % (self.indent, opcode.r1, opcode.r2))
902
903    def _pythonsource_dispatch_neg(self, opcode):
904        self.lines.append("%sreg%d = -reg%d" % (self.indent, opcode.r1, opcode.r2))
905
906    def _pythonsource_dispatch_contains(self, opcode):
907        self.lines.append("%sreg%d = reg%d in reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
908
909    def _pythonsource_dispatch_notcontains(self, opcode):
910        self.lines.append("%sreg%d = reg%d not in reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
911
912    def _pythonsource_dispatch_eq(self, opcode):
913        self.lines.append("%sreg%d = reg%d == reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
914
915    def _pythonsource_dispatch_ne(self, opcode):
916        self.lines.append("%sreg%d = reg%d != reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
917
918    def _pythonsource_dispatch_lt(self, opcode):
919        self.lines.append("%sreg%d = reg%d < reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
920
921    def _pythonsource_dispatch_le(self, opcode):
922        self.lines.append("%sreg%d = reg%d <= reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
923
924    def _pythonsource_dispatch_gt(self, opcode):
925        self.lines.append("%sreg%d = reg%d > reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
926
927    def _pythonsource_dispatch_ge(self, opcode):
928        self.lines.append("%sreg%d = reg%d >= reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
929
930    def _pythonsource_dispatch_add(self, opcode):
931        self.lines.append("%sreg%d = reg%d + reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
932
933    def _pythonsource_dispatch_sub(self, opcode):
934        self.lines.append("%sreg%d = reg%d - reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
935
936    def _pythonsource_dispatch_mul(self, opcode):
937        self.lines.append("%sreg%d = reg%d * reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
938
939    def _pythonsource_dispatch_floordiv(self, opcode):
940        self.lines.append("%sreg%d = reg%d // reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
941
942    def _pythonsource_dispatch_truediv(self, opcode):
943        self.lines.append("%sreg%d = reg%d / reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
944
945    def _pythonsource_dispatch_and(self, opcode):
946        self.lines.append("%sreg%d = reg%d and reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
947
948    def _pythonsource_dispatch_or(self, opcode):
949        self.lines.append("%sreg%d = reg%d or reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
950
951    def _pythonsource_dispatch_mod(self, opcode):
952        self.lines.append("%sreg%d = reg%d %% reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
953
954    def _pythonsource_dispatch_mod(self, opcode):
955        self.lines.append("%sreg%d = reg%d %% reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
956
957    def _pythonsource_dispatch_callfunc0(self, opcode):
958        try:
959            getattr(self, "_pythonsource_dispatch_callfunc0_%s" % opcode.arg)(opcode)
960        except AttributeError:
961            raise UnknownFunctionError(opcode.arg)
962
963    def _pythonsource_dispatch_callfunc1(self, opcode):
964        try:
965            getattr(self, "_pythonsource_dispatch_callfunc1_%s" % opcode.arg)(opcode)
966        except AttributeError:
967            raise UnknownFunctionError(opcode.arg)
968
969    def _pythonsource_dispatch_callfunc2(self, opcode):
970        try:
971            getattr(self, "_pythonsource_dispatch_callfunc2_%s" % opcode.arg)(opcode)
972        except AttributeError:
973            raise UnknownFunctionError(opcode.arg)
974
975    def _pythonsource_dispatch_callfunc3(self, opcode):
976        try:
977            getattr(self, "_pythonsource_dispatch_callfunc3_%s" % opcode.arg)(opcode)
978        except AttributeError:
979            raise UnknownFunctionError(opcode.arg)
980
981    def _pythonsource_dispatch_callfunc4(self, opcode):
982        try:
983            getattr(self, "_pythonsource_dispatch_callfunc4_%s" % opcode.arg)(opcode)
984        except AttributeError:
985            raise UnknownFunctionError(opcode.arg)
986
987    def _pythonsource_dispatch_callmeth0(self, opcode):
988        if opcode.arg in ("split", "rsplit", "strip", "lstrip", "rstrip", "upper", "lower", "capitalize", "isoformat", "r", "g", "b", "a", "hls", "hlsa", "hsv", "hsva", "lum"):
989            self.lines.append("%sreg%d = reg%d.%s()" % (self.indent, opcode.r1, opcode.r2, opcode.arg))
990        elif opcode.arg == "items":
991            self.lines.append("%sreg%d = reg%d.iteritems()" % (self.indent, opcode.r1, opcode.r2))
992        elif opcode.arg == "render":
993            self.lines.append('%sreg%d = "".join(reg%d())' % (self.indent, opcode.r1, opcode.r2))
994        else:
995            raise UnknownMethodError(opcode.arg)
996
997    def _pythonsource_dispatch_callmeth1(self, opcode):
998        if opcode.arg in ("split", "rsplit", "strip", "lstrip", "rstrip", "startswith", "endswith", "find", "get", "withlum", "witha"):
999            self.lines.append("%sreg%d = reg%d.%s(reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.arg, opcode.r3))
1000        elif opcode.arg == "join":
1001            self.lines.append("%sreg%d = reg%d.join(unicode(x) for x in reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1002        elif opcode.arg == "format":
1003            self.lines.append("%sreg%d = ul4c._format(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1004        else:
1005            raise UnknownMethodError(opcode.arg)
1006
1007    def _pythonsource_dispatch_callmeth2(self, opcode):
1008        if opcode.arg in ("split", "rsplit", "find", "replace", "get"):
1009            self.lines.append("%sreg%d = reg%d.%s(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.arg, opcode.r3, opcode.r4))
1010        else:
1011            raise UnknownMethodError(opcode.arg)
1012
1013    def _pythonsource_dispatch_callmeth3(self, opcode):
1014        if opcode.arg == "find":
1015            self.lines.append("%sreg%d = reg%d.%s(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.arg, opcode.r3, opcode.r4, opcode.r5))
1016        else:
1017            raise UnknownMethodError(opcode.arg)
1018
1019    def _pythonsource_dispatch_callmethkw(self, opcode):
1020        if opcode.arg == "render":
1021            self.lines.append('%sreg%d = "".join(reg%d(**dict((key.encode("utf-8"), value) for (key, value) in reg%d.iteritems())))' % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1022        else:
1023            raise UnknownMethodError(opcode.arg)
1024
1025    def _pythonsource_dispatch_if(self, opcode):
1026        self.lines.append("%sif reg%d:" % (self.indent, opcode.r1))
1027        self.indent += "\t"
1028
1029    def _pythonsource_dispatch_else(self, opcode):
1030        if self.lastopcode == "if":
1031            self.lines[-1] += " pass"
1032        self.indent = self.indent[:-1]
1033        self.lines.append("%selse:" % self.indent)
1034        self.indent += "\t"
1035
1036    def _pythonsource_dispatch_endif(self, opcode):
1037        if self.lastopcode in ("if", "else"):
1038            self.lines[-1] += " pass"
1039        self.indent = self.indent[:-1]
1040        self.lines.append("%s# end if" % self.indent)
1041
1042    def _pythonsource_dispatch_render(self, opcode):
1043        self.lines.append('%sfor chunk in reg%d(**dict((key.encode("utf-8"), value) for (key, value) in reg%d.iteritems())): yield chunk' % (self.indent, opcode.r1, opcode.r2))
1044
1045    def _pythonsource_dispatch_callfunc0_now(self, opcode):
1046        self.lines.append("%sreg%d = datetime.datetime.now()" % (self.indent, opcode.r1))
1047
1048    def _pythonsource_dispatch_callfunc0_vars(self, opcode):
1049        self.lines.append("%sreg%d = variables" % (self.indent, opcode.r1))
1050
1051    def _pythonsource_dispatch_callfunc1_xmlescape(self, opcode):
1052        self.lines.append("%sreg%d = xmlescape(unicode(reg%d)) if reg%d is not None else u''" % (self.indent, opcode.r1, opcode.r2, opcode.r2))
1053
1054    def _pythonsource_dispatch_callfunc1_csv(self, opcode):
1055        self.lines.append("%sreg%d = ul4c._csv(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1056
1057    def _pythonsource_dispatch_callfunc1_json(self, opcode):
1058        self.lines.append("%sreg%d = json.dumps(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1059
1060    def _pythonsource_dispatch_callfunc1_str(self, opcode):
1061        self.lines.append("%sreg%d = unicode(reg%d) if reg%d is not None else u''" % (self.indent, opcode.r1, opcode.r2, opcode.r2))
1062
1063    def _pythonsource_dispatch_callfunc1_int(self, opcode):
1064        self.lines.append("%sreg%d = int(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1065
1066    def _pythonsource_dispatch_callfunc1_bool(self, opcode):
1067        self.lines.append("%sreg%d = bool(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1068
1069    def _pythonsource_dispatch_callfunc1_len(self, opcode):
1070        self.lines.append("%sreg%d = len(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1071
1072    def _pythonsource_dispatch_callfunc1_enumerate(self, opcode):
1073        self.lines.append("%sreg%d = enumerate(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1074
1075    def _pythonsource_dispatch_callfunc1_isnone(self, opcode):
1076        self.lines.append("%sreg%d = reg%d is None" % (self.indent, opcode.r1, opcode.r2))
1077
1078    def _pythonsource_dispatch_callfunc1_isstr(self, opcode):
1079        self.lines.append("%sreg%d = isinstance(reg%d, basestring)" % (self.indent, opcode.r1, opcode.r2))
1080
1081    def _pythonsource_dispatch_callfunc1_isint(self, opcode):
1082        self.lines.append("%sreg%d = isinstance(reg%d, (int, long)) and not isinstance(reg%d, bool)" % (self.indent, opcode.r1, opcode.r2, opcode.r2))
1083
1084    def _pythonsource_dispatch_callfunc1_isfloat(self, opcode):
1085        self.lines.append("%sreg%d = isinstance(reg%d, float)" % (self.indent, opcode.r1, opcode.r2))
1086
1087    def _pythonsource_dispatch_callfunc1_isbool(self, opcode):
1088        self.lines.append("%sreg%d = isinstance(reg%d, bool)" % (self.indent, opcode.r1, opcode.r2))
1089
1090    def _pythonsource_dispatch_callfunc1_isdate(self, opcode):
1091        self.lines.append("%sreg%d = isinstance(reg%d, datetime.datetime)" % (self.indent, opcode.r1, opcode.r2))
1092
1093    def _pythonsource_dispatch_callfunc1_islist(self, opcode):
1094        self.lines.append("%sreg%d = isinstance(reg%d, (list, tuple))" % (self.indent, opcode.r1, opcode.r2))
1095
1096    def _pythonsource_dispatch_callfunc1_isdict(self, opcode):
1097        self.lines.append("%sreg%d = isinstance(reg%d, dict)" % (self.indent, opcode.r1, opcode.r2))
1098
1099    def _pythonsource_dispatch_callfunc1_istemplate(self, opcode):
1100        self.lines.append("%sreg%d = hasattr(reg%d, '__call__')" % (self.indent, opcode.r1, opcode.r2)) # this supports normal generators too
1101
1102    def _pythonsource_dispatch_callfunc1_repr(self, opcode):
1103        self.lines.append("%sreg%d = ul4c._repr(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1104
1105    def _pythonsource_dispatch_callfunc1_get(self, opcode):
1106        self.lines.append("%sreg%d = variables.get(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1107
1108    def _pythonsource_dispatch_callfunc1_chr(self, opcode):
1109        self.lines.append("%sreg%d = unichr(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1110
1111    def _pythonsource_dispatch_callfunc1_ord(self, opcode):
1112        self.lines.append("%sreg%d = ord(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1113
1114    def _pythonsource_dispatch_callfunc1_hex(self, opcode):
1115        self.lines.append("%sreg%d = hex(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1116
1117    def _pythonsource_dispatch_callfunc1_oct(self, opcode):
1118        self.lines.append("%sreg%d = ul4c._oct(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1119
1120    def _pythonsource_dispatch_callfunc1_bin(self, opcode):
1121        self.lines.append("%sreg%d = ul4c._bin(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1122
1123    def _pythonsource_dispatch_callfunc1_sorted(self, opcode):
1124        self.lines.append("%sreg%d = sorted(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1125
1126    def _pythonsource_dispatch_callfunc1_range(self, opcode):
1127        self.lines.append("%sreg%d = xrange(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1128
1129    def _pythonsource_dispatch_callfunc1_type(self, opcode):
1130        self.lines.append("%sreg%d = ul4c._type(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1131
1132    def _pythonsource_dispatch_callfunc1_reversed(self, opcode):
1133        self.lines.append("%sreg%d = reversed(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1134
1135    def _pythonsource_dispatch_callfunc2_range(self, opcode):
1136        self.lines.append("%sreg%d = xrange(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1137
1138    def _pythonsource_dispatch_callfunc2_get(self, opcode):
1139        self.lines.append("%sreg%d = variables.get(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1140
1141    def _pythonsource_dispatch_callfunc2_zip(self, opcode):
1142        self.lines.append("%sreg%d = itertools.izip(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1143
1144    def _pythonsource_dispatch_callfunc2_int(self, opcode):
1145        self.lines.append("%sreg%d = int(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1146
1147    def _pythonsource_dispatch_callfunc3_range(self, opcode):
1148        self.lines.append("%sreg%d = xrange(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
1149
1150    def _pythonsource_dispatch_callfunc3_zip(self, opcode):
1151        self.lines.append("%sreg%d = itertools.izip(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
1152
1153    def _pythonsource_dispatch_callfunc3_rgb(self, opcode):
1154        self.lines.append("%sreg%d = color.Color.fromrgb(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
1155
1156    def _pythonsource_dispatch_callfunc3_hls(self, opcode):
1157        self.lines.append("%sreg%d = color.Color.fromhls(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
1158
1159    def _pythonsource_dispatch_callfunc3_hsv(self, opcode):
1160        self.lines.append("%sreg%d = color.Color.fromhsv(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
1161
1162    def _pythonsource_dispatch_callfunc4_rgb(self, opcode):
1163        self.lines.append("%sreg%d = color.Color.fromrgb(reg%d, reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4, opcode.r5))
1164
1165    def _pythonsource_dispatch_callfunc4_hls(self, opcode):
1166        self.lines.append("%sreg%d = color.Color.fromhls(reg%d, reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4, opcode.r5))
1167
1168    def _pythonsource_dispatch_callfunc4_hsv(self, opcode):
1169        self.lines.append("%sreg%d = color.Color.fromhsv(reg%d, reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4, opcode.r5))
1170
1171    def pythonsource(self, function=None):
1172        """
1173        Return the template as Python source code. If :var:`function` is specified
1174        the code will be wrapped in a function with this name.
1175        """
1176        self.indent = ""
1177        self.lines = []
1178
1179        if function is not None:
1180            self.lines.append("%sdef %s(**variables):" % (self.indent, function))
1181            self.indent += "\t"
1182        self.lines.append("%simport sys, datetime, itertools" % self.indent)
1183        self.lines.append("%stry:" % self.indent)
1184        self.indent += "\t"
1185        self.lines.append("%simport json" % self.indent)
1186        self.indent = self.indent[:-1]
1187        self.lines.append("%sexcept ImportError:" % self.indent)
1188        self.indent += "\t"
1189        self.lines.append("%stry:" % self.indent)
1190        self.indent += "\t"
1191        self.lines.append("%simport simplejson as json" % self.indent)
1192        self.indent = self.indent[:-1]
1193        self.lines.append("%sexcept ImportError:" % self.indent)
1194        self.indent += "\t"
1195        self.lines.append("%spass" % self.indent)
1196        self.indent = self.indent[:-2]
1197        self.lines.append("%sfrom ll.misc import xmlescape" % self.indent)
1198        self.lines.append("%sfrom ll import ul4c, color" % self.indent)
1199        self.lines.append("%ssource = %r" % (self.indent, self.source))
1200        self.lines.append('%svariables = dict((key.decode("utf-8"), value) for (key, value) in variables.iteritems())' % self.indent) # FIXME: This can be dropped in Python 3.0 where strings are unicode
1201        locations = []
1202        lines2locs = []
1203        index = -1
1204        for oc in self.opcodes:
1205            loc = (oc.location.type, oc.location.starttag, oc.location.endtag, oc.location.startcode, oc.location.endcode)
1206            if not locations or locations[-1] != loc:
1207                locations.append(loc)
1208                index += 1
1209            lines2locs.append(index)
1210        locations = tuple(locations)
1211        lines2locs = tuple(lines2locs)
1212        self.lines.append("%sreg0 = reg1 = reg2 = reg3 = reg4 = reg5 = reg6 = reg7 = reg8 = reg9 = None" % self.indent)
1213        self.lines.append("%stry:" % self.indent)
1214        self.indent += "\t"
1215        self.lines.append("%sstartline = sys._getframe().f_lineno+1" % self.indent) # The source line of the first opcode
1216        try:
1217            self.lastopcode = None
1218            for opcode in self.opcodes:
1219                # The following code ensures that each opcode outputs exactly one source code line
1220                # This makes it possible in case of an error to find out which opcode produced the error
1221                try:
1222                    getattr(self, "_pythonsource_dispatch_%s" % opcode.code)(opcode)
1223                except AttributeError:
1224                    raise UnknownOpcodeError(opcode.code)
1225                self.lastopcode = opcode.code
1226        except Exception, exc:
1227            raise #Error(opcode.location, exc)
1228        self.indent = self.indent[:-1]
1229        self.lines.append("%sexcept Exception, exc:" % self.indent)
1230        self.indent += "\t"
1231        self.lines.append("%slocations = %r" % (self.indent, locations))
1232        self.lines.append("%slines2locs = %r" % (self.indent, lines2locs))
1233        self.lines.append("%sraise ul4c.Error(ul4c.Location(source, *locations[lines2locs[sys.exc_info()[2].tb_lineno-startline]]), exc)" % self.indent)
1234        result = "\n".join(self.lines)
1235        del self.lines
1236        del self.indent
1237        return result
1238
1239    def pythonfunction(self):
1240        """
1241        Return a Python generator that can be called to render the template. The
1242        argument signature of the function will be ``**variables``.
1243        """
1244        if self._pythonfunction is None:
1245            code = self.pythonsource("render")
1246            ns = {}
1247            exec code.encode("utf-8") in ns # FIXME: no need to encode in Python 3.0
1248            self._pythonfunction = ns["render"]
1249        return self._pythonfunction
1250
1251    def __call__(self, **variables):
1252        return self.pythonfunction()(**variables)
1253
1254    def render(self, **variables):
1255        """
1256        Render the template iteratively (i.e. this is a generator).
1257        :var:`variables` contains the top level variables available to the
1258        template code.
1259        """
1260        return self.pythonfunction()(**variables)
1261
1262    def renders(self, **variables):
1263        """
1264        Render the template as a string. :var:`variables` contains the top level
1265        variables available to the template code.
1266        """
1267        return "".join(self.render(**variables))
1268
1269    def format(self, indent="\t"):
1270        """
1271        Format the list of opcodes. This is a generator yielding lines to be output
1272        (but without trailing newlines). :var:`indent` can be used to specify how
1273        to indent blocks (defaulting to ``"\\t"``).
1274        """
1275        i = 0
1276        for opcode in self.opcodes:
1277            if opcode.code in ("else", "endif", "endfor"):
1278                i -= 1
1279            if opcode.code in ("endif", "endfor"):
1280                yield "%s}" % (i*indent)
1281            elif opcode.code in ("for", "if"):
1282                yield "%s%s {" % (i*indent, opcode)
1283            elif opcode.code == "else":
1284                yield "%s} else {" % (i*indent)
1285            else:
1286                yield "%s%s" % (i*indent, opcode)
1287            if opcode.code in ("for", "if", "else"):
1288                i += 1
1289
1290    def _tokenize(self, source, startdelim, enddelim):
1291        """
1292        Tokenize the template source code :var:`source` into tags and non-tag
1293        text. :var:`startdelim` and :var:`enddelim` are used as the tag delimiters.
1294
1295        This is a generator which produces :class:`Location` objects for each tag
1296        or non-tag text. It will be called by :meth:`_compile` internally.
1297        """
1298        pattern = u"%s(printx|print|code|for|if|elif|else|end|break|continue|render|note)(\s*((.|\\n)*?)\s*)?%s" % (re.escape(startdelim), re.escape(enddelim))
1299        pos = 0
1300        for match in re.finditer(pattern, source):
1301            if match.start() != pos:
1302                yield Location(source, None, pos, match.start(), pos, match.start())
1303            type = source[match.start(1):match.end(1)]
1304            if type != "note":
1305                yield Location(source, type, match.start(), match.end(), match.start(3), match.end(3))
1306            pos = match.end()
1307        end = len(source)
1308        if pos != end:
1309            yield Location(source, None, pos, end, pos, end)
1310
1311    def _allocreg(self):
1312        """
1313        Allocates a free register from the pool of available registers.
1314        """
1315        try:
1316            return self.registers.pop()
1317        except KeyError:
1318            raise OutOfRegistersError()
1319
1320    def _freereg(self, register):
1321        """
1322        Returns the register :var:`register` to the pool of available registers.
1323        """
1324        self.registers.add(register)
1325
1326    def opcode(self, code, r1=None, r2=None, r3=None, r4=None, r5=None, arg=None):
1327        """
1328        Creates an :class:`Opcode` object and appends it to :var:`self`\s list of
1329        opcodes.
1330        """
1331        self.opcodes.append(Opcode(code, r1, r2, r3, r4, r5, arg, self.location))
1332
1333    def _compile(self, source, startdelim, enddelim):
1334        """
1335        Compile the template source code :var:`source` into opcodes.
1336        :var:`startdelim` and :var:`enddelim` are used as the tag delimiters.
1337        """
1338        self.startdelim = startdelim
1339        self.enddelim = enddelim
1340        scanner = Scanner()
1341        parseexpr = ExprParser(scanner).compile
1342        parsestmt = StmtParser(scanner).compile
1343        parsefor = ForParser(scanner).compile
1344        parserender = RenderParser(scanner).compile
1345
1346        # This stack stores for each nested for/foritem/if/elif/else the following information:
1347        # 1) Which construct we're in (i.e. "if" or "for")
1348        # 2) The start location of the construct
1349        # For ifs:
1350        # 3) How many if's or elif's we have seen (this is used for simulating elif's via nested if's, for each additional elif, we have one more endif to add)
1351        # 4) Whether we've already seen the else
1352        stack = []
1353
1354        self.source = source
1355        self.opcodes = []
1356
1357        for location in self._tokenize(source, startdelim, enddelim):
1358            self.location = location
1359            try:
1360                if location.type is None:
1361                    self.opcode(None)
1362                elif location.type == "print":
1363                    r = parseexpr(self)
1364                    self.opcode("print", r1=r)
1365                elif location.type == "printx":
1366                    r = parseexpr(self)
1367                    self.opcode("printx", r1=r)
1368                elif location.type == "code":
1369                    parsestmt(self)
1370                elif location.type == "if":
1371                    r = parseexpr(self)
1372                    self.opcode("if", r1=r)
1373                    stack.append(("if", location, 1, False))
1374                elif location.type == "elif":
1375                    if not stack or stack[-1][0] != "if":
1376                        raise BlockError("elif doesn't match any if")
1377                    elif stack[-1][3]:
1378                        raise BlockError("else already seen in elif")
1379                    self.opcode("else")
1380                    r = parseexpr(self)
1381                    self.opcode("if", r1=r)
1382                    stack[-1] = ("if", stack[-1][1], stack[-1][2]+1, False)
1383                elif location.type == "else":
1384                    if not stack or stack[-1][0] != "if":
1385                        raise BlockError("else doesn't match any if")
1386                    elif stack[-1][3]:
1387                        raise BlockError("duplicate else")
1388                    self.opcode("else")
1389                    stack[-1] = ("if", stack[-1][1], stack[-1][2], True)
1390                elif location.type == "end":
1391                    if not stack:
1392                        raise BlockError("not in any block")
1393                    code = location.code
1394                    if code:
1395                        if code == "if":
1396                            if stack[-1][0] != "if":
1397                                raise BlockError("endif doesn't match any if")
1398                        elif code == "for":
1399                            if stack[-1][0] != "for":
1400                                raise BlockError("endfor doesn't match any for")
1401                        else:
1402                            raise BlockError("illegal end value %r" % code)
1403                    last = stack.pop()
1404                    if last[0] == "if":
1405                        for i in xrange(last[2]):
1406                            self.opcode("endif")
1407                    else: # last[0] == "for":
1408                        self.opcode("endfor")
1409                elif location.type == "for":
1410                    parsefor(self)
1411                    stack.append(("for", location))
1412                elif location.type == "break":
1413                    if not any(entry[0] == "for" for entry in stack):
1414                        raise BlockError("break outside of for loop")
1415                    self.opcode("break")
1416                elif location.type == "continue":
1417                    if not any(entry[0] == "for" for entry in stack):
1418                        raise BlockError("continue outside of for loop")
1419                    self.opcode("continue")
1420                elif location.type == "render":
1421                    parserender(self)
1422                else: # Can't happen
1423                    raise ValueError("unknown tag %r" % location.type)
1424            except Exception, exc:
1425                raise Error(location, exc)
1426            finally:
1427                del self.location
1428        if stack:
1429            raise Error(stack[-1][1], BlockError("block unclosed"))
1430
1431    def __str__(self):
1432        return "\n".join(self.format())
1433
1434    def __unicode__(self):
1435        return u"\n".join(self.format())
1436
1437    def __repr__(self):
1438        return "<%s.%s object with %d opcodes at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, len(self.opcodes), id(self))
1439
1440
1441def compile(source, startdelim="<?", enddelim="?>"):
1442    template = Template()
1443    template._compile(source, startdelim, enddelim)
1444    return template
1445
1446load = Template.load
1447loads = Template.loads
1448
1449
1450###
1451### Tokens and nodes for the AST
1452###
1453
1454class Token(object):
1455    def __init__(self, start, end, type):
1456        self.start = start
1457        self.end = end
1458        self.type = type
1459
1460    def __repr__(self):
1461        return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.type)
1462
1463    def __str__(self):
1464        return self.type
1465
1466
1467class AST(object):
1468    """
1469    Baseclass for all syntax tree nodes.
1470    """
1471
1472    def __init__(self, start, end):
1473        self.start = start
1474        self.end = end
1475
1476
1477class Const(AST):
1478    """
1479    Common baseclass for all constants (used for type testing in constant folding)
1480    """
1481
1482    def __repr__(self):
1483        return "%s(%r, %r)" % (self.__class__.__name__, self.start, self.end)
1484
1485    def compile(self, template):
1486        r = template._allocreg()
1487        template.opcode("load%s" % self.type, r1=r)
1488        return r
1489
1490
1491class None_(Const):
1492    type = "none"
1493    value = None
1494
1495
1496class True_(Const):
1497    type = "true"
1498    value = True
1499
1500
1501class False_(Const):
1502    type = "false"
1503    value = False
1504
1505
1506class Value(Const):
1507    def __init__(self, start, end, value):
1508        Const.__init__(self, start, end)
1509        self.value = value
1510
1511    def __repr__(self):
1512        return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.value)
1513
1514    def compile(self, template):
1515        r = template._allocreg()
1516        template.opcode("load%s" % self.type, r1=r, arg=unicode(self.value))
1517        return r
1518
1519
1520class Int(Value):
1521    type = "int"
1522
1523
1524class Float(Value):
1525    type = "float"
1526
1527    def compile(self, template):
1528        r = template._allocreg()
1529        template.opcode("load%s" % self.type, r1=r, arg=repr(self.value))
1530        return r
1531
1532
1533class Str(Value):
1534    type = "str"
1535
1536
1537class Date(Value):
1538    type = "date"
1539
1540    def compile(self, template):
1541        r = template._allocreg()
1542        template.opcode("load%s" % self.type, r1=r, arg=self.value.isoformat())
1543        return r
1544
1545
1546class Color(Value):
1547    type = "color"
1548
1549    def compile(self, template):
1550        r = template._allocreg()
1551        template.opcode("load%s" % self.type, r1=r, arg="%02x%02x%02x%02x" % self.value)
1552        return r
1553
1554
1555class List(AST):
1556    def __init__(self, start, end, *items):
1557        AST.__init__(self, start, end)
1558        self.items = list(items)
1559
1560    def __repr__(self):
1561        return "%s(%r, %r, %s)" % (self.__class__.__name__, self.start, self.end, repr(self.items)[1:-1])
1562
1563    def compile(self, template):
1564        r = template._allocreg()
1565        template.opcode("buildlist", r1=r)
1566        for item in self.items:
1567            ri = item.compile(template)
1568            template.opcode("addlist", r1=r, r2=ri)
1569            template._freereg(ri)
1570        return r
1571
1572
1573class Dict(AST):
1574    def __init__(self, start, end, *items):
1575        AST.__init__(self, start, end)
1576        self.items = list(items)
1577
1578    def __repr__(self):
1579        return "%s(%r, %r, %s)" % (self.__class__.__name__, self.start, self.end, repr(self.items)[1:-1])
1580
1581    def compile(self, template):
1582        r = template._allocreg()
1583        template.opcode("builddict", r1=r)
1584        for item in self.items:
1585            if len(item) == 1:
1586                rd = item[0].compile(template)
1587                template.opcode("updatedict", r1=r, r2=rd)
1588                template._freereg(rd)
1589            else:
1590                (key, value) = item
1591                rk = key.compile(template)
1592                rv = value.compile(template)
1593                template.opcode("adddict", r1=r, r2=rk, r3=rv)
1594                template._freereg(rk)
1595                template._freereg(rv)
1596        return r
1597
1598
1599class Name(AST):
1600    type = "name"
1601
1602    def __init__(self, start, end, name):
1603        AST.__init__(self, start, end)
1604        self.name = name
1605
1606    def __repr__(self):
1607        return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name)
1608
1609    def compile(self, template):
1610        r = template._allocreg()
1611        template.opcode("loadvar", r1=r, arg=self.name)
1612        return r
1613
1614
1615class For(AST):
1616    def __init__(self, start, end, iter, cont):
1617        AST.__init__(self, start, end)
1618        self.iter = iter
1619        self.cont = cont
1620
1621    def __repr__(self):
1622        return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.iter, self.cont)
1623
1624    def compile(self, template):
1625        rc = self.cont.compile(template)
1626        ri = template._allocreg()
1627        template.opcode("for", r1=ri, r2=rc)
1628        if isinstance(self.iter, list):
1629            for (i, iter) in enumerate(self.iter):
1630                rii = template._allocreg()
1631                template.opcode("loadint", r1=rii, arg=str(i))
1632                template.opcode("getitem", r1=rii, r2=ri, r3=rii)
1633                template.opcode("storevar", r1=rii, arg=iter.name)
1634                template._freereg(rii)
1635        else:
1636            template.opcode("storevar", r1=ri, arg=self.iter.name)
1637        template._freereg(ri)
1638        template._freereg(rc)
1639
1640
1641class GetAttr(AST):
1642    def __init__(self, start, end, obj, attr):
1643        AST.__init__(self, start, end)
1644        self.obj = obj
1645        self.attr = attr
1646
1647    def __repr__(self):
1648        return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.obj, self.attr)
1649
1650    def compile(self, template):
1651        r = self.obj.compile(template)
1652        template.opcode("getattr", r1=r, r2=r, arg=self.attr.name)
1653        return r
1654
1655
1656class GetSlice12(AST):
1657    def __init__(self, start, end, obj, index1, index2):
1658        AST.__init__(self, start, end)
1659        self.obj = obj
1660        self.index1 = index1
1661        self.index2 = index2
1662
1663    def __repr__(self):
1664        return "%s(%r, %r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.obj, self.index1, self.index2)
1665
1666    def compile(self, template):
1667        r1 = self.obj.compile(template)
1668        r2 = self.index1.compile(template)
1669        r3 = self.index2.compile(template)
1670        template.opcode("getslice12", r1=r1, r2=r1, r3=r2, r4=r3)
1671        template._freereg(r2)
1672        template._freereg(r3)
1673        return r1
1674
1675
1676class Unary(AST):
1677    opcode = None
1678
1679    def __init__(self, start, end, obj):
1680        AST.__init__(self, start, end)
1681        self.obj = obj
1682
1683    def __repr__(self):
1684        return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.obj)
1685
1686    def compile(self, template):
1687        r = self.obj.compile(template)
1688        template.opcode(self.opcode, r1=r, r2=r)
1689        return r
1690
1691
1692class Not(Unary):
1693    opcode = "not"
1694
1695
1696class Neg(Unary):
1697    opcode = "neg"
1698
1699
1700class Binary(AST):
1701    opcode = None
1702
1703    def __init__(self, start, end, obj1, obj2):
1704        AST.__init__(self, start, end)
1705        self.obj1 = obj1
1706        self.obj2 = obj2
1707
1708    def __repr__(self):
1709        return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.obj1, self.obj2)
1710
1711    def compile(self, template):
1712        r1 = self.obj1.compile(template)
1713        r2 = self.obj2.compile(template)
1714        template.opcode(self.opcode, r1=r1, r2=r1, r3=r2)
1715        template._freereg(r2)
1716        return r1
1717
1718
1719class GetItem(Binary):
1720    opcode = "getitem"
1721
1722
1723class GetSlice1(Binary):
1724    opcode = "getslice1"
1725
1726
1727class GetSlice2(Binary):
1728    opcode = "getslice2"
1729
1730
1731class EQ(Binary):
1732    opcode = "eq"
1733
1734
1735class NE(Binary):
1736    opcode = "ne"
1737
1738
1739class LT(Binary):
1740    opcode = "lt"
1741
1742
1743class LE(Binary):
1744    opcode = "le"
1745
1746
1747class GT(Binary):
1748    opcode = "gt"
1749
1750
1751class GE(Binary):
1752    opcode = "ge"
1753
1754
1755class Contains(Binary):
1756    opcode = "contains"
1757
1758
1759class NotContains(Binary):
1760    opcode = "notcontains"
1761
1762
1763class Add(Binary):
1764    opcode = "add"
1765
1766
1767class Sub(Binary):
1768    opcode = "sub"
1769
1770
1771class Mul(Binary):
1772    opcode = "mul"
1773
1774
1775class FloorDiv(Binary):
1776    opcode = "floordiv"
1777
1778
1779class TrueDiv(Binary):
1780    opcode = "truediv"
1781
1782
1783class Or(Binary):
1784    opcode = "or"
1785
1786
1787class And(Binary):
1788    opcode = "and"
1789
1790
1791class Mod(Binary):
1792    opcode = "mod"
1793
1794
1795class ChangeVar(AST):
1796    opcode = None
1797
1798    def __init__(self, start, end, name, value):
1799        AST.__init__(self, start, end)
1800        self.name = name
1801        self.value = value
1802
1803    def __repr__(self):
1804        return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name, self.value)
1805
1806    def compile(self, template):
1807        r = self.value.compile(template)
1808        template.opcode(self.opcode, r1=r, arg=self.name.name)
1809        template._freereg(r)
1810
1811
1812class StoreVar(ChangeVar):
1813    opcode = "storevar"
1814
1815
1816class AddVar(ChangeVar):
1817    opcode = "addvar"
1818
1819
1820class SubVar(ChangeVar):
1821    opcode = "subvar"
1822
1823
1824class MulVar(ChangeVar):
1825    opcode = "mulvar"
1826
1827
1828class TrueDivVar(ChangeVar):
1829    opcode = "truedivvar"
1830
1831
1832class FloorDivVar(ChangeVar):
1833    opcode = "floordivvar"
1834
1835
1836class ModVar(ChangeVar):
1837    opcode = "modvar"
1838
1839
1840class DelVar(AST):
1841    def __init__(self, start, end, name):
1842        AST.__init__(self, start, end)
1843        self.name = name
1844
1845    def __repr__(self):
1846        return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name)
1847
1848    def compile(self, template):
1849        template.opcode("delvar", arg=self.name.name)
1850
1851
1852class CallFunc(AST):
1853    def __init__(self, start, end, name, args):
1854        AST.__init__(self, start, end)
1855        self.name = name
1856        self.args = args
1857
1858    def __repr__(self):
1859        if self.args:
1860            return "%s(%r, %r, %r, %s)" % (self.__class__.__name__, self.start, self.end, self.name, repr(self.args)[1:-1])
1861        else:
1862            return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name)
1863
1864    def compile(self, template):
1865        if len(self.args) == 0:
1866            r = template._allocreg()
1867            template.opcode("callfunc0", r1=r, arg=self.name.name)
1868            return r
1869        elif len(self.args) > 4:
1870            raise ValueError("%d function arguments not supported" % len(self.args))
1871        else:
1872            rs = [arg.compile(template) for arg in self.args]
1873            template.opcode("callfunc%d" % len(self.args), rs[0], *rs, **dict(arg=self.name.name)) # FIXME: Replace **dict(arg=) with arg= in Python 2.6?
1874            for i in xrange(1, len(self.args)):
1875                template._freereg(rs[i])
1876            return rs[0]
1877
1878
1879class CallMeth(AST):
1880    def __init__(self, start, end, name, obj, args):
1881        AST.__init__(self, start, end)
1882        self.name = name
1883        self.obj = obj
1884        self.args = args
1885
1886    def __repr__(self):
1887        if self.args:
1888            return "%s(%r, %r, %r, %r, %s)" % (self.__class__.__name__, self.start, self.end, self.name, self.obj, repr(self.args)[1:-1])
1889        else:
1890            return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name, self.obj)
1891
1892    def compile(self, template):
1893        if len(self.args) > 3:
1894            raise ValueError("%d method arguments not supported" % len(self.args))
1895        ro = self.obj.compile(template)
1896        rs = [arg.compile(template) for arg in self.args]
1897        template.opcode("callmeth%d" % len(self.args), ro, ro, *rs, **dict(arg=self.name.name))
1898        for r in rs:
1899            template._freereg(r)
1900        return ro
1901
1902
1903class CallMethKeywords(AST):
1904    def __init__(self, start, end, name, obj, args):
1905        AST.__init__(self, start, end)
1906        self.name = name
1907        self.obj = obj
1908        self.args = args
1909
1910    def __repr__(self):
1911        return "%s(%r, %r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name, self.obj, self.args)
1912
1913    def compile(self, template):
1914        ra = template._allocreg()
1915        template.opcode("builddict", r1=ra)
1916        for item in self.args:
1917            if len(item) == 1:
1918                rd = item[0].compile(template)
1919                template.opcode("updatedict", r1=ra, r2=rd)
1920                template._freereg(rd)
1921            else:
1922                (key, value) = item
1923                rv = value.compile(template)
1924                rk = template._allocreg()
1925                template.opcode("loadstr", r1=rk, arg=key.name)
1926                template.opcode("adddict", r1=ra, r2=rk, r3=rv)
1927                template._freereg(rk)
1928                template._freereg(rv)
1929        ro = self.obj.compile(template)
1930        template.opcode("callmethkw", r1=ro, r2=ro, r3=ra, arg=self.name.name)
1931        template._freereg(ra)
1932        return ro
1933
1934
1935class Render(AST):
1936    def __init__(self, start, end, template, *variables):
1937        AST.__init__(self, start, end)
1938        self.template = template
1939        self.variables = list(variables)
1940
1941    def __repr__(self):
1942        return "%s(%r, %r, %r, %s)" % (self.__class__.__name__, self.start, self.end, self.template, repr(self.variables)[1:-1])
1943
1944    def compile(self, template):
1945        ra = template._allocreg()
1946        template.opcode("builddict", r1=ra)
1947        for item in self.variables:
1948            if len(item) == 1:
1949                rd = item[0].compile(template)
1950                template.opcode("updatedict", r1=ra, r2=rd)
1951                template._freereg(rd)
1952            else:
1953                (key, value) = item
1954                rv = value.compile(template)
1955                rk = template._allocreg()
1956                template.opcode("loadstr", r1=rk, arg=key.name)
1957                template.opcode("adddict", r1=ra, r2=rk, r3=rv)
1958                template._freereg(rk)
1959                template._freereg(rv)
1960        rt = self.template.compile(template)
1961        template.opcode("render", r1=rt, r2=ra)
1962        template._freereg(rt)
1963        template._freereg(ra)
1964
1965
1966###
1967### Tokenizer
1968###
1969
1970class Scanner(spark.Scanner):
1971    reflags = re.UNICODE
1972
1973    def tokenize(self, location):
1974        self.collectstr = []
1975        self.rv = []
1976        self.start = 0
1977        try:
1978            spark.Scanner.tokenize(self, location.code)
1979            if self.mode != "default":
1980                raise UnterminatedStringError()
1981        except Exception, exc:
1982            raise Error(location, exc)
1983        return self.rv
1984
1985    # Color tokens must be in the order of decreasing length
1986    @spark.token("\\#[0-9a-fA-F]{8}", "default")
1987    def color8(self, start, end, s):
1988        self.rv.append(Color(start, end, color.Color(int(s[1:3], 16), int(s[3:5], 16), int(s[5:7], 16), int(s[7:], 16))))
1989
1990    @spark.token("\\#[0-9a-fA-F]{6}", "default")
1991    def color6(self, start, end, s):
1992        self.rv.append(Color(start, end, color.Color(int(s[1:3], 16), int(s[3:5], 16), int(s[5:], 16))))
1993
1994    @spark.token("\\#[0-9a-fA-F]{4}", "default")
1995    def color4(self, start, end, s):
1996        self.rv.append(Color(start, end, color.Color(17*int(s[1], 16), 17*int(s[2], 16), 17*int(s[3], 16), 17*int(s[4], 16))))
1997
1998    @spark.token("\\#[0-9a-fA-F]{3}", "default")
1999    def color3(self, start, end, s):
2000        self.rv.append(Color(start, end, color.Color(17*int(s[1], 16), 17*int(s[2], 16), 17*int(s[3], 16))))
2001
2002    # Must be before the int and float constants
2003    @spark.token("\\d{4}-\\d{2}-\\d{2}T(\\d{2}:\\d{2}(:\\d{2}(\\.\\d{6})?)?)?", "default")
2004    def date(self, start, end, s):
2005        self.rv.append(Date(start, end, datetime.datetime(*map(int, filter(None, datesplitter.split(s))))))
2006
2007    @spark.token("\\(|\\)|\\[|\\]|\\{|\\}|\\.|,|==|\\!=|<=|<|>=|>|=|\\+=|\\-=|\\*=|//=|/=|%=|%|:|\\+|-|\\*\\*|\\*|//|/", "default")
2008    def token(self, start, end, s):
2009        self.rv.append(Token(start, end, s))
2010
2011    @spark.token("[a-zA-Z_][\\w]*", "default")
2012    def name(self, start, end, s):
2013        if s in ("in", "not", "or", "and", "del"):
2014            self.rv.append(Token(start, end, s))
2015        elif s == "None":
2016            self.rv.append(None_(start, end))
2017        elif s == "True":
2018            self.rv.append(True_(start, end))
2019        elif s == "False":
2020            self.rv.append(False_(start, end))
2021        else:
2022            self.rv.append(Name(start, end, s))
2023
2024    # We don't have negatve numbers, this is handled by constant folding in the AST for unary minus
2025    @spark.token("\\d+\\.\\d*([eE][+-]?\\d+)?", "default")
2026    @spark.token("\\d+(\\.\\d*)?[eE][+-]?\\d+", "default")
2027    def float(self, start, end, s):
2028        self.rv.append(Float(start, end, float(s)))
2029
2030    @spark.token("0[xX][\\da-fA-F]+", "default")
2031    def hexint(self, start, end, s):
2032        self.rv.append(Int(start, end, int(s[2:], 16)))
2033
2034    @spark.token("0[oO][0-7]+", "default")
2035    def octint(self, start, end, s):
2036        self.rv.append(Int(start, end, int(s[2:], 8)))
2037
2038    @spark.token("0[bB][01]+", "default")
2039    def binint(self, start, end, s):
2040        self.rv.append(Int(start, end, int(s[2:], 2)))
2041
2042    @spark.token("\\d+", "default")
2043    def int(self, start, end, s):
2044        self.rv.append(Int(start, end, int(s)))
2045
2046    @spark.token("'", "default")
2047    def beginstr1(self, start, end, s):
2048        self.mode = "str1"
2049        self.start = start
2050
2051    @spark.token('"', "default")
2052    def beginstr2(self, start, end, s):
2053        self.mode = "str2"
2054        self.start = start
2055
2056    @spark.token("'", "str1")
2057    @spark.token('"', "str2")
2058    def endstr(self, start, end, s):
2059        self.rv.append(Str(self.start, end, "".join(self.collectstr)))
2060        self.collectstr = []
2061        self.mode = "default"
2062
2063    @spark.token("\\s+", "default")
2064    def whitespace(self, start, end, s):
2065        pass
2066
2067    @spark.token("\\\\\\\\", "str1", "str2")
2068    def escapedbackslash(self, start, end, s):
2069        self.collectstr.append("\\")
2070
2071    @spark.token("\\\\'", "str1", "str2")
2072    def escapedapos(self, start, end, s):
2073        self.collectstr.append("'")
2074
2075    @spark.token('\\\\"', "str1", "str2")
2076    def escapedquot(self, start, end, s):
2077        self.collectstr.append('"')
2078
2079    @spark.token("\\\\a", "str1", "str2")
2080    def escapedbell(self, start, end, s):
2081        self.collectstr.append("\a")
2082
2083    @spark.token("\\\\b", "str1", "str2")
2084    def escapedbackspace(self, start, end, s):
2085        self.collectstr.append("\b")
2086
2087    @spark.token("\\\\f", "str1", "str2")
2088    def escapedformfeed(self, start, end, s):
2089        self.collectstr.append("\f")
2090
2091    @spark.token("\\\\n", "str1", "str2")
2092    def escapedlinefeed(self, start, end, s):
2093        self.collectstr.append("\n")
2094
2095    @spark.token("\\\\r", "str1", "str2")
2096    def escapedcarriagereturn(self, start, end, s):
2097        self.collectstr.append("\r")
2098
2099    @spark.token("\\\\t", "str1", "str2")
2100    def escapedtab(self, start, end, s):
2101        self.collectstr.append("\t")
2102
2103    @spark.token("\\\\v", "str1", "str2")
2104    def escapedverticaltab(self, start, end, s):
2105        self.collectstr.append("\v")
2106
2107    @spark.token("\\\\e", "str1", "str2")
2108    def escapedescape(self, start, end, s):
2109        self.collectstr.append("\x1b")
2110
2111    @spark.token("\\\\x[0-9a-fA-F]{2}", "str1", "str2")
2112    def escaped8bitchar(self, start, end, s):
2113        self.collectstr.append(unichr(int(s[2:], 16)))
2114
2115    @spark.token("\\\\u[0-9a-fA-F]{4}", "str1", "str2")
2116    def escaped16bitchar(self, start, end, s):
2117        self.collectstr.append(unichr(int(s[2:], 16)))
2118
2119    @spark.token(".|\\n", "str1", "str2")
2120    def text(self, start, end, s):
2121        self.collectstr.append(s)
2122
2123    @spark.token("(.|\\n)+", "default", "str1", "str2")
2124    def default(self, start, end, s):
2125        raise LexicalError(start, end, s)
2126
2127    def error(self, start, end, s):
2128        raise LexicalError(start, end, s)
2129
2130
2131###
2132### Parsers for different types of code
2133###
2134
2135class ExprParser(spark.Parser):
2136    emptyerror = "expression required"
2137    start = "expr0"
2138
2139    def __init__(self, scanner):
2140        spark.Parser.__init__(self)
2141        self.scanner = scanner
2142
2143    def compile(self, template):
2144        location = template.location
2145        if not location.code:
2146            raise ValueError(self.emptyerror)
2147        template.registers = set(xrange(10))
2148        try:
2149            ast = self.parse(self.scanner.tokenize(location))
2150            return ast.compile(template)
2151        except Exception, exc:
2152            raise Error(location, exc)
2153        finally:
2154            del template.registers
2155
2156    def typestring(self, token):
2157        return token.type
2158
2159    def error(self, token):
2160        raise SyntaxError(token)
2161
2162    def makeconst(self, start, end, value):
2163        if value is None:
2164            return None_(start, end)
2165        elif value is True:
2166            return True_(start, end)
2167        elif value is False:
2168            return False_(start, end)
2169        elif isinstance(value, int):
2170            return Int(start, end, value)
2171        elif isinstance(value, float):
2172            return Float(start, end, value)
2173        elif isinstance(value, basestring):
2174            return Str(start, end, value)
2175        elif isinstance(value, color.Color):
2176            return Color(start, end, value)
2177        else:
2178            raise TypeError("can't convert %r" % value)
2179
2180    # To implement operator precedence, each expression rule has the precedence in its name. The highest precedence is 11 for atomic expressions.
2181    # Each expression can have only expressions as parts which have the some or a higher precedence with two exceptions:
2182    #    1. Expressions where there's no ambiguity, like the index for a getitem/getslice or function/method arguments;
2183    #    2. Brackets, which can be used to boost the precedence of an expression to the level of an atomic expression.
2184
2185    @spark.production('expr11 ::= none')
2186    @spark.production('expr11 ::= true')
2187    @spark.production('expr11 ::= false')
2188    @spark.production('expr11 ::= str')
2189    @spark.production('expr11 ::= int')
2190    @spark.production('expr11 ::= float')
2191    @spark.production('expr11 ::= date')
2192    @spark.production('expr11 ::= color')
2193    @spark.production('expr11 ::= name')
2194    def expr_atom(self, atom):
2195        return atom
2196
2197    @spark.production('expr11 ::= [ ]')
2198    def expr_emptylist(self, _0, _1):
2199        return List(_0.start, _1.end)
2200
2201    @spark.production('buildlist ::= [ expr0')
2202    def expr_buildlist(self, _0, expr):
2203        return List(_0.start, expr.end, expr)
2204
2205    @spark.production('buildlist ::= buildlist , expr0')
2206    def expr_addlist(self, list, _0, expr):
2207        list.items.append(expr)
2208        list.end = expr.end
2209        return list
2210
2211    @spark.production('expr11 ::= buildlist ]')
2212    def expr_finishlist(self, list, _0):
2213        list.end = _0.end
2214        return list
2215
2216    @spark.production('expr11 ::= buildlist , ]')
2217    def expr_finishlist1(self, list, _0, _1):
2218        list.end = _1.end
2219        return list
2220
2221    @spark.production('expr11 ::= { }')
2222    def expr_emptydict(self, _0, _1):
2223        return Dict(_0.start, _1.end)
2224
2225    @spark.production('builddict ::= { expr0 : expr0')
2226    def expr_builddict(self, _0, exprkey, _1, exprvalue):
2227        return Dict(_0.start, exprvalue.end, (exprkey, exprvalue))
2228
2229    @spark.production('builddict ::= { ** expr0')
2230    def expr_builddictupdate(self, _0, _1, expr):
2231        return Dict(_0.start, expr.end, (expr,))
2232
2233    @spark.production('builddict ::= builddict , expr0 : expr0')
2234    def expr_adddict(self, dict, _0, exprkey, _1, exprvalue):
2235        dict.items.append((exprkey, exprvalue))
2236        dict.end = exprvalue.end
2237        return dict
2238
2239    @spark.production('builddict ::= builddict , ** expr0')
2240    def expr_updatedict(self, dict, _0, _1, expr):
2241        dict.items.append((expr,))
2242        dict.end = expr.end
2243        return dict
2244
2245    @spark.production('expr11 ::= builddict }')
2246    def expr_finishdict(self, dict, _0):
2247        dict.end = _0.end
2248        return dict
2249
2250    @spark.production('expr11 ::= builddict , }')
2251    def expr_finishdict1(self, dict, _0, _1):
2252        dict.end = _1.end
2253        return dict
2254
2255    @spark.production('expr11 ::= ( expr0 )')
2256    def expr_bracket(self, _0, expr, _1):
2257        return expr
2258
2259    @spark.production('expr10 ::= name ( )')
2260    def expr_callfunc0(self, name, _0, _1):
2261        return CallFunc(name.start, _1.end, name, [])
2262
2263    @spark.production('expr10 ::= name ( expr0 )')
2264    def expr_callfunc1(self, name, _0, arg0, _1):
2265        return CallFunc(name.start, _1.end, name, [arg0])
2266
2267    @spark.production('expr10 ::= name ( expr0 , expr0 )')
2268    def expr_callfunc2(self, name, _0, arg0, _1, arg1, _2):
2269        return CallFunc(name.start, _2.end, name, [arg0, arg1])
2270
2271    @spark.production('expr10 ::= name ( expr0 , expr0 , expr0 )')
2272    def expr_callfunc3(self, name, _0, arg0, _1, arg1, _2, arg2, _3):
2273        return CallFunc(name.start, _3.end, name, [arg0, arg1, arg2])
2274
2275    @spark.production('expr10 ::= name ( expr0 , expr0 , expr0 , expr0 )')
2276    def expr_callfunc4(self, name, _0, arg0, _1, arg1, _2, arg2, _3, arg3, _4):
2277        return CallFunc(name.start, _4.end, name, [arg0, arg1, arg2, arg3])
2278
2279    @spark.production('expr9 ::= expr9 . name')
2280    def expr_getattr(self, expr, _0, name):
2281        return GetAttr(expr.start, name.end, expr, name)
2282
2283    @spark.production('expr9 ::= expr9 . name ( )')
2284    def expr_callmeth0(self, expr, _0, name, _1, _2):
2285        return CallMeth(expr.start, _2.end, name, expr, [])
2286
2287    @spark.production('expr9 ::= expr9 . name ( expr0 )')
2288    def expr_callmeth1(self, expr, _0, name, _1, arg1, _2):
2289        return CallMeth(expr.start, _2.end, name, expr, [arg1])
2290
2291    @spark.production('expr9 ::= expr9 . name ( expr0 , expr0 )')
2292    def expr_callmeth2(self, expr, _0, name, _1, arg1, _2, arg2, _3):
2293        return CallMeth(expr.start, _3.end, name, expr, [arg1, arg2])
2294
2295    @spark.production('expr9 ::= expr9 . name ( expr0 , expr0 , expr0 )')
2296    def expr_callmeth3(self, expr, _0, name, _1, arg1, _2, arg2, _3, arg3, _4):
2297        return CallMeth(expr.start, _4.end, name, expr, [arg1, arg2, arg3])
2298
2299    @spark.production('callmethkw ::= expr9 . name ( name = expr0')
2300    def methkw_startname(self, expr, _0, methname, _1, argname, _2, argvalue):
2301        return CallMethKeywords(expr.start, argvalue.end, methname, expr, [(argname, argvalue)])
2302
2303    @spark.production('callmethkw ::= expr9 . name ( ** expr0')
2304    def methkw_startdict(self, expr, _0, methname, _1, _2, argvalue):
2305        return CallMethKeywords(expr.start, argvalue.end, methname, expr, [(argvalue,)])
2306
2307    @spark.production('callmethkw ::= callmethkw , name = expr0')
2308    def methkw_buildname(self, call, _0, argname, _1, argvalue):
2309        call.args.append((argname, argvalue))
2310        call.end = argvalue.end
2311        return call
2312
2313    @spark.production('callmethkw ::= callmethkw , ** expr0')
2314    def methkw_builddict(self, call, _0, _1, argvalue):
2315        call.args.append((argvalue,))
2316        call.end = argvalue.end
2317        return call
2318
2319    @spark.production('expr9 ::= callmethkw )')
2320    def methkw_finish(self, call, _0):
2321        call.end = _0.end
2322        return call
2323
2324    @spark.production('expr9 ::= expr9 [ expr0 ]')
2325    def expr_getitem(self, expr, _0, key, _1):
2326        if isinstance(expr, Const) and isinstance(key, Const): # Constant folding
2327            return self.makeconst(expr.start, _1.end, expr.value[key.value])
2328        return GetItem(expr.start, _1.end, expr, key)
2329
2330    @spark.production('expr8 ::= expr8 [ expr0 : expr0 ]')
2331    def expr_getslice12(self, expr, _0, index1, _1, index2, _2):
2332        if isinstance(expr, Const) and isinstance(index1, Const) and isinstance(index2, Const): # Constant folding
2333            return self.makeconst(expr.start, _2.end, expr.value[index1.value:index2.value])
2334        return GetSlice12(expr.start, _2.end, expr, index1, index2)
2335
2336    @spark.production('expr8 ::= expr8 [ expr0 : ]')
2337    def expr_getslice1(self, expr, _0, index1, _1, _2):
2338        if isinstance(expr, Const) and isinstance(index1, Const): # Constant folding
2339            return self.makeconst(expr.start, _2.end, expr.value[index1.value:])
2340        return GetSlice1(expr.start, _2.end, expr, index1)
2341
2342    @spark.production('expr8 ::= expr8 [ : expr0 ]')
2343    def expr_getslice2(self, expr, _0, _1, index2, _2):
2344        if isinstance(expr, Const) and isinstance(index2, Const): # Constant folding
2345            return self.makeconst(expr.start, _2.end, expr.value[:index2.value])
2346        return GetSlice2(expr.start, _2.end, expr, index2)
2347
2348    @spark.production('expr7 ::= - expr7')
2349    def expr_neg(self, _0, expr):
2350        if isinstance(expr, Const): # Constant folding
2351            return self.makeconst(_0.start, expr.end, -expr.value)
2352        return Neg(_0.start, expr.end, expr)
2353
2354    @spark.production('expr6 ::= expr6 * expr6')
2355    def expr_mul(self, obj1, _0, obj2):
2356        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2357            return self.makeconst(obj1.start, obj2.end, obj1.value * obj2.value)
2358        return Mul(obj1.start, obj2.end, obj1, obj2)
2359
2360    @spark.production('expr6 ::= expr6 // expr6')
2361    def expr_floordiv(self, obj1, _0, obj2):
2362        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2363            return self.makeconst(obj1.start, obj2.end, obj1.value // obj2.value)
2364        return FloorDiv(obj1.start, obj2.end, obj1, obj2)
2365
2366    @spark.production('expr6 ::= expr6 / expr6')
2367    def expr_truediv(self, obj1, _0, obj2):
2368        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2369            return self.makeconst(obj1.start, obj2.end, obj1.value / obj2.value)
2370        return TrueDiv(obj1.start, obj2.end, obj1, obj2)
2371
2372    @spark.production('expr6 ::= expr6 % expr6')
2373    def expr_mod(self, obj1, _0, obj2):
2374        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2375            return self.makeconst(obj1.start, obj2.end, obj1.value % obj2.value)
2376        return Mod(obj1.start, obj2.end, obj1, obj2)
2377
2378    @spark.production('expr5 ::= expr5 + expr5')
2379    def expr_add(self, obj1, _0, obj2):
2380        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2381            return self.makeconst(obj1.start, obj2.end, obj1.value + obj2.value)
2382        return Add(obj1.start, obj2.end, obj1, obj2)
2383
2384    @spark.production('expr5 ::= expr5 - expr5')
2385    def expr_sub(self, obj1, _0, obj2):
2386        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2387            return self.makeconst(obj1.start, obj2.end, obj1.value - obj2.value)
2388        return Sub(obj1.start, obj2.end, obj1, obj2)
2389
2390    @spark.production('expr4 ::= expr4 == expr4')
2391    def expr_eq(self, obj1, _0, obj2):
2392        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2393            return self.makeconst(obj1.start, obj2.end, obj1.value == obj2.value)
2394        return EQ(obj1.start, obj2.end, obj1, obj2)
2395
2396    @spark.production('expr4 ::= expr4 != expr4')
2397    def expr_ne(self, obj1, _0, obj2):
2398        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2399            return self.makeconst(obj1.start, obj2.end, obj1.value != obj2.value)
2400        return NE(obj1.start, obj2.end, obj1, obj2)
2401
2402    @spark.production('expr4 ::= expr4 < expr4')
2403    def expr_lt(self, obj1, _0, obj2):
2404        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2405            return self.makeconst(obj1.start, obj2.end, obj1.value < obj2.value)
2406        return LT(obj1.start, obj2.end, obj1, obj2)
2407
2408    @spark.production('expr4 ::= expr4 <= expr4')
2409    def expr_le(self, obj1, _0, obj2):
2410        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2411            return self.makeconst(obj1.start, obj2.end, obj1.value <= obj2.value)
2412        return LE(obj1.start, obj2.end, obj1, obj2)
2413
2414    @spark.production('expr4 ::= expr4 > expr4')
2415    def expr_gt(self, obj1, _0, obj2):
2416        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2417            return self.makeconst(obj1.start, obj2.end, obj1.value > obj2.value)
2418        return GT(obj1.start, obj2.end, obj1, obj2)
2419
2420    @spark.production('expr4 ::= expr4 >= expr4')
2421    def expr_ge(self, obj1, _0, obj2):
2422        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2423            return self.makeconst(obj1.start, obj2.end, obj1.value >= obj2.value)
2424        return GE(obj1.start, obj2.end, obj1, obj2)
2425
2426    @spark.production('expr3 ::= expr3 in expr3')
2427    def expr_contains(self, obj, _0, container):
2428        if isinstance(obj, Const) and isinstance(container, Const): # Constant folding
2429            return self.makeconst(obj.start, container.end, obj.value in container.value)
2430        return Contains(obj.start, container.end, obj, container)
2431
2432    @spark.production('expr3 ::= expr3 not in expr3')
2433    def expr_notcontains(self, obj, _0, _1, container):
2434        if isinstance(obj, Const) and isinstance(container, Const): # Constant folding
2435            return self.makeconst(obj.start, container.end, obj.value not in container.value)
2436        return NotContains(obj.start, container.end, obj, container)
2437
2438    @spark.production('expr2 ::= not expr2')
2439    def expr_not(self, _0, expr):
2440        if isinstance(expr, Const): # Constant folding
2441            return self.makeconst(_0.start, expr.end, not expr.value)
2442        return Not(_0.start, expr.end, expr)
2443
2444    @spark.production('expr1 ::= expr1 and expr1')
2445    def expr_and(self, obj1, _0, obj2):
2446        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2447            return self.makeconst(obj1.start, obj2.end, bool(obj1.value and obj2.value))
2448        return And(obj1.start, obj2.end, obj1, obj2)
2449
2450    @spark.production('expr0 ::= expr0 or expr0')
2451    def expr_or(self, obj1, _0, obj2):
2452        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2453            return self.makeconst(obj1.start, obj2.end, bool(obj1.value or obj2.value))
2454        return Or(obj1.start, obj2.end, obj1, obj2)
2455
2456    # These rules make operators of different precedences interoperable, by allowing an expression to "drop" its precedence.
2457    @spark.production('expr10 ::= expr11')
2458    @spark.production('expr9 ::= expr10')
2459    @spark.production('expr8 ::= expr9')
2460    @spark.production('expr7 ::= expr8')
2461    @spark.production('expr6 ::= expr7')
2462    @spark.production('expr5 ::= expr6')
2463    @spark.production('expr4 ::= expr5')
2464    @spark.production('expr3 ::= expr4')
2465    @spark.production('expr2 ::= expr3')
2466    @spark.production('expr1 ::= expr2')
2467    @spark.production('expr0 ::= expr1')
2468    def expr_dropprecedence(self, expr):
2469        return expr
2470
2471
2472class ForParser(ExprParser):
2473    emptyerror = "loop expression required"
2474    start = "for"
2475   
2476    @spark.production('for ::= name in expr0')
2477    def for0(self, iter, _0, cont):
2478        return For(iter.start, cont.end, iter, cont)
2479
2480    @spark.production('for ::= ( name , ) in expr0')
2481    def for1(self, _0, iter, _1, _2, _3, cont):
2482        return For(_0.start, cont.end, [iter], cont)
2483
2484    @spark.production('for ::= ( name , name ) in expr0')
2485    def for2a(self, _0, iter1, _1, iter2, _2, _3, cont):
2486        return For(_0.start, cont.end, [iter1, iter2], cont)
2487
2488    @spark.production('for ::= ( name , name , ) in expr0')
2489    def for2b(self, _0, iter1, _1, iter2, _2, _3, _4, cont):
2490        return For(_0.start, cont.end, [iter1, iter2], cont)
2491
2492    @spark.production('for ::= ( name , name , name ) in expr0')
2493    def for3a(self, _0, iter1, _1, iter2, _2, iter3, _3, _4, cont):
2494        return For(_0.start, cont.end, [iter1, iter2, iter3], cont)
2495
2496    @spark.production('for ::= ( name , name , name , ) in expr0')
2497    def for3b(self, _0, iter1, _1, iter2, _2, iter3, _3, _4, _5, cont):
2498        return For(_0.start, cont.end, [iter1, iter2, iter3], cont)
2499
2500
2501class StmtParser(ExprParser):
2502    emptyerror = "statement required"
2503    start = "stmt"
2504
2505    @spark.production('stmt ::= name = expr0')
2506    def stmt_assign(self, name, _0, value):
2507        return StoreVar(name.start, value.end, name, value)
2508
2509    @spark.production('stmt ::= name += expr0')
2510    def stmt_iadd(self, name, _0, value):
2511        return AddVar(name.start, value.end, name, value)
2512
2513    @spark.production('stmt ::= name -= expr0')
2514    def stmt_isub(self, name, _0, value):
2515        return SubVar(name.start, value.end, name, value)
2516
2517    @spark.production('stmt ::= name *= expr0')
2518    def stmt_imul(self, name, _0, value):
2519        return MulVar(name.start, value.end, name, value)
2520
2521    @spark.production('stmt ::= name /= expr0')
2522    def stmt_itruediv(self, name, _0, value):
2523        return TrueDivVar(name.start, value.end, name, value)
2524
2525    @spark.production('stmt ::= name //= expr0')
2526    def stmt_ifloordiv(self, name, _0, value):
2527        return FloorDivVar(name.start, value.end, name, value)
2528
2529    @spark.production('stmt ::= name %= expr0')
2530    def stmt_imod(self, name, _0, value):
2531        return ModVar(name.start, value.end, name, value)
2532
2533    @spark.production('stmt ::= del name')
2534    def stmt_del(self, _0, name):
2535        return DelVar(_0.start, name.end, name)
2536
2537
2538class RenderParser(ExprParser):
2539    emptyerror = "render statement required"
2540    start = "render"
2541
2542    @spark.production('render ::= expr0 ( )')
2543    def emptyrender(self, template, _0, _1):
2544        return Render(template.start, _1.end, template)
2545
2546    @spark.production('buildrender ::= expr0 ( name = expr0')
2547    def startrender(self, template, _0, argname, _1, argvalue):
2548        return Render(template.start, argvalue.end, template, (argname, argvalue))
2549
2550    @spark.production('buildrender ::= expr0 ( ** expr0')
2551    def startrenderupdate(self, template, _0, _1, arg):
2552        return Render(template.start, arg.end, template, (arg, ))
2553
2554    @spark.production('buildrender ::= buildrender , name = expr0')
2555    def buildrender(self, render, _0, argname, _1, argvalue):
2556        render.variables.append((argname, argvalue))
2557        render.end = argvalue.end
2558        return render
2559
2560    @spark.production('buildrender ::= buildrender , ** expr0')
2561    def buildrenderupdate(self, render, _0, _1, arg):
2562        render.variables.append((arg,))
2563        render.end = arg.end
2564        return render
2565
2566    @spark.production('render ::= buildrender )')
2567    def finishrender(self, render, _0):
2568        render.end = _0.end
2569        return render
2570
2571    @spark.production('render ::= buildrender , )')
2572    def finishrender1(self, render, _0, _1):
2573        render.end = _1.end
2574        return render
2575
2576
2577###
2578### Helper functions used at template runtime
2579###
2580
2581def _oct(value):
2582    """
2583    Helper for the ``oct`` function.
2584    """
2585    if value == 0:
2586        return "0o0"
2587    elif value < 0:
2588        return "-0o" + oct(value)[2:]
2589    else:
2590        return "0o" + oct(value)[1:]
2591
2592
2593def _bin(value):
2594    """
2595    Helper for the ``bin`` function.
2596    """
2597    if value == 0:
2598        return "0b0"
2599    if value < 0:
2600        value = -value
2601        prefix = "-0b"
2602    else:
2603        prefix = "0b"
2604    v = []
2605    while value:
2606        v.append(str(value&1))
2607        value >>= 1
2608    return prefix+"".join(v)[::-1]
2609
2610
2611def _format(obj, format):
2612    """
2613    Helper for the ``format`` method.
2614    """
2615    if isinstance(obj, datetime.datetime):
2616        if "%f" in format:
2617            format = format.replace("%f", "%06d" % obj.microsecond) # FIXME: This would replace "%%f", which is wrong (wait for Python 2.6)
2618        return obj.strftime(format.encode("utf-8")) # FIXME: We shouldn't have to encode the format string (wait for Python 3.0)
2619    elif obj is None or isinstance(obj, (int, long, float, str, unicode)):
2620        from ll import stringformat
2621        return stringformat.format_builtin_type(obj, format)
2622    else:
2623        return obj.format(format) # This will raise an ``AttributeError``
2624
2625
2626def _repr(obj):
2627    """
2628    Helper for the ``repr`` function.
2629    """
2630    if isinstance(obj, unicode):
2631        return unicode(repr(obj)[1:])
2632    elif isinstance(obj, str):
2633        return unicode(repr(obj))
2634    elif isinstance(obj, datetime.datetime):
2635        return unicode(obj.isoformat())
2636    elif isinstance(obj, color.Color):
2637        if obj[3] == 0xff:
2638            s = "#%02x%02x%02x" % (obj[0], obj[1], obj[2])
2639            if s[1]==s[2] and s[3]==s[4] and s[5]==s[6]:
2640                return "#%s%s%s" % (s[1], s[3], s[5])
2641            return s
2642        else:
2643            s = "#%02x%02x%02x%02x" % obj
2644            if s[1]==s[2] and s[3]==s[4] and s[5]==s[6] and s[7]==s[8]:
2645                return "#%s%s%s%s" % (s[1], s[3], s[5], s[7])
2646            return s
2647    elif isinstance(obj, list):
2648        return u"[%s]" % u", ".join(_repr(item) for item in obj)
2649    elif isinstance(obj, dict):
2650        return u"{%s}" % u", ".join(u"%s: %s" % (_repr(key), _repr(value)) for (key, value) in obj.iteritems())
2651    else:
2652        return unicode(repr(obj))
2653
2654
2655def _csv(obj):
2656    """
2657    Helper for the ``csv`` function.
2658    """
2659    if obj is None:
2660        return u""
2661    elif not isinstance(obj, basestring):
2662        obj = _repr(obj)
2663    if any(c in obj for c in ',"\n'):
2664        return u'"%s"' % obj.replace('"', '""')
2665    return obj
2666
2667
2668def _type(obj):
2669    """
2670    Helper for the ``type`` function.
2671    """
2672    if obj is None:
2673        return u"none"
2674    elif isinstance(obj, basestring):
2675        return u"str"
2676    elif isinstance(obj, bool):
2677        return u"bool"
2678    elif isinstance(obj, (int, long)):
2679        return u"int"
2680    elif isinstance(obj, float):
2681        return u"float"
2682    elif isinstance(obj, (datetime.datetime, datetime.date)):
2683        return u"date"
2684    elif isinstance(obj, color.Color):
2685        return u"color"
2686    elif isinstance(obj, (list, tuple)):
2687        return u"list"
2688    elif isinstance(obj, dict):
2689        return u"dict"
2690    elif hasattr(obj, "__call__"):
2691        return u"template"
2692    return None
Note: See TracBrowser for help on using the browser.