root/livinglogic.python.xist/src/ll/ul4c.py @ 3440:e9732c5765c6

Revision 3440:e9732c5765c6, 61.1 KB (checked in by Walter Doerwald <walter@…>, 11 years ago)

Implement format for the rest of the types by reusing a module from the Python SVN repo.

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