root/livinglogic.python.xist/src/ll/ul4c.py @ 4507:a4fb11bc4477

Revision 4507:a4fb11bc4477, 123.2 KB (checked in by Walter Doerwald <walter@…>, 8 years ago)

"Escape" C-style comments in the Java source code for UL4 templates.

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