root/livinglogic.googleappengine.lltools/site/ll/ul4c.py @ 28:ffac60e84a1c

Revision 28:ffac60e84a1c, 86.9 KB (checked in by Walter Doerwald <walter@…>, 10 years ago)

Update XIST to 3.6.2.

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