root/livinglogic.googleappengine.lltools/site/ll/ul4c.py @ 27:2221cfba1675

Revision 27:2221cfba1675, 84.5 KB (checked in by Walter Doerwald <walter@…>, 10 years ago)

Updated XIST to version 3.6.1.

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 == "render":
606            return "render r%r(r%r)" % (self.r1, self.r2)
607        else:
608            raise UnknownOpcodeError(self.code)
609
610
611class Template(object):
612    """
613    A template object can be compiled via the class method :meth:`compile` from
614    source. It can be loaded from the compiled format via :meth:`load` (from a
615    stream) or :meth:`loads` (from a string).
616   
617    The compiled format can be generated with the methods :meth:`dump` (which
618    dumps the format to a stream) or :meth:`dumps` (which returns a string with
619    the compiled format).
620
621    Rendering the template can be done with the methods :meth:`render` (which
622    is a generator) or :meth:`renders` (which returns a string).
623    """
624    version = "7"
625
626    def __init__(self):
627        self.startdelim = None
628        self.enddelim = None
629        self.source = None
630        self.opcodes = None
631        # The following is used for converting the opcodes back to executable Python code
632        self._pythonfunction = None
633
634    @classmethod
635    def loads(cls, data):
636        """
637        The class method :meth:`loads` loads the template from string :var:`data`.
638        :var:`data` must contain the template in compiled format.
639        """
640        def _readint(term):
641            i = 0
642            while True:
643                c = stream.read(1)
644                if c.isdigit():
645                    i = 10*i+int(c)
646                elif c == term:
647                    return i
648                else:
649                    raise ValueError("invalid terminator, expected %r, got %r" % (term, c))
650
651        def _readstr(term):
652            i = 0
653            digit = False
654            while True:
655                c = stream.read(1)
656                if c.isdigit():
657                    i = 10*i+int(c)
658                    digit = True
659                elif c == term:
660                    if digit:
661                        break
662                    return None
663                else:
664                    raise ValueError("invalid terminator, expected %r, got %r" % (term, c))
665            s = stream.read(i)
666            if len(s) != i:
667                raise ValueError("short read")
668            return s
669
670        def _readspec():
671            c = stream.read(1)
672            if c == "-":
673                return None
674            elif c.isdigit():
675                return int(c)
676            else:
677                raise ValueError("invalid register spec %r" % c)
678
679        def _readcr():
680            c = stream.read(1)
681            if c != "\n":
682                raise ValueError("invalid linefeed %r" % c)
683
684        self = cls()
685        stream = StringIO.StringIO(data)
686        header = stream.readline()
687        header = header.rstrip()
688        if header != "ul4":
689            raise ValueError("invalid header, expected 'ul4', got %r" % header)
690        version = stream.readline()
691        version = version.rstrip()
692        if version != self.version:
693            raise ValueError("invalid version, expected %r got, %r" % (self.version, version))
694        self.startdelim = _readstr(u"<")
695        _readcr()
696        self.enddelim = _readstr(u">")
697        _readcr()
698        self.source = _readstr('"')
699        self.opcodes = []
700        _readcr()
701        count = _readint(u"#")
702        _readcr()
703        location = None
704        while count:
705            r1 = _readspec()
706            r2 = _readspec()
707            r3 = _readspec()
708            r4 = _readspec()
709            r5 = _readspec()
710            code = _readstr(":")
711            arg = _readstr(".")
712            locspec = stream.read(1)
713            if locspec == u"^":
714                if location is None:
715                    raise ValueError("no previous location")
716            elif locspec == u"*":
717                location = Location(self.source, _readstr("="), _readint("("), _readint(")"), _readint("{"), _readint("}"))
718            else:
719                raise ValueError("invalid location spec %r" % locspec)
720            _readcr()
721            count -= 1
722            self.opcodes.append(Opcode(code, r1, r2, r3, r4, r5, arg, location))
723        return self
724
725    @classmethod
726    def load(cls, stream):
727        """
728        The class method :meth:`load` loads the template from the stream
729        :var:`stream`. The stream must contain the template in compiled format.
730        """
731        return cls.loads(stream.read())
732
733    def iterdump(self):
734        """
735        This generator outputs the template in compiled format.
736        """
737        def _writeint(term, number):
738            yield unicode(number)
739            yield term
740
741        def _writestr(term, string):
742            if string is None:
743                yield term
744            else:
745                yield str(len(string))
746                yield term
747                yield string
748
749        yield "ul4\n%s\n" % self.version
750        for p in _writestr("<", self.startdelim): yield p
751        yield "\n"
752        for p in _writestr(">", self.enddelim): yield p
753        yield "\n"
754        for p in _writestr('"', self.source): yield p
755        yield "\n"
756        for p in _writeint("#", len(self.opcodes)): yield p
757        yield "\n"
758        lastlocation = None
759        for opcode in self.opcodes:
760            yield str(opcode.r1) if opcode.r1 is not None else u"-"
761            yield str(opcode.r2) if opcode.r2 is not None else u"-"
762            yield str(opcode.r3) if opcode.r3 is not None else u"-"
763            yield str(opcode.r4) if opcode.r4 is not None else u"-"
764            yield str(opcode.r5) if opcode.r5 is not None else u"-"
765            for p in _writestr(":", opcode.code): yield p
766            for p in _writestr(".", opcode.arg): yield p
767            if opcode.location is not lastlocation:
768                lastlocation = opcode.location
769                yield u"*"
770                for p in _writestr("=", lastlocation.type): yield p
771                for p in _writeint("(", lastlocation.starttag): yield p
772                for p in _writeint(")", lastlocation.endtag): yield p
773                for p in _writeint("{", lastlocation.startcode): yield p
774                for p in _writeint("}", lastlocation.endcode): yield p
775            else:
776                yield "^"
777            yield "\n"
778
779    def dump(self, stream):
780        """
781        :meth:`dump` dumps the template in compiled format to the stream
782        :var:`stream`.
783        """
784        for part in self.iterdump():
785            stream.write(part)
786
787    def dumps(self):
788        """
789        :meth:`dumps` returns the template in compiled format (as a string).
790        """
791        return "".join(self.iterdump())
792
793    def _pythonsource_dispatch_None(self, opcode):
794        self.lines.append("%syield %r" % (self.indent, opcode.location.code))
795
796    def _pythonsource_dispatch_loadstr(self, opcode):
797        self.lines.append("%sreg%d = %r" % (self.indent, opcode.r1, opcode.arg))
798
799    def _pythonsource_dispatch_loadint(self, opcode):
800        self.lines.append("%sreg%d = %s" % (self.indent, opcode.r1, opcode.arg))
801
802    def _pythonsource_dispatch_loadfloat(self, opcode):
803        self.lines.append("%sreg%d = %s" % (self.indent, opcode.r1, opcode.arg))
804
805    def _pythonsource_dispatch_loadnone(self, opcode):
806        self.lines.append("%sreg%d = None" % (self.indent, opcode.r1))
807
808    def _pythonsource_dispatch_loadfalse(self, opcode):
809        self.lines.append("%sreg%d = False" % (self.indent, opcode.r1))
810
811    def _pythonsource_dispatch_loadtrue(self, opcode):
812        self.lines.append("%sreg%d = True" % (self.indent, opcode.r1))
813
814    def _pythonsource_dispatch_loaddate(self, opcode):
815        self.lines.append("%sreg%d = datetime.datetime(%s)" % (self.indent, opcode.r1, ", ".join(str(int(p)) for p in datesplitter.split(opcode.arg))))
816
817    def _pythonsource_dispatch_loadcolor(self, opcode):
818        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:]))
819
820    def _pythonsource_dispatch_buildlist(self, opcode):
821        self.lines.append("%sreg%d = []" % (self.indent, opcode.r1))
822
823    def _pythonsource_dispatch_builddict(self, opcode):
824        self.lines.append("%sreg%d = {}" % (self.indent, opcode.r1))
825
826    def _pythonsource_dispatch_addlist(self, opcode):
827        self.lines.append("%sreg%d.append(reg%d)" % (self.indent, opcode.r1, opcode.r2))
828
829    def _pythonsource_dispatch_adddict(self, opcode):
830        self.lines.append("%sreg%d[reg%d] = reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
831
832    def _pythonsource_dispatch_updatedict(self, opcode):
833        self.lines.append("%sreg%d.update(reg%d)" % (self.indent, opcode.r1, opcode.r2))
834
835    def _pythonsource_dispatch_loadvar(self, opcode):
836        self.lines.append("%sreg%d = variables[%r]" % (self.indent, opcode.r1, opcode.arg))
837
838    def _pythonsource_dispatch_storevar(self, opcode):
839        self.lines.append("%svariables[%r] = reg%d" % (self.indent, opcode.arg, opcode.r1))
840
841    def _pythonsource_dispatch_addvar(self, opcode):
842        self.lines.append("%svariables[%r] += reg%d" % (self.indent, opcode.arg, opcode.r1))
843
844    def _pythonsource_dispatch_subvar(self, opcode):
845        self.lines.append("%svariables[%r] -= reg%d" % (self.indent, opcode.arg, opcode.r1))
846
847    def _pythonsource_dispatch_mulvar(self, opcode):
848        self.lines.append("%svariables[%r] *= reg%d" % (self.indent, opcode.arg, opcode.r1))
849
850    def _pythonsource_dispatch_truedivvar(self, opcode):
851        self.lines.append("%svariables[%r] /= reg%d" % (self.indent, opcode.arg, opcode.r1))
852
853    def _pythonsource_dispatch_floordivvar(self, opcode):
854        self.lines.append("%svariables[%r] //= reg%d" % (self.indent, opcode.arg, opcode.r1))
855
856    def _pythonsource_dispatch_modvar(self, opcode):
857        self.lines.append("%svariables[%r] %%= reg%d" % (self.indent, opcode.arg, opcode.r1))
858
859    def _pythonsource_dispatch_delvar(self, opcode):
860        self.lines.append("%sdel variables[%r]" % (self.indent, opcode.arg))
861
862    def _pythonsource_dispatch_getattr(self, opcode):
863        self.lines.append("%sreg%d = reg%d[%r]" % (self.indent, opcode.r1, opcode.r2, opcode.arg))
864
865    def _pythonsource_dispatch_getitem(self, opcode):
866        self.lines.append("%sreg%d = reg%d[reg%d]" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
867
868    def _pythonsource_dispatch_getslice12(self, opcode):
869        self.lines.append("%sreg%d = reg%d[reg%d:reg%d]" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
870
871    def _pythonsource_dispatch_getslice1(self, opcode):
872        self.lines.append("%sreg%d = reg%d[reg%d:]" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
873
874    def _pythonsource_dispatch_getslice2(self, opcode):
875        self.lines.append("%sreg%d = reg%d[:reg%d]" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
876
877    def _pythonsource_dispatch_print(self, opcode):
878        self.lines.append("%sif reg%d is not None: yield unicode(reg%d)" % (self.indent, opcode.r1, opcode.r1))
879
880    def _pythonsource_dispatch_printx(self, opcode):
881        self.lines.append("%sif reg%d is not None: yield xmlescape(unicode(reg%d))" % (self.indent, opcode.r1, opcode.r1))
882
883    def _pythonsource_dispatch_for(self, opcode):
884        self.lines.append("%sfor reg%d in reg%d:" % (self.indent, opcode.r1, opcode.r2))
885        self.indent += "\t"
886
887    def _pythonsource_dispatch_endfor(self, opcode):
888        # we don't have to check for empty loops here, as a ``<?for?>`` tag always generates at least one ``storevar`` opcode inside the loop
889        self.indent = self.indent[:-1]
890        self.lines.append("%s# end for" % self.indent)
891
892    def _pythonsource_dispatch_break(self, opcode):
893        self.lines.append("%sbreak" % self.indent)
894
895    def _pythonsource_dispatch_continue(self, opcode):
896        self.lines.append("%scontinue" % self.indent)
897
898    def _pythonsource_dispatch_not(self, opcode):
899        self.lines.append("%sreg%d = not reg%d" % (self.indent, opcode.r1, opcode.r2))
900
901    def _pythonsource_dispatch_neg(self, opcode):
902        self.lines.append("%sreg%d = -reg%d" % (self.indent, opcode.r1, opcode.r2))
903
904    def _pythonsource_dispatch_contains(self, opcode):
905        self.lines.append("%sreg%d = reg%d in reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
906
907    def _pythonsource_dispatch_notcontains(self, opcode):
908        self.lines.append("%sreg%d = reg%d not in reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
909
910    def _pythonsource_dispatch_eq(self, opcode):
911        self.lines.append("%sreg%d = reg%d == reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
912
913    def _pythonsource_dispatch_ne(self, opcode):
914        self.lines.append("%sreg%d = reg%d != reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
915
916    def _pythonsource_dispatch_lt(self, opcode):
917        self.lines.append("%sreg%d = reg%d < reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
918
919    def _pythonsource_dispatch_le(self, opcode):
920        self.lines.append("%sreg%d = reg%d <= reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
921
922    def _pythonsource_dispatch_gt(self, opcode):
923        self.lines.append("%sreg%d = reg%d > reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
924
925    def _pythonsource_dispatch_ge(self, opcode):
926        self.lines.append("%sreg%d = reg%d >= reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
927
928    def _pythonsource_dispatch_add(self, opcode):
929        self.lines.append("%sreg%d = reg%d + reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
930
931    def _pythonsource_dispatch_sub(self, opcode):
932        self.lines.append("%sreg%d = reg%d - reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
933
934    def _pythonsource_dispatch_mul(self, opcode):
935        self.lines.append("%sreg%d = reg%d * reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
936
937    def _pythonsource_dispatch_floordiv(self, opcode):
938        self.lines.append("%sreg%d = reg%d // reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
939
940    def _pythonsource_dispatch_truediv(self, opcode):
941        self.lines.append("%sreg%d = reg%d / reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
942
943    def _pythonsource_dispatch_and(self, opcode):
944        self.lines.append("%sreg%d = reg%d and reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
945
946    def _pythonsource_dispatch_or(self, opcode):
947        self.lines.append("%sreg%d = reg%d or reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
948
949    def _pythonsource_dispatch_mod(self, opcode):
950        self.lines.append("%sreg%d = reg%d %% reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
951
952    def _pythonsource_dispatch_mod(self, opcode):
953        self.lines.append("%sreg%d = reg%d %% reg%d" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
954
955    def _pythonsource_dispatch_callfunc0(self, opcode):
956        try:
957            getattr(self, "_pythonsource_dispatch_callfunc0_%s" % opcode.arg)(opcode)
958        except AttributeError:
959            raise UnknownFunctionError(opcode.arg)
960
961    def _pythonsource_dispatch_callfunc1(self, opcode):
962        try:
963            getattr(self, "_pythonsource_dispatch_callfunc1_%s" % opcode.arg)(opcode)
964        except AttributeError:
965            raise UnknownFunctionError(opcode.arg)
966
967    def _pythonsource_dispatch_callfunc2(self, opcode):
968        try:
969            getattr(self, "_pythonsource_dispatch_callfunc2_%s" % opcode.arg)(opcode)
970        except AttributeError:
971            raise UnknownFunctionError(opcode.arg)
972
973    def _pythonsource_dispatch_callfunc3(self, opcode):
974        try:
975            getattr(self, "_pythonsource_dispatch_callfunc3_%s" % opcode.arg)(opcode)
976        except AttributeError:
977            raise UnknownFunctionError(opcode.arg)
978
979    def _pythonsource_dispatch_callfunc4(self, opcode):
980        try:
981            getattr(self, "_pythonsource_dispatch_callfunc4_%s" % opcode.arg)(opcode)
982        except AttributeError:
983            raise UnknownFunctionError(opcode.arg)
984
985    def _pythonsource_dispatch_callmeth0(self, opcode):
986        if opcode.arg in ("split", "rsplit", "strip", "lstrip", "rstrip", "upper", "lower", "capitalize", "isoformat", "r", "g", "b", "a", "hls", "hlsa", "hsv", "hsva", "lum"):
987            self.lines.append("%sreg%d = reg%d.%s()" % (self.indent, opcode.r1, opcode.r2, opcode.arg))
988        elif opcode.arg == "items":
989            self.lines.append("%sreg%d = reg%d.iteritems()" % (self.indent, opcode.r1, opcode.r2))
990        elif opcode.arg == "render":
991            self.lines.append('%sreg%d = "".join(reg%d())' % (self.indent, opcode.r1, opcode.r2))
992        else:
993            raise UnknownMethodError(opcode.arg)
994
995    def _pythonsource_dispatch_callmeth1(self, opcode):
996        if opcode.arg in ("split", "rsplit", "strip", "lstrip", "rstrip", "startswith", "endswith", "find", "get", "withlum", "witha"):
997            self.lines.append("%sreg%d = reg%d.%s(reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.arg, opcode.r3))
998        elif opcode.arg == "format":
999            self.lines.append("%sreg%d = ul4c._format(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1000        elif opcode.arg == "render":
1001            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))
1002        else:
1003            raise UnknownMethodError(opcode.arg)
1004
1005    def _pythonsource_dispatch_callmeth2(self, opcode):
1006        if opcode.arg in ("split", "rsplit", "find", "replace", "get"):
1007            self.lines.append("%sreg%d = reg%d.%s(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.arg, opcode.r3, opcode.r4))
1008        else:
1009            raise UnknownMethodError(opcode.arg)
1010
1011    def _pythonsource_dispatch_callmeth3(self, opcode):
1012        if opcode.arg == "find":
1013            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))
1014        else:
1015            raise UnknownMethodError(opcode.arg)
1016
1017    def _pythonsource_dispatch_if(self, opcode):
1018        self.lines.append("%sif reg%d:" % (self.indent, opcode.r1))
1019        self.indent += "\t"
1020
1021    def _pythonsource_dispatch_else(self, opcode):
1022        if self.lastopcode == "if":
1023            self.lines[-1] += " pass"
1024        self.indent = self.indent[:-1]
1025        self.lines.append("%selse:" % self.indent)
1026        self.indent += "\t"
1027
1028    def _pythonsource_dispatch_endif(self, opcode):
1029        if self.lastopcode in ("if", "else"):
1030            self.lines[-1] += " pass"
1031        self.indent = self.indent[:-1]
1032        self.lines.append("%s# end if" % self.indent)
1033
1034    def _pythonsource_dispatch_render(self, opcode):
1035        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))
1036
1037    def _pythonsource_dispatch_callfunc0_now(self, opcode):
1038        self.lines.append("%sreg%d = datetime.datetime.now()" % (self.indent, opcode.r1))
1039
1040    def _pythonsource_dispatch_callfunc0_vars(self, opcode):
1041        self.lines.append("%sreg%d = variables" % (self.indent, opcode.r1))
1042
1043    def _pythonsource_dispatch_callfunc1_xmlescape(self, opcode):
1044        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))
1045
1046    def _pythonsource_dispatch_callfunc1_csv(self, opcode):
1047        self.lines.append("%sreg%d = ul4c._csv(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1048
1049    def _pythonsource_dispatch_callfunc1_json(self, opcode):
1050        self.lines.append("%sreg%d = json.dumps(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1051
1052    def _pythonsource_dispatch_callfunc1_str(self, opcode):
1053        self.lines.append("%sreg%d = unicode(reg%d) if reg%d is not None else u''" % (self.indent, opcode.r1, opcode.r2, opcode.r2))
1054
1055    def _pythonsource_dispatch_callfunc1_int(self, opcode):
1056        self.lines.append("%sreg%d = int(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1057
1058    def _pythonsource_dispatch_callfunc1_bool(self, opcode):
1059        self.lines.append("%sreg%d = bool(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1060
1061    def _pythonsource_dispatch_callfunc1_len(self, opcode):
1062        self.lines.append("%sreg%d = len(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1063
1064    def _pythonsource_dispatch_callfunc1_enumerate(self, opcode):
1065        self.lines.append("%sreg%d = enumerate(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1066
1067    def _pythonsource_dispatch_callfunc1_isnone(self, opcode):
1068        self.lines.append("%sreg%d = reg%d is None" % (self.indent, opcode.r1, opcode.r2))
1069
1070    def _pythonsource_dispatch_callfunc1_isstr(self, opcode):
1071        self.lines.append("%sreg%d = isinstance(reg%d, basestring)" % (self.indent, opcode.r1, opcode.r2))
1072
1073    def _pythonsource_dispatch_callfunc1_isint(self, opcode):
1074        self.lines.append("%sreg%d = isinstance(reg%d, (int, long)) and not isinstance(reg%d, bool)" % (self.indent, opcode.r1, opcode.r2, opcode.r2))
1075
1076    def _pythonsource_dispatch_callfunc1_isfloat(self, opcode):
1077        self.lines.append("%sreg%d = isinstance(reg%d, float)" % (self.indent, opcode.r1, opcode.r2))
1078
1079    def _pythonsource_dispatch_callfunc1_isbool(self, opcode):
1080        self.lines.append("%sreg%d = isinstance(reg%d, bool)" % (self.indent, opcode.r1, opcode.r2))
1081
1082    def _pythonsource_dispatch_callfunc1_isdate(self, opcode):
1083        self.lines.append("%sreg%d = isinstance(reg%d, datetime.datetime)" % (self.indent, opcode.r1, opcode.r2))
1084
1085    def _pythonsource_dispatch_callfunc1_islist(self, opcode):
1086        self.lines.append("%sreg%d = isinstance(reg%d, (list, tuple))" % (self.indent, opcode.r1, opcode.r2))
1087
1088    def _pythonsource_dispatch_callfunc1_isdict(self, opcode):
1089        self.lines.append("%sreg%d = isinstance(reg%d, dict)" % (self.indent, opcode.r1, opcode.r2))
1090
1091    def _pythonsource_dispatch_callfunc1_istemplate(self, opcode):
1092        self.lines.append("%sreg%d = hasattr(reg%d, '__call__')" % (self.indent, opcode.r1, opcode.r2)) # this supports normal generators too
1093
1094    def _pythonsource_dispatch_callfunc1_repr(self, opcode):
1095        self.lines.append("%sreg%d = ul4c._repr(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1096
1097    def _pythonsource_dispatch_callfunc1_get(self, opcode):
1098        self.lines.append("%sreg%d = variables.get(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1099
1100    def _pythonsource_dispatch_callfunc1_chr(self, opcode):
1101        self.lines.append("%sreg%d = unichr(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1102
1103    def _pythonsource_dispatch_callfunc1_ord(self, opcode):
1104        self.lines.append("%sreg%d = ord(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1105
1106    def _pythonsource_dispatch_callfunc1_hex(self, opcode):
1107        self.lines.append("%sreg%d = hex(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1108
1109    def _pythonsource_dispatch_callfunc1_oct(self, opcode):
1110        self.lines.append("%sreg%d = ul4c._oct(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1111
1112    def _pythonsource_dispatch_callfunc1_bin(self, opcode):
1113        self.lines.append("%sreg%d = ul4c._bin(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1114
1115    def _pythonsource_dispatch_callfunc1_sorted(self, opcode):
1116        self.lines.append("%sreg%d = sorted(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1117
1118    def _pythonsource_dispatch_callfunc1_range(self, opcode):
1119        self.lines.append("%sreg%d = xrange(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1120
1121    def _pythonsource_dispatch_callfunc1_type(self, opcode):
1122        self.lines.append("%sreg%d = ul4c._type(reg%d)" % (self.indent, opcode.r1, opcode.r2))
1123
1124    def _pythonsource_dispatch_callfunc2_range(self, opcode):
1125        self.lines.append("%sreg%d = xrange(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1126
1127    def _pythonsource_dispatch_callfunc2_get(self, opcode):
1128        self.lines.append("%sreg%d = variables.get(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1129
1130    def _pythonsource_dispatch_callfunc2_zip(self, opcode):
1131        self.lines.append("%sreg%d = itertools.izip(reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3))
1132
1133    def _pythonsource_dispatch_callfunc3_range(self, opcode):
1134        self.lines.append("%sreg%d = xrange(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
1135
1136    def _pythonsource_dispatch_callfunc3_zip(self, opcode):
1137        self.lines.append("%sreg%d = itertools.izip(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
1138
1139    def _pythonsource_dispatch_callfunc3_rgb(self, opcode):
1140        self.lines.append("%sreg%d = color.Color.fromrgb(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
1141
1142    def _pythonsource_dispatch_callfunc3_hls(self, opcode):
1143        self.lines.append("%sreg%d = color.Color.fromhls(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
1144
1145    def _pythonsource_dispatch_callfunc3_hsv(self, opcode):
1146        self.lines.append("%sreg%d = color.Color.fromhsv(reg%d, reg%d, reg%d)" % (self.indent, opcode.r1, opcode.r2, opcode.r3, opcode.r4))
1147
1148    def _pythonsource_dispatch_callfunc4_rgb(self, opcode):
1149        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))
1150
1151    def _pythonsource_dispatch_callfunc4_hls(self, opcode):
1152        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))
1153
1154    def _pythonsource_dispatch_callfunc4_hsv(self, opcode):
1155        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))
1156
1157    def pythonsource(self, function=None):
1158        """
1159        Return the template as Python source code. If :var:`function` is specified
1160        the code will be wrapped in a function with this name.
1161        """
1162        self.indent = ""
1163        self.lines = []
1164
1165        if function is not None:
1166            self.lines.append("%sdef %s(**variables):" % (self.indent, function))
1167            self.indent += "\t"
1168        self.lines.append("%simport sys, datetime, itertools" % self.indent)
1169        self.lines.append("%stry:" % self.indent)
1170        self.indent += "\t"
1171        self.lines.append("%simport json" % self.indent)
1172        self.indent = self.indent[:-1]
1173        self.lines.append("%sexcept ImportError:" % self.indent)
1174        self.indent += "\t"
1175        self.lines.append("%simport simplejson as json" % self.indent)
1176        self.indent = self.indent[:-1]
1177        self.lines.append("%sfrom ll.misc import xmlescape" % self.indent)
1178        self.lines.append("%sfrom ll import ul4c, color" % self.indent)
1179        self.lines.append("%ssource = %r" % (self.indent, self.source))
1180        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
1181        locations = []
1182        lines2locs = []
1183        index = -1
1184        for oc in self.opcodes:
1185            loc = (oc.location.type, oc.location.starttag, oc.location.endtag, oc.location.startcode, oc.location.endcode)
1186            if not locations or locations[-1] != loc:
1187                locations.append(loc)
1188                index += 1
1189            lines2locs.append(index)
1190        locations = tuple(locations)
1191        lines2locs = tuple(lines2locs)
1192        self.lines.append("%sreg0 = reg1 = reg2 = reg3 = reg4 = reg5 = reg6 = reg7 = reg8 = reg9 = None" % self.indent)
1193        self.lines.append("%stry:" % self.indent)
1194        self.indent += "\t"
1195        self.lines.append("%sstartline = sys._getframe().f_lineno+1" % self.indent) # The source line of the first opcode
1196        try:
1197            self.lastopcode = None
1198            for opcode in self.opcodes:
1199                # The following code ensures that each opcode outputs exactly one source code line
1200                # This makes it possible in case of an error to find out which opcode produced the error
1201                try:
1202                    getattr(self, "_pythonsource_dispatch_%s" % opcode.code)(opcode)
1203                except AttributeError:
1204                    raise UnknownOpcodeError(opcode.code)
1205                self.lastopcode = opcode.code
1206        except Exception, exc:
1207            raise #Error(opcode.location, exc)
1208        self.indent = self.indent[:-1]
1209        self.lines.append("%sexcept Exception, exc:" % self.indent)
1210        self.indent += "\t"
1211        self.lines.append("%slocations = %r" % (self.indent, locations))
1212        self.lines.append("%slines2locs = %r" % (self.indent, lines2locs))
1213        self.lines.append("%sraise ul4c.Error(ul4c.Location(source, *locations[lines2locs[sys.exc_info()[2].tb_lineno-startline]]), exc)" % self.indent)
1214        result = "\n".join(self.lines)
1215        del self.lines
1216        del self.indent
1217        return result
1218
1219    def pythonfunction(self):
1220        """
1221        Return a Python generator that can be called to render the template. The
1222        argument signature of the function will be ``**variables``.
1223        """
1224        if self._pythonfunction is None:
1225            code = self.pythonsource("render")
1226            ns = {}
1227            exec code.encode("utf-8") in ns # FIXME: no need to encode in Python 3.0
1228            self._pythonfunction = ns["render"]
1229        return self._pythonfunction
1230
1231    def __call__(self, **variables):
1232        return self.pythonfunction()(**variables)
1233
1234    def render(self, **variables):
1235        """
1236        Render the template iteratively (i.e. this is a generator).
1237        :var:`variables` contains the top level variables available to the
1238        template code.
1239        """
1240        return self.pythonfunction()(**variables)
1241
1242    def renders(self, **variables):
1243        """
1244        Render the template as a string. :var:`variables` contains the top level
1245        variables available to the template code.
1246        """
1247        return "".join(self.render(**variables))
1248
1249    def format(self, indent="\t"):
1250        """
1251        Format the list of opcodes. This is a generator yielding lines to be output
1252        (but without trailing newlines). :var:`indent` can be used to specify how
1253        to indent blocks (defaulting to ``"\\t"``).
1254        """
1255        i = 0
1256        for opcode in self.opcodes:
1257            if opcode.code in ("else", "endif", "endfor"):
1258                i -= 1
1259            if opcode.code in ("endif", "endfor"):
1260                yield "%s}" % (i*indent)
1261            elif opcode.code in ("for", "if"):
1262                yield "%s%s {" % (i*indent, opcode)
1263            elif opcode.code == "else":
1264                yield "%s} else {" % (i*indent)
1265            else:
1266                yield "%s%s" % (i*indent, opcode)
1267            if opcode.code in ("for", "if", "else"):
1268                i += 1
1269
1270    def _tokenize(self, source, startdelim, enddelim):
1271        """
1272        Tokenize the template source code :var:`source` into tags and non-tag
1273        text. :var:`startdelim` and :var:`enddelim` are used as the tag delimiters.
1274
1275        This is a generator which produces :class:`Location` objects for each tag
1276        or non-tag text. It will be called by :meth:`_compile` internally.
1277        """
1278        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))
1279        pos = 0
1280        for match in re.finditer(pattern, source):
1281            if match.start() != pos:
1282                yield Location(source, None, pos, match.start(), pos, match.start())
1283            type = source[match.start(1):match.end(1)]
1284            if type != "note":
1285                yield Location(source, type, match.start(), match.end(), match.start(3), match.end(3))
1286            pos = match.end()
1287        end = len(source)
1288        if pos != end:
1289            yield Location(source, None, pos, end, pos, end)
1290
1291    def _allocreg(self):
1292        """
1293        Allocates a free register from the pool of available registers.
1294        """
1295        try:
1296            return self.registers.pop()
1297        except KeyError:
1298            raise OutOfRegistersError()
1299
1300    def _freereg(self, register):
1301        """
1302        Returns the register :var:`register` to the pool of available registers.
1303        """
1304        self.registers.add(register)
1305
1306    def opcode(self, code, r1=None, r2=None, r3=None, r4=None, r5=None, arg=None):
1307        """
1308        Creates an :class:`Opcode` object and appends it to :var:`self`\s list of
1309        opcodes.
1310        """
1311        self.opcodes.append(Opcode(code, r1, r2, r3, r4, r5, arg, self.location))
1312
1313    def _compile(self, source, startdelim, enddelim):
1314        """
1315        Compile the template source code :var:`source` into opcodes.
1316        :var:`startdelim` and :var:`enddelim` are used as the tag delimiters.
1317        """
1318        self.startdelim = startdelim
1319        self.enddelim = enddelim
1320        scanner = Scanner()
1321        parseexpr = ExprParser(scanner).compile
1322        parsestmt = StmtParser(scanner).compile
1323        parsefor = ForParser(scanner).compile
1324        parserender = RenderParser(scanner).compile
1325
1326        # This stack stores for each nested for/foritem/if/elif/else the following information:
1327        # 1) Which construct we're in (i.e. "if" or "for")
1328        # 2) The start location of the construct
1329        # For ifs:
1330        # 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)
1331        # 4) Whether we've already seen the else
1332        stack = []
1333
1334        self.source = source
1335        self.opcodes = []
1336
1337        for location in self._tokenize(source, startdelim, enddelim):
1338            self.location = location
1339            try:
1340                if location.type is None:
1341                    self.opcode(None)
1342                elif location.type == "print":
1343                    r = parseexpr(self)
1344                    self.opcode("print", r1=r)
1345                elif location.type == "printx":
1346                    r = parseexpr(self)
1347                    self.opcode("printx", r1=r)
1348                elif location.type == "code":
1349                    parsestmt(self)
1350                elif location.type == "if":
1351                    r = parseexpr(self)
1352                    self.opcode("if", r1=r)
1353                    stack.append(("if", location, 1, False))
1354                elif location.type == "elif":
1355                    if not stack or stack[-1][0] != "if":
1356                        raise BlockError("elif doesn't match any if")
1357                    elif stack[-1][3]:
1358                        raise BlockError("else already seen in elif")
1359                    self.opcode("else")
1360                    r = parseexpr(self)
1361                    self.opcode("if", r1=r)
1362                    stack[-1] = ("if", stack[-1][1], stack[-1][2]+1, False)
1363                elif location.type == "else":
1364                    if not stack or stack[-1][0] != "if":
1365                        raise BlockError("else doesn't match any if")
1366                    elif stack[-1][3]:
1367                        raise BlockError("duplicate else")
1368                    self.opcode("else")
1369                    stack[-1] = ("if", stack[-1][1], stack[-1][2], True)
1370                elif location.type == "end":
1371                    if not stack:
1372                        raise BlockError("not in any block")
1373                    code = location.code
1374                    if code:
1375                        if code == "if":
1376                            if stack[-1][0] != "if":
1377                                raise BlockError("endif doesn't match any if")
1378                        elif code == "for":
1379                            if stack[-1][0] != "for":
1380                                raise BlockError("endfor doesn't match any for")
1381                        else:
1382                            raise BlockError("illegal end value %r" % code)
1383                    last = stack.pop()
1384                    if last[0] == "if":
1385                        for i in xrange(last[2]):
1386                            self.opcode("endif")
1387                    else: # last[0] == "for":
1388                        self.opcode("endfor")
1389                elif location.type == "for":
1390                    parsefor(self)
1391                    stack.append(("for", location))
1392                elif location.type == "break":
1393                    if not any(entry[0] == "for" for entry in stack):
1394                        raise BlockError("break outside of for loop")
1395                    self.opcode("break")
1396                elif location.type == "continue":
1397                    if not any(entry[0] == "for" for entry in stack):
1398                        raise BlockError("continue outside of for loop")
1399                    self.opcode("continue")
1400                elif location.type == "render":
1401                    parserender(self)
1402                else: # Can't happen
1403                    raise ValueError("unknown tag %r" % location.type)
1404            except Exception, exc:
1405                raise Error(location, exc)
1406            finally:
1407                del self.location
1408        if stack:
1409            raise Error(stack[-1][1], BlockError("block unclosed"))
1410
1411    def __str__(self):
1412        return "\n".join(self.format())
1413
1414    def __unicode__(self):
1415        return u"\n".join(self.format())
1416
1417    def __repr__(self):
1418        return "<%s.%s object with %d opcodes at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, len(self.opcodes), id(self))
1419
1420
1421def compile(source, startdelim="<?", enddelim="?>"):
1422    template = Template()
1423    template._compile(source, startdelim, enddelim)
1424    return template
1425
1426load = Template.load
1427loads = Template.loads
1428
1429
1430###
1431### Tokens and nodes for the AST
1432###
1433
1434class Token(object):
1435    def __init__(self, start, end, type):
1436        self.start = start
1437        self.end = end
1438        self.type = type
1439
1440    def __repr__(self):
1441        return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.type)
1442
1443    def __str__(self):
1444        return self.type
1445
1446
1447class AST(object):
1448    """
1449    Baseclass for all syntax tree nodes.
1450    """
1451
1452    def __init__(self, start, end):
1453        self.start = start
1454        self.end = end
1455
1456
1457class Const(AST):
1458    """
1459    Common baseclass for all constants (used for type testing in constant folding)
1460    """
1461
1462    def __repr__(self):
1463        return "%s(%r, %r)" % (self.__class__.__name__, self.start, self.end)
1464
1465    def compile(self, template):
1466        r = template._allocreg()
1467        template.opcode("load%s" % self.type, r1=r)
1468        return r
1469
1470
1471class None_(Const):
1472    type = "none"
1473    value = None
1474
1475
1476class True_(Const):
1477    type = "true"
1478    value = True
1479
1480
1481class False_(Const):
1482    type = "false"
1483    value = False
1484
1485
1486class Value(Const):
1487    def __init__(self, start, end, value):
1488        Const.__init__(self, start, end)
1489        self.value = value
1490
1491    def __repr__(self):
1492        return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.value)
1493
1494    def compile(self, template):
1495        r = template._allocreg()
1496        template.opcode("load%s" % self.type, r1=r, arg=unicode(self.value))
1497        return r
1498
1499
1500class Int(Value):
1501    type = "int"
1502
1503
1504class Float(Value):
1505    type = "float"
1506
1507    def compile(self, template):
1508        r = template._allocreg()
1509        template.opcode("load%s" % self.type, r1=r, arg=repr(self.value))
1510        return r
1511
1512
1513class Str(Value):
1514    type = "str"
1515
1516
1517class Date(Value):
1518    type = "date"
1519
1520    def compile(self, template):
1521        r = template._allocreg()
1522        template.opcode("load%s" % self.type, r1=r, arg=self.value.isoformat())
1523        return r
1524
1525
1526class Color(Value):
1527    type = "color"
1528
1529    def compile(self, template):
1530        r = template._allocreg()
1531        template.opcode("load%s" % self.type, r1=r, arg="%02x%02x%02x%02x" % self.value)
1532        return r
1533
1534
1535class List(AST):
1536    def __init__(self, start, end, *items):
1537        AST.__init__(self, start, end)
1538        self.items = list(items)
1539
1540    def __repr__(self):
1541        return "%s(%r, %r, %s)" % (self.__class__.__name__, self.start, self.end, repr(self.items)[1:-1])
1542
1543    def compile(self, template):
1544        r = template._allocreg()
1545        template.opcode("buildlist", r1=r)
1546        for item in self.items:
1547            ri = item.compile(template)
1548            template.opcode("addlist", r1=r, r2=ri)
1549            template._freereg(ri)
1550        return r
1551
1552
1553class Dict(AST):
1554    def __init__(self, start, end, *items):
1555        AST.__init__(self, start, end)
1556        self.items = list(items)
1557
1558    def __repr__(self):
1559        return "%s(%r, %r, %s)" % (self.__class__.__name__, self.start, self.end, repr(self.items)[1:-1])
1560
1561    def compile(self, template):
1562        r = template._allocreg()
1563        template.opcode("builddict", r1=r)
1564        for item in self.items:
1565            if len(item) == 1:
1566                rd = item[0].compile(template)
1567                template.opcode("updatedict", r1=r, r2=rd)
1568                template._freereg(rd)
1569            else:
1570                (key, value) = item
1571                rk = key.compile(template)
1572                rv = value.compile(template)
1573                template.opcode("adddict", r1=r, r2=rk, r3=rv)
1574                template._freereg(rk)
1575                template._freereg(rv)
1576        return r
1577
1578
1579class Name(AST):
1580    type = "name"
1581
1582    def __init__(self, start, end, name):
1583        AST.__init__(self, start, end)
1584        self.name = name
1585
1586    def __repr__(self):
1587        return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name)
1588
1589    def compile(self, template):
1590        r = template._allocreg()
1591        template.opcode("loadvar", r1=r, arg=self.name)
1592        return r
1593
1594
1595class For(AST):
1596    def __init__(self, start, end, iter, cont):
1597        AST.__init__(self, start, end)
1598        self.iter = iter
1599        self.cont = cont
1600
1601    def __repr__(self):
1602        return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.iter, self.cont)
1603
1604    def compile(self, template):
1605        rc = self.cont.compile(template)
1606        ri = template._allocreg()
1607        template.opcode("for", r1=ri, r2=rc)
1608        if isinstance(self.iter, list):
1609            for (i, iter) in enumerate(self.iter):
1610                rii = template._allocreg()
1611                template.opcode("loadint", r1=rii, arg=str(i))
1612                template.opcode("getitem", r1=rii, r2=ri, r3=rii)
1613                template.opcode("storevar", r1=rii, arg=iter.name)
1614                template._freereg(rii)
1615        else:
1616            template.opcode("storevar", r1=ri, arg=self.iter.name)
1617        template._freereg(ri)
1618        template._freereg(rc)
1619
1620
1621class GetAttr(AST):
1622    def __init__(self, start, end, obj, attr):
1623        AST.__init__(self, start, end)
1624        self.obj = obj
1625        self.attr = attr
1626
1627    def __repr__(self):
1628        return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.obj, self.attr)
1629
1630    def compile(self, template):
1631        r = self.obj.compile(template)
1632        template.opcode("getattr", r1=r, r2=r, arg=self.attr.name)
1633        return r
1634
1635
1636class GetSlice12(AST):
1637    def __init__(self, start, end, obj, index1, index2):
1638        AST.__init__(self, start, end)
1639        self.obj = obj
1640        self.index1 = index1
1641        self.index2 = index2
1642
1643    def __repr__(self):
1644        return "%s(%r, %r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.obj, self.index1, self.index2)
1645
1646    def compile(self, template):
1647        r1 = self.obj.compile(template)
1648        r2 = self.index1.compile(template)
1649        r3 = self.index2.compile(template)
1650        template.opcode("getslice12", r1=r1, r2=r1, r3=r2, r4=r3)
1651        template._freereg(r2)
1652        template._freereg(r3)
1653        return r1
1654
1655
1656class Unary(AST):
1657    opcode = None
1658
1659    def __init__(self, start, end, obj):
1660        AST.__init__(self, start, end)
1661        self.obj = obj
1662
1663    def __repr__(self):
1664        return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.obj)
1665
1666    def compile(self, template):
1667        r = self.obj.compile(template)
1668        template.opcode(self.opcode, r1=r, r2=r)
1669        return r
1670
1671
1672class Not(Unary):
1673    opcode = "not"
1674
1675
1676class Neg(Unary):
1677    opcode = "neg"
1678
1679
1680class Binary(AST):
1681    opcode = None
1682
1683    def __init__(self, start, end, obj1, obj2):
1684        AST.__init__(self, start, end)
1685        self.obj1 = obj1
1686        self.obj2 = obj2
1687
1688    def __repr__(self):
1689        return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.obj1, self.obj2)
1690
1691    def compile(self, template):
1692        r1 = self.obj1.compile(template)
1693        r2 = self.obj2.compile(template)
1694        template.opcode(self.opcode, r1=r1, r2=r1, r3=r2)
1695        template._freereg(r2)
1696        return r1
1697
1698
1699class GetItem(Binary):
1700    opcode = "getitem"
1701
1702
1703class GetSlice1(Binary):
1704    opcode = "getslice1"
1705
1706
1707class GetSlice2(Binary):
1708    opcode = "getslice2"
1709
1710
1711class EQ(Binary):
1712    opcode = "eq"
1713
1714
1715class NE(Binary):
1716    opcode = "ne"
1717
1718
1719class LT(Binary):
1720    opcode = "lt"
1721
1722
1723class LE(Binary):
1724    opcode = "le"
1725
1726
1727class GT(Binary):
1728    opcode = "gt"
1729
1730
1731class GE(Binary):
1732    opcode = "ge"
1733
1734
1735class Contains(Binary):
1736    opcode = "contains"
1737
1738
1739class NotContains(Binary):
1740    opcode = "notcontains"
1741
1742
1743class Add(Binary):
1744    opcode = "add"
1745
1746
1747class Sub(Binary):
1748    opcode = "sub"
1749
1750
1751class Mul(Binary):
1752    opcode = "mul"
1753
1754
1755class FloorDiv(Binary):
1756    opcode = "floordiv"
1757
1758
1759class TrueDiv(Binary):
1760    opcode = "truediv"
1761
1762
1763class Or(Binary):
1764    opcode = "or"
1765
1766
1767class And(Binary):
1768    opcode = "and"
1769
1770
1771class Mod(Binary):
1772    opcode = "mod"
1773
1774
1775class ChangeVar(AST):
1776    opcode = None
1777
1778    def __init__(self, start, end, name, value):
1779        AST.__init__(self, start, end)
1780        self.name = name
1781        self.value = value
1782
1783    def __repr__(self):
1784        return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name, self.value)
1785
1786    def compile(self, template):
1787        r = self.value.compile(template)
1788        template.opcode(self.opcode, r1=r, arg=self.name.name)
1789        template._freereg(r)
1790
1791
1792class StoreVar(ChangeVar):
1793    opcode = "storevar"
1794
1795
1796class AddVar(ChangeVar):
1797    opcode = "addvar"
1798
1799
1800class SubVar(ChangeVar):
1801    opcode = "subvar"
1802
1803
1804class MulVar(ChangeVar):
1805    opcode = "mulvar"
1806
1807
1808class TrueDivVar(ChangeVar):
1809    opcode = "truedivvar"
1810
1811
1812class FloorDivVar(ChangeVar):
1813    opcode = "floordivvar"
1814
1815
1816class ModVar(ChangeVar):
1817    opcode = "modvar"
1818
1819
1820class DelVar(AST):
1821    def __init__(self, start, end, name):
1822        AST.__init__(self, start, end)
1823        self.name = name
1824
1825    def __repr__(self):
1826        return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name)
1827
1828    def compile(self, template):
1829        template.opcode("delvar", arg=self.name.name)
1830
1831
1832class CallFunc(AST):
1833    def __init__(self, start, end, name, args):
1834        AST.__init__(self, start, end)
1835        self.name = name
1836        self.args = args
1837
1838    def __repr__(self):
1839        if self.args:
1840            return "%s(%r, %r, %r, %s)" % (self.__class__.__name__, self.start, self.end, self.name, repr(self.args)[1:-1])
1841        else:
1842            return "%s(%r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name)
1843
1844    def compile(self, template):
1845        if len(self.args) == 0:
1846            r = template._allocreg()
1847            template.opcode("callfunc0", r1=r, arg=self.name.name)
1848            return r
1849        elif len(self.args) > 4:
1850            raise ValueError("%d function arguments not supported" % len(self.args))
1851        else:
1852            rs = [arg.compile(template) for arg in self.args]
1853            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?
1854            for i in xrange(1, len(self.args)):
1855                template._freereg(rs[i])
1856            return rs[0]
1857
1858
1859class CallMeth(AST):
1860    def __init__(self, start, end, name, obj, args):
1861        AST.__init__(self, start, end)
1862        self.name = name
1863        self.obj = obj
1864        self.args = args
1865
1866    def __repr__(self):
1867        if self.args:
1868            return "%s(%r, %r, %r, %r, %s)" % (self.__class__.__name__, self.start, self.end, self.name, self.obj, repr(self.args)[1:-1])
1869        else:
1870            return "%s(%r, %r, %r, %r)" % (self.__class__.__name__, self.start, self.end, self.name, self.obj)
1871
1872    def compile(self, template):
1873        if len(self.args) > 3:
1874            raise ValueError("%d method arguments not supported" % len(self.args))
1875        ro = self.obj.compile(template)
1876        rs = [arg.compile(template) for arg in self.args]
1877        template.opcode("callmeth%d" % len(self.args), ro, ro, *rs, **dict(arg=self.name.name))
1878        for r in rs:
1879            template._freereg(r)
1880        return ro
1881
1882
1883class Render(AST):
1884    def __init__(self, start, end, template, *variables):
1885        AST.__init__(self, start, end)
1886        self.template = template
1887        self.variables = list(variables)
1888
1889    def __repr__(self):
1890        return "%s(%r, %r, %r, %s)" % (self.__class__.__name__, self.start, self.end, self.template, repr(self.variables)[1:-1])
1891
1892    def compile(self, template):
1893        ra = template._allocreg()
1894        template.opcode("builddict", r1=ra)
1895        for item in self.variables:
1896            if len(item) == 1:
1897                rd = item[0].compile(template)
1898                template.opcode("updatedict", r1=ra, r2=rd)
1899                template._freereg(rd)
1900            else:
1901                (key, value) = item
1902                rv = value.compile(template)
1903                rk = template._allocreg()
1904                template.opcode("loadstr", r1=rk, arg=key.name)
1905                template.opcode("adddict", r1=ra, r2=rk, r3=rv)
1906                template._freereg(rk)
1907                template._freereg(rv)
1908        rt = self.template.compile(template)
1909        template.opcode("render", r1=rt, r2=ra)
1910        template._freereg(rt)
1911        template._freereg(ra)
1912
1913
1914###
1915### Tokenizer
1916###
1917
1918class Scanner(spark.Scanner):
1919    reflags = re.UNICODE
1920
1921    def tokenize(self, location):
1922        self.collectstr = []
1923        self.rv = []
1924        self.start = 0
1925        try:
1926            spark.Scanner.tokenize(self, location.code)
1927            if self.mode != "default":
1928                raise UnterminatedStringError()
1929        except Exception, exc:
1930            raise Error(location, exc)
1931        return self.rv
1932
1933    # Color tokens must be in the order of decreasing length
1934    @spark.token("\\#[0-9a-fA-F]{8}", "default")
1935    def color8(self, start, end, s):
1936        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))))
1937
1938    @spark.token("\\#[0-9a-fA-F]{6}", "default")
1939    def color6(self, start, end, s):
1940        self.rv.append(Color(start, end, color.Color(int(s[1:3], 16), int(s[3:5], 16), int(s[5:], 16))))
1941
1942    @spark.token("\\#[0-9a-fA-F]{4}", "default")
1943    def color4(self, start, end, s):
1944        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))))
1945
1946    @spark.token("\\#[0-9a-fA-F]{3}", "default")
1947    def color3(self, start, end, s):
1948        self.rv.append(Color(start, end, color.Color(17*int(s[1], 16), 17*int(s[2], 16), 17*int(s[3], 16))))
1949
1950    # Must be before the int and float constants
1951    @spark.token("\\d{4}-\\d{2}-\\d{2}T(\\d{2}:\\d{2}(:\\d{2}(\\.\\d{6})?)?)?", "default")
1952    def date(self, start, end, s):
1953        self.rv.append(Date(start, end, datetime.datetime(*map(int, filter(None, datesplitter.split(s))))))
1954
1955    @spark.token("\\(|\\)|\\[|\\]|\\{|\\}|\\.|,|==|\\!=|<=|<|>=|>|=|\\+=|\\-=|\\*=|//=|/=|%=|%|:|\\+|-|\\*\\*|\\*|//|/", "default")
1956    def token(self, start, end, s):
1957        self.rv.append(Token(start, end, s))
1958
1959    @spark.token("[a-zA-Z_][\\w]*", "default")
1960    def name(self, start, end, s):
1961        if s in ("in", "not", "or", "and", "del"):
1962            self.rv.append(Token(start, end, s))
1963        elif s == "None":
1964            self.rv.append(None_(start, end))
1965        elif s == "True":
1966            self.rv.append(True_(start, end))
1967        elif s == "False":
1968            self.rv.append(False_(start, end))
1969        else:
1970            self.rv.append(Name(start, end, s))
1971
1972    # We don't have negatve numbers, this is handled by constant folding in the AST for unary minus
1973    @spark.token("\\d+\\.\\d*([eE][+-]?\\d+)?", "default")
1974    @spark.token("\\d+(\\.\\d*)?[eE][+-]?\\d+", "default")
1975    def float(self, start, end, s):
1976        self.rv.append(Float(start, end, float(s)))
1977
1978    @spark.token("0[xX][\\da-fA-F]+", "default")
1979    def hexint(self, start, end, s):
1980        self.rv.append(Int(start, end, int(s[2:], 16)))
1981
1982    @spark.token("0[oO][0-7]+", "default")
1983    def octint(self, start, end, s):
1984        self.rv.append(Int(start, end, int(s[2:], 8)))
1985
1986    @spark.token("0[bB][01]+", "default")
1987    def binint(self, start, end, s):
1988        self.rv.append(Int(start, end, int(s[2:], 2)))
1989
1990    @spark.token("\\d+", "default")
1991    def int(self, start, end, s):
1992        self.rv.append(Int(start, end, int(s)))
1993
1994    @spark.token("'", "default")
1995    def beginstr1(self, start, end, s):
1996        self.mode = "str1"
1997        self.start = start
1998
1999    @spark.token('"', "default")
2000    def beginstr2(self, start, end, s):
2001        self.mode = "str2"
2002        self.start = start
2003
2004    @spark.token("'", "str1")
2005    @spark.token('"', "str2")
2006    def endstr(self, start, end, s):
2007        self.rv.append(Str(self.start, end, "".join(self.collectstr)))
2008        self.collectstr = []
2009        self.mode = "default"
2010
2011    @spark.token("\\s+", "default")
2012    def whitespace(self, start, end, s):
2013        pass
2014
2015    @spark.token("\\\\\\\\", "str1", "str2")
2016    def escapedbackslash(self, start, end, s):
2017        self.collectstr.append("\\")
2018
2019    @spark.token("\\\\'", "str1", "str2")
2020    def escapedapos(self, start, end, s):
2021        self.collectstr.append("'")
2022
2023    @spark.token('\\\\"', "str1", "str2")
2024    def escapedquot(self, start, end, s):
2025        self.collectstr.append('"')
2026
2027    @spark.token("\\\\a", "str1", "str2")
2028    def escapedbell(self, start, end, s):
2029        self.collectstr.append("\a")
2030
2031    @spark.token("\\\\b", "str1", "str2")
2032    def escapedbackspace(self, start, end, s):
2033        self.collectstr.append("\b")
2034
2035    @spark.token("\\\\f", "str1", "str2")
2036    def escapedformfeed(self, start, end, s):
2037        self.collectstr.append("\f")
2038
2039    @spark.token("\\\\n", "str1", "str2")
2040    def escapedlinefeed(self, start, end, s):
2041        self.collectstr.append("\n")
2042
2043    @spark.token("\\\\r", "str1", "str2")
2044    def escapedcarriagereturn(self, start, end, s):
2045        self.collectstr.append("\r")
2046
2047    @spark.token("\\\\t", "str1", "str2")
2048    def escapedtab(self, start, end, s):
2049        self.collectstr.append("\t")
2050
2051    @spark.token("\\\\v", "str1", "str2")
2052    def escapedverticaltab(self, start, end, s):
2053        self.collectstr.append("\v")
2054
2055    @spark.token("\\\\e", "str1", "str2")
2056    def escapedescape(self, start, end, s):
2057        self.collectstr.append("\x1b")
2058
2059    @spark.token("\\\\x[0-9a-fA-F]{2}", "str1", "str2")
2060    def escaped8bitchar(self, start, end, s):
2061        self.collectstr.append(unichr(int(s[2:], 16)))
2062
2063    @spark.token("\\\\u[0-9a-fA-F]{4}", "str1", "str2")
2064    def escaped16bitchar(self, start, end, s):
2065        self.collectstr.append(unichr(int(s[2:], 16)))
2066
2067    @spark.token(".|\\n", "str1", "str2")
2068    def text(self, start, end, s):
2069        self.collectstr.append(s)
2070
2071    @spark.token("(.|\\n)+", "default", "str1", "str2")
2072    def default(self, start, end, s):
2073        raise LexicalError(start, end, s)
2074
2075    def error(self, start, end, s):
2076        raise LexicalError(start, end, s)
2077
2078
2079###
2080### Parsers for different types of code
2081###
2082
2083class ExprParser(spark.Parser):
2084    emptyerror = "expression required"
2085    start = "expr0"
2086
2087    def __init__(self, scanner):
2088        spark.Parser.__init__(self)
2089        self.scanner = scanner
2090
2091    def compile(self, template):
2092        location = template.location
2093        if not location.code:
2094            raise ValueError(self.emptyerror)
2095        template.registers = set(xrange(10))
2096        try:
2097            ast = self.parse(self.scanner.tokenize(location))
2098            return ast.compile(template)
2099        except Exception, exc:
2100            raise Error(location, exc)
2101        finally:
2102            del template.registers
2103
2104    def typestring(self, token):
2105        return token.type
2106
2107    def error(self, token):
2108        raise SyntaxError(token)
2109
2110    def makeconst(self, start, end, value):
2111        if value is None:
2112            return None_(start, end)
2113        elif value is True:
2114            return True_(start, end)
2115        elif value is False:
2116            return False_(start, end)
2117        elif isinstance(value, int):
2118            return Int(start, end, value)
2119        elif isinstance(value, float):
2120            return Float(start, end, value)
2121        elif isinstance(value, basestring):
2122            return Str(start, end, value)
2123        elif isinstance(value, color.Color):
2124            return Color(start, end, value)
2125        else:
2126            raise TypeError("can't convert %r" % value)
2127
2128    # To implement operator precedence, each expression rule has the precedence in its name. The highest precedence is 11 for atomic expressions.
2129    # Each expression can have only expressions as parts which have the some or a higher precedence with two exceptions:
2130    #    1. Expressions where there's no ambiguity, like the index for a getitem/getslice or function/method arguments;
2131    #    2. Brackets, which can be used to boost the precedence of an expression to the level of an atomic expression.
2132
2133    @spark.production('expr11 ::= none')
2134    @spark.production('expr11 ::= true')
2135    @spark.production('expr11 ::= false')
2136    @spark.production('expr11 ::= str')
2137    @spark.production('expr11 ::= int')
2138    @spark.production('expr11 ::= float')
2139    @spark.production('expr11 ::= date')
2140    @spark.production('expr11 ::= color')
2141    @spark.production('expr11 ::= name')
2142    def expr_atom(self, atom):
2143        return atom
2144
2145    @spark.production('expr11 ::= [ ]')
2146    def expr_emptylist(self, _0, _1):
2147        return List(_0.start, _1.end)
2148
2149    @spark.production('buildlist ::= [ expr0')
2150    def expr_buildlist(self, _0, expr):
2151        return List(_0.start, expr.end, expr)
2152
2153    @spark.production('buildlist ::= buildlist , expr0')
2154    def expr_addlist(self, list, _0, expr):
2155        list.items.append(expr)
2156        list.end = expr.end
2157        return list
2158
2159    @spark.production('expr11 ::= buildlist ]')
2160    def expr_finishlist(self, list, _0):
2161        list.end = _0.end
2162        return list
2163
2164    @spark.production('expr11 ::= buildlist , ]')
2165    def expr_finishlist1(self, list, _0, _1):
2166        list.end = _1.end
2167        return list
2168
2169    @spark.production('expr11 ::= { }')
2170    def expr_emptydict(self, _0, _1):
2171        return Dict(_0.start, _1.end)
2172
2173    @spark.production('builddict ::= { expr0 : expr0')
2174    def expr_builddict(self, _0, exprkey, _1, exprvalue):
2175        return Dict(_0.start, exprvalue.end, (exprkey, exprvalue))
2176
2177    @spark.production('builddict ::= { ** expr0')
2178    def expr_builddictupdate(self, _0, _1, expr):
2179        return Dict(_0.start, expr.end, (expr,))
2180
2181    @spark.production('builddict ::= builddict , expr0 : expr0')
2182    def expr_adddict(self, dict, _0, exprkey, _1, exprvalue):
2183        dict.items.append((exprkey, exprvalue))
2184        dict.end = exprvalue.end
2185        return dict
2186
2187    @spark.production('builddict ::= builddict , ** expr0')
2188    def expr_updatedict(self, dict, _0, _1, expr):
2189        dict.items.append((expr,))
2190        dict.end = expr.end
2191        return dict
2192
2193    @spark.production('expr11 ::= builddict }')
2194    def expr_finishdict(self, dict, _0):
2195        dict.end = _0.end
2196        return dict
2197
2198    @spark.production('expr11 ::= builddict , }')
2199    def expr_finishdict1(self, dict, _0, _1):
2200        dict.end = _1.end
2201        return dict
2202
2203    @spark.production('expr11 ::= ( expr0 )')
2204    def expr_bracket(self, _0, expr, _1):
2205        return expr
2206
2207    @spark.production('expr10 ::= name ( )')
2208    def expr_callfunc0(self, name, _0, _1):
2209        return CallFunc(name.start, _1.end, name, [])
2210
2211    @spark.production('expr10 ::= name ( expr0 )')
2212    def expr_callfunc1(self, name, _0, arg0, _1):
2213        return CallFunc(name.start, _1.end, name, [arg0])
2214
2215    @spark.production('expr10 ::= name ( expr0 , expr0 )')
2216    def expr_callfunc2(self, name, _0, arg0, _1, arg1, _2):
2217        return CallFunc(name.start, _2.end, name, [arg0, arg1])
2218
2219    @spark.production('expr10 ::= name ( expr0 , expr0 , expr0 )')
2220    def expr_callfunc3(self, name, _0, arg0, _1, arg1, _2, arg2, _3):
2221        return CallFunc(name.start, _3.end, name, [arg0, arg1, arg2])
2222
2223    @spark.production('expr10 ::= name ( expr0 , expr0 , expr0 , expr0 )')
2224    def expr_callfunc4(self, name, _0, arg0, _1, arg1, _2, arg2, _3, arg3, _4):
2225        return CallFunc(name.start, _4.end, name, [arg0, arg1, arg2, arg3])
2226
2227    @spark.production('expr9 ::= expr9 . name')
2228    def expr_getattr(self, expr, _0, name):
2229        return GetAttr(expr.start, name.end, expr, name)
2230
2231    @spark.production('expr9 ::= expr9 . name ( )')
2232    def expr_callmeth0(self, expr, _0, name, _1, _2):
2233        return CallMeth(expr.start, _2.end, name, expr, [])
2234
2235    @spark.production('expr9 ::= expr9 . name ( expr0 )')
2236    def expr_callmeth1(self, expr, _0, name, _1, arg1, _2):
2237        return CallMeth(expr.start, _2.end, name, expr, [arg1])
2238
2239    @spark.production('expr9 ::= expr9 . name ( expr0 , expr0 )')
2240    def expr_callmeth2(self, expr, _0, name, _1, arg1, _2, arg2, _3):
2241        return CallMeth(expr.start, _3.end, name, expr, [arg1, arg2])
2242
2243    @spark.production('expr9 ::= expr9 . name ( expr0 , expr0 , expr0 )')
2244    def expr_callmeth3(self, expr, _0, name, _1, arg1, _2, arg2, _3, arg3, _4):
2245        return CallMeth(expr.start, _4.end, name, expr, [arg1, arg2, arg3])
2246
2247    @spark.production('expr9 ::= expr9 [ expr0 ]')
2248    def expr_getitem(self, expr, _0, key, _1):
2249        if isinstance(expr, Const) and isinstance(key, Const): # Constant folding
2250            return self.makeconst(expr.start, _1.end, expr.value[key.value])
2251        return GetItem(expr.start, _1.end, expr, key)
2252
2253    @spark.production('expr8 ::= expr8 [ expr0 : expr0 ]')
2254    def expr_getslice12(self, expr, _0, index1, _1, index2, _2):
2255        if isinstance(expr, Const) and isinstance(index1, Const) and isinstance(index2, Const): # Constant folding
2256            return self.makeconst(expr.start, _2.end, expr.value[index1.value:index2.value])
2257        return GetSlice12(expr.start, _2.end, expr, index1, index2)
2258
2259    @spark.production('expr8 ::= expr8 [ expr0 : ]')
2260    def expr_getslice1(self, expr, _0, index1, _1, _2):
2261        if isinstance(expr, Const) and isinstance(index1, Const): # Constant folding
2262            return self.makeconst(expr.start, _2.end, expr.value[index1.value:])
2263        return GetSlice1(expr.start, _2.end, expr, index1)
2264
2265    @spark.production('expr8 ::= expr8 [ : expr0 ]')
2266    def expr_getslice2(self, expr, _0, _1, index2, _2):
2267        if isinstance(expr, Const) and isinstance(index2, Const): # Constant folding
2268            return self.makeconst(expr.start, _2.end, expr.value[:index2.value])
2269        return GetSlice2(expr.start, _2.end, expr, index2)
2270
2271    @spark.production('expr7 ::= - expr7')
2272    def expr_neg(self, _0, expr):
2273        if isinstance(expr, Const): # Constant folding
2274            return self.makeconst(_0.start, expr.end, -expr.value)
2275        return Neg(_0.start, expr.end, expr)
2276
2277    @spark.production('expr6 ::= expr6 * expr6')
2278    def expr_mul(self, obj1, _0, obj2):
2279        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2280            return self.makeconst(obj1.start, obj2.end, obj1.value * obj2.value)
2281        return Mul(obj1.start, obj2.end, obj1, obj2)
2282
2283    @spark.production('expr6 ::= expr6 // expr6')
2284    def expr_floordiv(self, obj1, _0, obj2):
2285        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2286            return self.makeconst(obj1.start, obj2.end, obj1.value // obj2.value)
2287        return FloorDiv(obj1.start, obj2.end, obj1, obj2)
2288
2289    @spark.production('expr6 ::= expr6 / expr6')
2290    def expr_truediv(self, obj1, _0, obj2):
2291        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2292            return self.makeconst(obj1.start, obj2.end, obj1.value / obj2.value)
2293        return TrueDiv(obj1.start, obj2.end, obj1, obj2)
2294
2295    @spark.production('expr6 ::= expr6 % expr6')
2296    def expr_mod(self, obj1, _0, obj2):
2297        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2298            return self.makeconst(obj1.start, obj2.end, obj1.value % obj2.value)
2299        return Mod(obj1.start, obj2.end, obj1, obj2)
2300
2301    @spark.production('expr5 ::= expr5 + expr5')
2302    def expr_add(self, obj1, _0, obj2):
2303        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2304            return self.makeconst(obj1.start, obj2.end, obj1.value + obj2.value)
2305        return Add(obj1.start, obj2.end, obj1, obj2)
2306
2307    @spark.production('expr5 ::= expr5 - expr5')
2308    def expr_sub(self, obj1, _0, obj2):
2309        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2310            return self.makeconst(obj1.start, obj2.end, obj1.value - obj2.value)
2311        return Sub(obj1.start, obj2.end, obj1, obj2)
2312
2313    @spark.production('expr4 ::= expr4 == expr4')
2314    def expr_eq(self, obj1, _0, obj2):
2315        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2316            return self.makeconst(obj1.start, obj2.end, obj1.value == obj2.value)
2317        return EQ(obj1.start, obj2.end, obj1, obj2)
2318
2319    @spark.production('expr4 ::= expr4 != expr4')
2320    def expr_ne(self, obj1, _0, obj2):
2321        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2322            return self.makeconst(obj1.start, obj2.end, obj1.value != obj2.value)
2323        return NE(obj1.start, obj2.end, obj1, obj2)
2324
2325    @spark.production('expr4 ::= expr4 < expr4')
2326    def expr_lt(self, obj1, _0, obj2):
2327        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2328            return self.makeconst(obj1.start, obj2.end, obj1.value < obj2.value)
2329        return LT(obj1.start, obj2.end, obj1, obj2)
2330
2331    @spark.production('expr4 ::= expr4 <= expr4')
2332    def expr_le(self, obj1, _0, obj2):
2333        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2334            return self.makeconst(obj1.start, obj2.end, obj1.value <= obj2.value)
2335        return LE(obj1.start, obj2.end, obj1, obj2)
2336
2337    @spark.production('expr4 ::= expr4 > expr4')
2338    def expr_gt(self, obj1, _0, obj2):
2339        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2340            return self.makeconst(obj1.start, obj2.end, obj1.value > obj2.value)
2341        return GT(obj1.start, obj2.end, obj1, obj2)
2342
2343    @spark.production('expr4 ::= expr4 >= expr4')
2344    def expr_ge(self, obj1, _0, obj2):
2345        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2346            return self.makeconst(obj1.start, obj2.end, obj1.value >= obj2.value)
2347        return GE(obj1.start, obj2.end, obj1, obj2)
2348
2349    @spark.production('expr3 ::= expr3 in expr3')
2350    def expr_contains(self, obj, _0, container):
2351        if isinstance(obj, Const) and isinstance(container, Const): # Constant folding
2352            return self.makeconst(obj.start, container.end, obj.value in container.value)
2353        return Contains(obj.start, container.end, obj, container)
2354
2355    @spark.production('expr3 ::= expr3 not in expr3')
2356    def expr_notcontains(self, obj, _0, _1, container):
2357        if isinstance(obj, Const) and isinstance(container, Const): # Constant folding
2358            return self.makeconst(obj.start, container.end, obj.value not in container.value)
2359        return NotContains(obj.start, container.end, obj, container)
2360
2361    @spark.production('expr2 ::= not expr2')
2362    def expr_not(self, _0, expr):
2363        if isinstance(expr, Const): # Constant folding
2364            return self.makeconst(_0.start, expr.end, not expr.value)
2365        return Not(_0.start, expr.end, expr)
2366
2367    @spark.production('expr1 ::= expr1 and expr1')
2368    def expr_and(self, obj1, _0, obj2):
2369        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2370            return self.makeconst(obj1.start, obj2.end, bool(obj1.value and obj2.value))
2371        return And(obj1.start, obj2.end, obj1, obj2)
2372
2373    @spark.production('expr0 ::= expr0 or expr0')
2374    def expr_or(self, obj1, _0, obj2):
2375        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
2376            return self.makeconst(obj1.start, obj2.end, bool(obj1.value or obj2.value))
2377        return Or(obj1.start, obj2.end, obj1, obj2)
2378
2379    # These rules make operators of different precedences interoperable, by allowing an expression to "drop" its precedence.
2380    @spark.production('expr10 ::= expr11')
2381    @spark.production('expr9 ::= expr10')
2382    @spark.production('expr8 ::= expr9')
2383    @spark.production('expr7 ::= expr8')
2384    @spark.production('expr6 ::= expr7')
2385    @spark.production('expr5 ::= expr6')
2386    @spark.production('expr4 ::= expr5')
2387    @spark.production('expr3 ::= expr4')
2388    @spark.production('expr2 ::= expr3')
2389    @spark.production('expr1 ::= expr2')
2390    @spark.production('expr0 ::= expr1')
2391    def expr_dropprecedence(self, expr):
2392        return expr
2393
2394
2395class ForParser(ExprParser):
2396    emptyerror = "loop expression required"
2397    start = "for"
2398   
2399    @spark.production('for ::= name in expr0')
2400    def for0(self, iter, _0, cont):
2401        return For(iter.start, cont.end, iter, cont)
2402
2403    @spark.production('for ::= ( name , ) in expr0')
2404    def for1(self, _0, iter, _1, _2, _3, cont):
2405        return For(_0.start, cont.end, [iter], cont)
2406
2407    @spark.production('for ::= ( name , name ) in expr0')
2408    def for2a(self, _0, iter1, _1, iter2, _2, _3, cont):
2409        return For(_0.start, cont.end, [iter1, iter2], cont)
2410
2411    @spark.production('for ::= ( name , name , ) in expr0')
2412    def for2b(self, _0, iter1, _1, iter2, _2, _3, _4, cont):
2413        return For(_0.start, cont.end, [iter1, iter2], cont)
2414
2415    @spark.production('for ::= ( name , name , name ) in expr0')
2416    def for3a(self, _0, iter1, _1, iter2, _2, iter3, _3, _4, cont):
2417        return For(_0.start, cont.end, [iter1, iter2, iter3], cont)
2418
2419    @spark.production('for ::= ( name , name , name , ) in expr0')
2420    def for3b(self, _0, iter1, _1, iter2, _2, iter3, _3, _4, _5, cont):
2421        return For(_0.start, cont.end, [iter1, iter2, iter3], cont)
2422
2423
2424class StmtParser(ExprParser):
2425    emptyerror = "statement required"
2426    start = "stmt"
2427
2428    @spark.production('stmt ::= name = expr0')
2429    def stmt_assign(self, name, _0, value):
2430        return StoreVar(name.start, value.end, name, value)
2431
2432    @spark.production('stmt ::= name += expr0')
2433    def stmt_iadd(self, name, _0, value):
2434        return AddVar(name.start, value.end, name, value)
2435
2436    @spark.production('stmt ::= name -= expr0')
2437    def stmt_isub(self, name, _0, value):
2438        return SubVar(name.start, value.end, name, value)
2439
2440    @spark.production('stmt ::= name *= expr0')
2441    def stmt_imul(self, name, _0, value):
2442        return MulVar(name.start, value.end, name, value)
2443
2444    @spark.production('stmt ::= name /= expr0')
2445    def stmt_itruediv(self, name, _0, value):
2446        return TrueDivVar(name.start, value.end, name, value)
2447
2448    @spark.production('stmt ::= name //= expr0')
2449    def stmt_ifloordiv(self, name, _0, value):
2450        return FloorDivVar(name.start, value.end, name, value)
2451
2452    @spark.production('stmt ::= name %= expr0')
2453    def stmt_imod(self, name, _0, value):
2454        return ModVar(name.start, value.end, name, value)
2455
2456    @spark.production('stmt ::= del name')
2457    def stmt_del(self, _0, name):
2458        return DelVar(_0.start, name.end, name)
2459
2460
2461class RenderParser(ExprParser):
2462    emptyerror = "render statement required"
2463    start = "render"
2464
2465    @spark.production('render ::= expr0 ( )')
2466    def emptyrender(self, template, _0, _1):
2467        return Render(template.start, _1.end, template)
2468
2469    @spark.production('buildrender ::= expr0 ( name = expr0')
2470    def startrender(self, template, _0, argname, _1, argvalue):
2471        return Render(template.start, argvalue.end, template, (argname, argvalue))
2472
2473    @spark.production('buildrender ::= expr0 ( ** expr0')
2474    def startrenderupdate(self, template, _0, _1, arg):
2475        return Render(template.start, arg.end, template, (arg, ))
2476
2477    @spark.production('buildrender ::= buildrender , name = expr0')
2478    def buildrender(self, render, _0, argname, _1, argvalue):
2479        render.variables.append((argname, argvalue))
2480        render.end = argvalue.end
2481        return render
2482
2483    @spark.production('buildrender ::= buildrender , ** expr0')
2484    def buildrenderupdate(self, render, _0, _1, arg):
2485        render.variables.append((arg,))
2486        render.end = arg.end
2487        return render
2488
2489    @spark.production('render ::= buildrender )')
2490    def finishrender(self, render, _0):
2491        render.end = _0.end
2492        return render
2493
2494    @spark.production('render ::= buildrender , )')
2495    def finishrender1(self, render, _0, _1):
2496        render.end = _1.end
2497        return render
2498
2499
2500###
2501### Helper functions used at template runtime
2502###
2503
2504def _oct(value):
2505    """
2506    Helper for the ``oct`` function.
2507    """
2508    if value == 0:
2509        return "0o0"
2510    elif value < 0:
2511        return "-0o" + oct(value)[2:]
2512    else:
2513        return "0o" + oct(value)[1:]
2514
2515
2516def _bin(value):
2517    """
2518    Helper for the ``bin`` function.
2519    """
2520    if value == 0:
2521        return "0b0"
2522    if value < 0:
2523        value = -value
2524        prefix = "-0b"
2525    else:
2526        prefix = "0b"
2527    v = []
2528    while value:
2529        v.append(str(value&1))
2530        value >>= 1
2531    return prefix+"".join(v)[::-1]
2532
2533
2534def _format(obj, format):
2535    """
2536    Helper for the ``format`` method.
2537    """
2538    if isinstance(obj, datetime.datetime):
2539        if "%f" in format:
2540            format = format.replace("%f", "%06d" % obj.microsecond) # FIXME: This would replace "%%f", which is wrong (wait for Python 2.6)
2541        return obj.strftime(format.encode("utf-8")) # FIXME: We shouldn't have to encode the format string (wait for Python 3.0)
2542    elif obj is None or isinstance(obj, (int, long, float, str, unicode)):
2543        from ll import stringformat
2544        return stringformat.format_builtin_type(obj, format)
2545    else:
2546        return obj.format(format) # This will raise an ``AttributeError``
2547
2548
2549def _repr(obj):
2550    """
2551    Helper for the ``repr`` function.
2552    """
2553    if isinstance(obj, unicode):
2554        return unicode(repr(obj)[1:])
2555    elif isinstance(obj, str):
2556        return unicode(repr(obj))
2557    elif isinstance(obj, datetime.datetime):
2558        return unicode(obj.isoformat())
2559    elif isinstance(obj, color.Color):
2560        if obj[3] == 0xff:
2561            s = "#%02x%02x%02x" % (obj[0], obj[1], obj[2])
2562            if s[1]==s[2] and s[3]==s[4] and s[5]==s[6]:
2563                return "#%s%s%s" % (s[1], s[3], s[5])
2564            return s
2565        else:
2566            s = "#%02x%02x%02x%02x" % obj
2567            if s[1]==s[2] and s[3]==s[4] and s[5]==s[6] and s[7]==s[8]:
2568                return "#%s%s%s%s" % (s[1], s[3], s[5], s[7])
2569            return s
2570    elif isinstance(obj, list):
2571        return u"[%s]" % u", ".join(_repr(item) for item in obj)
2572    elif isinstance(obj, dict):
2573        return u"{%s}" % u", ".join(u"%s: %s" % (_repr(key), _repr(value)) for (key, value) in obj.iteritems())
2574    else:
2575        return unicode(repr(obj))
2576
2577
2578def _csv(obj):
2579    """
2580    Helper for the ``csv`` function.
2581    """
2582    if obj is None:
2583        return u""
2584    elif not isinstance(obj, basestring):
2585        obj = _repr(obj)
2586    if any(c in obj for c in ',"\n'):
2587        return u'"%s"' % obj.replace('"', '""')
2588    return obj
2589
2590
2591def _type(obj):
2592    """
2593    Helper for the ``type`` function.
2594    """
2595    if obj is None:
2596        return u"none"
2597    elif isinstance(obj, basestring):
2598        return u"str"
2599    elif isinstance(obj, bool):
2600        return u"bool"
2601    elif isinstance(obj, (int, long)):
2602        return u"int"
2603    elif isinstance(obj, float):
2604        return u"float"
2605    elif isinstance(obj, (datetime.datetime, datetime.date)):
2606        return u"date"
2607    elif isinstance(obj, color.Color):
2608        return u"color"
2609    elif isinstance(obj, (list, tuple)):
2610        return u"list"
2611    elif isinstance(obj, dict):
2612        return u"dict"
2613    elif hasattr(obj, "__call__"):
2614        return u"template"
2615    return None
Note: See TracBrowser for help on using the browser.