root/livinglogic.python.xist/src/ll/ul4c.py @ 3546:cd35d2265b48

Revision 3546:cd35d2265b48, 72.5 KB (checked in by Walter Doerwald <walter@…>, 11 years ago)

Fix format() for truediv opcode. Add tests for format.

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