root/livinglogic.python.xist/src/ll/ul4c.py @ 3466:bea8815e1f2c

Revision 3466:bea8815e1f2c, 68.7 KB (checked in by Walter Doerwald <walter@…>, 11 years ago)

More docstrings. Fix opcode iteration in format method.

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