root/livinglogic.python.xist/src/ll/ul4c.py @ 4526:84f2d5c0262e

Revision 4526:84f2d5c0262e, 124.3 KB (checked in by Walter Doerwald <walter@…>, 8 years ago)

Include the template name in the Javascript source code comments.

Line 
1# -*- coding: utf-8 -*-
2
3## Copyright 2009-2011 by LivingLogic AG, Bayreuth/Germany
4## Copyright 2009-2011 by Walter Dörwald
5##
6## All Rights Reserved
7##
8## See ll/__init__.py for the license
9
10
11"""
12:mod:`ll.ul4c` provides templating for XML/HTML as well as any other text-based
13format. A template defines placeholders for data output and basic logic (like
14loops and conditional blocks), that define how the final rendered output will
15look.
16
17:mod:`ll.ul4c` compiles a template to a bytecode format, which makes it possible
18to implement template renderers in multiple programming languages.
19"""
20
21from __future__ import division
22
23__docformat__ = "reStructuredText"
24
25
26import re, datetime, StringIO, locale, json, collections
27
28from ll import spark, color, misc
29
30
31# Regular expression used for splitting dates in isoformat
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", "name", "type", "starttag", "endtag", "startcode", "endcode")
45
46    def __init__(self, source, name, 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:`name`
55                The name of the template the location belongs to.
56
57            :var:`type`
58                The tag type (i.e. ``"for"``, ``"if"``, etc. or ``None`` for
59                literal text)
60
61            :var:`starttag`
62                The start position of the start delimiter.
63
64            :var:`endtag`
65                The end position of the end delimiter.
66
67            :var:`startcode`
68                The start position of the tag code.
69
70            :var:`endcode`
71                The end position of the tag code.
72        """
73        self.source = source
74        self.name = name
75        self.type = type
76        self.starttag = starttag
77        self.endtag = endtag
78        self.startcode = startcode
79        self.endcode = endcode
80
81    def __getitem__(self, key):
82        if key in {"name", "type", "starttag", "endtag", "startcode", "endcode"}:
83            return getattr(self, key)
84        raise KeyError(key)
85
86    @property
87    def code(self):
88        return self.source[self.startcode:self.endcode]
89
90    @property
91    def tag(self):
92        return self.source[self.starttag:self.endtag]
93
94    def __repr__(self):
95        return "<{}.{} {} at {:#x}>".format(self.__class__.__module__, self.__class__.__name__, self, id(self))
96
97    def pos(self):
98        lastlinefeed = self.source.rfind("\n", 0, self.starttag)
99        if lastlinefeed >= 0:
100            return (self.source.count("\n", 0, self.starttag)+1, self.starttag-lastlinefeed)
101        else:
102            return (1, self.starttag + 1)
103
104    def __str__(self):
105        (line, col) = self.pos()
106        return "{!r} at {} (line {}, col {}, template {})".format(self.tag, self.starttag+1, line, col, self.name)
107
108
109###
110### Exceptions
111###
112
113class Error(Exception):
114    """
115    Exception class that wraps another exception and provides a location.
116    """
117    def __init__(self, location):
118        self.location = location
119        self.__cause__ = None
120
121    def __repr__(self):
122        return "<{}.{} in {} at {:#x}>".format(self.__class__.__module__, self.__class__.__name__, self.location, id(self))
123
124    def __str__(self):
125        path = []
126
127        # FIXME: Drop ``__cause__`` traversal in Python 3, as this is done by Python itself
128        exc = self
129        while isinstance(exc, Error):
130            if not path or path[-1] is not exc.location:
131                path.append(exc.location)
132            exc = exc.__cause__
133        name = exc.__class__.__name__
134        module = exc.__class__.__module__
135        if module != "exceptions":
136            name = "{}.{}".format(module, name)
137        return "{} {} {}".format(" ".join("in {}:".format(location) for location in path), name, exc)
138
139
140class LexicalError(Exception):
141    def __init__(self, start, end, input):
142        self.start = start
143        self.end = end
144        self.input = input
145
146    def __str__(self):
147        return "Unmatched input {!r}".format(self.input)
148
149
150class SyntaxError(Exception):
151    def __init__(self, token):
152        self.token = token
153
154    def __str__(self):
155        return "Lexical error near {!r}".format(str(self.token))
156
157
158class UnterminatedStringError(Exception):
159    """
160    Exception that is raised by the parser when a string constant is not
161    terminated.
162    """
163    def __str__(self):
164        return "Unterminated string"
165
166
167class BlockError(Exception):
168    """
169    Exception that is raised by the compiler when an illegal block structure is
170    detected (e.g. an ``endif`` without a previous ``if``).
171    """
172
173    def __init__(self, message):
174        self.message = message
175
176    def __str__(self):
177        return self.message
178
179
180class UnknownFunctionError(Exception):
181    """
182    Exception that is raised by the renderer if the function to be executed by
183    the ``callfunc0``, ``callfunc1``, ``callfunc2``, ``callfunc3`` or
184    ``callfunc4`` opcodes is unknown.
185    """
186
187    def __init__(self, funcname):
188        self.funcname = funcname
189
190    def __str__(self):
191        return "function {!r} unknown".format(self.funcname)
192
193
194class UnknownMethodError(Exception):
195    """
196    Exception that is raised by the renderer if the method to be executed by the
197    ``callmeth0``, ``callmeth1``, ``callmeth2``  or ``callmeth3`` opcodes is
198    unknown.
199    """
200
201    def __init__(self, methname):
202        self.methname = methname
203
204    def __str__(self):
205        return "method {!r} unknown".format(self.methname)
206
207
208class UnknownOpcodeError(Exception):
209    """
210    Exception that is raised when an unknown opcode is encountered by the renderer.
211    """
212
213    def __init__(self, opcode):
214        self.opcode = opcode
215
216    def __str__(self):
217        return "opcode {!r} unknown".format(self.opcode)
218
219
220class OutOfRegistersError(Exception):
221    """
222    Exception that is raised by the compiler when there are no more free
223    registers. This might happen with complex expressions in tag code.
224    """
225
226    def __str__(self):
227        return "out of registers"
228
229
230###
231### opcode class
232###
233
234class Opcode(object):
235    """
236    An :class:`Opcode` stores an opcode. An :class:`Opcode` object has the
237    following attributes:
238
239    :attr:`code` : string or :const:`None`
240        The opcode type (see below for a list).
241
242    :attr:`r1`, :attr:`r2`, :attr:`r3`, :attr:`r4`, :attr:`r5` : integer or ``None``
243         Register specifications (for the sources or the target of the opcode)
244
245    :attr:`arg` : string or :const:`None`
246        Used if the opcode requires an additional argument (like a variable name
247        or the value of a constant).
248
249    :attr:`location` : :class:`Location` object
250        The location of the tag to which this opcode belongs.
251
252    The following opcode types are available:
253
254    ``None``:
255        Print text. The text is available from ``location.code``.
256
257    ``"print"``:
258        Print the content of register :attr:`r1`. (If the object in the register
259        is not a string, it will be converted to a string first.)
260
261    ``"loadnone"``:
262        Load the constant ``None`` into register :attr:`r1`.
263
264    ``"loadfalse"``:
265        Load the constant :const:`False` into register :attr:`r1`.
266
267    ``"loadtrue"``:
268        Load the constant :const:`True` into register :attr:`r1`.
269
270    ``"loadstr"``:
271        Load the string :attr:`arg` into register :attr:`r1`.
272
273    ``"loadint"``:
274        Load the integer value :attr:`arg` into register :attr:`r1`.
275
276    ``"loadfloat"``:
277        Load the float value :attr:`arg` into register :attr:`r1`.
278
279    ``"loaddate"``:
280        Load the date value :attr:`arg` into register :attr:`r1`. :attr:`arg` must
281        be in ISO format (e.g. ``2008-07-02T11:05:55.460464``).
282
283    ``"loadcolor"``:
284        Load the color value :attr:`arg` into register :attr:`r1`. :attr:`arg` must
285        be in the format ``rrggbbaa``).
286
287    ``"buildlist"``:
288        Load an empty list into register :attr:`r1`.
289
290    ``"builddict"``:
291        Load an empty dictionary into register :attr:`r1`.
292
293    ``"addlist"``
294        Append the object in register :attr:`r2` to the list in register :attr:`r1`.
295
296    ``"adddict"``
297        Add a new entry to the dictionary in register :attr:`r1`. The object in
298        :attr:`r2` is the key and the object in register :attr:`r3` is the value.
299
300    ``"updatedict"``
301        Update the dictionary in register :attr:`r1` with the items from the
302        dictionary in :attr:`r2`.
303
304    ``"loadvar"``:
305        Load the variable named :attr:`arg` into the register :attr:`r1`.
306
307    ``"storevar"``:
308        Store the content of register :attr:`r1` in the variable named :attr:`arg`.
309
310    ``"addvar"``:
311        Add the content of register :attr:`r1` to the variable named :attr:`arg`.
312
313    ``"for"``:
314        Start a loop over the object in the register :attr:`r2` and store the
315        object from each loop iteration in the register :attr:`r1`.
316
317    ``"endfor"``:
318        End the innermost running ``for`` loop.
319
320    ``"break"``:
321        Breaks the innermost running ``for`` loop.
322
323    ``"continue"``:
324        Continues the innermost running ``for`` loop (i.e. jumps back to the
325        start of the loop body).
326
327    ``"if"``:
328        Start a conditional block. If the objects in the register :attr:`r1` is
329        true the block will be executed. The "block" consists of all opcodes after
330        the ``if`` upto the matching ``else`` or ``endif`` opcode.
331
332    ``"else"``:
333        Start the else branch of the previous ``if``.
334
335    ``"endif"``:
336        End a conditional block.
337
338    ``"getattr"``:
339        Get the attribute named :attr:`arg` from the object in register :attr:`r2`
340        and store it in register :attr:`r1`.
341
342    ``"getitem"``:
343        Get an item from the object in register :attr:`r2`. If this object is a
344        list or string the object in register :attr:`r3` will be used as the
345        index. If it is a dictionary :attr:`r3` will be used as the key. The
346        result will be stored in register :attr:`r1`.
347
348    ``"getslice12"``:
349        Get an slice from the object in register :attr:`r2`. The object in
350        register :attr:`r3` (which must be an ``int`` or ``None``) specifies
351        the start index, the object in register :attr:`r4` specifies the end index.
352        The result will be stored in register :attr:`r1`.
353
354    ``"getslice1"``:
355        Similar to ``getslice12`` except that the end index is always the length
356        of the object.
357
358    ``"getslice2"``:
359        Similar to ``getslice12`` except that the start index is always 0 and the
360        end index is in register :attr:`r3`.
361
362    ``"not"``:
363        Invert the truth value of the object in register :attr:`r2` and stores the
364        resulting bool in the register :attr:`r1`.
365
366    ``"eq"``:
367        Compare the objects in register :attr:`r2` and :attr:`r3` and store
368        ``True`` in the register :attr:`r1` if they are equal, ``False`` otherwise.
369
370    ``"ne"``:
371        Compare the objects in register :attr:`r2` and :attr:`r3` and store
372        ``False`` in the register :attr:`r1` if they are equal, ``True`` otherwise.
373
374    ``"lt"``:
375        Does a "<" comparison of the objects in register :attr:`r2` and :attr:`r3`
376        and stores the result in register :attr:`r1`.
377
378    ``"le"``:
379        Does a "<=" comparison of the objects in register :attr:`r2` and :attr:`r3`
380        and stores the result in register :attr:`r1`.
381
382    ``"gt"``:
383        Does a ">" comparison of the objects in register :attr:`r2` and :attr:`r3`
384        and stores the result in register :attr:`r1`.
385
386    ``"ge"``:
387        Does a ">=" comparison of the objects in register :attr:`r2` and :attr:`r3`
388        and stores the result in register :attr:`r1`.
389
390    ``"contains"``:
391        Test whether the object in register :attr:`r3` contains the object in
392        register :attr:`r2` (either as a key if :attr:`r3` is a dictionary or as
393        an item if it's a list or as a substring if it's a string) and store
394        ``True`` into the register :attr:`r1` if it does, ``False`` otherwise.
395
396    ``"notcontains"``:
397        Test whether the object in register :attr:`r3` contains the object in
398        register :attr:`r2` (either as a key if :attr:`r3` is a dictionary or as
399        an item if it's a list or as a substring if it's a string) and store
400        ``False`` into the register :attr:`r1` if it does, ``True`` otherwise.
401
402    ``"or"``:
403        Check the truth value of the two objects in registers :attr:`r2` and
404        :attr:`r3` and store :attr:`r2` in the register :attr:`r1` if it is true,
405        :attr:`r3` otherwise).
406
407    ``"and"``:
408        Check the truth value of the two objects in registers :attr:`r2` and
409        :attr:`r3` and store :attr:`r3` in the register :attr:`r1` if :attr:`r2`
410        is true, :attr:`r3` otherwise).
411
412    ``"mod"``:
413        Does a modulo operation: Calculates :attr:`r2` modulo :attr:`r3` and stores
414        the result in register :attr:`r1`.
415
416    ``"callfunc0"``:
417        Call the function named :attr:`arg` without any arguments and store the
418        return value in register :attr:`r1`.
419
420    ``"callfunc1"``:
421        Call the function named :attr:`arg` with the content of register :attr:`r2`
422        as an argument and store the return value in register :attr:`r1`.
423
424    ``"callfunc2"``:
425        Call the function named :attr:`arg` with the contents of register
426        :attr:`r2` and :attr:`r3` as the two arguments and store the return value
427        in register :attr:`r1`.
428
429    ``"callfunc3"``:
430        Call the function named :attr:`arg` with the contents of register
431        :attr:`r2`, :attr:`r3` and :attr:`r4` as the three arguments and store
432        the return value in register :attr:`r1`.
433
434    ``"callfunc4"``:
435        Call the function named :attr:`arg` with the contents of register
436        :attr:`r2`, :attr:`r3`, :attr:`r4` and :attr:`r5` as the four arguments
437        and store the return value in register :attr:`r1`.
438
439    ``"callmeth0"``:
440        Call the method named :attr:`arg` on the object in register :attr:`r2`
441        and store the return value in register :attr:`r1`.
442
443    ``"callmeth1"``:
444        Call the method named :attr:`arg` on the object in register :attr:`r2`
445        using the object in register :attr:`r3` as the only argument and store the
446        return value in register :attr:`r1`.
447
448    ``"callmeth2"``:
449        Call the method named :attr:`arg` on the object in register :attr:`r2`
450        using the objects in register :attr:`r3` and :attr:`r4` as arguments and
451        store the return value in register :attr:`r1`.
452
453    ``"callmeth3"``:
454        Call the method named :attr:`arg` on the object in register :attr:`r2`
455        using the objects in register :attr:`r3`, :attr:`r4` and :attr:`r5` as
456        arguments and store the return value in register :attr:`r1`.
457
458    ``"render"``:
459        Render the template in the attribute :attr:`r1`. The content of register
460        :attr:`r2` (which must be a dictionary) will be passed to the template as
461        the variable dictionary.
462
463    ``"def"``
464        Begin the definition of a local template. The template will be stored in
465        the variable named :attr:`arg`.
466
467    ``"enddef"``
468        End the definition of a local template.
469
470    """
471    __slots__ = ("code", "r1", "r2", "r3", "r4", "r5", "arg", "location")
472
473    def __init__(self, code, r1=None, r2=None, r3=None, r4=None, r5=None, arg=None, location=None):
474        self.code = code
475        self.r1 = r1
476        self.r2 = r2
477        self.r3 = r3
478        self.r4 = r4
479        self.r5 = r5
480        self.arg = arg
481        self.location = location
482
483    def __getitem__(self, key):
484        if key in {"code", "r1", "r2", "r3", "r4", "r5", "arg", "location"}:
485            return getattr(self, key)
486        raise KeyError(key)
487
488    def __repr__(self):
489        v = ["<", self.__class__.__name__, " code={!r}".format(self.code)]
490        for attrname in ("r1", "r2", "r3", "r4", "r5", "arg"):
491            attr = getattr(self, attrname)
492            if attr is not None:
493                v.append(" {}={!r}".format(attrname, attr))
494        if self.code is None:
495            v.append(" text={!r}".format(self.location.code))
496        v.append(" at {:#x}>".format(id(self)))
497        return "".join(v)
498
499    def __str__(self):
500        formats = {
501            None: "print {op.location.code!r}",
502            "print": "print r{op.r1!r}",
503            "printx": "print xmlescape(r{op.r1!r})",
504            "loadnone": "r{op.r1!r} = None",
505            "loadfalse": "r{op.r1!r} = False",
506            "loadtrue": "r{op.r1!r} = True",
507            "loadstr": "r{op.r1!r} = {op.arg!r}",
508            "loadint": "r{op.r1!r} = {op.arg}",
509            "loadfloat": "r{op.r1!r} = {op.arg}",
510            "loaddate": "r{op.r1!r} = {op.arg}",
511            "loadcolor": "r{op.r1!r} = #{op.arg}",
512            "buildlist": "r{op.r1!r} = []",
513            "builddict": "r{op.r1!r} = {{}}",
514            "addlist": "r{op.r1!r}.append(r{op.r2!r})",
515            "adddict": "r{op.r1!r}[r{op.r2!r}] = r{op.r3!r}",
516            "updatedict": "r{op.r1!r}.update(r{op.r2!r})",
517            "loadvar": "r{op.r1!r} = vars[{op.arg!r}]",
518            "storevar": "vars[{op.arg!r}] = r{op.r1!r}",
519            "addvar": "vars[{op.arg!r}] += r{op.r1!r}",
520            "subvar": "vars[{op.arg!r}] -= r{op.r1!r}",
521            "mulvar": "vars[{op.arg!r}] *= r{op.r1!r}",
522            "truedivvar": "vars[{op.arg!r}] /= r{op.r1!r}",
523            "floordivvar": "vars[{op.arg!r}] //= r{op.r1!r}",
524            "modvar": "vars[{op.arg!r}] %= r{op.r1!r}",
525            "delvar": "del vars[{op.arg!r}]",
526            "for": "for r{op.r1!r} in r{op.r2!r}",
527            "endfor": "endfor",
528            "break": "break",
529            "continue": "continue",
530            "if": "if r{op.r1!r}",
531            "else": "else",
532            "endif": "endif",
533            "getattr": "r{op.r1!r} = getattr(r{op.r2!r}, {op.arg!r})",
534            "getitem": "r{op.r1!r} = r{op.r2!r}[r{op.r3!r}]",
535            "getslice1": "r{op.r1!r} = r{op.r2!r}[r{op.r3!r}:]",
536            "getslice2": "r{op.r1!r} = r{op.r2!r}[:r{op.r3!r}]",
537            "getslice12": "r{op.r1!r} = r{op.r2!r}[r{op.r3!r}:r{op.r4!r}]",
538            "not": "r{op.r1!r} = not r{op.r2!r}",
539            "eq": "r{op.r1!r} = r{op.r2!r} == r{op.r3!r}",
540            "ne": "r{op.r1!r} = r{op.r2!r} != r{op.r3!r}",
541            "lt": "r{op.r1!r} = r{op.r2!r} < r{op.r3!r}",
542            "le": "r{op.r1!r} = r{op.r2!r} <= r{op.r3!r}",
543            "gt": "r{op.r1!r} = r{op.r2!r} > r{op.r3!r}",
544            "ge": "r{op.r1!r} = r{op.r2!r} >= r{op.r3!r}",
545            "contains": "r{op.r1!r} = r{op.r2!r} in r{op.r3!r}",
546            "notcontains": "r{op.r1!r} = r{op.r2!r} not in r{op.r3!r}",
547            "add": "r{op.r1!r} = r{op.r2!r} + r{op.r3!r}",
548            "sub": "r{op.r1!r} = r{op.r2!r} - r{op.r3!r}",
549            "mul": "r{op.r1!r} = r{op.r2!r} * r{op.r3!r}",
550            "floordiv": "r{op.r1!r} = r{op.r2!r} // r{op.r3!r}",
551            "truediv": "r{op.r1!r} = r{op.r2!r} / r{op.r3!r}",
552            "and": "r{op.r1!r} = r{op.r2!r} and r{op.r3!r}",
553            "or": "r{op.r1!r} = r{op.r2!r} or r{op.r3!r}",
554            "mod": "r{op.r1!r} = r{op.r2!r} % r{op.r3!r}",
555            "neg":"r{op.r1!r} = -r{op.r2!r}",
556            "callfunc0": "r{op.r1!r} = {op.arg}()",
557            "callfunc1": "r{op.r1!r} = {op.arg}(r{op.r2!r})",
558            "callfunc2": "r{op.r1!r} = {op.arg}(r{op.r2!r}, r{op.r3!r})",
559            "callfunc3": "r{op.r1!r} = {op.arg}(r{op.r2!r}, r{op.r3!r}, r{op.r4!r})",
560            "callfunc4": "r{op.r1!r} = {op.arg}(r{op.r2!r}, r{op.r3!r}, r{op.r4!r}, r{op.r5!r})",
561            "callmeth0": "r{op.r1!r} = r{op.r2!r}.{op.arg}()",
562            "callmeth1": "r{op.r1!r} = r{op.r2!r}.{op.arg}(r{op.r3!r})",
563            "callmeth2": "r{op.r1!r} = r{op.r2!r}.{op.arg}(r{op.r3!r}, r{op.r4!r})",
564            "callmeth3": "r{op.r1!r} = r{op.r3!r}.{op.arg}(r{op.r3!r}, r{op.r4!r}, r{op.r5!r})",
565            "callmethkw": "r{op.r1!r} = r{op.r2!r}.{op.arg}(**r{op.r3!r})",
566            "render": "render r{op.r1!r}(r{op.r2!r})",
567            "def": "def {op.arg}(vars)",
568            "enddef": "endfor",
569        }
570        try:
571            return formats[self.code].format(op=self)
572        except KeyError:
573            raise UnknownOpcodeError(self.code)
574
575
576class Template(object):
577    """
578    A template object is normally creating by passing the template source to the
579    constructor. It can also be loaded from the compiled format via the class
580    methods :meth:`load` (from a stream) or :meth:`loads` (from a string).
581
582    The compiled format can be generated with the methods :meth:`dump` (which
583    dumps the format to a stream) or :meth:`dumps` (which returns a string with
584    the compiled format).
585
586    Rendering the template can be done with the methods :meth:`render` (which
587    is a generator) or :meth:`renders` (which returns a string).
588    """
589    version = "16"
590
591    def __init__(self, source=None, name="unnamed", startdelim="<?", enddelim="?>"):
592        """
593        Create a :class:`Template` object. If :var:`source` is ``None``, the
594        :class:`Template` remains uninitialized, otherwise :var:`source` will be
595        compiled (using :var:`startdelim` and :var:`enddelim` as the tag
596        delimiters). :var:`name` is the name of the template. It will be used in
597        exception messages and should be a valid Python identifier.
598
599        """
600        self.startdelim = startdelim
601        self.enddelim = enddelim
602        self.name = name
603        self.source = None
604        self.opcodes = None
605        # The following is used for converting the opcodes back to executable Python code
606        self._pythonfunction = None
607        if source is not None:
608            self._compile(source, name, startdelim, enddelim)
609
610    def __getitem__(self, key):
611        if key in {"startdelim", "enddelim", "source", "opcodes"}:
612            return getattr(self, key)
613        raise KeyError(key)
614
615    @classmethod
616    def loads(cls, data):
617        """
618        The class method :meth:`loads` loads the template from string :var:`data`.
619        :var:`data` must contain the template in compiled format.
620        """
621        defnames = [] # Names of nested templates
622
623        def _readint(prefix):
624            if prefix is not None:
625                c = stream.read(len(prefix))
626                if c != prefix:
627                    raise ValueError("invalid prefix, expected {!r}, got {!r}".format(prefix, c))
628            i = None
629            while True:
630                c = stream.read(1)
631                if c.isdigit():
632                    if i is None:
633                        i = 0
634                    i = 10*i+int(c)
635                elif c == "|":
636                    return i
637                else:
638                    raise ValueError("invalid separator, expected '|', got {!r}".format(c))
639
640        def _readstr(prefix):
641            if prefix is not None:
642                c = stream.read(len(prefix))
643                if c != prefix:
644                    raise ValueError("invalid prefix, expected {!r}, got {!r}".format(prefix, c))
645            i = None
646            while True:
647                c = stream.read(1)
648                if c.isdigit():
649                    if i is None:
650                        i = 0
651                    i = 10*i+int(c)
652                elif c == "|":
653                    if i is None:
654                        return None
655                    break
656                else:
657                    raise ValueError("invalid separator, expected '|', got {!r}".format(c))
658            s = stream.read(i)
659            if len(s) != i:
660                raise ValueError("short read")
661            c = stream.read(1)
662            if c != "|":
663                raise ValueError("invalid separator, expected '|', got {!r}".format(c))
664            return s
665
666        def _readcr():
667            c = stream.read(1)
668            if c != "\n":
669                raise ValueError("invalid linefeed {!r}".format(c))
670
671        self = cls()
672        stream = StringIO.StringIO(data)
673        header = stream.readline()
674        header = header.rstrip()
675        if header != "ul4":
676            raise ValueError("invalid header, expected 'ul4', got {!r}".format(header))
677        version = stream.readline()
678        version = version.rstrip()
679        if version != self.version:
680            raise ValueError("invalid version, expected {!r}, got {!r}".format(self.version, version))
681        self.name = _readstr(u"N")
682        defnames.append(self.name)
683        _readcr()
684        self.startdelim = _readstr(u"SD")
685        _readcr()
686        self.enddelim = _readstr(u"ED")
687        _readcr()
688        self.source = _readstr("SRC")
689        self.opcodes = []
690        _readcr()
691        count = _readint(u"n")
692        _readcr()
693        location = None
694        while count:
695            r1 = _readint(None)
696            r2 = _readint(None)
697            r3 = _readint(None)
698            r4 = _readint(None)
699            r5 = _readint(None)
700            code = _readstr("C")
701            arg = _readstr("A")
702            locspec = stream.read(1)
703            if code == "enddef":
704                defnames.pop()
705            if locspec == u"^":
706                if location is None:
707                    raise ValueError("no previous location")
708            elif locspec == u"*":
709                locspec2 = stream.read(1)
710                if locspec2 != "|":
711                    raise ValueError("invalid location spec {!r}".format(locspec + locspec2))
712                location = Location(self.source, defnames[-1], _readstr("T"), _readint("st"), _readint("et"), _readint("sc"), _readint("ec"))
713            else:
714                raise ValueError("invalid location spec {!r}".format(locspec))
715            _readcr()
716            count -= 1
717            self.opcodes.append(Opcode(code, r1, r2, r3, r4, r5, arg, location))
718            if code == "def":
719                defnames.append(arg)
720        return self
721
722    @classmethod
723    def load(cls, stream):
724        """
725        The class method :meth:`load` loads the template from the stream
726        :var:`stream`. The stream must contain the template in compiled format.
727        """
728        return cls.loads(stream.read())
729
730    def iterdump(self):
731        """
732        This generator outputs the template in compiled format.
733        """
734        def _writeint(prefix, number):
735            if prefix is not None:
736                yield prefix
737            if number is not None:
738                yield unicode(number)
739            yield u"|"
740
741        def _writestr(prefix, string):
742            yield prefix
743            if string is not None:
744                yield str(len(string))
745                yield u"|"
746                yield string
747            yield u"|"
748
749        yield "ul4\n{}\n".format(self.version)
750        for p in _writestr("N", self.name): yield p
751        yield "\n"
752        for p in _writestr("SD", self.startdelim): yield p
753        yield "\n"
754        for p in _writestr("ED", self.enddelim): yield p
755        yield "\n"
756        for p in _writestr("SRC", self.source): yield p
757        yield "\n"
758        for p in _writeint("n", len(self.opcodes)): yield p
759        yield "\n"
760        lastlocation = None
761        for opcode in self.opcodes:
762            for p in _writeint(None, opcode.r1): yield p
763            for p in _writeint(None, opcode.r2): yield p
764            for p in _writeint(None, opcode.r3): yield p
765            for p in _writeint(None, opcode.r4): yield p
766            for p in _writeint(None, opcode.r5): yield p
767            for p in _writestr("C", opcode.code): yield p
768            for p in _writestr("A", opcode.arg): yield p
769            if opcode.location is not lastlocation:
770                lastlocation = opcode.location
771                yield u"*|"
772                for p in _writestr("T", lastlocation.type): yield p
773                for p in _writeint("st", lastlocation.starttag): yield p
774                for p in _writeint("et", lastlocation.endtag): yield p
775                for p in _writeint("sc", lastlocation.startcode): yield p
776                for p in _writeint("ec", lastlocation.endcode): yield p
777            else:
778                yield "^"
779            yield "\n"
780
781    def dump(self, stream):
782        """
783        :meth:`dump` dumps the template in compiled format to the stream
784        :var:`stream`.
785        """
786        for part in self.iterdump():
787            stream.write(part)
788
789    def dumps(self):
790        """
791        :meth:`dumps` returns the template in compiled format (as a string).
792        """
793        return "".join(self.iterdump())
794
795    def render(self, **variables):
796        """
797        Render the template iteratively (i.e. this is a generator).
798        :var:`variables` contains the top level variables available to the
799        template code.
800        """
801        return self.pythonfunction()(**variables)
802
803    def renders(self, **variables):
804        """
805        Render the template as a string. :var:`variables` contains the top level
806        variables available to the template code.
807        """
808        return "".join(self.pythonfunction()(**variables))
809
810    def pythonfunction(self):
811        """
812        Return a Python generator that can be called to render the template. The
813        argument signature of the function will be ``**variables``.
814        """
815        if self._pythonfunction is None:
816            code = self.pythonsource()
817            ns = {}
818            exec code.encode("utf-8") in ns # FIXME: no need to encode in Python 3
819            self._pythonfunction = ns[self.name]
820        return self._pythonfunction
821
822    def __call__(self, **variables):
823        return self.pythonfunction()(**variables)
824
825    def pythonsource(self, *args, **kwargs):
826        """
827        Return the template as Python source code. All arguments in :var:`args`
828        and :var:`kwargs` will be passed on to the :class:`PythonSource` object
829        which creates the sourcecode. See its constructor for more info.
830        """
831        return unicode(PythonSource(self, *args, **kwargs))
832
833    def jssource(self):
834        """
835        Return the template as the source code of a Javascript function. A
836        :class:`JavascriptSource` object will be used to generated the sourcecode.
837        """
838        return unicode(JavascriptSource(self))
839
840    def javasource(self, *args, **kwargs):
841        """
842        Return the template as Java source code. All arguments in :var:`args`
843        and :var:`kwargs` will be passed on to the :class:`JavaSource` object
844        which creates the sourcecode. See its constructor for more info.
845        """
846        return unicode(JavaSource(self, *args, **kwargs))
847
848    def format(self, indent="\t"):
849        """
850        Format the list of opcodes. This is a generator yielding lines to be output
851        (but without trailing newlines). :var:`indent` can be used to specify how
852        to indent blocks (defaulting to ``"\\t"``).
853        """
854        yield "def {} {{".format(self.name)
855        i = 1
856        for opcode in self.opcodes:
857            if opcode.code in ("else", "endif", "endfor", "enddef"):
858                i -= 1
859            if opcode.code in ("endif", "endfor", "enddef"):
860                yield "{}}}".format(i*indent)
861            elif opcode.code in ("for", "if", "def"):
862                yield "{}{} {{".format(i*indent, opcode)
863            elif opcode.code == "else":
864                yield "{}}} else {{".format(i*indent)
865            else:
866                yield "{}{}".format(i*indent, opcode)
867            if opcode.code in ("for", "if", "else", "def"):
868                i += 1
869        yield "}"
870
871    def _tokenize(self, source, name, startdelim, enddelim):
872        """
873        Tokenize the template source code :var:`source` into tags and non-tag
874        text. :var:`startdelim` and :var:`enddelim` are used as the tag delimiters.
875
876        This is a generator which produces :class:`Location` objects for each tag
877        or non-tag text. It will be called by :meth:`_compile` internally.
878        """
879        pattern = u"{}(printx|print|code|for|if|elif|else|end|break|continue|render|def|note)(\s*((.|\\n)*?)\s*)?{}".format(re.escape(startdelim), re.escape(enddelim))
880        pos = 0
881        for match in re.finditer(pattern, source):
882            if match.start() != pos:
883                yield Location(source, None, None, pos, match.start(), pos, match.start())
884            type = source[match.start(1):match.end(1)]
885            if type != "note":
886                yield Location(source, None, type, match.start(), match.end(), match.start(3), match.end(3))
887            pos = match.end()
888        end = len(source)
889        if pos != end:
890            yield Location(source, None, None, pos, end, pos, end)
891
892    def _allocreg(self):
893        """
894        Allocates a free register from the pool of available registers.
895        """
896        try:
897            return self.registers.pop()
898        except KeyError:
899            raise OutOfRegistersError()
900
901    def _freereg(self, register):
902        """
903        Returns the register :var:`register` to the pool of available registers.
904        """
905        self.registers.add(register)
906
907    def opcode(self, code, r1=None, r2=None, r3=None, r4=None, r5=None, arg=None):
908        """
909        Creates an :class:`Opcode` object and appends it to :var:`self`\s list of
910        opcodes.
911        """
912        self.opcodes.append(Opcode(code, r1, r2, r3, r4, r5, arg, self.location))
913
914    def _compile(self, source, name, startdelim, enddelim):
915        """
916        Compile the template source code :var:`source` into opcodes.
917        :var:`startdelim` and :var:`enddelim` are used as the tag delimiters.
918        """
919        self.name = name
920        self.startdelim = startdelim
921        self.enddelim = enddelim
922        scanner = Scanner()
923        parseexpr = ExprParser(scanner).compile
924        parsestmt = StmtParser(scanner).compile
925        parsefor = ForParser(scanner).compile
926        parserender = RenderParser(scanner).compile
927
928        # This stack stores for each nested for/if/elif/else/def the following information:
929        # 1) Which construct we're in (i.e. "if" or "for")
930        # 2) The start location of the construct
931        # For ifs:
932        # 3) How many if's or elif's we have seen (this is used for simulating elif's via nested if's, for each additional elif, we have one more endif to add)
933        # 4) Whether we've already seen the else
934        stack = []
935
936        self.source = source
937        self.opcodes = []
938
939        for location in self._tokenize(source, name, startdelim, enddelim):
940            self.location = location
941            try:
942                if location.type is None:
943                    self.opcode(None)
944                elif location.type == "print":
945                    r = parseexpr(self)
946                    self.opcode("print", r1=r)
947                elif location.type == "printx":
948                    r = parseexpr(self)
949                    self.opcode("printx", r1=r)
950                elif location.type == "code":
951                    parsestmt(self)
952                elif location.type == "if":
953                    r = parseexpr(self)
954                    self.opcode("if", r1=r)
955                    stack.append(("if", location, 1, False))
956                elif location.type == "elif":
957                    if not stack or stack[-1][0] != "if":
958                        raise BlockError("elif doesn't match any if")
959                    elif stack[-1][3]:
960                        raise BlockError("else already seen in elif")
961                    self.opcode("else")
962                    r = parseexpr(self)
963                    self.opcode("if", r1=r)
964                    stack[-1] = ("if", stack[-1][1], stack[-1][2]+1, False)
965                elif location.type == "else":
966                    if not stack or stack[-1][0] != "if":
967                        raise BlockError("else doesn't match any if")
968                    elif stack[-1][3]:
969                        raise BlockError("duplicate else")
970                    self.opcode("else")
971                    stack[-1] = ("if", stack[-1][1], stack[-1][2], True)
972                elif location.type == "end":
973                    if not stack:
974                        raise BlockError("not in any block")
975                    code = location.code
976                    if code:
977                        if code == "if":
978                            if stack[-1][0] != "if":
979                                raise BlockError("endif doesn't match any if")
980                        elif code == "for":
981                            if stack[-1][0] != "for":
982                                raise BlockError("endfor doesn't match any for")
983                        elif code == "def":
984                            if stack[-1][0] != "def":
985                                raise BlockError("enddef doesn't match any def")
986                        else:
987                            raise BlockError("illegal end value {!r}".format(code))
988                    last = stack.pop()
989                    if last[0] == "if":
990                        for i in xrange(last[2]):
991                            self.opcode("endif")
992                    elif last[0] == "for":
993                        self.opcode("endfor")
994                    else: # last[0] == "def":
995                        self.opcode("enddef")
996                elif location.type == "for":
997                    parsefor(self)
998                    stack.append(("for", location))
999                elif location.type == "break":
1000                    if not any(entry[0] == "for" for entry in stack):
1001                        raise BlockError("break outside of for loop")
1002                    self.opcode("break")
1003                elif location.type == "continue":
1004                    if not any(entry[0] == "for" for entry in stack):
1005                        raise BlockError("continue outside of for loop")
1006                    self.opcode("continue")
1007                elif location.type == "render":
1008                    parserender(self)
1009                elif location.type == "def":
1010                    self.opcode("def", arg=location.code)
1011                    stack.append(("def", location))
1012                else: # Can't happen
1013                    raise ValueError("unknown tag {!r}".format(location.type))
1014            except Exception, exc:
1015                newexc = Error(location) # FIXME: use ``raise ... from`` in Python 3
1016                newexc.__cause__ = exc
1017                raise newexc
1018            finally:
1019                del self.location
1020        if stack:
1021            newexc = Error(stack[-1][1]) # FIXME: use ``raise ... from`` in Python 3
1022            newexc.__cause__ = BlockError("block unclosed")
1023            raise newexc
1024
1025        # Do an extra loop over the opcodes to fix the template names in the location objects
1026        defnames = [name] # This stack stores the names of the nested templates.
1027        for opcode in self.opcodes:
1028            if opcode.code == "enddef":
1029                defnames.pop()
1030            opcode.location.name = defnames[-1]
1031            if opcode.code == "def":
1032                defnames.append(opcode.arg)
1033
1034    def __str__(self):
1035        return "\n".join(self.format())
1036
1037    def __unicode__(self):
1038        return u"\n".join(self.format())
1039
1040    def __repr__(self):
1041        return "<{}.{} object with {} opcodes at {:#x}>".format(self.__class__.__module__, self.__class__.__name__, len(self.opcodes), id(self))
1042
1043
1044###
1045### Code generators for various languages
1046###
1047
1048class PythonSource(object):
1049    """
1050    A :class:`PythonSource` object generates Python sourcecode from a UL4
1051    template.
1052    """
1053
1054    def __init__(self, template):
1055        """
1056        Create a :class:`PythonSource` object. :var:`template` is the
1057        :class:`Template` object.
1058        """
1059        self.template = template
1060
1061    def __unicode__(self):
1062        """
1063        Return the Python sourcecode for the :class:`Template` object passed to
1064        the constructor.
1065        """
1066        self.indent = 0
1067        self.lines = []
1068        self.locations = []
1069        self.lines2locs = []
1070        self.defs = [] # Stack for currently open def opcodes
1071        self.lastopcode = None
1072        self.lastlocation = Location(self.template.source, self.template.name, None, 0, 0, 0, 0)
1073
1074        self._line(self.lastlocation, "def {}(**variables):".format(self.template.name))
1075        self.indent += 1
1076        self.lines2locs = [] # We initialize startline one line below, which restarts the counter
1077        self._line(self.lastlocation, "import sys, datetime, itertools, json, random, collections; from ll.misc import xmlescape; from ll import ul4c, color; startline = sys._getframe().f_lineno") # The line number of this line
1078        self._line(self.lastlocation, "__1__")
1079        self._line(self.lastlocation, "__2__")
1080        self._line(self.lastlocation, "source = {!r}".format(self.template.source))
1081        self._line(self.lastlocation, "name = {!r}".format(self.template.name))
1082        self._line(self.lastlocation, 'variables = {key.decode("utf-8"): value for (key, value) in variables.iteritems()}') # FIXME: This can be dropped in Python 3 where strings are unicode
1083        self._line(self.lastlocation, "r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = r8 = r9 = None")
1084        self._line(self.lastlocation, "try:")
1085        self.indent += 1
1086        # Make sure that the resulting code is a generator even if the byte codes produce no yield statement
1087        self._line(self.lastlocation, "if 0: yield ''")
1088        try:
1089            for opcode in self.template.opcodes:
1090                try:
1091                    getattr(self, "_dispatch_{}".format(opcode.code))(opcode)
1092                except AttributeError:
1093                    raise UnknownOpcodeError(opcode.code)
1094                self.lastopcode = opcode.code
1095        except Exception, exc:
1096            newexc = Error(opcode.location) # FIXME: Use ``raise ... from`` in Python 3
1097            newexc.__cause__ = exc
1098            raise newexc
1099        self.indent -= 1
1100        self._line(self.lastlocation, "except Exception, exc:")
1101        self.indent += 1
1102        self._line(self.lastlocation, "newexc = ul4c.Error(ul4c.Location(source, name, *locations[lines2locs[sys.exc_info()[2].tb_lineno-startline]]))") # FIXME: Use ``raise ... from`` in Python 3
1103        self._line(self.lastlocation, "newexc.__cause__ = exc")
1104        self._line(self.lastlocation, "raise newexc")
1105        locoffset = 1+int(self.lines[0].strip() != "__1__")
1106        self.lines[locoffset] = self.lines[locoffset].replace("__1__", "locations = {!r}".format(tuple(self.locations)))
1107        self.lines[locoffset+1] = self.lines[locoffset+1].replace("__2__", "lines2locs = {!r}".format(tuple(self.lines2locs)))
1108        return "\n".join(self.lines)
1109
1110    def _line(self, location, line):
1111        self.lines.append("\t"*self.indent + line)
1112        if self.lastlocation is not location or not self.locations:
1113            self.locations.append((location.type, location.starttag, location.endtag, location.startcode, location.endcode))
1114            self.lastlocation = location
1115        self.lines2locs.append(len(self.locations)-1)
1116
1117    def _dispatch_None(self, opcode):
1118        self._line(opcode.location, "yield {op.location.code!r}".format(op=opcode))
1119    def _dispatch_loadstr(self, opcode):
1120        self._line(opcode.location, "r{op.r1:d} = {op.arg!r}".format(op=opcode))
1121    def _dispatch_loadint(self, opcode):
1122        self._line(opcode.location, "r{op.r1:d} = {op.arg}".format(op=opcode))
1123    def _dispatch_loadfloat(self, opcode):
1124        self._line(opcode.location, "r{op.r1:d} = {op.arg}".format(op=opcode))
1125    def _dispatch_loadnone(self, opcode):
1126        self._line(opcode.location, "r{op.r1:d} = None".format(op=opcode))
1127    def _dispatch_loadfalse(self, opcode):
1128        self._line(opcode.location, "r{op.r1:d} = False".format(op=opcode))
1129    def _dispatch_loadtrue(self, opcode):
1130        self._line(opcode.location, "r{op.r1:d} = True".format(op=opcode))
1131    def _dispatch_loaddate(self, opcode):
1132        self._line(opcode.location, "r{op.r1:d} = datetime.datetime({date})".format(op=opcode, date=", ".join(str(int(p)) for p in datesplitter.split(opcode.arg))))
1133    def _dispatch_loadcolor(self, opcode):
1134        self._line(opcode.location, "r{op.r1:d} = color.Color({r}, {g}, {b}, {a})".format(op=opcode, r=int(opcode.arg[:2], 16), g=int(opcode.arg[2:4], 16), b=int(opcode.arg[4:6], 16), a=int(opcode.arg[6:], 16)))
1135    def _dispatch_buildlist(self, opcode):
1136        self._line(opcode.location, "r{op.r1:d} = []".format(op=opcode))
1137    def _dispatch_builddict(self, opcode):
1138        self._line(opcode.location, "r{op.r1:d} = {{}}".format(op=opcode))
1139    def _dispatch_addlist(self, opcode):
1140        self._line(opcode.location, "r{op.r1:d}.append(r{op.r2:d})".format(op=opcode))
1141    def _dispatch_adddict(self, opcode):
1142        self._line(opcode.location, "r{op.r1:d}[r{op.r2:d}] = r{op.r3:d}".format(op=opcode))
1143    def _dispatch_updatedict(self, opcode):
1144        self._line(opcode.location, "r{op.r1:d}.update(r{op.r2:d})".format(op=opcode))
1145    def _dispatch_loadvar(self, opcode):
1146        self._line(opcode.location, "r{op.r1:d} = variables[{op.arg!r}]".format(op=opcode))
1147    def _dispatch_storevar(self, opcode):
1148        self._line(opcode.location, "variables[{op.arg!r}] = r{op.r1:d}".format(op=opcode))
1149    def _dispatch_addvar(self, opcode):
1150        self._line(opcode.location, "variables[{op.arg!r}] += r{op.r1:d}".format(op=opcode))
1151    def _dispatch_subvar(self, opcode):
1152        self._line(opcode.location, "variables[{op.arg!r}] -= r{op.r1:d}".format(op=opcode))
1153    def _dispatch_mulvar(self, opcode):
1154        self._line(opcode.location, "variables[{op.arg!r}] *= r{op.r1:d}".format(op=opcode))
1155    def _dispatch_truedivvar(self, opcode):
1156        self._line(opcode.location, "variables[{op.arg!r}] /= r{op.r1:d}".format(op=opcode))
1157    def _dispatch_floordivvar(self, opcode):
1158        self._line(opcode.location, "variables[{op.arg!r}] //= r{op.r1:d}".format(op=opcode))
1159    def _dispatch_modvar(self, opcode):
1160        self._line(opcode.location, "variables[{op.arg!r}] %= r{op.r1:d}".format(op=opcode))
1161    def _dispatch_delvar(self, opcode):
1162        self._line(opcode.location, "del variables[{op.arg!r}]".format(op=opcode))
1163    def _dispatch_getattr(self, opcode):
1164        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}[{op.arg!r}]".format(op=opcode))
1165    def _dispatch_getitem(self, opcode):
1166        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}[r{op.r3:d}]".format(op=opcode))
1167    def _dispatch_getslice12(self, opcode):
1168        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}[r{op.r3:d}:r{op.r4:d}]".format(op=opcode))
1169    def _dispatch_getslice1(self, opcode):
1170        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}[r{op.r3:d}:]".format(op=opcode))
1171    def _dispatch_getslice2(self, opcode):
1172        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}[:r{op.r3:d}]".format(op=opcode))
1173    def _dispatch_print(self, opcode):
1174        self._line(opcode.location, "if r{op.r1:d} is not None: yield unicode(r{op.r1:d})".format(op=opcode))
1175    def _dispatch_printx(self, opcode):
1176        self._line(opcode.location, "if r{op.r1:d} is not None: yield xmlescape(unicode(r{op.r1:d}))".format(op=opcode))
1177    def _dispatch_for(self, opcode):
1178        self._line(opcode.location, "for r{op.r1:d} in r{op.r2:d}:".format(op=opcode))
1179        self.indent += 1
1180    def _dispatch_endfor(self, opcode):
1181        # we don't have to check for empty loops here, as a ``<?for?>`` tag always generates at least one ``storevar`` opcode inside the loop
1182        self.indent -= 1
1183    def _dispatch_break(self, opcode):
1184        self._line(opcode.location, "break")
1185    def _dispatch_continue(self, opcode):
1186        self._line(opcode.location, "continue")
1187    def _dispatch_not(self, opcode):
1188        self._line(opcode.location, "r{op.r1:d} = not r{op.r2:d}".format(op=opcode))
1189    def _dispatch_neg(self, opcode):
1190        self._line(opcode.location, "r{op.r1:d} = -r{op.r2:d}".format(op=opcode))
1191    def _dispatch_contains(self, opcode):
1192        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} in r{op.r3:d}".format(op=opcode))
1193    def _dispatch_notcontains(self, opcode):
1194        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} not in r{op.r3:d}".format(op=opcode))
1195    def _dispatch_eq(self, opcode):
1196        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} == r{op.r3:d}".format(op=opcode))
1197    def _dispatch_ne(self, opcode):
1198        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} != r{op.r3:d}".format(op=opcode))
1199    def _dispatch_lt(self, opcode):
1200        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} < r{op.r3:d}".format(op=opcode))
1201    def _dispatch_le(self, opcode):
1202        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} <= r{op.r3:d}".format(op=opcode))
1203    def _dispatch_gt(self, opcode):
1204        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} > r{op.r3:d}".format(op=opcode))
1205    def _dispatch_ge(self, opcode):
1206        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} >= r{op.r3:d}".format(op=opcode))
1207    def _dispatch_add(self, opcode):
1208        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} + r{op.r3:d}".format(op=opcode))
1209    def _dispatch_sub(self, opcode):
1210        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} - r{op.r3:d}".format(op=opcode))
1211    def _dispatch_mul(self, opcode):
1212        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} * r{op.r3:d}".format(op=opcode))
1213    def _dispatch_floordiv(self, opcode):
1214        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} // r{op.r3:d}".format(op=opcode))
1215    def _dispatch_truediv(self, opcode):
1216        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} / r{op.r3:d}".format(op=opcode))
1217    def _dispatch_and(self, opcode):
1218        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} and r{op.r3:d}".format(op=opcode))
1219    def _dispatch_or(self, opcode):
1220        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} or r{op.r3:d}".format(op=opcode))
1221    def _dispatch_mod(self, opcode):
1222        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} % r{op.r3:d}".format(op=opcode))
1223    def _dispatch_callfunc0(self, opcode):
1224        try:
1225            getattr(self, "_dispatch_callfunc0_{op.arg}".format(op=opcode))(opcode)
1226        except AttributeError:
1227            raise UnknownFunctionError(opcode.arg)
1228    def _dispatch_callfunc1(self, opcode):
1229        try:
1230            getattr(self, "_dispatch_callfunc1_{op.arg}".format(op=opcode))(opcode)
1231        except AttributeError:
1232            raise UnknownFunctionError(opcode.arg)
1233    def _dispatch_callfunc2(self, opcode):
1234        try:
1235            getattr(self, "_dispatch_callfunc2_{op.arg}".format(op=opcode))(opcode)
1236        except AttributeError:
1237            raise UnknownFunctionError(opcode.arg)
1238    def _dispatch_callfunc3(self, opcode):
1239        try:
1240            getattr(self, "_dispatch_callfunc3_{op.arg}".format(op=opcode))(opcode)
1241        except AttributeError:
1242            raise UnknownFunctionError(opcode.arg)
1243    def _dispatch_callfunc4(self, opcode):
1244        try:
1245            getattr(self, "_dispatch_callfunc4_{op.arg}".format(op=opcode))(opcode)
1246        except AttributeError:
1247            raise UnknownFunctionError(opcode.arg)
1248    def _dispatch_callmeth0(self, opcode):
1249        if opcode.arg in ("split", "rsplit", "strip", "lstrip", "rstrip", "upper", "lower", "capitalize", "r", "g", "b", "a", "hls", "hlsa", "hsv", "hsva", "lum", "weekday"):
1250            self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}.{op.arg}()".format(op=opcode))
1251        elif opcode.arg == "items":
1252            self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}.iteritems()".format(op=opcode))
1253        elif opcode.arg == "render":
1254            self._line(opcode.location, 'r{op.r1:d} = "".join(r{op.r2:d}())'.format(op=opcode))
1255        elif opcode.arg in ("mimeformat", "yearday", "isoformat"):
1256            self._line(opcode.location, 'r{op.r1:d} = ul4c._{op.arg}(r{op.r2:d})'.format(op=opcode))
1257        elif opcode.arg in ("day", "month", "year", "hour", "minute", "second", "microsecond"):
1258            self._line(opcode.location, 'r{op.r1:d} = r{op.r2:d}.{op.arg}'.format(op=opcode))
1259        else:
1260            raise UnknownMethodError(opcode.arg)
1261    def _dispatch_callmeth1(self, opcode):
1262        if opcode.arg in ("split", "rsplit", "strip", "lstrip", "rstrip", "startswith", "endswith", "find", "rfind", "get", "withlum", "witha"):
1263            self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}.{op.arg}(r{op.r3:d})".format(op=opcode))
1264        elif opcode.arg == "join":
1265            self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}.join(unicode(x) for x in r{op.r3:d})".format(op=opcode))
1266        elif opcode.arg == "format":
1267            self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}.__format__(r{op.r3:d})".format(op=opcode))
1268        else:
1269            raise UnknownMethodError(opcode.arg)
1270    def _dispatch_callmeth2(self, opcode):
1271        if opcode.arg in ("split", "rsplit", "find", "rfind", "replace", "get"):
1272            self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}.{op.arg}(r{op.r3:d}, r{op.r4:d})".format(op=opcode))
1273        else:
1274            raise UnknownMethodError(opcode.arg)
1275    def _dispatch_callmeth3(self, opcode):
1276        if opcode.arg in {"find", "rfind"}:
1277            self._line(opcode.location, "r{op.r1:d} = r{op.r2:d}.{op.arg}(r{op.r3:d}, r{op.r4:d}, r{op.r5:d})".format(op=opcode))
1278        else:
1279            raise UnknownMethodError(opcode.arg)
1280    def _dispatch_callmethkw(self, opcode):
1281        if opcode.arg == "render":
1282            self._line(opcode.location, 'r{op.r1:d} = "".join(r{op.r2:d}(**{{key.encode("utf-8"): value for (key, value) in r{op.r3:d}.iteritems()}}))'.format(op=opcode)) # FIXME: This can be simplified in Python 3 where strings are unicode
1283        else:
1284            raise UnknownMethodError(opcode.arg)
1285    def _dispatch_if(self, opcode):
1286        self._line(opcode.location, "if r{op.r1:d}:".format(op=opcode))
1287        self.indent += 1
1288    def _dispatch_else(self, opcode):
1289        if self.lastopcode == "if":
1290            self.lines[-1] += " pass"
1291        self.indent -= 1
1292        self._line(opcode.location, "else:")
1293        self.indent += 1
1294    def _dispatch_endif(self, opcode):
1295        if self.lastopcode in ("if", "else"):
1296            lines[-1] += " pass"
1297        self.indent -= 1
1298    def _dispatch_def(self, opcode):
1299        self._line(opcode.location, "def _template_{}(**variables):".format(opcode.arg))
1300        self.defs.append(opcode)
1301        self.indent += 1
1302        self._line(opcode.location, "name = {!r}".format(opcode.arg))
1303        self._line(opcode.location, 'variables = {key.decode("utf-8"): value for (key, value) in variables.iteritems()}') # FIXME: This can be dropped in Python 3 where strings are unicode
1304        self._line(opcode.location, "r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = r8 = r9 = None")
1305        self._line(opcode.location, "try:")
1306        self.indent += 1
1307        # Make sure that the resulting code is a generator even if the byte codes produce no yield statement
1308        self._line(opcode.location, "if 0: yield ''")
1309    def _dispatch_enddef(self, opcode):
1310        defopcode = self.defs.pop()
1311        self.indent -= 1
1312        self._line(opcode.location, "except Exception, exc:")
1313        self.indent += 1
1314        self._line(opcode.location, "newexc = ul4c.Error(ul4c.Location(source, name, *locations[lines2locs[sys.exc_info()[2].tb_lineno-startline]]))") # FIXME: Use ``raise ... from`` in Python 3
1315        self._line(opcode.location, "newexc.__cause__ = exc")
1316        self._line(opcode.location, "raise newexc")
1317        self.indent -= 2
1318        self._line(opcode.location, "variables[{op.arg!r}] = _template_{op.arg}".format(op=defopcode))
1319    def _dispatch_render(self, opcode):
1320        self._line(opcode.location, 'for chunk in r{op.r1:d}(**{{key.encode("utf-8"): value for (key, value) in r{op.r2:d}.iteritems()}}): yield chunk'.format(op=opcode))
1321    def _dispatch_callfunc0_now(self, opcode):
1322        self._line(opcode.location, "r{op.r1:d} = datetime.datetime.now()".format(op=opcode))
1323    def _dispatch_callfunc0_utcnow(self, opcode):
1324        self._line(opcode.location, "r{op.r1:d} = datetime.datetime.utcnow()".format(op=opcode))
1325    def _dispatch_callfunc0_vars(self, opcode):
1326        self._line(opcode.location, "r{op.r1:d} = variables".format(op=opcode))
1327    def _dispatch_callfunc0_random(self, opcode):
1328        self._line(opcode.location, "r{op.r1:d} = random.random()".format(op=opcode))
1329    def _dispatch_callfunc1_xmlescape(self, opcode):
1330        self._line(opcode.location, "r{op.r1:d} = xmlescape(unicode(r{op.r2:d})) if r{op.r2:d} is not None else u''".format(op=opcode))
1331    def _dispatch_callfunc1_csv(self, opcode):
1332        self._line(opcode.location, "r{op.r1:d} = ul4c._csv(r{op.r2:d})".format(op=opcode))
1333    def _dispatch_callfunc1_json(self, opcode):
1334        self._line(opcode.location, "r{op.r1:d} = ul4c._json(r{op.r2:d})".format(op=opcode))
1335    def _dispatch_callfunc1_str(self, opcode):
1336        self._line(opcode.location, "r{op.r1:d} = unicode(r{op.r2:d}) if r{op.r2:d} is not None else u''".format(op=opcode))
1337    def _dispatch_callfunc1_int(self, opcode):
1338        self._line(opcode.location, "r{op.r1:d} = int(r{op.r2:d})".format(op=opcode))
1339    def _dispatch_callfunc1_float(self, opcode):
1340        self._line(opcode.location, "r{op.r1:d} = float(r{op.r2:d})".format(op=opcode))
1341    def _dispatch_callfunc1_bool(self, opcode):
1342        self._line(opcode.location, "r{op.r1:d} = bool(r{op.r2:d})".format(op=opcode))
1343    def _dispatch_callfunc1_len(self, opcode):
1344        self._line(opcode.location, "r{op.r1:d} = len(r{op.r2:d})".format(op=opcode))
1345    def _dispatch_callfunc1_abs(self, opcode):
1346        self._line(opcode.location, "r{op.r1:d} = abs(r{op.r2:d})".format(op=opcode))
1347    def _dispatch_callfunc1_enumerate(self, opcode):
1348        self._line(opcode.location, "r{op.r1:d} = enumerate(r{op.r2:d})".format(op=opcode))
1349    def _dispatch_callfunc1_isnone(self, opcode):
1350        self._line(opcode.location, "r{op.r1:d} = r{op.r2:d} is None".format(op=opcode))
1351    def _dispatch_callfunc1_isstr(self, opcode):
1352        self._line(opcode.location, "r{op.r1:d} = isinstance(r{op.r2:d}, basestring)".format(op=opcode))
1353    def _dispatch_callfunc1_isint(self, opcode):
1354        self._line(opcode.location, "r{op.r1:d} = isinstance(r{op.r2:d}, (int, long)) and not isinstance(r{op.r2:d}, bool)".format(op=opcode))
1355    def _dispatch_callfunc1_isfloat(self, opcode):
1356        self._line(opcode.location, "r{op.r1:d} = isinstance(r{op.r2:d}, float)".format(op=opcode))
1357    def _dispatch_callfunc1_isbool(self, opcode):
1358        self._line(opcode.location, "r{op.r1:d} = isinstance(r{op.r2:d}, bool)".format(op=opcode))
1359    def _dispatch_callfunc1_isdate(self, opcode):
1360        self._line(opcode.location, "r{op.r1:d} = isinstance(r{op.r2:d}, datetime.datetime)".format(op=opcode))
1361    def _dispatch_callfunc1_islist(self, opcode):
1362        self._line(opcode.location, "r{op.r1:d} = isinstance(r{op.r2:d}, collections.Sequence) and not isinstance(r{op.r2:d}, (str, unicode, color.Color))".format(op=opcode))
1363    def _dispatch_callfunc1_isdict(self, opcode):
1364        self._line(opcode.location, "r{op.r1:d} = isinstance(r{op.r2:d}, collections.Mapping)".format(op=opcode))
1365    def _dispatch_callfunc1_istemplate(self, opcode):
1366        self._line(opcode.location, "r{op.r1:d} = hasattr(r{op.r2:d}, '__call__')".format(op=opcode)) # this supports normal generators too
1367    def _dispatch_callfunc1_iscolor(self, opcode):
1368        self._line(opcode.location, "r{op.r1:d} = isinstance(r{op.r2:d}, color.Color)".format(op=opcode))
1369    def _dispatch_callfunc1_repr(self, opcode):
1370        self._line(opcode.location, "r{op.r1:d} = ul4c._repr(r{op.r2:d})".format(op=opcode))
1371    def _dispatch_callfunc1_get(self, opcode):
1372        self._line(opcode.location, "r{op.r1:d} = variables.get(r{op.r2:d})".format(op=opcode))
1373    def _dispatch_callfunc1_chr(self, opcode):
1374        self._line(opcode.location, "r{op.r1:d} = unichr(r{op.r2:d})".format(op=opcode))
1375    def _dispatch_callfunc1_ord(self, opcode):
1376        self._line(opcode.location, "r{op.r1:d} = ord(r{op.r2:d})".format(op=opcode))
1377    def _dispatch_callfunc1_hex(self, opcode):
1378        self._line(opcode.location, "r{op.r1:d} = hex(r{op.r2:d})".format(op=opcode))
1379    def _dispatch_callfunc1_oct(self, opcode):
1380        self._line(opcode.location, "r{op.r1:d} = ul4c._oct(r{op.r2:d})".format(op=opcode))
1381    def _dispatch_callfunc1_bin(self, opcode):
1382        self._line(opcode.location, "r{op.r1:d} = bin(r{op.r2:d})".format(op=opcode))
1383    def _dispatch_callfunc1_sorted(self, opcode):
1384        self._line(opcode.location, "r{op.r1:d} = sorted(r{op.r2:d})".format(op=opcode))
1385    def _dispatch_callfunc1_range(self, opcode):
1386        self._line(opcode.location, "r{op.r1:d} = xrange(r{op.r2:d})".format(op=opcode))
1387    def _dispatch_callfunc1_type(self, opcode):
1388        self._line(opcode.location, "r{op.r1:d} = ul4c._type(r{op.r2:d})".format(op=opcode))
1389    def _dispatch_callfunc1_reversed(self, opcode):
1390        self._line(opcode.location, "r{op.r1:d} = reversed(r{op.r2:d})".format(op=opcode))
1391    def _dispatch_callfunc1_randrange(self, opcode):
1392        self._line(opcode.location, "r{op.r1:d} = random.randrange(r{op.r2:d})".format(op=opcode))
1393    def _dispatch_callfunc1_randchoice(self, opcode):
1394        self._line(opcode.location, "r{op.r1:d} = random.choice(r{op.r2:d})".format(op=opcode))
1395    def _dispatch_callfunc2_format(self, opcode):
1396        self._line(opcode.location, "r{op.r1:d} = format(r{op.r2:d}, r{op.r3:d})".format(op=opcode))
1397    def _dispatch_callfunc2_range(self, opcode):
1398        self._line(opcode.location, "r{op.r1:d} = xrange(r{op.r2:d}, r{op.r3:d})".format(op=opcode))
1399    def _dispatch_callfunc2_get(self, opcode):
1400        self._line(opcode.location, "r{op.r1:d} = variables.get(r{op.r2:d}, r{op.r3:d})".format(op=opcode))
1401    def _dispatch_callfunc2_zip(self, opcode):
1402        self._line(opcode.location, "r{op.r1:d} = itertools.izip(r{op.r2:d}, r{op.r3:d})".format(op=opcode))
1403    def _dispatch_callfunc2_int(self, opcode):
1404        self._line(opcode.location, "r{op.r1:d} = int(r{op.r2:d}, r{op.r3:d})".format(op=opcode))
1405    def _dispatch_callfunc2_randrange(self, opcode):
1406        self._line(opcode.location, "r{op.r1:d} = random.randrange(r{op.r2:d}, r{op.r3:d})".format(op=opcode))
1407    def _dispatch_callfunc3_range(self, opcode):
1408        self._line(opcode.location, "r{op.r1:d} = xrange(r{op.r2:d}, r{op.r3:d}, r{op.r4:d})".format(op=opcode))
1409    def _dispatch_callfunc3_zip(self, opcode):
1410        self._line(opcode.location, "r{op.r1:d} = itertools.izip(r{op.r2:d}, r{op.r3:d}, r{op.r4:d})".format(op=opcode))
1411    def _dispatch_callfunc3_rgb(self, opcode):
1412        self._line(opcode.location, "r{op.r1:d} = color.Color.fromrgb(r{op.r2:d}, r{op.r3:d}, r{op.r4:d})".format(op=opcode))
1413    def _dispatch_callfunc3_hls(self, opcode):
1414        self._line(opcode.location, "r{op.r1:d} = color.Color.fromhls(r{op.r2:d}, r{op.r3:d}, r{op.r4:d})".format(op=opcode))
1415    def _dispatch_callfunc3_hsv(self, opcode):
1416        self._line(opcode.location, "r{op.r1:d} = color.Color.fromhsv(r{op.r2:d}, r{op.r3:d}, r{op.r4:d})".format(op=opcode))
1417    def _dispatch_callfunc3_randrange(self, opcode):
1418        self._line(opcode.location, "r{op.r1:d} = random.randrange(r{op.r2:d}, r{op.r3:d}, r{op.r4:d})".format(op=opcode))
1419    def _dispatch_callfunc4_rgb(self, opcode):
1420        self._line(opcode.location, "r{op.r1:d} = color.Color.fromrgb(r{op.r2:d}, r{op.r3:d}, r{op.r4:d}, r{op.r5:d})".format(op=opcode))
1421    def _dispatch_callfunc4_hls(self, opcode):
1422        self._line(opcode.location, "r{op.r1:d} = color.Color.fromhls(r{op.r2:d}, r{op.r3:d}, r{op.r4:d}, r{op.r5:d})".format(op=opcode))
1423    def _dispatch_callfunc4_hsv(self, opcode):
1424        self._line(opcode.location, "r{op.r1:d} = color.Color.fromhsv(r{op.r2:d}, r{op.r3:d}, r{op.r4:d}, r{op.r5:d})".format(op=opcode))
1425
1426
1427class JavascriptSource(object):
1428    """
1429    A :class:`JavascriptSource` object generates javascript sourcecode from a UL4
1430    template.
1431
1432    The signature of the generated Javascript function will be ``function(vars)``,
1433    i.e. all template variables will be attributes of the object ``vars``.
1434
1435    Note that the generated code will require the ``ul4`` Javascript support
1436    library.
1437    """
1438    def __init__(self, template):
1439        """
1440        Create a :class:`JavascriptSource` object. :var:`template` is the
1441        :class:`Template` object.
1442        """
1443        self.template = template
1444
1445    def __unicode__(self):
1446        """
1447        Return the Javascript sourcecode for the :class:`Template` object passed
1448        to the constructor.
1449        """
1450        self._indent = 0
1451        self._lines = []
1452        self._varcounter = 0
1453
1454        self._line("ul4.Template.create('{}', function(vars){{".format(self.template.name))
1455        self._indent += 1
1456
1457        self._line(u"//@@@ BEGIN template source")
1458        lines = self.template.source.splitlines(False)
1459        width = len(str(len(lines)+1))
1460        for (i, line) in enumerate(lines):
1461            self._line(u"// {1:{0}} {2}".format(width, i+1, line))
1462        self._line(u"//@@@ BEGIN template code")
1463
1464        self._line(u"var out = [], {};".format(", ".join("r{} = null".format(i) for i in xrange(10))))
1465
1466        lastloc = None
1467        for opcode in self.template.opcodes:
1468            if opcode.code is not None and opcode.location is not lastloc:
1469                lastloc = opcode.location
1470                (line, col) = lastloc.pos()
1471                tag = lastloc.tag
1472                self._line(u"// <?{}?> tag at position {} (line {}, col {}, template {}): {}".format(lastloc.type, lastloc.starttag+1, line, col, lastloc.name, repr(tag)[1+isinstance(tag, unicode):-1]))
1473            try:
1474                getattr(self, "_dispatch_{}".format(opcode.code))(opcode)
1475            except AttributeError:
1476                raise UnknownOpcodeError(opcode.code)
1477
1478        self._line(u'return out;')
1479        self._line(u"//@@@ END template code")
1480
1481        self._indent -= 1
1482        self._line("})")
1483
1484        return "\n".join(self._lines)
1485
1486    def _line(self, line):
1487        self._lines.append(u"\t"*self._indent + line)
1488
1489    def _dispatch_None(self, opcode):
1490        self._line("out.push({});".format(json.dumps(opcode.location.code)))
1491    def _dispatch_loadstr(self, opcode):
1492        self._line(u'r{op.r1} = {arg};'.format(op=opcode, arg=json.dumps(opcode.arg)))
1493    def _dispatch_loadint(self, opcode):
1494        self._line(u"r{op.r1} = {op.arg};".format(op=opcode))
1495    def _dispatch_loadfloat(self, opcode):
1496        self._line(u"r{op.r1} = {op.arg};".format(op=opcode))
1497    def _dispatch_loadnone(self, opcode):
1498        self._line(u"r{op.r1} = null;".format(op=opcode))
1499    def _dispatch_loadfalse(self, opcode):
1500        self._line(u"r{op.r1} = false;".format(op=opcode))
1501    def _dispatch_loadtrue(self, opcode):
1502        self._line(u"r{op.r1} = true;".format(op=opcode))
1503    def _dispatch_loaddate(self, opcode):
1504        args = map(int, datesplitter.split(opcode.arg))
1505        args[1] -= 1
1506        if len(args) == 7:
1507            args[6] //= 1000
1508        self._line(u"r{op.r1} = new Date({date});".format(op=opcode, date=", ".join(map(str, args))))
1509    def _dispatch_loadcolor(self, opcode):
1510        self._line(u"r{op.r1} = ul4.Color.create({r}, {g}, {b}, {a});".format(op=opcode, r=int(opcode.arg[:2], 16), g=int(opcode.arg[2:4], 16), b=int(opcode.arg[4:6], 16), a=int(opcode.arg[6:], 16)))
1511    def _dispatch_buildlist(self, opcode):
1512        self._line(u"r{op.r1} = [];".format(op=opcode))
1513    def _dispatch_builddict(self, opcode):
1514        self._line(u"r{op.r1} = {{}};".format(op=opcode))
1515    def _dispatch_addlist(self, opcode):
1516        self._line(u"r{op.r1}.push(r{op.r2});".format(op=opcode))
1517    def _dispatch_adddict(self, opcode):
1518        self._line(u"r{op.r1}[r{op.r2}] = r{op.r3};".format(op=opcode))
1519    def _dispatch_updatedict(self, opcode):
1520        self._line(u"for (var key in r{op.r2})".format(op=opcode))
1521        self._indent += 1
1522        self._line(u"r{op.r1}[key] = r{op.r2}[key];".format(op=opcode))
1523        self._indent -= 1
1524    def _dispatch_loadvar(self, opcode):
1525        self._line(u"r{op.r1} = ul4._op_getitem(vars, {arg});".format(op=opcode, arg=json.dumps(opcode.arg)))
1526    def _dispatch_storevar(self, opcode):
1527        self._line(u"vars[{arg}] = r{op.r1};".format(op=opcode, arg=json.dumps(opcode.arg)))
1528    def _dispatch_addvar(self, opcode):
1529        self._line(u"vars[{arg}] = ul4._op_add(vars[{arg}], r{op.r1});".format(op=opcode, arg=json.dumps(opcode.arg)))
1530    def _dispatch_subvar(self, opcode):
1531        self._line(u"vars[{arg}] = ul4._op_sub(vars[{arg}], r{op.r1});".format(op=opcode, arg=json.dumps(opcode.arg)))
1532    def _dispatch_mulvar(self, opcode):
1533        self._line(u"vars[{arg}] = ul4._op_mul(vars[{arg}], r{op.r1});".format(op=opcode, arg=json.dumps(opcode.arg)))
1534    def _dispatch_truedivvar(self, opcode):
1535        self._line(u"vars[{arg}] = ul4._op_truediv(vars[{arg}], r{op.r1});".format(op=opcode, arg=json.dumps(opcode.arg)))
1536    def _dispatch_floordivvar(self, opcode):
1537        self._line(u"vars[{arg}] = ul4._op_floordiv(vars[{arg}], r{op.r1});".format(op=opcode, arg=json.dumps(opcode.arg)))
1538    def _dispatch_modvar(self, opcode):
1539        self._line(u"vars[{arg}] = ul4._op_mod(vars[{arg}], r{op.r1});".format(op=opcode, arg=json.dumps(opcode.arg)))
1540    def _dispatch_delvar(self, opcode):
1541        self._line(u"vars[{arg}] = undefined;".format(arg=json.dumps(opcode.arg)))
1542    def _dispatch_getattr(self, opcode):
1543        self._line(u"r{op.r1} = ul4._op_getitem(r{op.r2}, {arg});".format(op=opcode, arg=json.dumps(opcode.arg)))
1544    def _dispatch_getitem(self, opcode):
1545        self._line(u"r{op.r1} = ul4._op_getitem(r{op.r2}, r{op.r3});".format(op=opcode))
1546    def _dispatch_getslice12(self, opcode):
1547        self._line(u"r{op.r1} = ul4._op_getslice(r{op.r2}, r{op.r3}, r{op.r4});".format(op=opcode))
1548    def _dispatch_getslice1(self, opcode):
1549        self._line(u"r{op.r1} = ul4._op_getslice(r{op.r2}, r{op.r3}, null);".format(op=opcode))
1550    def _dispatch_getslice2(self, opcode):
1551        self._line(u"r{op.r1} = ul4._op_getslice(r{op.r2}, null, r{op.r3});".format(op=opcode))
1552    def _dispatch_print(self, opcode):
1553        self._line(u"out.push(ul4._fu_str(r{op.r1}));".format(op=opcode))
1554    def _dispatch_printx(self, opcode):
1555        self._line(u"out.push(ul4._fu_xmlescape(r{op.r1}));".format(op=opcode))
1556    def _dispatch_for(self, opcode):
1557        self._varcounter += 1
1558        self._line(u"for (var iter{counter} = ul4._iter(r{op.r2});;)".format(op=opcode, counter=self._varcounter))
1559        self._line(u"{")
1560        self._indent += 1
1561        self._line(u"r{op.r1} = iter{counter}();".format(op=opcode, counter=self._varcounter))
1562        self._line(u"if (r{op.r1} === null)".format(op=opcode))
1563        self._indent += 1
1564        self._line(u"break;")
1565        self._indent -= 1
1566        self._line(u"r{op.r1} = r{op.r1}[0];".format(op=opcode))
1567    def _dispatch_endfor(self, opcode):
1568        self._indent -= 1
1569        self._line(u"}")
1570    def _dispatch_def(self, opcode):
1571        self._line(u"vars[{arg}] = ul4.Template.create({arg}, function(vars){{".format(arg=json.dumps(opcode.arg)))
1572        self._indent += 1
1573        self._line(u"var out = [], {};".format(", ".join("r{} = null".format(i) for i in xrange(10))))
1574    def _dispatch_enddef(self, opcode):
1575        self._line(u'return out;')
1576        self._indent -= 1
1577        self._line(u"});")
1578    def _dispatch_break(self, opcode):
1579        self._line(u"break;")
1580    def _dispatch_continue(self, opcode):
1581        self._line(u"continue;")
1582    def _dispatch_not(self, opcode):
1583        self._line(u"r{op.r1} = !ul4._fu_bool(r{op.r2});".format(op=opcode))
1584    def _dispatch_neg(self, opcode):
1585        self._line(u"r{op.r1} = ul4._op_neg(r{op.r2});".format(op=opcode))
1586    def _dispatch_contains(self, opcode):
1587        self._line(u"r{op.r1} = ul4._op_contains(r{op.r2}, r{op.r3});".format(op=opcode))
1588    def _dispatch_notcontains(self, opcode):
1589        self._line(u"r{op.r1} = !ul4._op_contains(r{op.r2}, r{op.r3});".format(op=opcode))
1590    def _dispatch_eq(self, opcode):
1591        self._line(u"r{op.r1} = ul4._op_eq(r{op.r2}, r{op.r3});".format(op=opcode))
1592    def _dispatch_ne(self, opcode):
1593        self._line(u"r{op.r1} = !ul4._op_eq(r{op.r2}, r{op.r3});".format(op=opcode))
1594    def _dispatch_lt(self, opcode):
1595        self._line(u"r{op.r1} = ul4._op_lt(r{op.r2}, r{op.r3});".format(op=opcode))
1596    def _dispatch_le(self, opcode):
1597        self._line(u"r{op.r1} = ul4._op_le(r{op.r2}, r{op.r3});".format(op=opcode))
1598    def _dispatch_gt(self, opcode):
1599        self._line(u"r{op.r1} = !ul4._op_le(r{op.r2}, r{op.r3});".format(op=opcode))
1600    def _dispatch_ge(self, opcode):
1601        self._line(u"r{op.r1} = !ul4._op_lt(r{op.r2}, r{op.r3});".format(op=opcode))
1602    def _dispatch_add(self, opcode):
1603        self._line(u"r{op.r1} = ul4._op_add(r{op.r2}, r{op.r3});".format(op=opcode))
1604    def _dispatch_sub(self, opcode):
1605        self._line(u"r{op.r1} = ul4._op_sub(r{op.r2}, r{op.r3});".format(op=opcode))
1606    def _dispatch_mul(self, opcode):
1607        self._line(u"r{op.r1} = ul4._op_mul(r{op.r2}, r{op.r3});".format(op=opcode))
1608    def _dispatch_floordiv(self, opcode):
1609        self._line(u"r{op.r1} = ul4._op_floordiv(r{op.r2}, r{op.r3});".format(op=opcode))
1610    def _dispatch_truediv(self, opcode):
1611        self._line(u"r{op.r1} = ul4._op_truediv(r{op.r2}, r{op.r3});".format(op=opcode))
1612    def _dispatch_and(self, opcode):
1613        self._line(u"r{op.r1} = ul4._fu_bool(r{op.r3}) ? r{op.r2} : r{op.r3};".format(op=opcode))
1614    def _dispatch_or(self, opcode):
1615        self._line(u"r{op.r1} = ul4._fu_bool(r{op.r2}) ? r{op.r2} : r{op.r3};".format(op=opcode))
1616    def _dispatch_mod(self, opcode):
1617        self._line(u"r{op.r1} = ul4._op_mod(r{op.r2}, r{op.r3});".format(op=opcode))
1618    def _dispatch_callfunc0(self, opcode):
1619        if opcode.arg == "now":
1620            self._line(u"r{op.r1} = new Date();".format(op=opcode))
1621        elif opcode.arg == "utcnow":
1622            self._line(u"r{op.r1} = ul4._fu_utcnow();".format(op=opcode))
1623        elif opcode.arg == "random":
1624            self._line(u"r{op.r1} = Math.random();".format(op=opcode))
1625        elif opcode.arg == "vars":
1626            self._line(u"r{op.r1} = vars;".format(op=opcode))
1627        else:
1628            raise UnknownFunctionError(opcode.arg)
1629    def _dispatch_callfunc1(self, opcode):
1630        if opcode.arg in {"xmlescape", "csv", "repr", "enumerate", "chr", "ord", "hex", "oct", "bin", "sorted", "type", "json", "reversed", "randchoice", "str", "int", "float", "bool", "len", "isstr", "isint", "isfloat", "isbool", "isdate", "islist", "isdict", "istemplate", "iscolor", "abs"}:
1631            self._line(u"r{op.r1} = ul4._fu_{op.arg}(r{op.r2});".format(op=opcode))
1632        elif opcode.arg in {"range", "randrange"}:
1633            self._line(u"r{op.r1} = ul4._fu_{op.arg}(0, r{op.r2}, 1);".format(op=opcode))
1634        elif opcode.arg == "isnone":
1635            self._line(u"r{op.r1} = (r{op.r2} === null);".format(op=opcode))
1636        elif opcode.arg == "get":
1637            self._line(u"r{op.r1} = ul4._me_get(vars, r{op.r2});".format(op=opcode))
1638        else:
1639            raise UnknownFunctionError(opcode.arg)
1640    def _dispatch_callfunc2(self, opcode):
1641        if opcode.arg in {"format", "zip", "int"}:
1642            self._line(u"r{op.r1} = ul4._fu_{op.arg}(r{op.r2}, r{op.r3});".format(op=opcode))
1643        elif opcode.arg in {"range", "randrange"}:
1644            self._line(u"r{op.r1} = ul4._fu_{op.arg}(r{op.r2}, r{op.r3}, 1);".format(op=opcode))
1645        elif opcode.arg == "get":
1646            self._line(u"r{op.r1} = ul4._me_get(vars, r{op.r2}, r{op.r3});".format(op=opcode))
1647        else:
1648            raise UnknownFunctionError(opcode.arg)
1649    def _dispatch_callfunc3(self, opcode):
1650        if opcode.arg in {"range", "zip", "randrange"}:
1651            self._line(u"r{op.r1} = ul4._fu_{op.arg}(r{op.r2}, r{op.r3}, r{op.r4});".format(op=opcode))
1652        elif opcode.arg in {"rgb", "hls", "hsv"}:
1653            self._line(u"r{op.r1} = ul4._fu_{op.arg}(r{op.r2}, r{op.r3}, r{op.r4}, 1.0);".format(op=opcode))
1654        else:
1655            raise UnknownFunctionError(opcode.arg)
1656    def _dispatch_callfunc4(self, opcode):
1657        if opcode.arg in {"rgb", "hls", "hsv"}:
1658            self._line(u"r{op.r1} = ul4._fu_{op.arg}(r{op.r2}, r{op.r3}, r{op.r4}, r{op.r5});".format(op=opcode))
1659        else:
1660            raise UnknownFunctionError(opcode.arg)
1661    def _dispatch_callmeth0(self, opcode):
1662        if opcode.arg in {"strip", "lstrip", "rstrip", "upper", "lower", "capitalize", "items", "isoformat", "mimeformat", "day", "month", "year", "hour", "minute", "second", "microsecond", "weekday", "yearday", "r", "g", "b", "a", "lum", "hls", "hlsa", "hsv", "hsva"}:
1663            self._line(u"r{op.r1} = ul4._me_{op.arg}(r{op.r2});".format(op=opcode))
1664        elif opcode.arg in {"split", "rsplit"}:
1665            self._line(u"r{op.r1} = ul4._me_{op.arg}(r{op.r2}, null, null);".format(op=opcode))
1666        elif opcode.arg == "render":
1667            self._line(u"r{op.r1} = r{op.r2}.renders({{}});".format(op=opcode))
1668        else:
1669            raise UnknownMethodError(opcode.arg)
1670    def _dispatch_callmeth1(self, opcode):
1671        if opcode.arg in {"join", "strip", "lstrip", "rstrip", "startswith", "endswith", "withlum", "witha"}:
1672            self._line(u"r{op.r1} = ul4._me_{op.arg}(r{op.r2}, r{op.r3});".format(op=opcode))
1673        elif opcode.arg in {"split", "rsplit", "get"}:
1674            self._line(u"r{op.r1} = ul4._me_{op.arg}(r{op.r2}, r{op.r3}, null);".format(op=opcode))
1675        elif opcode.arg in {"find", "rfind"}:
1676            self._line(u"r{op.r1} = ul4._me_{op.arg}(r{op.r2}, r{op.r3}, null, null);".format(op=opcode))
1677        else:
1678            raise UnknownMethodError(opcode.arg)
1679    def _dispatch_callmeth2(self, opcode):
1680        if opcode.arg in {"split", "rsplit", "replace", "get"}:
1681            self._line(u"r{op.r1} = ul4._me_{op.arg}(r{op.r2}, r{op.r3}, r{op.r4});".format(op=opcode))
1682        elif opcode.arg in {"find", "rfind"}:
1683            self._line(u"r{op.r1} = ul4._me_{op.arg}(r{op.r2}, r{op.r3}, r{op.r4}, null);".format(op=opcode))
1684        else:
1685            raise UnknownMethodError(opcode.arg)
1686    def _dispatch_callmeth3(self, opcode):
1687        if opcode.arg in {"find", "rfind"}:
1688            self._line(u"r{op.r1} = ul4._me_{op.arg}(r{op.r2}, r{op.r3}, r{op.r4}, r{op.r5});".format(op=opcode))
1689        else:
1690            raise UnknownMethodError(opcode.arg)
1691    def _dispatch_callmethkw(self, opcode):
1692        if opcode.arg == "render":
1693            self._line(u"r{op.r1} = r{op.r2}.renders(r{op.r3});".format(op=opcode))
1694        else:
1695            raise UnknownMethodError(opcode.arg)
1696    def _dispatch_if(self, opcode):
1697        self._line(u"if (ul4._fu_bool(r{op.r1}))".format(op=opcode))
1698        self._line(u"{")
1699        self._indent += 1
1700    def _dispatch_else(self, opcode):
1701        self._indent -= 1
1702        self._line(u"}")
1703        self._line(u"else")
1704        self._line(u"{")
1705        self._indent += 1
1706    def _dispatch_endif(self, opcode):
1707        self._indent -= 1
1708        self._line(u"}")
1709    def _dispatch_render(self, opcode):
1710        self._line(u"out = out.concat(r{op.r1}.render(r{op.r2}));".format(op=opcode))
1711
1712
1713class _JavaTemplateLevel(object):
1714    def __init__(self, variables, name=None):
1715        self.variables = variables # Name of the variables dict
1716        self.name = name
1717        self.lines = [] # contains source code lines and indentation info
1718        self.varcounter = 0 # Counter for variables names (loop variable etc.)
1719        self.regsused = set() # Which registers have been used?
1720
1721
1722class JavaSource(object):
1723    """
1724    A :class:`JavaSource` object generates Java sourcecode from a UL4
1725    template.
1726
1727    The code produced requires the `UL4 Java package`__.
1728
1729    __ http://hg.livinglogic.de/LivingLogic.Java.ul4
1730    """
1731
1732    def __init__(self, template, indent=2, variables="variables"):
1733        """
1734        Create a :class:`JavaSource` object. :var:`template` is the
1735        :class:`Template` object.
1736
1737        :var:`indent` is the current indent level (defaulting to 2 for normal
1738        method source code).
1739
1740        :var:`variables` is the variable name of a ``Map`` object containing the
1741        template variables.
1742        """
1743        self.template = template
1744        self.indent = indent
1745        self.variables = variables
1746
1747    def __unicode__(self):
1748        """
1749        Return the Java sourcecode for the :class:`Template` object passed to
1750        the constructor.
1751        """
1752
1753        self._stack = [_JavaTemplateLevel(self.variables)] # Stack for info about nested def opcodes
1754
1755        lines = []
1756
1757        lastloc = None
1758        for opcode in self.template.opcodes:
1759            if opcode.code is not None and opcode.location is not lastloc:
1760                lastloc = opcode.location
1761                (line, col) = lastloc.pos()
1762                tag = lastloc.tag
1763                self._do(u"/* <?{}?> tag at position {} (line {}, col {}, template {}): {} */".format(lastloc.type, lastloc.starttag+1, line, col, lastloc.name, repr(tag)[1+isinstance(tag, unicode):-1]))
1764            try:
1765                getattr(self, "_dispatch_{}".format(opcode.code))(opcode)
1766            except AttributeError:
1767                raise UnknownOpcodeError(opcode.code)
1768
1769        # Add source and register declaration at the beginning
1770        lines.append(u"/*@@@ BEGIN template source */")
1771        sourcelines = self.template.source.splitlines(False)
1772        width = len(str(len(sourcelines)))
1773        for (i, line) in enumerate(sourcelines):
1774            lines.append(u"/* {1:{0}} {2} */".format(width, i+1, line.replace("/*", "*").replace("*/", "*")))
1775        lines.append(u"/*@@@ BEGIN template code */")
1776       
1777        for i in sorted(self._stack[-1].regsused):
1778            lines.append(u"Object r{} = null;".format(i))
1779
1780        # copy over generated source code
1781        lines.extend(self._stack[-1].lines)
1782
1783        lines.append(u"/*@@@ END template code */")
1784
1785        v = []
1786        indent = self.indent
1787        for line in lines:
1788            if isinstance(line, int):
1789                indent += line
1790            else:
1791                v.append("\t"*indent + line)
1792        return u"\n".join(v)
1793
1794    def output(self, expression):
1795        """
1796        Return a statement for outputting the Java expression :var:`expression`.
1797        This uses ``out.write()`` (for JSP etc.) but can be overwritten in
1798        subclasses.
1799        """
1800        return u"out.write({});".format(expression)
1801
1802    def _usereg(self, r):
1803        self._stack[-1].regsused.add(r)
1804
1805    def _do(self, line):
1806        # :var:`line` is either an ``int`` (which is added to the current indentation) or a line of source code.
1807        self._stack[-1].lines.append(line)
1808
1809    def _dispatch_None(self, opcode):
1810        (line, col) = opcode.location.pos()
1811        self._do(u"/* Literal at {} (line {}, col {}) */".format(opcode.location.starttag+1, line, col))
1812        self._do(self.output(misc.javaexpr(opcode.location.code)))
1813    def _dispatch_loadstr(self, opcode):
1814        self._do(u"r{op.r1} = {arg};".format(op=opcode, arg=misc.javaexpr(opcode.arg)))
1815        self._usereg(opcode.r1)
1816    def _dispatch_loadint(self, opcode):
1817        self._do(u"r{op.r1} = new Integer({op.arg});".format(op=opcode))
1818        self._usereg(opcode.r1)
1819    def _dispatch_loadfloat(self, opcode):
1820        self._do(u"r{op.r1} = new Double({op.arg});".format(op=opcode))
1821        self._usereg(opcode.r1)
1822    def _dispatch_loadnone(self, opcode):
1823        self._do(u"r{op.r1} = null;".format(op=opcode))
1824        self._usereg(opcode.r1)
1825    def _dispatch_loadfalse(self, opcode):
1826        self._do(u"r{op.r1} = false;".format(op=opcode))
1827        self._usereg(opcode.r1)
1828    def _dispatch_loadtrue(self, opcode):
1829        self._do(u"r{op.r1} = true;".format(op=opcode))
1830        self._usereg(opcode.r1)
1831    def _dispatch_loaddate(self, opcode):
1832        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.makeDate({date});".format(op=opcode, date=", ".join(str(int(p)) for p in datesplitter.split(opcode.arg))))
1833        self._usereg(opcode.r1)
1834    def _dispatch_loadcolor(self, opcode):
1835        self._do(u"r{op.r1} = new com.livinglogic.ul4.Color(0x{r}, 0x{g}, 0x{b}, 0x{a});".format(op=opcode, r=opcode.arg[:2], g=opcode.arg[2:4], b=opcode.arg[4:6], a=opcode.arg[6:]))
1836        self._usereg(opcode.r1)
1837    def _dispatch_buildlist(self, opcode):
1838        self._do(u"r{op.r1} = new java.util.ArrayList();".format(op=opcode))
1839        self._usereg(opcode.r1)
1840    def _dispatch_builddict(self, opcode):
1841        self._do(u"r{op.r1} = new java.util.HashMap();".format(op=opcode))
1842        self._usereg(opcode.r1)
1843    def _dispatch_addlist(self, opcode):
1844        self._do(u"((java.util.List)r{op.r1}).add(r{op.r2});".format(op=opcode))
1845        self._usereg(opcode.r1)
1846    def _dispatch_adddict(self, opcode):
1847        self._do(u"((java.util.Map)r{op.r1}).put(r{op.r2}, r{op.r3});".format(op=opcode))
1848        self._usereg(opcode.r1)
1849    def _dispatch_updatedict(self, opcode):
1850        self._do(u"((java.util.Map)r{op.r1}).putAll((java.util.Map)r{op.r2});".format(op=opcode))
1851        self._usereg(opcode.r1)
1852    def _dispatch_loadvar(self, opcode):
1853        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.getItem({var}, {arg});".format(op=opcode, var=self._stack[-1].variables, arg=misc.javaexpr(opcode.arg)))
1854        self._usereg(opcode.r1)
1855    def _dispatch_storevar(self, opcode):
1856        self._do(u"{var}.put({arg}, r{op.r1});".format(var=self._stack[-1].variables, arg=misc.javaexpr(opcode.arg), op=opcode))
1857    def _dispatch_addvar(self, opcode):
1858        self._do(u"{var}.put({arg}, com.livinglogic.ul4.Utils.add({var}.get({arg}), r{op.r1}));".format(var=self._stack[-1].variables, arg=misc.javaexpr(opcode.arg), op=opcode))
1859    def _dispatch_subvar(self, opcode):
1860        self._do(u"{var}.put({arg}, com.livinglogic.ul4.Utils.sub({var}.get({arg}), r{op.r1}));".format(var=self._stack[-1].variables, arg=misc.javaexpr(opcode.arg), op=opcode))
1861    def _dispatch_mulvar(self, opcode):
1862        self._do(u"{var}.put({arg}, com.livinglogic.ul4.Utils.mul({var}.get({arg}), r{op.r1}));".format(var=self._stack[-1].variables, arg=misc.javaexpr(opcode.arg), op=opcode))
1863    def _dispatch_truedivvar(self, opcode):
1864        self._do(u"{var}.put({arg}, com.livinglogic.ul4.Utils.truediv({var}.get({arg}), r{op.r1}));".format(var=self._stack[-1].variables, arg=misc.javaexpr(opcode.arg), op=opcode))
1865    def _dispatch_floordivvar(self, opcode):
1866        self._do(u"{var}.put({arg}, com.livinglogic.ul4.Utils.floordiv({var}.get({arg}), r{op.r1}));".format(var=self._stack[-1].variables, arg=misc.javaexpr(opcode.arg), op=opcode))
1867    def _dispatch_modvar(self, opcode):
1868        self._do(u"{var}.put({arg}, com.livinglogic.ul4.Utils.mod({var}.get({arg}), r{op.r1}));".format(var=self._stack[-1].variables, arg=misc.javaexpr(opcode.arg), op=opcode))
1869    def _dispatch_delvar(self, opcode):
1870        self._do(u"{var}.remove({arg});".format(var=self._stack[-1].variables, arg=misc.javaexpr(opcode.arg)))
1871    def _dispatch_getattr(self, opcode):
1872        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.getItem(r{op.r2}, {arg});".format(op=opcode, arg=misc.javaexpr(opcode.arg)))
1873        self._usereg(opcode.r1)
1874    def _dispatch_getitem(self, opcode):
1875        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.getItem(r{op.r2}, r{op.r3});".format(op=opcode))
1876        self._usereg(opcode.r1)
1877    def _dispatch_getslice12(self, opcode):
1878        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.getSlice(r{op.r2}, r{op.r3}, r{op.r4});".format(op=opcode))
1879        self._usereg(opcode.r1)
1880    def _dispatch_getslice1(self, opcode):
1881        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.getSlice(r{op.r2}, r{op.r3}, null);".format(op=opcode))
1882        self._usereg(opcode.r1)
1883    def _dispatch_getslice2(self, opcode):
1884        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.getSlice(r{op.r2}, null, r{op.r3});".format(op=opcode))
1885        self._usereg(opcode.r1)
1886    def _dispatch_print(self, opcode):
1887        self._do(self.output(u"com.livinglogic.ul4.Utils.str(r{op.r1})".format(op=opcode)))
1888    def _dispatch_printx(self, opcode):
1889        self._do(self.output(u"com.livinglogic.ul4.Utils.xmlescape(r{op.r1})".format(op=opcode)))
1890    def _dispatch_for(self, opcode):
1891        varcounter = self._stack[-1].varcounter
1892        self._do(u"for (java.util.Iterator iterator{count} = com.livinglogic.ul4.Utils.iterator(r{op.r2}); iterator{count}.hasNext();)".format(op=opcode, count=varcounter))
1893        self._do(u"{")
1894        self._do(1)
1895        self._do(u"r{op.r1} = iterator{count}.next();".format(op=opcode, count=varcounter))
1896        self._usereg(opcode.r1)
1897        self._stack[-1].varcounter += 1
1898    def _dispatch_endfor(self, opcode):
1899        self._do(-1)
1900        self._do(u"}")
1901    def _dispatch_def(self, opcode):
1902        self._stack.append(_JavaTemplateLevel("variables", opcode.arg))
1903    def _dispatch_enddef(self, opcode):
1904        level = self._stack.pop()
1905        # define new template object
1906        self._do(u'{var}.put({arg}, new com.livinglogic.ul4.JSPTemplate()'.format(var=self._stack[-1].variables, arg=misc.javaexpr(level.name)))
1907        self._do(u"{")
1908        self._do(1)
1909        self._do(u"public String getName()")
1910        self._do(u"{")
1911        self._do(1)
1912        self._do(u'return {};'.format(misc.javaexpr(level.name)))
1913        self._do(-1)
1914        self._do(u"}")
1915        self._do(u"public void render(java.io.Writer out, java.util.Map<String, Object> variables) throws java.io.IOException")
1916        self._do(u"{")
1917        self._do(1)
1918        # registers
1919        for i in sorted(level.regsused):
1920            self._do(u"Object r{} = null;".format(i))
1921        # copy over source from the nested template
1922        self._stack[-1].lines.extend(level.lines)
1923        # end object and put it into variables
1924        self._do(-1)
1925        self._do(u"}")
1926        self._do(-1)
1927        self._do(u"});")
1928    def _dispatch_break(self, opcode):
1929        self._do(u"break;")
1930    def _dispatch_continue(self, opcode):
1931        self._do(u"continue;")
1932    def _dispatch_not(self, opcode):
1933        self._do(u"r{op.r1} = !com.livinglogic.ul4.Utils.getBool(r{op.r2});".format(op=opcode))
1934        self._usereg(opcode.r1)
1935    def _dispatch_neg(self, opcode):
1936        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.neg(r{op.r2});".format(op=opcode))
1937        self._usereg(opcode.r1)
1938    def _dispatch_contains(self, opcode):
1939        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.contains(r{op.r2}, r{op.r3});".format(op=opcode))
1940        self._usereg(opcode.r1)
1941    def _dispatch_notcontains(self, opcode):
1942        self._do(u"r{op.r1} = !com.livinglogic.ul4.Utils.contains(r{op.r2}, r{op.r3});".format(op=opcode))
1943        self._usereg(opcode.r1)
1944    def _dispatch_eq(self, opcode):
1945        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.eq(r{op.r2}, r{op.r3});".format(op=opcode))
1946        self._usereg(opcode.r1)
1947    def _dispatch_ne(self, opcode):
1948        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.ne(r{op.r2}, r{op.r3});".format(op=opcode))
1949        self._usereg(opcode.r1)
1950    def _dispatch_lt(self, opcode):
1951        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.lt(r{op.r2}, r{op.r3});".format(op=opcode))
1952        self._usereg(opcode.r1)
1953    def _dispatch_le(self, opcode):
1954        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.le(r{op.r2}, r{op.r3});".format(op=opcode))
1955        self._usereg(opcode.r1)
1956    def _dispatch_gt(self, opcode):
1957        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.gt(r{op.r2}, r{op.r3});".format(op=opcode))
1958        self._usereg(opcode.r1)
1959    def _dispatch_ge(self, opcode):
1960        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.ge(r{op.r2}, r{op.r3});".format(op=opcode))
1961        self._usereg(opcode.r1)
1962    def _dispatch_add(self, opcode):
1963        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.add(r{op.r2}, r{op.r3});".format(op=opcode))
1964        self._usereg(opcode.r1)
1965    def _dispatch_sub(self, opcode):
1966        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.sub(r{op.r2}, r{op.r3});".format(op=opcode))
1967        self._usereg(opcode.r1)
1968    def _dispatch_mul(self, opcode):
1969        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.mul(r{op.r2}, r{op.r3});".format(op=opcode))
1970        self._usereg(opcode.r1)
1971    def _dispatch_floordiv(self, opcode):
1972        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.floordiv(r{op.r2}, r{op.r3});".format(op=opcode))
1973        self._usereg(opcode.r1)
1974    def _dispatch_truediv(self, opcode):
1975        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.truediv(r{op.r2}, r{op.r3});".format(op=opcode))
1976        self._usereg(opcode.r1)
1977    def _dispatch_and(self, opcode):
1978        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.getBool(r{op.r3}) ? r{op.r2} : r{op.r3};".format(op=opcode))
1979        self._usereg(opcode.r1)
1980    def _dispatch_or(self, opcode):
1981        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.getBool(r{op.r2}) ? r{op.r2} : r{op.r3};".format(op=opcode))
1982        self._usereg(opcode.r1)
1983    def _dispatch_mod(self, opcode):
1984        self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.mod(r{op.r2}, r{op.r3});".format(op=opcode))
1985        self._usereg(opcode.r1)
1986    def _dispatch_callfunc0(self, opcode):
1987        if opcode.arg == "now":
1988            self._do(u"r{op.r1} = new java.util.Date();".format(op=opcode))
1989        elif opcode.arg in {"utcnow", "random"}:
1990            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.{op.arg}();".format(op=opcode))
1991        elif opcode.arg == "vars":
1992            self._do(u"r{op.r1} = {var};".format(op=opcode, var=self._stack[-1].variables))
1993        else:
1994            raise UnknownFunctionError(opcode.arg)
1995        self._usereg(opcode.r1)
1996    def _dispatch_callfunc1(self, opcode):
1997        if opcode.arg in {"xmlescape", "csv", "repr", "enumerate", "chr", "ord", "hex", "oct", "bin", "sorted", "range", "type", "json", "reversed", "randrange", "randchoice", "abs", "str"}:
1998            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.{op.arg}(r{op.r2});".format(op=opcode))
1999        elif opcode.arg == "int":
2000            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.toInteger(r{op.r2});".format(op=opcode))
2001        elif opcode.arg == "float":
2002            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.toFloat(r{op.r2});".format(op=opcode))
2003        elif opcode.arg == "bool":
2004            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.getBool(r{op.r2});".format(op=opcode))
2005        elif opcode.arg == "len":
2006            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.length(r{op.r2});".format(op=opcode))
2007        elif opcode.arg == "isnone":
2008            self._do(u"r{op.r1} = (r{op.r2} == null);".format(op=opcode))
2009        elif opcode.arg == "isstr":
2010            self._do(u"r{op.r1} = ((r{op.r2} != null) && (r{op.r2} instanceof String));".format(op=opcode))
2011        elif opcode.arg == "isint":
2012            self._do(u"r{op.r1} = ((r{op.r2} != null) && (r{op.r2} instanceof Integer));".format(op=opcode))
2013        elif opcode.arg == "isfloat":
2014            self._do(u"r{op.r1} = ((r{op.r2} != null) && (r{op.r2} instanceof Double));".format(op=opcode))
2015        elif opcode.arg == "isbool":
2016            self._do(u"r{op.r1} = ((r{op.r2} != null) && (r{op.r2} instanceof Boolean));".format(op=opcode))
2017        elif opcode.arg == "isdate":
2018            self._do(u"r{op.r1} = ((r{op.r2} != null) && (r{op.r2} instanceof java.util.Date));".format(op=opcode))
2019        elif opcode.arg == "islist":
2020            self._do(u"r{op.r1} = ((r{op.r2} != null) && (r{op.r2} instanceof java.util.List));".format(op=opcode))
2021        elif opcode.arg == "isdict":
2022            self._do(u"r{op.r1} = ((r{op.r2} != null) && (r{op.r2} instanceof java.util.Map));".format(op=opcode))
2023        elif opcode.arg == "istemplate":
2024            self._do(u"r{op.r1} = ((r{op.r2} != null) && (r{op.r2} instanceof com.livinglogic.ul4.Template));".format(op=opcode))
2025        elif opcode.arg == "iscolor":
2026            self._do(u"r{op.r1} = ((r{op.r2} != null) && (r{op.r2} instanceof com.livinglogic.ul4.Color));".format(op=opcode))
2027        elif opcode.arg == "get":
2028            self._do(u"r{op.r1} = {var}.get(r{op.r2});".format(op=opcode, var=self._stack[-1].variables))
2029        else:
2030            raise UnknownFunctionError(opcode.arg)
2031        self._usereg(opcode.r1)
2032    def _dispatch_callfunc2(self, opcode):
2033        if opcode.arg in {"format", "range", "zip", "randrange"}:
2034            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.{op.arg}(r{op.r2}, r{op.r3});".format(op=opcode))
2035        elif opcode.arg == "int":
2036            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.toInteger(r{op.r2}, r{op.r3});".format(op=opcode))
2037        elif opcode.arg == "get":
2038            self._do(u"r{op.r1} = {var}.containsKey(r{op.r2}) ? {var}.get(r{op.r2}) : r{op.r3};".format(op=opcode, var=self._stack[-1].variables))
2039        else:
2040            raise UnknownFunctionError(opcode.arg)
2041        self._usereg(opcode.r1)
2042    def _dispatch_callfunc3(self, opcode):
2043        if opcode.arg in {"range", "zip", "rgb", "hls", "hsv", "randrange"}:
2044            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.{op.arg}(r{op.r2}, r{op.r3}, r{op.r4});".format(op=opcode))
2045        else:
2046            raise UnknownFunctionError(opcode.arg)
2047        self._usereg(opcode.r1)
2048    def _dispatch_callfunc4(self, opcode):
2049        if opcode.arg in {"rgb", "hls", "hsv"}:
2050            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.{op.arg}(r{op.r2}, r{op.r3}, r{op.r4}, r{op.r5});".format(op=opcode))
2051        else:
2052            raise UnknownFunctionError(opcode.arg)
2053        self._usereg(opcode.r1)
2054    def _dispatch_callmeth0(self, opcode):
2055        if opcode.arg in {"split", "rsplit", "strip", "lstrip", "rstrip", "upper", "lower", "capitalize", "items", "isoformat", "mimeformat", "day", "month", "year", "hour", "minute", "second", "microsecond", "weekday", "yearday"}:
2056            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.{op.arg}(r{op.r2});".format(op=opcode))
2057        elif opcode.arg in {"r", "g", "b", "a"}:
2058            self._do(u"r{op.r1} = ((com.livinglogic.ul4.Color)r{op.r2}).get{arg}();".format(op=opcode, arg=opcode.arg.upper()))
2059        elif opcode.arg in {"hls", "hlsa", "hsv", "hsva"}:
2060            self._do(u"r{op.r1} = ((com.livinglogic.ul4.Color)r{op.r2}).{op.arg}();".format(op=opcode))
2061        elif opcode.arg == "lum":
2062            self._do(u"r{op.r1} = ((com.livinglogic.ul4.Color)r{op.r2}).lum();".format(op=opcode))
2063        elif opcode.arg == "render":
2064            self._do(u"r{op.r1} = ((com.livinglogic.ul4.Template)r{op.r2}).renders(null);".format(op=opcode))
2065        else:
2066            raise UnknownMethodError(opcode.arg)
2067        self._usereg(opcode.r1)
2068    def _dispatch_callmeth1(self, opcode):
2069        if opcode.arg in {"join", "split", "rsplit", "strip", "lstrip", "rstrip", "startswith", "endswith", "find", "rfind", "withlum", "witha"}:
2070            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.{op.arg}(r{op.r2}, r{op.r3});".format(op=opcode))
2071        elif opcode.arg == "get":
2072            self._do(u"r{op.r1} = ((java.util.Map)r{op.r2}).get(r{op.r3});".format(op=opcode))
2073        else:
2074            raise UnknownMethodError(opcode.arg)
2075        self._usereg(opcode.r1)
2076    def _dispatch_callmeth2(self, opcode):
2077        if opcode.arg in {"split", "rsplit", "find", "rfind", "replace"}:
2078            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.{op.arg}(r{op.r2}, r{op.r3}, r{op.r4});".format(op=opcode))
2079        elif opcode.arg == "get":
2080            self._do(u"r{op.r1} = ((java.util.Map)r{op.r2}).containsKey(r{op.r3}) ? ((java.util.Map)r{op.r2}).get(r{op.r3}) : r{op.r4};".format(op=opcode))
2081        else:
2082            raise UnknownMethodError(opcode.arg)
2083        self._usereg(opcode.r1)
2084    def _dispatch_callmeth3(self, opcode):
2085        if opcode.arg in {"find", "rfind"}:
2086            self._do(u"r{op.r1} = com.livinglogic.ul4.Utils.{op.arg}(r{op.r2}, r{op.r3}, r{op.r4}, r{op.r5});".format(op=opcode))
2087        else:
2088            raise UnknownMethodError(opcode.arg)
2089        self._usereg(opcode.r1)
2090    def _dispatch_callmethkw(self, opcode):
2091        if opcode.arg == "render":
2092            self._do(u"r{op.r1} = ((com.livinglogic.ul4.Template)r{op.r2}).renders((java.util.Map)r{op.r3});".format(op=opcode))
2093        else:
2094            raise UnknownMethodError(opcode.arg)
2095        self._usereg(opcode.r1)
2096    def _dispatch_if(self, opcode):
2097        self._do(u"if (com.livinglogic.ul4.Utils.getBool(r{op.r1}))".format(op=opcode))
2098        self._do(u"{")
2099        self._do(1)
2100    def _dispatch_else(self, opcode):
2101        self._do(-1)
2102        self._do(u"}")
2103        self._do(u"else")
2104        self._do(u"{")
2105        self._do(1)
2106    def _dispatch_endif(self, opcode):
2107        self._do(-1)
2108        self._do(u"}")
2109    def _dispatch_render(self, opcode):
2110        self._do(u"((com.livinglogic.ul4.Template)r{op.r1}).render(out, (java.util.Map)r{op.r2});".format(op=opcode))
2111
2112
2113###
2114### Compiler stuff: Tokens and nodes for the AST
2115###
2116
2117class Token(object):
2118    def __init__(self, start, end, type):
2119        self.start = start
2120        self.end = end
2121        self.type = type
2122
2123    def __repr__(self):
2124        return "{}({!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.type)
2125
2126    def __str__(self):
2127        return self.type
2128
2129
2130class AST(object):
2131    """
2132    Baseclass for all syntax tree nodes.
2133    """
2134
2135    def __init__(self, start, end):
2136        self.start = start
2137        self.end = end
2138
2139
2140class Const(AST):
2141    """
2142    Common baseclass for all constants (used for type testing in constant folding)
2143    """
2144
2145    def __repr__(self):
2146        return "{}({!r}, {!r})".format(self.__class__.__name__, self.start, self.end)
2147
2148    def compile(self, template):
2149        r = template._allocreg()
2150        template.opcode("load{}".format(self.type), r1=r)
2151        return r
2152
2153
2154class None_(Const):
2155    type = "none"
2156    value = None
2157
2158
2159class True_(Const):
2160    type = "true"
2161    value = True
2162
2163
2164class False_(Const):
2165    type = "false"
2166    value = False
2167
2168
2169class Value(Const):
2170    def __init__(self, start, end, value):
2171        Const.__init__(self, start, end)
2172        self.value = value
2173
2174    def __repr__(self):
2175        return "{}({!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.value)
2176
2177    def compile(self, template):
2178        r = template._allocreg()
2179        template.opcode("load{}".format(self.type), r1=r, arg=unicode(self.value))
2180        return r
2181
2182
2183class Int(Value):
2184    type = "int"
2185
2186
2187class Float(Value):
2188    type = "float"
2189
2190    def compile(self, template):
2191        r = template._allocreg()
2192        template.opcode("load{}".format(self.type), r1=r, arg=repr(self.value))
2193        return r
2194
2195
2196class Str(Value):
2197    type = "str"
2198
2199
2200class Date(Value):
2201    type = "date"
2202
2203    def compile(self, template):
2204        r = template._allocreg()
2205        template.opcode("load{}".format(self.type), r1=r, arg=self.value.isoformat())
2206        return r
2207
2208
2209class Color(Value):
2210    type = "color"
2211
2212    def compile(self, template):
2213        r = template._allocreg()
2214        template.opcode("load{}".format(self.type), r1=r, arg="{:02x}{:02x}{:02x}{:02x}".format(*self.value))
2215        return r
2216
2217
2218class List(AST):
2219    def __init__(self, start, end, *items):
2220        AST.__init__(self, start, end)
2221        self.items = list(items)
2222
2223    def __repr__(self):
2224        return "{}({!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, repr(self.items)[1:-1])
2225
2226    def compile(self, template):
2227        r = template._allocreg()
2228        template.opcode("buildlist", r1=r)
2229        for item in self.items:
2230            ri = item.compile(template)
2231            template.opcode("addlist", r1=r, r2=ri)
2232            template._freereg(ri)
2233        return r
2234
2235
2236class Dict(AST):
2237    def __init__(self, start, end, *items):
2238        AST.__init__(self, start, end)
2239        self.items = list(items)
2240
2241    def __repr__(self):
2242        return "{}({!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, repr(self.items)[1:-1])
2243
2244    def compile(self, template):
2245        r = template._allocreg()
2246        template.opcode("builddict", r1=r)
2247        for item in self.items:
2248            if len(item) == 1:
2249                rd = item[0].compile(template)
2250                template.opcode("updatedict", r1=r, r2=rd)
2251                template._freereg(rd)
2252            else:
2253                (key, value) = item
2254                rk = key.compile(template)
2255                rv = value.compile(template)
2256                template.opcode("adddict", r1=r, r2=rk, r3=rv)
2257                template._freereg(rk)
2258                template._freereg(rv)
2259        return r
2260
2261
2262class Name(AST):
2263    type = "name"
2264
2265    def __init__(self, start, end, name):
2266        AST.__init__(self, start, end)
2267        self.name = name
2268
2269    def __repr__(self):
2270        return "{}({!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.name)
2271
2272    def compile(self, template):
2273        r = template._allocreg()
2274        template.opcode("loadvar", r1=r, arg=self.name)
2275        return r
2276
2277
2278class For(AST):
2279    def __init__(self, start, end, iter, cont):
2280        AST.__init__(self, start, end)
2281        self.iter = iter
2282        self.cont = cont
2283
2284    def __repr__(self):
2285        return "{}({!r}, {!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.iter, self.cont)
2286
2287    def compile(self, template):
2288        rc = self.cont.compile(template)
2289        ri = template._allocreg()
2290        template.opcode("for", r1=ri, r2=rc)
2291        if isinstance(self.iter, list):
2292            rii = template._allocreg()
2293            for (i, iter) in enumerate(self.iter):
2294                template.opcode("loadint", r1=rii, arg=str(i))
2295                template.opcode("getitem", r1=rii, r2=ri, r3=rii)
2296                template.opcode("storevar", r1=rii, arg=iter.name)
2297            template._freereg(rii)
2298        else:
2299            template.opcode("storevar", r1=ri, arg=self.iter.name)
2300        template._freereg(ri)
2301        template._freereg(rc)
2302
2303
2304class GetAttr(AST):
2305    def __init__(self, start, end, obj, attr):
2306        AST.__init__(self, start, end)
2307        self.obj = obj
2308        self.attr = attr
2309
2310    def __repr__(self):
2311        return "{}({!r}, {!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.obj, self.attr)
2312
2313    def compile(self, template):
2314        r = self.obj.compile(template)
2315        template.opcode("getattr", r1=r, r2=r, arg=self.attr.name)
2316        return r
2317
2318
2319class GetSlice12(AST):
2320    def __init__(self, start, end, obj, index1, index2):
2321        AST.__init__(self, start, end)
2322        self.obj = obj
2323        self.index1 = index1
2324        self.index2 = index2
2325
2326    def __repr__(self):
2327        return "{}({!r}, {!r}, {!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.obj, self.index1, self.index2)
2328
2329    def compile(self, template):
2330        r1 = self.obj.compile(template)
2331        r2 = self.index1.compile(template)
2332        r3 = self.index2.compile(template)
2333        template.opcode("getslice12", r1=r1, r2=r1, r3=r2, r4=r3)
2334        template._freereg(r2)
2335        template._freereg(r3)
2336        return r1
2337
2338
2339class Unary(AST):
2340    opcode = None
2341
2342    def __init__(self, start, end, obj):
2343        AST.__init__(self, start, end)
2344        self.obj = obj
2345
2346    def __repr__(self):
2347        return "{}({!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.obj)
2348
2349    def compile(self, template):
2350        r = self.obj.compile(template)
2351        template.opcode(self.opcode, r1=r, r2=r)
2352        return r
2353
2354
2355class Not(Unary):
2356    opcode = "not"
2357
2358
2359class Neg(Unary):
2360    opcode = "neg"
2361
2362
2363class Binary(AST):
2364    opcode = None
2365
2366    def __init__(self, start, end, obj1, obj2):
2367        AST.__init__(self, start, end)
2368        self.obj1 = obj1
2369        self.obj2 = obj2
2370
2371    def __repr__(self):
2372        return "{}({!r}, {!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.obj1, self.obj2)
2373
2374    def compile(self, template):
2375        r1 = self.obj1.compile(template)
2376        r2 = self.obj2.compile(template)
2377        template.opcode(self.opcode, r1=r1, r2=r1, r3=r2)
2378        template._freereg(r2)
2379        return r1
2380
2381
2382class GetItem(Binary):
2383    opcode = "getitem"
2384
2385
2386class GetSlice1(Binary):
2387    opcode = "getslice1"
2388
2389
2390class GetSlice2(Binary):
2391    opcode = "getslice2"
2392
2393
2394class EQ(Binary):
2395    opcode = "eq"
2396
2397
2398class NE(Binary):
2399    opcode = "ne"
2400
2401
2402class LT(Binary):
2403    opcode = "lt"
2404
2405
2406class LE(Binary):
2407    opcode = "le"
2408
2409
2410class GT(Binary):
2411    opcode = "gt"
2412
2413
2414class GE(Binary):
2415    opcode = "ge"
2416
2417
2418class Contains(Binary):
2419    opcode = "contains"
2420
2421
2422class NotContains(Binary):
2423    opcode = "notcontains"
2424
2425
2426class Add(Binary):
2427    opcode = "add"
2428
2429
2430class Sub(Binary):
2431    opcode = "sub"
2432
2433
2434class Mul(Binary):
2435    opcode = "mul"
2436
2437
2438class FloorDiv(Binary):
2439    opcode = "floordiv"
2440
2441
2442class TrueDiv(Binary):
2443    opcode = "truediv"
2444
2445
2446class Or(Binary):
2447    opcode = "or"
2448
2449
2450class And(Binary):
2451    opcode = "and"
2452
2453
2454class Mod(Binary):
2455    opcode = "mod"
2456
2457
2458class ChangeVar(AST):
2459    opcode = None
2460
2461    def __init__(self, start, end, name, value):
2462        AST.__init__(self, start, end)
2463        self.name = name
2464        self.value = value
2465
2466    def __repr__(self):
2467        return "{}({!r}, {!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.name, self.value)
2468
2469    def compile(self, template):
2470        r = self.value.compile(template)
2471        template.opcode(self.opcode, r1=r, arg=self.name.name)
2472        template._freereg(r)
2473
2474
2475class StoreVar(ChangeVar):
2476    opcode = "storevar"
2477
2478
2479class AddVar(ChangeVar):
2480    opcode = "addvar"
2481
2482
2483class SubVar(ChangeVar):
2484    opcode = "subvar"
2485
2486
2487class MulVar(ChangeVar):
2488    opcode = "mulvar"
2489
2490
2491class TrueDivVar(ChangeVar):
2492    opcode = "truedivvar"
2493
2494
2495class FloorDivVar(ChangeVar):
2496    opcode = "floordivvar"
2497
2498
2499class ModVar(ChangeVar):
2500    opcode = "modvar"
2501
2502
2503class DelVar(AST):
2504    def __init__(self, start, end, name):
2505        AST.__init__(self, start, end)
2506        self.name = name
2507
2508    def __repr__(self):
2509        return "{}({!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.name)
2510
2511    def compile(self, template):
2512        template.opcode("delvar", arg=self.name.name)
2513
2514
2515class CallFunc(AST):
2516    def __init__(self, start, end, name, args):
2517        AST.__init__(self, start, end)
2518        self.name = name
2519        self.args = args
2520
2521    def __repr__(self):
2522        if self.args:
2523            return "{}({!r}, {!r}, {!r}, {})".format(self.__class__.__name__, self.start, self.end, self.name, repr(self.args)[1:-1])
2524        else:
2525            return "{}({!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.name)
2526
2527    def compile(self, template):
2528        if len(self.args) == 0:
2529            r = template._allocreg()
2530            template.opcode("callfunc0", r1=r, arg=self.name.name)
2531            return r
2532        elif len(self.args) > 4:
2533            raise ValueError("{} function arguments not supported".format(len(self.args)))
2534        else:
2535            rs = [arg.compile(template) for arg in self.args]
2536            template.opcode("callfunc{}".format(len(self.args)), rs[0], *rs, **dict(arg=self.name.name)) # FIXME: Replace **dict(arg=) with arg= in Python 2.6?
2537            for i in xrange(1, len(self.args)):
2538                template._freereg(rs[i])
2539            return rs[0]
2540
2541
2542class CallMeth(AST):
2543    def __init__(self, start, end, name, obj, args):
2544        AST.__init__(self, start, end)
2545        self.name = name
2546        self.obj = obj
2547        self.args = args
2548
2549    def __repr__(self):
2550        if self.args:
2551            return "{}({!r}, {!r}, {!r}, {!r}, {})".format(self.__class__.__name__, self.start, self.end, self.name, self.obj, repr(self.args)[1:-1])
2552        else:
2553            return "{}({!r}, {!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.name, self.obj)
2554
2555    def compile(self, template):
2556        if len(self.args) > 3:
2557            raise ValueError("{} method arguments not supported".format(len(self.args)))
2558        ro = self.obj.compile(template)
2559        rs = [arg.compile(template) for arg in self.args]
2560        template.opcode("callmeth{}".format(len(self.args)), ro, ro, *rs, **dict(arg=self.name.name))
2561        for r in rs:
2562            template._freereg(r)
2563        return ro
2564
2565
2566class CallMethKeywords(AST):
2567    def __init__(self, start, end, name, obj, args):
2568        AST.__init__(self, start, end)
2569        self.name = name
2570        self.obj = obj
2571        self.args = args
2572
2573    def __repr__(self):
2574        return "{}({!r}, {!r}, {!r}, {!r}, {!r})".format(self.__class__.__name__, self.start, self.end, self.name, self.obj, self.args)
2575
2576    def compile(self, template):
2577        ra = template._allocreg()
2578        template.opcode("builddict", r1=ra)
2579        for item in self.args:
2580            if len(item) == 1:
2581                rd = item[0].compile(template)
2582                template.opcode("updatedict", r1=ra, r2=rd)
2583                template._freereg(rd)
2584            else:
2585                (key, value) = item
2586                rv = value.compile(template)
2587                rk = template._allocreg()
2588                template.opcode("loadstr", r1=rk, arg=key.name)
2589                template.opcode("adddict", r1=ra, r2=rk, r3=rv)
2590                template._freereg(rk)
2591                template._freereg(rv)
2592        ro = self.obj.compile(template)
2593        template.opcode("callmethkw", r1=ro, r2=ro, r3=ra, arg=self.name.name)
2594        template._freereg(ra)
2595        return ro
2596
2597
2598class Render(AST):
2599    def __init__(self, start, end, template, *variables):
2600        AST.__init__(self, start, end)
2601        self.template = template
2602        self.variables = list(variables)
2603
2604    def __repr__(self):
2605        return "{}({!r}, {!r}, {!r}, {})".format(self.__class__.__name__, self.start, self.end, self.template, repr(self.variables)[1:-1])
2606
2607    def compile(self, template):
2608        ra = template._allocreg()
2609        template.opcode("builddict", r1=ra)
2610        for item in self.variables:
2611            if len(item) == 1:
2612                rd = item[0].compile(template)
2613                template.opcode("updatedict", r1=ra, r2=rd)
2614                template._freereg(rd)
2615            else:
2616                (key, value) = item
2617                rv = value.compile(template)
2618                rk = template._allocreg()
2619                template.opcode("loadstr", r1=rk, arg=key.name)
2620                template.opcode("adddict", r1=ra, r2=rk, r3=rv)
2621                template._freereg(rk)
2622                template._freereg(rv)
2623        rt = self.template.compile(template)
2624        template.opcode("render", r1=rt, r2=ra)
2625        template._freereg(rt)
2626        template._freereg(ra)
2627
2628
2629###
2630### Tokenizer
2631###
2632
2633class Scanner(spark.Scanner):
2634    reflags = re.UNICODE
2635
2636    def tokenize(self, location):
2637        self.collectstr = []
2638        self.rv = []
2639        self.start = 0
2640        try:
2641            spark.Scanner.tokenize(self, location.code)
2642            if self.mode != "default":
2643                raise UnterminatedStringError()
2644        except Exception, exc:
2645            newexc = Error(location) # FIXME: use ``raise ... from`` in Python 3
2646            newexc.__cause__ = exc
2647            raise newexc
2648        return self.rv
2649
2650    # Color tokens must be in the order of decreasing length
2651    @spark.token("\\#[0-9a-fA-F]{8}", "default")
2652    def color8(self, start, end, s):
2653        self.rv.append(Color(start, end, color.Color(int(s[1:3], 16), int(s[3:5], 16), int(s[5:7], 16), int(s[7:], 16))))
2654
2655    @spark.token("\\#[0-9a-fA-F]{6}", "default")
2656    def color6(self, start, end, s):
2657        self.rv.append(Color(start, end, color.Color(int(s[1:3], 16), int(s[3:5], 16), int(s[5:], 16))))
2658
2659    @spark.token("\\#[0-9a-fA-F]{4}", "default")
2660    def color4(self, start, end, s):
2661        self.rv.append(Color(start, end, color.Color(17*int(s[1], 16), 17*int(s[2], 16), 17*int(s[3], 16), 17*int(s[4], 16))))
2662
2663    @spark.token("\\#[0-9a-fA-F]{3}", "default")
2664    def color3(self, start, end, s):
2665        self.rv.append(Color(start, end, color.Color(17*int(s[1], 16), 17*int(s[2], 16), 17*int(s[3], 16))))
2666
2667    @spark.token("@\\d{4}-\\d{2}-\\d{2}T(\\d{2}:\\d{2}(:\\d{2}(\\.\\d{6})?)?)?", "default")
2668    def date(self, start, end, s):
2669        self.rv.append(Date(start, end, datetime.datetime(*map(int, filter(None, datesplitter.split(s[1:]))))))
2670
2671    @spark.token("\\(|\\)|\\[|\\]|\\{|\\}|\\.|,|==|\\!=|<=|<|>=|>|=|\\+=|\\-=|\\*=|//=|/=|%=|%|:|\\+|-|\\*\\*|\\*|//|/", "default")
2672    def token(self, start, end, s):
2673        self.rv.append(Token(start, end, s))
2674
2675    @spark.token("[a-zA-Z_][\\w]*", "default")
2676    def name(self, start, end, s):
2677        if s in ("in", "not", "or", "and", "del"):
2678            self.rv.append(Token(start, end, s))
2679        elif s == "None":
2680            self.rv.append(None_(start, end))
2681        elif s == "True":
2682            self.rv.append(True_(start, end))
2683        elif s == "False":
2684            self.rv.append(False_(start, end))
2685        else:
2686            self.rv.append(Name(start, end, s))
2687
2688    # We don't have negatve numbers, this is handled by constant folding in the AST for unary minus
2689    @spark.token("\\d+\\.\\d*([eE][+-]?\\d+)?", "default")
2690    @spark.token("\\d+(\\.\\d*)?[eE][+-]?\\d+", "default")
2691    def float(self, start, end, s):
2692        self.rv.append(Float(start, end, float(s)))
2693
2694    @spark.token("0[xX][\\da-fA-F]+", "default")
2695    def hexint(self, start, end, s):
2696        self.rv.append(Int(start, end, int(s[2:], 16)))
2697
2698    @spark.token("0[oO][0-7]+", "default")
2699    def octint(self, start, end, s):
2700        self.rv.append(Int(start, end, int(s[2:], 8)))
2701
2702    @spark.token("0[bB][01]+", "default")
2703    def binint(self, start, end, s):
2704        self.rv.append(Int(start, end, int(s[2:], 2)))
2705
2706    @spark.token("\\d+", "default")
2707    def int(self, start, end, s):
2708        self.rv.append(Int(start, end, int(s)))
2709
2710    @spark.token("'", "default")
2711    def beginstr1(self, start, end, s):
2712        self.mode = "str1"
2713        self.start = start
2714
2715    @spark.token('"', "default")
2716    def beginstr2(self, start, end, s):
2717        self.mode = "str2"
2718        self.start = start
2719
2720    @spark.token("'", "str1")
2721    @spark.token('"', "str2")
2722    def endstr(self, start, end, s):
2723        self.rv.append(Str(self.start, end, "".join(self.collectstr)))
2724        self.collectstr = []
2725        self.mode = "default"
2726
2727    @spark.token("\\s+", "default")
2728    def whitespace(self, start, end, s):
2729        pass
2730
2731    @spark.token("\\\\\\\\", "str1", "str2")
2732    def escapedbackslash(self, start, end, s):
2733        self.collectstr.append("\\")
2734
2735    @spark.token("\\\\'", "str1", "str2")
2736    def escapedapos(self, start, end, s):
2737        self.collectstr.append("'")
2738
2739    @spark.token('\\\\"', "str1", "str2")
2740    def escapedquot(self, start, end, s):
2741        self.collectstr.append('"')
2742
2743    @spark.token("\\\\a", "str1", "str2")
2744    def escapedbell(self, start, end, s):
2745        self.collectstr.append("\a")
2746
2747    @spark.token("\\\\b", "str1", "str2")
2748    def escapedbackspace(self, start, end, s):
2749        self.collectstr.append("\b")
2750
2751    @spark.token("\\\\f", "str1", "str2")
2752    def escapedformfeed(self, start, end, s):
2753        self.collectstr.append("\f")
2754
2755    @spark.token("\\\\n", "str1", "str2")
2756    def escapedlinefeed(self, start, end, s):
2757        self.collectstr.append("\n")
2758
2759    @spark.token("\\\\r", "str1", "str2")
2760    def escapedcarriagereturn(self, start, end, s):
2761        self.collectstr.append("\r")
2762
2763    @spark.token("\\\\t", "str1", "str2")
2764    def escapedtab(self, start, end, s):
2765        self.collectstr.append("\t")
2766
2767    @spark.token("\\\\v", "str1", "str2")
2768    def escapedverticaltab(self, start, end, s):
2769        self.collectstr.append("\v")
2770
2771    @spark.token("\\\\e", "str1", "str2")
2772    def escapedescape(self, start, end, s):
2773        self.collectstr.append("\x1b")
2774
2775    @spark.token("\\\\x[0-9a-fA-F]{2}", "str1", "str2")
2776    def escaped8bitchar(self, start, end, s):
2777        self.collectstr.append(unichr(int(s[2:], 16)))
2778
2779    @spark.token("\\\\u[0-9a-fA-F]{4}", "str1", "str2")
2780    def escaped16bitchar(self, start, end, s):
2781        self.collectstr.append(unichr(int(s[2:], 16)))
2782
2783    @spark.token(".|\\n", "str1", "str2")
2784    def text(self, start, end, s):
2785        self.collectstr.append(s)
2786
2787    @spark.token("(.|\\n)+", "default", "str1", "str2")
2788    def default(self, start, end, s):
2789        raise LexicalError(start, end, s)
2790
2791    def error(self, start, end, s):
2792        raise LexicalError(start, end, s)
2793
2794
2795###
2796### Parsers for different types of code
2797###
2798
2799class ExprParser(spark.Parser):
2800    emptyerror = "expression required"
2801    start = "expr0"
2802
2803    def __init__(self, scanner):
2804        spark.Parser.__init__(self)
2805        self.scanner = scanner
2806
2807    def compile(self, template):
2808        location = template.location
2809        if not location.code:
2810            raise ValueError(self.emptyerror)
2811        template.registers = set(xrange(10))
2812        try:
2813            ast = self.parse(self.scanner.tokenize(location))
2814            return ast.compile(template)
2815        except Exception, exc:
2816            newexc = Error(location) # FIXME: Use ``raise ... from`` in Python 3
2817            newexc.__cause__ = exc
2818            raise newexc
2819        finally:
2820            del template.registers
2821
2822    def typestring(self, token):
2823        return token.type
2824
2825    def error(self, token):
2826        raise SyntaxError(token)
2827
2828    def makeconst(self, start, end, value):
2829        if value is None:
2830            return None_(start, end)
2831        elif value is True:
2832            return True_(start, end)
2833        elif value is False:
2834            return False_(start, end)
2835        elif isinstance(value, (int, long)):
2836            return Int(start, end, value)
2837        elif isinstance(value, float):
2838            return Float(start, end, value)
2839        elif isinstance(value, basestring):
2840            return Str(start, end, value)
2841        elif isinstance(value, color.Color):
2842            return Color(start, end, value)
2843        else:
2844            raise TypeError("can't convert {!r}".format(value))
2845
2846    # To implement operator precedence, each expression rule has the precedence in its name. The highest precedence is 11 for atomic expressions.
2847    # Each expression can have only expressions as parts which have the some or a higher precedence with two exceptions:
2848    #    1. Expressions where there's no ambiguity, like the index for a getitem/getslice or function/method arguments;
2849    #    2. Brackets, which can be used to boost the precedence of an expression to the level of an atomic expression.
2850
2851    @spark.production('expr11 ::= none')
2852    @spark.production('expr11 ::= true')
2853    @spark.production('expr11 ::= false')
2854    @spark.production('expr11 ::= str')
2855    @spark.production('expr11 ::= int')
2856    @spark.production('expr11 ::= float')
2857    @spark.production('expr11 ::= date')
2858    @spark.production('expr11 ::= color')
2859    @spark.production('expr11 ::= name')
2860    def expr_atom(self, atom):
2861        return atom
2862
2863    @spark.production('expr11 ::= [ ]')
2864    def expr_emptylist(self, _0, _1):
2865        return List(_0.start, _1.end)
2866
2867    @spark.production('buildlist ::= [ expr0')
2868    def expr_buildlist(self, _0, expr):
2869        return List(_0.start, expr.end, expr)
2870
2871    @spark.production('buildlist ::= buildlist , expr0')
2872    def expr_addlist(self, list, _0, expr):
2873        list.items.append(expr)
2874        list.end = expr.end
2875        return list
2876
2877    @spark.production('expr11 ::= buildlist ]')
2878    def expr_finishlist(self, list, _0):
2879        list.end = _0.end
2880        return list
2881
2882    @spark.production('expr11 ::= buildlist , ]')
2883    def expr_finishlist1(self, list, _0, _1):
2884        list.end = _1.end
2885        return list
2886
2887    @spark.production('expr11 ::= { }')
2888    def expr_emptydict(self, _0, _1):
2889        return Dict(_0.start, _1.end)
2890
2891    @spark.production('builddict ::= { expr0 : expr0')
2892    def expr_builddict(self, _0, exprkey, _1, exprvalue):
2893        return Dict(_0.start, exprvalue.end, (exprkey, exprvalue))
2894
2895    @spark.production('builddict ::= { ** expr0')
2896    def expr_builddictupdate(self, _0, _1, expr):
2897        return Dict(_0.start, expr.end, (expr,))
2898
2899    @spark.production('builddict ::= builddict , expr0 : expr0')
2900    def expr_adddict(self, dict, _0, exprkey, _1, exprvalue):
2901        dict.items.append((exprkey, exprvalue))
2902        dict.end = exprvalue.end
2903        return dict
2904
2905    @spark.production('builddict ::= builddict , ** expr0')
2906    def expr_updatedict(self, dict, _0, _1, expr):
2907        dict.items.append((expr,))
2908        dict.end = expr.end
2909        return dict
2910
2911    @spark.production('expr11 ::= builddict }')
2912    def expr_finishdict(self, dict, _0):
2913        dict.end = _0.end
2914        return dict
2915
2916    @spark.production('expr11 ::= builddict , }')
2917    def expr_finishdict1(self, dict, _0, _1):
2918        dict.end = _1.end
2919        return dict
2920
2921    @spark.production('expr11 ::= ( expr0 )')
2922    def expr_bracket(self, _0, expr, _1):
2923        return expr
2924
2925    @spark.production('expr10 ::= name ( )')
2926    def expr_callfunc0(self, name, _0, _1):
2927        return CallFunc(name.start, _1.end, name, [])
2928
2929    @spark.production('expr10 ::= name ( expr0 )')
2930    def expr_callfunc1(self, name, _0, arg0, _1):
2931        return CallFunc(name.start, _1.end, name, [arg0])
2932
2933    @spark.production('expr10 ::= name ( expr0 , expr0 )')
2934    def expr_callfunc2(self, name, _0, arg0, _1, arg1, _2):
2935        return CallFunc(name.start, _2.end, name, [arg0, arg1])
2936
2937    @spark.production('expr10 ::= name ( expr0 , expr0 , expr0 )')
2938    def expr_callfunc3(self, name, _0, arg0, _1, arg1, _2, arg2, _3):
2939        return CallFunc(name.start, _3.end, name, [arg0, arg1, arg2])
2940
2941    @spark.production('expr10 ::= name ( expr0 , expr0 , expr0 , expr0 )')
2942    def expr_callfunc4(self, name, _0, arg0, _1, arg1, _2, arg2, _3, arg3, _4):
2943        return CallFunc(name.start, _4.end, name, [arg0, arg1, arg2, arg3])
2944
2945    @spark.production('expr9 ::= expr9 . name')
2946    def expr_getattr(self, expr, _0, name):
2947        return GetAttr(expr.start, name.end, expr, name)
2948
2949    @spark.production('expr9 ::= expr9 . name ( )')
2950    def expr_callmeth0(self, expr, _0, name, _1, _2):
2951        return CallMeth(expr.start, _2.end, name, expr, [])
2952
2953    @spark.production('expr9 ::= expr9 . name ( expr0 )')
2954    def expr_callmeth1(self, expr, _0, name, _1, arg1, _2):
2955        return CallMeth(expr.start, _2.end, name, expr, [arg1])
2956
2957    @spark.production('expr9 ::= expr9 . name ( expr0 , expr0 )')
2958    def expr_callmeth2(self, expr, _0, name, _1, arg1, _2, arg2, _3):
2959        return CallMeth(expr.start, _3.end, name, expr, [arg1, arg2])
2960
2961    @spark.production('expr9 ::= expr9 . name ( expr0 , expr0 , expr0 )')
2962    def expr_callmeth3(self, expr, _0, name, _1, arg1, _2, arg2, _3, arg3, _4):
2963        return CallMeth(expr.start, _4.end, name, expr, [arg1, arg2, arg3])
2964
2965    @spark.production('callmethkw ::= expr9 . name ( name = expr0')
2966    def methkw_startname(self, expr, _0, methname, _1, argname, _2, argvalue):
2967        return CallMethKeywords(expr.start, argvalue.end, methname, expr, [(argname, argvalue)])
2968
2969    @spark.production('callmethkw ::= expr9 . name ( ** expr0')
2970    def methkw_startdict(self, expr, _0, methname, _1, _2, argvalue):
2971        return CallMethKeywords(expr.start, argvalue.end, methname, expr, [(argvalue,)])
2972
2973    @spark.production('callmethkw ::= callmethkw , name = expr0')
2974    def methkw_buildname(self, call, _0, argname, _1, argvalue):
2975        call.args.append((argname, argvalue))
2976        call.end = argvalue.end
2977        return call
2978
2979    @spark.production('callmethkw ::= callmethkw , ** expr0')
2980    def methkw_builddict(self, call, _0, _1, argvalue):
2981        call.args.append((argvalue,))
2982        call.end = argvalue.end
2983        return call
2984
2985    @spark.production('expr9 ::= callmethkw )')
2986    def methkw_finish(self, call, _0):
2987        call.end = _0.end
2988        return call
2989
2990    @spark.production('expr9 ::= expr9 [ expr0 ]')
2991    def expr_getitem(self, expr, _0, key, _1):
2992        if isinstance(expr, Const) and isinstance(key, Const): # Constant folding
2993            return self.makeconst(expr.start, _1.end, expr.value[key.value])
2994        return GetItem(expr.start, _1.end, expr, key)
2995
2996    @spark.production('expr8 ::= expr8 [ expr0 : expr0 ]')
2997    def expr_getslice12(self, expr, _0, index1, _1, index2, _2):
2998        if isinstance(expr, Const) and isinstance(index1, Const) and isinstance(index2, Const): # Constant folding
2999            return self.makeconst(expr.start, _2.end, expr.value[index1.value:index2.value])
3000        return GetSlice12(expr.start, _2.end, expr, index1, index2)
3001
3002    @spark.production('expr8 ::= expr8 [ expr0 : ]')
3003    def expr_getslice1(self, expr, _0, index1, _1, _2):
3004        if isinstance(expr, Const) and isinstance(index1, Const): # Constant folding
3005            return self.makeconst(expr.start, _2.end, expr.value[index1.value:])
3006        return GetSlice1(expr.start, _2.end, expr, index1)
3007
3008    @spark.production('expr8 ::= expr8 [ : expr0 ]')
3009    def expr_getslice2(self, expr, _0, _1, index2, _2):
3010        if isinstance(expr, Const) and isinstance(index2, Const): # Constant folding
3011            return self.makeconst(expr.start, _2.end, expr.value[:index2.value])
3012        return GetSlice2(expr.start, _2.end, expr, index2)
3013
3014    @spark.production('expr7 ::= - expr7')
3015    def expr_neg(self, _0, expr):
3016        if isinstance(expr, Const): # Constant folding
3017            return self.makeconst(_0.start, expr.end, -expr.value)
3018        return Neg(_0.start, expr.end, expr)
3019
3020    @spark.production('expr6 ::= expr6 * expr6')
3021    def expr_mul(self, obj1, _0, obj2):
3022        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3023            return self.makeconst(obj1.start, obj2.end, obj1.value * obj2.value)
3024        return Mul(obj1.start, obj2.end, obj1, obj2)
3025
3026    @spark.production('expr6 ::= expr6 // expr6')
3027    def expr_floordiv(self, obj1, _0, obj2):
3028        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3029            return self.makeconst(obj1.start, obj2.end, obj1.value // obj2.value)
3030        return FloorDiv(obj1.start, obj2.end, obj1, obj2)
3031
3032    @spark.production('expr6 ::= expr6 / expr6')
3033    def expr_truediv(self, obj1, _0, obj2):
3034        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3035            return self.makeconst(obj1.start, obj2.end, obj1.value / obj2.value)
3036        return TrueDiv(obj1.start, obj2.end, obj1, obj2)
3037
3038    @spark.production('expr6 ::= expr6 % expr6')
3039    def expr_mod(self, obj1, _0, obj2):
3040        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3041            return self.makeconst(obj1.start, obj2.end, obj1.value % obj2.value)
3042        return Mod(obj1.start, obj2.end, obj1, obj2)
3043
3044    @spark.production('expr5 ::= expr5 + expr5')
3045    def expr_add(self, obj1, _0, obj2):
3046        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3047            return self.makeconst(obj1.start, obj2.end, obj1.value + obj2.value)
3048        return Add(obj1.start, obj2.end, obj1, obj2)
3049
3050    @spark.production('expr5 ::= expr5 - expr5')
3051    def expr_sub(self, obj1, _0, obj2):
3052        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3053            return self.makeconst(obj1.start, obj2.end, obj1.value - obj2.value)
3054        return Sub(obj1.start, obj2.end, obj1, obj2)
3055
3056    @spark.production('expr4 ::= expr4 == expr4')
3057    def expr_eq(self, obj1, _0, obj2):
3058        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3059            return self.makeconst(obj1.start, obj2.end, obj1.value == obj2.value)
3060        return EQ(obj1.start, obj2.end, obj1, obj2)
3061
3062    @spark.production('expr4 ::= expr4 != expr4')
3063    def expr_ne(self, obj1, _0, obj2):
3064        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3065            return self.makeconst(obj1.start, obj2.end, obj1.value != obj2.value)
3066        return NE(obj1.start, obj2.end, obj1, obj2)
3067
3068    @spark.production('expr4 ::= expr4 < expr4')
3069    def expr_lt(self, obj1, _0, obj2):
3070        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3071            return self.makeconst(obj1.start, obj2.end, obj1.value < obj2.value)
3072        return LT(obj1.start, obj2.end, obj1, obj2)
3073
3074    @spark.production('expr4 ::= expr4 <= expr4')
3075    def expr_le(self, obj1, _0, obj2):
3076        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3077            return self.makeconst(obj1.start, obj2.end, obj1.value <= obj2.value)
3078        return LE(obj1.start, obj2.end, obj1, obj2)
3079
3080    @spark.production('expr4 ::= expr4 > expr4')
3081    def expr_gt(self, obj1, _0, obj2):
3082        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3083            return self.makeconst(obj1.start, obj2.end, obj1.value > obj2.value)
3084        return GT(obj1.start, obj2.end, obj1, obj2)
3085
3086    @spark.production('expr4 ::= expr4 >= expr4')
3087    def expr_ge(self, obj1, _0, obj2):
3088        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3089            return self.makeconst(obj1.start, obj2.end, obj1.value >= obj2.value)
3090        return GE(obj1.start, obj2.end, obj1, obj2)
3091
3092    @spark.production('expr3 ::= expr3 in expr3')
3093    def expr_contains(self, obj, _0, container):
3094        if isinstance(obj, Const) and isinstance(container, Const): # Constant folding
3095            return self.makeconst(obj.start, container.end, obj.value in container.value)
3096        return Contains(obj.start, container.end, obj, container)
3097
3098    @spark.production('expr3 ::= expr3 not in expr3')
3099    def expr_notcontains(self, obj, _0, _1, container):
3100        if isinstance(obj, Const) and isinstance(container, Const): # Constant folding
3101            return self.makeconst(obj.start, container.end, obj.value not in container.value)
3102        return NotContains(obj.start, container.end, obj, container)
3103
3104    @spark.production('expr2 ::= not expr2')
3105    def expr_not(self, _0, expr):
3106        if isinstance(expr, Const): # Constant folding
3107            return self.makeconst(_0.start, expr.end, not expr.value)
3108        return Not(_0.start, expr.end, expr)
3109
3110    @spark.production('expr1 ::= expr1 and expr1')
3111    def expr_and(self, obj1, _0, obj2):
3112        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3113            return self.makeconst(obj1.start, obj2.end, bool(obj1.value and obj2.value))
3114        return And(obj1.start, obj2.end, obj1, obj2)
3115
3116    @spark.production('expr0 ::= expr0 or expr0')
3117    def expr_or(self, obj1, _0, obj2):
3118        if isinstance(obj1, Const) and isinstance(obj2, Const): # Constant folding
3119            return self.makeconst(obj1.start, obj2.end, bool(obj1.value or obj2.value))
3120        return Or(obj1.start, obj2.end, obj1, obj2)
3121
3122    # These rules make operators of different precedences interoperable, by allowing an expression to "drop" its precedence.
3123    @spark.production('expr10 ::= expr11')
3124    @spark.production('expr9 ::= expr10')
3125    @spark.production('expr8 ::= expr9')
3126    @spark.production('expr7 ::= expr8')
3127    @spark.production('expr6 ::= expr7')
3128    @spark.production('expr5 ::= expr6')
3129    @spark.production('expr4 ::= expr5')
3130    @spark.production('expr3 ::= expr4')
3131    @spark.production('expr2 ::= expr3')
3132    @spark.production('expr1 ::= expr2')
3133    @spark.production('expr0 ::= expr1')
3134    def expr_dropprecedence(self, expr):
3135        return expr
3136
3137
3138class ForParser(ExprParser):
3139    emptyerror = "loop expression required"
3140    start = "for"
3141
3142    @spark.production('for ::= name in expr0')
3143    def for0(self, iter, _0, cont):
3144        return For(iter.start, cont.end, iter, cont)
3145
3146    @spark.production('for ::= ( name , ) in expr0')
3147    def for1(self, _0, iter, _1, _2, _3, cont):
3148        return For(_0.start, cont.end, [iter], cont)
3149
3150    @spark.production('for ::= ( name , name ) in expr0')
3151    def for2a(self, _0, iter1, _1, iter2, _2, _3, cont):
3152        return For(_0.start, cont.end, [iter1, iter2], cont)
3153
3154    @spark.production('for ::= ( name , name , ) in expr0')
3155    def for2b(self, _0, iter1, _1, iter2, _2, _3, _4, cont):
3156        return For(_0.start, cont.end, [iter1, iter2], cont)
3157
3158    @spark.production('for ::= ( name , name , name ) in expr0')
3159    def for3a(self, _0, iter1, _1, iter2, _2, iter3, _3, _4, cont):
3160        return For(_0.start, cont.end, [iter1, iter2, iter3], cont)
3161
3162    @spark.production('for ::= ( name , name , name , ) in expr0')
3163    def for3b(self, _0, iter1, _1, iter2, _2, iter3, _3, _4, _5, cont):
3164        return For(_0.start, cont.end, [iter1, iter2, iter3], cont)
3165
3166
3167class StmtParser(ExprParser):
3168    emptyerror = "statement required"
3169    start = "stmt"
3170
3171    @spark.production('stmt ::= name = expr0')
3172    def stmt_assign(self, name, _0, value):
3173        return StoreVar(name.start, value.end, name, value)
3174
3175    @spark.production('stmt ::= name += expr0')
3176    def stmt_iadd(self, name, _0, value):
3177        return AddVar(name.start, value.end, name, value)
3178
3179    @spark.production('stmt ::= name -= expr0')
3180    def stmt_isub(self, name, _0, value):
3181        return SubVar(name.start, value.end, name, value)
3182
3183    @spark.production('stmt ::= name *= expr0')
3184    def stmt_imul(self, name, _0, value):
3185        return MulVar(name.start, value.end, name, value)
3186
3187    @spark.production('stmt ::= name /= expr0')
3188    def stmt_itruediv(self, name, _0, value):
3189        return TrueDivVar(name.start, value.end, name, value)
3190
3191    @spark.production('stmt ::= name //= expr0')
3192    def stmt_ifloordiv(self, name, _0, value):
3193        return FloorDivVar(name.start, value.end, name, value)
3194
3195    @spark.production('stmt ::= name %= expr0')
3196    def stmt_imod(self, name, _0, value):
3197        return ModVar(name.start, value.end, name, value)
3198
3199    @spark.production('stmt ::= del name')
3200    def stmt_del(self, _0, name):
3201        return DelVar(_0.start, name.end, name)
3202
3203
3204class RenderParser(ExprParser):
3205    emptyerror = "render statement required"
3206    start = "render"
3207
3208    @spark.production('render ::= expr0 ( )')
3209    def emptyrender(self, template, _0, _1):
3210        return Render(template.start, _1.end, template)
3211
3212    @spark.production('buildrender ::= expr0 ( name = expr0')
3213    def startrender(self, template, _0, argname, _1, argvalue):
3214        return Render(template.start, argvalue.end, template, (argname, argvalue))
3215
3216    @spark.production('buildrender ::= expr0 ( ** expr0')
3217    def startrenderupdate(self, template, _0, _1, arg):
3218        return Render(template.start, arg.end, template, (arg, ))
3219
3220    @spark.production('buildrender ::= buildrender , name = expr0')
3221    def buildrender(self, render, _0, argname, _1, argvalue):
3222        render.variables.append((argname, argvalue))
3223        render.end = argvalue.end
3224        return render
3225
3226    @spark.production('buildrender ::= buildrender , ** expr0')
3227    def buildrenderupdate(self, render, _0, _1, arg):
3228        render.variables.append((arg,))
3229        render.end = arg.end
3230        return render
3231
3232    @spark.production('render ::= buildrender )')
3233    def finishrender(self, render, _0):
3234        render.end = _0.end
3235        return render
3236
3237    @spark.production('render ::= buildrender , )')
3238    def finishrender1(self, render, _0, _1):
3239        render.end = _1.end
3240        return render
3241
3242
3243###
3244### Helper functions used at template runtime
3245###
3246
3247def _repr(obj):
3248    """
3249    Helper for the ``repr`` function.
3250    """
3251    if isinstance(obj, unicode):
3252        return unicode(repr(obj)[1:])
3253    elif isinstance(obj, str):
3254        return unicode(repr(obj))
3255    elif isinstance(obj, datetime.datetime):
3256        s = unicode(obj.isoformat())
3257        if s.endswith(u"T00:00:00"):
3258            return u"@{}T".format(s[:-9])
3259        else:
3260            return u"@" + s
3261    elif isinstance(obj, datetime.date):
3262        return u"@{}T".format(obj.isoformat())
3263    elif isinstance(obj, color.Color):
3264        if obj[3] == 0xff:
3265            s = "#{:02x}{:02x}{:02x}".format(obj[0], obj[1], obj[2])
3266            if s[1]==s[2] and s[3]==s[4] and s[5]==s[6]:
3267                return "#{}{}{}".format(s[1], s[3], s[5])
3268            return s
3269        else:
3270            s = "#{:02x}{:02x}{:02x}{:02x}".format(*obj)
3271            if s[1]==s[2] and s[3]==s[4] and s[5]==s[6] and s[7]==s[8]:
3272                return "#{}{}{}{}".format(s[1], s[3], s[5], s[7])
3273            return s
3274    elif isinstance(obj, collections.Sequence):
3275        return u"[{}]".format(u", ".join(_repr(item) for item in obj))
3276    elif isinstance(obj, collections.Mapping):
3277        return u"{{{}}}".format(u", ".join(u"{}: {}".format(_repr(key), _repr(value)) for (key, value) in obj.iteritems()))
3278    else:
3279        return unicode(repr(obj))
3280
3281
3282def _json(obj):
3283    """
3284    Helper for the ``json`` function.
3285    """
3286    if obj is None:
3287        return u"null"
3288    if isinstance(obj, (bool, int, long, float, basestring)):
3289        return json.dumps(obj)
3290    elif isinstance(obj, datetime.datetime):
3291        return format(obj, u"new Date({}, {}, {}, {}, {}, {}, {})".format(obj.year, obj.month-1, obj.day, obj.hour, obj.minute, obj.second, obj.microsecond//1000))
3292    elif isinstance(obj, datetime.date):
3293        return format(obj, u"new Date({}, {}, {})".format(obj.year, obj.month-1, obj.day))
3294    elif isinstance(obj, color.Color):
3295        return u"ul4.Color.create({}, {}, {}, {})".format(*obj)
3296    elif isinstance(obj, collections.Mapping):
3297        return u"{{{}}}".format(u", ".join(u"{}: {}".format(_json(key), _json(value)) for (key, value) in obj.iteritems()))
3298    elif isinstance(obj, collections.Sequence):
3299        return u"[{}]".format(u", ".join(_json(item) for item in obj))
3300    elif isinstance(obj, Template):
3301        return obj.jssource()
3302    else:
3303        raise TypeError("can't handle object of type {}".format(type(obj)))
3304
3305
3306def _oct(value):
3307        """
3308        Helper for the ``oct`` function.
3309        """
3310        if value == 0:
3311            return "0o0"
3312        elif value < 0:
3313            return "-0o" + oct(value)[2:]
3314        else:
3315            return "0o" + oct(value)[1:]
3316
3317
3318def _csv(obj):
3319    """
3320    Helper for the ``csv`` function.
3321    """
3322    if obj is None:
3323        return u""
3324    elif not isinstance(obj, basestring):
3325        obj = _repr(obj)
3326    if any(c in obj for c in ',"\n'):
3327        return u'"{}"'.format(obj.replace('"', '""'))
3328    return obj
3329
3330
3331def _type(obj):
3332    """
3333    Helper for the ``type`` function.
3334    """
3335    if obj is None:
3336        return u"none"
3337    elif isinstance(obj, basestring):
3338        return u"str"
3339    elif isinstance(obj, bool):
3340        return u"bool"
3341    elif isinstance(obj, (int, long)):
3342        return u"int"
3343    elif isinstance(obj, float):
3344        return u"float"
3345    elif isinstance(obj, (datetime.datetime, datetime.date)):
3346        return u"date"
3347    elif isinstance(obj, color.Color):
3348        return u"color"
3349    elif isinstance(obj, collections.Mapping):
3350        return u"dict"
3351    elif isinstance(obj, collections.Sequence):
3352        return u"list"
3353    elif hasattr(obj, "__call__"):
3354        return u"template"
3355    elif isinstance(obj, color.Color):
3356        return u"color"
3357    return None
3358
3359
3360def _mimeformat(obj):
3361    """
3362    Helper for the ``mimeformat`` method.
3363    """
3364    weekdayname = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
3365    monthname = (None, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
3366    return "{1}, {0.day:02d} {2:3} {0.year:4} {0.hour:02}:{0.minute:02}:{0.second:02} GMT".format(obj, weekdayname[obj.weekday()], monthname[obj.month])
3367
3368
3369def _yearday(obj):
3370    """
3371    Helper for the ``yearday`` method.
3372    """
3373    return (obj - obj.__class__(obj.year, 1, 1)).days+1
3374
3375
3376def _isoformat(obj):
3377    """
3378    Helper for the ``isoformat`` method.
3379    """
3380    result = obj.isoformat()
3381    suffix = "T00:00:00"
3382    if result.endswith(suffix):
3383        return result[:-len(suffix)]
3384    return result
Note: See TracBrowser for help on using the browser.