root/livinglogic.python.xist/src/ll/ul4c.py @ 5347:da430915bf69

Revision 5347:da430915bf69, 74.9 KB (checked in by Walter Doerwald <walter@…>, 7 years ago)

Store source code start/end offsets for all AST nodes.

This simplifies str output of most nodes, as they can simply output the
appropriate slice of the original source code.

Line 
1# -*- coding: utf-8 -*-
2
3## Copyright 2009-2013 by LivingLogic AG, Bayreuth/Germany
4## Copyright 2009-2013 by Walter Dörwald
5##
6## All Rights Reserved
7##
8## See ll/xist/__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 an internal format, which makes it
18possible to implement template renderers in multiple programming languages.
19"""
20
21
22__docformat__ = "reStructuredText"
23
24
25import re, types, datetime, urllib.parse as urlparse, json, collections, locale, itertools, random, datetime, unicodedata
26
27import antlr3
28
29from ll import color, misc
30
31
32# Regular expression used for splitting dates in isoformat
33datesplitter = re.compile("[-T:.]")
34
35
36def register(name):
37    from ll import ul4on
38    def registration(cls):
39        ul4on.register("de.livinglogic.ul4." + name)(cls)
40        cls.type = name
41        return cls
42    return registration
43
44
45class Object:
46    fields = {}
47
48    def __getitem__(self, key):
49        if key in self.fields:
50            return getattr(self, key)
51        raise KeyError(key)
52
53
54###
55### Location information
56###
57
58@register("location")
59class Location(Object):
60    """
61    A :class:`Location` object contains information about the location of a
62    template tag.
63    """
64    __slots__ = ("root", "source", "type", "starttag", "endtag", "startcode", "endcode")
65    fields = {"root", "source", "type", "starttag", "endtag", "startcode", "endcode", "tag", "code"}
66
67    def __init__(self, root=None, source=None, type=None, starttag=None, endtag=None, startcode=None, endcode=None):
68        """
69        Create a new :class:`Location` object. The arguments have the following
70        meaning:
71
72            :var:`root`
73                The :class:`Template` object
74
75            :var:`source`
76                The complete source string
77
78            :var:`type`
79                The tag type (i.e. ``"for"``, ``"if"``, etc. or ``None`` for
80                literal text)
81
82            :var:`starttag`
83                The start position of the start delimiter.
84
85            :var:`endtag`
86                The end position of the end delimiter.
87
88            :var:`startcode`
89                The start position of the tag code.
90
91            :var:`endcode`
92                The end position of the tag code.
93        """
94        self.root = root
95        self.source = source
96        self.type = type
97        self.starttag = starttag
98        self.endtag = endtag
99        self.startcode = startcode
100        self.endcode = endcode
101
102    @property
103    def code(self):
104        return self.source[self.startcode:self.endcode]
105
106    @property
107    def tag(self):
108        return self.source[self.starttag:self.endtag]
109
110    def __repr__(self):
111        return "<{}.{} {} at {:#x}>".format(self.__class__.__module__, self.__class__.__name__, self, id(self))
112
113    def pos(self):
114        lastlinefeed = self.source.rfind("\n", 0, self.starttag)
115        if lastlinefeed >= 0:
116            return (self.source.count("\n", 0, self.starttag)+1, self.starttag-lastlinefeed)
117        else:
118            return (1, self.starttag + 1)
119
120    def __str__(self):
121        (line, col) = self.pos()
122        return "{!r} at {}:{} (line {}, col {})".format(self.tag, self.starttag, self.endtag, line, col)
123
124    def ul4ondump(self, encoder):
125        encoder.dump(self.root)
126        encoder.dump(self.source)
127        encoder.dump(self.type)
128        encoder.dump(self.starttag)
129        encoder.dump(self.endtag)
130        encoder.dump(self.startcode)
131        encoder.dump(self.endcode)
132
133    def ul4onload(self, decoder):
134        self.root = decoder.load()
135        self.source = decoder.load()
136        self.type = decoder.load()
137        self.starttag = decoder.load()
138        self.endtag = decoder.load()
139        self.startcode = decoder.load()
140        self.endcode = decoder.load()
141
142
143###
144### Exceptions
145###
146
147class Error(Exception):
148    """
149    Exception class that wraps another exception and provides a location.
150    """
151    def __init__(self, node):
152        self.node = node
153
154    def __repr__(self):
155        return "<{}.{} in {} at {:#x}>".format(self.__class__.__module__, self.__class__.__name__, self.node, id(self))
156
157    def __str__(self):
158        if isinstance(self.node, (Template, TemplateClosure)):
159            if self.node.name is not None:
160                return "in template named {}".format(self.node.name)
161            else:
162                return "in unnamed template"
163        else:
164            return "in {!r} in tag {}".format(str(self.node), self.node.location)
165
166
167class BlockError(Exception):
168    """
169    Exception that is raised by the compiler when an illegal block structure is
170    detected (e.g. an ``<?end if?>`` without a previous ``<?if?>``).
171    """
172
173    def __init__(self, message):
174        self.message = message
175
176    def __str__(self):
177        return self.message
178
179
180###
181### Exceptions used by the interpreted code for flow control
182###
183
184class BreakException(Exception):
185    pass
186
187
188class ContinueException(Exception):
189    pass
190
191
192class ReturnException(Exception):
193    def __init__(self, value):
194        self.value = value
195
196
197###
198### Various versions of undefined objects
199###
200
201class Undefined(object):
202    def __bool__(self):
203        return False
204
205    def __iter__(self):
206        raise TypeError("{!r} doesn't support iteration".format(self))
207
208    def __len__(self):
209        raise AttributeError("{!r} has no len()".format(self))
210
211    def __getattr__(self, key):
212        raise AttributeError("{!r} has no attribute {!r}".format(self, key))
213
214    def __getitem__(self, key):
215        raise TypeError("{!r} doesn't support indexing (key={!r})".format(self, key))
216
217
218class UndefinedKey(Undefined):
219    def __init__(self, key):
220        self.__key = key
221
222    def __repr__(self):
223        return "undefined object for key {!r}".format(self.__key)
224
225
226class UndefinedVariable(Undefined):
227    def __init__(self, name):
228        self.__name = name
229
230    def __repr__(self):
231        return "undefined variable {!r}".format(self.__name)
232
233
234class UndefinedIndex(Undefined):
235    def __init__(self, index):
236        self.__index = index
237
238    def __repr__(self):
239        return "undefined object at index {!r}".format(self.__index)
240
241
242###
243### Helper functions
244###
245
246
247def handleeval(f):
248    def wrapped(self, vars):
249        try:
250            return (yield from f(self, vars))
251        except (BreakException, ContinueException, ReturnException) as ex:
252            raise
253        except Error as ex:
254            if ex.node.location is not self.location:
255                raise Error(self) from ex
256            else:
257                raise
258        except Exception as ex:
259            raise Error(self) from ex
260    return wrapped
261
262
263def _unpackvar(vars, name, value):
264    if isinstance(name, str):
265        vars[name] = value
266    else:
267        if len(name) > len(value):
268            raise TypeError("too many values to unpack (expected {})".format(len(name)))
269        elif len(name) < len(value):
270            raise TypeError("need more than {} value{} to unpack)".format(len(values), "ss" if len(values) != 1 else ""))
271        for (name, value) in zip(name, value):
272            _unpackvar(vars, name, value)
273
274
275###
276### Compiler stuff: Nodes for the AST
277###
278
279class AST(Object):
280    """
281    Base class for all syntax tree nodes.
282    """
283
284    # Set of attributes available via :meth:`getitem`.
285    fields = {"type", "location", "start", "end"}
286
287    # "Global" functions and methods. Functions in ``functions`` will be exposed to UL4 code
288    functions = {}
289    methods = {}
290
291    def __init__(self, location=None, start=None, end=None):
292        self.location = location
293        self.start = start
294        self.end = end
295
296    def __getitem__(self, key):
297        if key in self.fields:
298            return getattr(self, key)
299        raise KeyError(key)
300
301    def __repr__(self):
302        return "<{0.__class__.__module__}.{0.__class__.__qualname__} at {1:#x}>".format(self, id(self))
303
304    def _repr_pretty_(self, p, cycle):
305        p.text(repr(self))
306
307    def __str__(self):
308        v = []
309        level = 0
310        needlf = False
311        for code in self._str():
312            if code is None:
313                needlf = True
314            elif isinstance(code, int):
315                level += code
316            else:
317                if needlf:
318                    v.append("\n")
319                    v.append(level*"\t")
320                    needlf = False
321                v.append(code)
322        if needlf:
323            v.append("\n")
324        return "".join(v)
325
326    def _str(self):
327        # Format :var:`self`.
328        # This is used by :meth:`__str__.
329        # ``_str`` is a generator an may output:
330        # ``None``, which means: "add a line feed and an indentation here"
331        # an int, which means: add the int to the indentation level
332        # a string, which means: add this string to the output
333        yield self.location.root.source[self.start:self.end].replace("\r\n", " ").replace("\n", " ")
334
335    @misc.notimplemented
336    def eval(self, vars):
337        """
338        This evaluates the node.
339
340        This is a generator, which yields the text output of the node. If the
341        node returns a value (as most nodes do), this is done as the value of a
342        :exc:`StopIteration` exception.
343        """
344
345    def ul4ondump(self, encoder):
346        encoder.dump(self.location)
347        encoder.dump(self.start)
348        encoder.dump(self.end)
349
350    def ul4onload(self, decoder):
351        self.location = decoder.load()
352        self.start = decoder.load()
353        self.end = decoder.load()
354
355    @classmethod
356    def makefunction(cls, f):
357        name = f.__name__
358        if name.startswith("_"):
359            name = name[1:]
360        cls.functions[name] = f
361        return f
362
363    @classmethod
364    def makemethod(cls, f):
365        name = f.__name__
366        if name.startswith("_"):
367            name = name[1:]
368        cls.methods[name] = f
369        return f
370
371
372@register("text")
373class Text(AST):
374    """
375    AST node for literal text.
376    """
377
378    def text(self):
379        # If ``keepws`` is true, we output the literal text from the location info.
380        # Otherwise we have to strip linefeeds and indentation
381        text = self.location.code
382        if not self.location.root.keepws:
383            text = "".join(line.lstrip() for line in text.splitlines())
384        return text
385
386    def __repr__(self):
387        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {1!r} at {2:#x}>".format(self, self.text(), id(self))
388
389    def _str(self):
390        yield "text {!r}".format(self.text())
391
392    def eval(self, vars):
393        yield self.text()
394
395
396@register("const")
397class Const(AST):
398    """
399    Load a constant
400    """
401    fields = AST.fields.union({"value"})
402
403    def __init__(self, location=None, start=None, end=None, value=None):
404        super().__init__(location, start, end)
405        self.value = value
406
407    def eval(self, vars):
408        yield from ()
409        return self.value
410
411    def ul4ondump(self, encoder):
412        super().ul4ondump(encoder)
413        encoder.dump(self.value)
414
415    def ul4onload(self, decoder):
416        super().ul4onload(decoder)
417        self.value = decoder.load()
418
419    def __repr__(self):
420        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.value!r} at {1:#x}>".format(self, id(self))
421
422
423@register("list")
424class List(AST):
425    """
426    AST nodes for loading a list object.
427    """
428
429    fields = AST.fields.union({"items"})
430
431    def __init__(self, location=None, start=None, end=None, *items):
432        super().__init__(location, start, end)
433        self.items = list(items)
434
435    def __repr__(self):
436        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.items!r} at {1:#x}>".format(self, id(self))
437
438    def _repr_pretty_(self, p, cycle):
439        if cycle:
440            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
441        else:
442            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
443                for (i, item) in enumerate(self.items):
444                    if i:
445                        p.breakable()
446                    else:
447                        p.breakable("")
448                    p.pretty(item)
449                p.breakable()
450                p.text("at {:#x}".format(id(self)))
451
452    @handleeval
453    def eval(self, vars):
454        result = []
455        for item in self.items:
456            item = (yield from item.eval(vars))
457            result.append(item)
458        return result
459
460    def ul4ondump(self, encoder):
461        super().ul4ondump(encoder)
462        encoder.dump(self.items)
463
464    def ul4onload(self, decoder):
465        super().ul4onload(decoder)
466        self.items = decoder.load()
467
468
469@register("listcomp")
470class ListComp(AST):
471    """
472    AST node for list comprehension.
473    """
474
475    fields = AST.fields.union({"item", "varname", "container", "condition"})
476
477
478    def __init__(self, location=None, start=None, end=None, item=None, varname=None, container=None, condition=None):
479        super().__init__(location, start, end)
480        self.item = item
481        self.varname = varname
482        self.container = container
483        self.condition = condition
484
485    def __repr__(self):
486        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} item={0.item!r} varname={0.varname!r} container={0.container!r}".format(self)
487        if self.condition is not None:
488            s += " condition={0.condition!r}".format(self)
489        return s + " at {:#x}>".format(id(self))
490
491    def _repr_pretty_(self, p, cycle):
492        if cycle:
493            p.text("{0.__class__.__module__}.{0.__class__.__qualname__}(...)".format(self))
494        else:
495            with p.group(4, "{0.__class__.__module__}.{0.__class__.__qualname__}(".format(self), ")"):
496                p.breakable("")
497                p.text("item=")
498                p.pretty(self.item)
499                p.text(",")
500                p.breakable()
501                p.text("varname=")
502                p.pretty(self.varname)
503                p.text(",")
504                p.breakable()
505                p.text("container=")
506                p.pretty(self.container)
507                if self.condition is not None:
508                    p.text(",")
509                    p.breakable()
510                    p.text("condition=")
511                    p.pretty(self.condition)
512                p.breakable()
513                p.text("at {:#x}".format(id(self)))
514
515    @handleeval
516    def eval(self, vars):
517        container = (yield from self.container.eval(vars))
518        vars = collections.ChainMap({}, vars) # Don't let loop variables leak into the surrounding scope
519        result = []
520        for item in container:
521            _unpackvar(vars, self.varname, item)
522            if self.condition is None or (yield from self.condition.eval(vars)):
523                item = (yield from self.item.eval(vars))
524                result.append(item)
525        return result
526
527    def ul4ondump(self, encoder):
528        super().ul4ondump(encoder)
529        encoder.dump(self.item)
530        encoder.dump(self.varname)
531        encoder.dump(self.container)
532        encoder.dump(self.condition)
533
534    def ul4onload(self, decoder):
535        super().ul4onload(decoder)
536        self.item = decoder.load()
537        self.varname = decoder.load()
538        self.container = decoder.load()
539        self.condition = decoder.load()
540
541
542@register("dict")
543class Dict(AST):
544    """
545    AST node for loading a dict object.
546    """
547
548    fields = AST.fields.union({"items"})
549
550    def __init__(self, location=None, start=None, end=None, *items):
551        super().__init__(location, start, end)
552        self.items = list(items)
553
554    def __repr__(self):
555        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.items!r} at {1:#x}>".format(self, id(self))
556
557    def _repr_pretty_(self, p, cycle):
558        if cycle:
559            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
560        else:
561            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
562                for item in self.items:
563                    p.breakable()
564                    p.pretty(item[0])
565                    p.text("=")
566                    p.pretty(item[1])
567                p.breakable()
568                p.text("at {:#x}".format(id(self)))
569
570    @handleeval
571    def eval(self, vars):
572        result = {}
573        for item in self.items:
574            key = (yield from item[0].eval(vars))
575            value = (yield from item[1].eval(vars))
576            result[key] = value
577        return result
578
579    def ul4ondump(self, encoder):
580        super().ul4ondump(encoder)
581        encoder.dump(self.items)
582
583    def ul4onload(self, decoder):
584        super().ul4onload(decoder)
585        self.items = [tuple(item) for item in decoder.load()]
586
587
588@register("dictcomp")
589class DictComp(AST):
590    """
591    AST node for dictionary comprehension.
592    """
593
594    fields = AST.fields.union({"key", "value", "varname", "container", "condition"})
595
596    def __init__(self, location=None, start=None, end=None, key=None, value=None, varname=None, container=None, condition=None):
597        super().__init__(location, start, end)
598        self.key = key
599        self.value = value
600        self.varname = varname
601        self.container = container
602        self.condition = condition
603
604    def __repr__(self):
605        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} key={0.key!r} value={0.value!r} varname={0.varname!r} container={0.container!r}".format(self)
606        if self.condition is not None:
607            s += " {0.condition!r}".format(self)
608        return s + " at {:#x}>".format(id(self))
609
610    def _repr_pretty_(self, p, cycle):
611        if cycle:
612            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
613        else:
614            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
615                p.breakable()
616                p.text("key=")
617                p.pretty(self.key)
618                p.breakable()
619                p.text("value=")
620                p.pretty(self.value)
621                p.breakable()
622                p.text("varname=")
623                p.pretty(self.varname)
624                p.breakable()
625                p.text("container=")
626                p.pretty(self.container)
627                if self.condition is not None:
628                    p.breakable()
629                    p.text("condition=")
630                    p.pretty(self.condition)
631                p.breakable()
632                p.text("at {:#x}".format(id(self)))
633
634    @handleeval
635    def eval(self, vars):
636        container = (yield from self.container.eval(vars))
637        vars = collections.ChainMap({}, vars) # Don't let loop variables leak into the surrounding scope
638        result = {}
639        for item in container:
640            _unpackvar(vars, self.varname, item)
641            if self.condition is None or (yield from self.condition.eval(vars)):
642                key = (yield from self.key.eval(vars))
643                value = (yield from self.value.eval(vars))
644                result[key] = value
645        return result
646
647    def ul4ondump(self, encoder):
648        super().ul4ondump(encoder)
649        encoder.dump(self.key)
650        encoder.dump(self.value)
651        encoder.dump(self.varname)
652        encoder.dump(self.container)
653        encoder.dump(self.condition)
654
655    def ul4onload(self, decoder):
656        super().ul4onload(decoder)
657        self.key = decoder.load()
658        self.value = decoder.load()
659        self.varname = decoder.load()
660        self.container = decoder.load()
661        self.condition = decoder.load()
662
663
664@register("genexpr")
665class GenExpr(AST):
666    """
667    AST node for a generator expression.
668    """
669
670    fields = AST.fields.union({"item", "varname", "container", "condition"})
671
672    def __init__(self, location=None, start=None, end=None, item=None, varname=None, container=None, condition=None):
673        super().__init__(location, start, end)
674        self.item = item
675        self.varname = varname
676        self.container = container
677        self.condition = condition
678
679    def __repr__(self):
680        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} item={0.item!r} varname={0.varname!r} container={0.container!r}".format(self)
681        if self.condition is not None:
682            s += " condition={0.condition!r}".format(self)
683        return s + " at {:#x}>".format(id(self))
684
685    def _repr_pretty_(self, p, cycle):
686        if cycle:
687            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
688        else:
689            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
690                p.breakable()
691                p.text("item=")
692                p.pretty(self.item)
693                p.breakable()
694                p.text("varname=")
695                p.pretty(self.varname)
696                p.breakable()
697                p.text("container=")
698                p.pretty(self.container)
699                if self.condition is not None:
700                    p.breakable()
701                    p.text("condition=")
702                    p.pretty(self.condition)
703                p.breakable()
704                p.text("at {:#x}".format(id(self)))
705
706    @handleeval
707    def eval(self, vars):
708        container = (yield from self.container.eval(vars))
709        vars = collections.ChainMap({}, vars) # Don't let loop variables leak into the surrounding scope
710        def result():
711            for item in container:
712                _unpackvar(vars, self.varname, item)
713                if self.condition is None or (yield from self.condition.eval(vars)):
714                    item = (yield from self.item.eval(vars))
715                    yield item
716        return result()
717
718    def ul4ondump(self, encoder):
719        super().ul4ondump(encoder)
720        encoder.dump(self.item)
721        encoder.dump(self.varname)
722        encoder.dump(self.container)
723        encoder.dump(self.condition)
724
725    def ul4onload(self, decoder):
726        super().ul4onload(decoder)
727        self.item = decoder.load()
728        self.varname = decoder.load()
729        self.container = decoder.load()
730        self.condition = decoder.load()
731
732
733@register("var")
734class Var(AST):
735    """
736    AST nodes for loading a variable.
737    """
738
739    fields = AST.fields.union({"name"})
740
741    def __init__(self, location=None, start=None, end=None, name=None):
742        super().__init__(location, start, end)
743        self.name = name
744
745    def __repr__(self):
746        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.name!r} at {1:#x}>".format(self, id(self))
747
748    @handleeval
749    def eval(self, vars):
750        yield from ()
751        try:
752            return vars[self.name]
753        except KeyError:
754            try:
755                return self.functions[self.name]
756            except KeyError:
757                return UndefinedVariable(self.name)
758
759    def ul4ondump(self, encoder):
760        super().ul4ondump(encoder)
761        encoder.dump(self.name)
762
763    def ul4onload(self, decoder):
764        super().ul4onload(decoder)
765        self.name = decoder.load()
766
767
768class Block(AST):
769    """
770    Base class for all AST nodes that are blocks.
771
772    A block contains a sequence of AST nodes that are executed sequencially.
773    A block may execute its content zero (e.g. an ``<?if?>`` block) or more times
774    (e.g. a ``<?for?>`` block).
775    """
776
777    fields = AST.fields.union({"endlocation", "content"})
778
779    def __init__(self, location=None, start=None, end=None):
780        super().__init__(location, start, end)
781        self.endlocation = None
782        self.content = []
783
784    def append(self, item):
785        self.content.append(item)
786
787    def _str(self):
788        if self.content:
789            for node in self.content:
790                yield from node._str()
791                yield None
792        else:
793            yield "pass"
794            yield None
795
796    @handleeval
797    def eval(self, vars):
798        for node in self.content:
799            yield from node.eval(vars)
800
801    def ul4ondump(self, encoder):
802        super().ul4ondump(encoder)
803        encoder.dump(self.endlocation)
804        encoder.dump(self.content)
805
806    def ul4onload(self, decoder):
807        super().ul4onload(decoder)
808        self.endlocation = decoder.load()
809        self.content = decoder.load()
810
811
812@register("ieie")
813class IfElIfElse(Block):
814    """
815    AST node for an conditional block.
816
817    The content of the :class:`IfElIfElse` block is one :class:`If` block
818    followed by zero or more :class:`ElIf` blocks followed by zero or one
819    :class:`Else` block.
820    """
821    def __init__(self, location=None, start=None, end=None, condition=None):
822        super().__init__(location, start, end)
823        if condition is not None:
824            self.newblock(If(location, start, end, condition))
825
826    def __repr__(self):
827        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {1} at {2:#x}>".format(self, repr(self.content)[1:-1], id(self))
828
829    def _repr_pretty_(self, p, cycle):
830        if cycle:
831            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
832        else:
833            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
834                for node in self.content:
835                    p.breakable()
836                    p.pretty(node)
837                p.breakable()
838                p.text("at {:#x}".format(id(self)))
839
840    def append(self, item):
841        self.content[-1].append(item)
842
843    def newblock(self, block):
844        if self.content:
845            self.content[-1].endlocation = block.location
846        self.content.append(block)
847
848    def _str(self):
849        for node in self.content:
850            yield from node._str()
851
852    @handleeval
853    def eval(self, vars):
854        for node in self.content:
855            if isinstance(node, Else) or (yield from node.condition.eval(vars)):
856                yield from node.eval(vars)
857                break
858
859
860@register("if")
861class If(Block):
862    """
863    AST node for an ``<?if?>`` block.
864    """
865
866    fields = Block.fields.union({"condition"})
867
868    def __init__(self, location=None, start=None, end=None, condition=None):
869        super().__init__(location, start, end)
870        self.condition = condition
871
872    def __repr__(self):
873        return "<{0.__class__.__module__}.{0.__class__.__qualname__} condition={0.condition!r} {1} at {2:#x}>".format(self, " ..." if self.content else "", id(self))
874
875    def _repr_pretty_(self, p, cycle):
876        if cycle:
877            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
878        else:
879            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
880                p.breakable()
881                p.text("condition=")
882                p.pretty(self.condition)
883                for node in self.content:
884                    p.breakable()
885                    p.pretty(node)
886                p.breakable()
887                p.text("at {:#x}".format(id(self)))
888
889    def _str(self):
890        yield "if "
891        yield from AST._str(self)
892        yield ":"
893        yield None
894        yield +1
895        yield from super()._str()
896        yield -1
897
898    def ul4ondump(self, encoder):
899        super().ul4ondump(encoder)
900        encoder.dump(self.condition)
901
902    def ul4onload(self, decoder):
903        super().ul4onload(decoder)
904        self.condition = decoder.load()
905
906
907@register("elif")
908class ElIf(Block):
909    """
910    AST node for an ``<?elif?>`` block.
911    """
912
913    fields = Block.fields.union({"condition"})
914
915    def __init__(self, location=None, start=None, end=None, condition=None):
916        super().__init__(location, start, end)
917        self.condition = condition
918
919    def __repr__(self):
920        return "<{0.__class__.__module__}.{0.__class__.__qualname__} condition={0.condition!r} {1} at {2:#x}>".format(self, " ..." if self.content else "", id(self))
921
922    def _repr_pretty_(self, p, cycle):
923        if cycle:
924            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
925        else:
926            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
927                p.breakable()
928                p.text("condition=")
929                p.pretty(self.condition)
930                for node in self.content:
931                    p.breakable()
932                    p.pretty(node)
933                p.breakable()
934                p.text("at {:#x}".format(id(self)))
935
936    def _str(self):
937        yield "elif "
938        yield from AST._str(self)
939        yield ":"
940        yield None
941        yield +1
942        yield from super()._str()
943        yield -1
944
945    def ul4ondump(self, encoder):
946        super().ul4ondump(encoder)
947        encoder.dump(self.condition)
948
949    def ul4onload(self, decoder):
950        super().ul4onload(decoder)
951        self.condition = decoder.load()
952
953
954@register("else")
955class Else(Block):
956    """
957    AST node for an ``<?else?>`` block.
958    """
959
960    def __repr__(self):
961        return "<{0.__class__.__module__}.{0.__class__.__qualname__} at {1:#x}>".format(self, id(self))
962
963    def _repr_pretty_(self, p, cycle):
964        if cycle:
965            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
966        else:
967            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
968                for node in self.content:
969                    p.breakable()
970                    p.pretty(node)
971                p.breakable()
972                p.text("at {:#x}".format(id(self)))
973
974    def _str(self):
975        yield "else:"
976        yield None
977        yield +1
978        yield from super()._str()
979        yield -1
980
981
982@register("for")
983class For(Block):
984    """
985    AST node for a ``<?for?>`` loop variable.
986    """
987
988    fields = Block.fields.union({"varname", "container"})
989
990    def __init__(self, location=None, start=None, end=None, varname=None, container=None):
991        super().__init__(location, start, end)
992        self.varname = varname
993        self.container = container
994
995    def __repr__(self):
996        return "<{0.__class__.__module__}.{0.__class__.__qualname__} varname={0.varname!r} container={0.container!r} {1} at {2:#x}>".format(self, " ..." if self.content else "", id(self))
997
998    def _repr_pretty_(self, p, cycle):
999        if cycle:
1000            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1001        else:
1002            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1003                p.breakable()
1004                p.text("varname=")
1005                p.pretty(self.varname)
1006                p.breakable()
1007                p.text("container=")
1008                p.pretty(self.container)
1009                for node in self.content:
1010                    p.breakable()
1011                    p.pretty(node)
1012                p.breakable()
1013                p.text("at {:#x}".format(id(self)))
1014
1015    def ul4ondump(self, encoder):
1016        super().ul4ondump(encoder)
1017        encoder.dump(self.varname)
1018        encoder.dump(self.container)
1019
1020    def ul4onload(self, decoder):
1021        super().ul4onload(decoder)
1022        self.varname = decoder.load()
1023        self.container = decoder.load()
1024
1025    def _str(self):
1026        yield "for "
1027        yield from AST._str(self)
1028        yield ":"
1029        yield None
1030        yield +1
1031        yield from super()._str()
1032        yield -1
1033
1034    @handleeval
1035    def eval(self, vars):
1036        container = (yield from self.container.eval(vars))
1037        vars = collections.ChainMap({}, vars) # Don't let loop variables leak into the surrounding scope
1038        for item in container:
1039            _unpackvar(vars, self.varname, item)
1040            try:
1041                yield from super().eval(vars)
1042            except BreakException:
1043                break
1044            except ContinueException:
1045                pass
1046
1047
1048@register("break")
1049class Break(AST):
1050    """
1051    AST node for a ``<?break?>`` inside a ``<?for?>`` block.
1052    """
1053
1054    def _str(self):
1055        yield "break"
1056
1057    def eval(self, vars):
1058        yield from ()
1059        raise BreakException()
1060
1061
1062@register("continue")
1063class Continue(AST):
1064    """
1065    AST node for a ``<?continue?>`` inside a ``<?for?>`` block.
1066    """
1067
1068    def _str(self):
1069        yield "continue"
1070
1071    def eval(self, vars):
1072        yield from ()
1073        raise ContinueException()
1074
1075
1076@register("getattr")
1077class GetAttr(AST):
1078    """
1079    AST node for getting an attribute from an object.
1080
1081    The object is loaded from the AST node :var:`obj` and the attribute name
1082    is stored in the string :var:`attrname`.
1083    """
1084    fields = AST.fields.union({"obj", "attrname"})
1085
1086    def __init__(self, location=None, start=None, end=None, obj=None, attrname=None):
1087        super().__init__(location, start, end)
1088        self.obj = obj
1089        self.attrname = attrname
1090
1091    def __repr__(self):
1092        return "<{0.__class__.__module__}.{0.__class__.__qualname__} obj={0.obj!r}, attrname={0.attrname!r} at {1:#x}>".format(self, id(self))
1093
1094    def _repr_pretty_(self, p, cycle):
1095        if cycle:
1096            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1097        else:
1098            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1099                p.breakable()
1100                p.text("obj=")
1101                p.pretty(self.obj)
1102                p.breakable()
1103                p.text("attrname=")
1104                p.pretty(self.attrname)
1105                p.breakable()
1106                p.text("at {:#x}".format(id(self)))
1107
1108    @handleeval
1109    def eval(self, vars):
1110        obj = (yield from self.obj.eval(vars))
1111        try:
1112            return obj[self.attrname]
1113        except KeyError:
1114            return UndefinedKey(self.attrname)
1115
1116    def ul4ondump(self, encoder):
1117        super().ul4ondump(encoder)
1118        encoder.dump(self.obj)
1119        encoder.dump(self.attrname)
1120
1121    def ul4onload(self, decoder):
1122        super().ul4onload(decoder)
1123        self.obj = decoder.load()
1124        self.attrname = decoder.load()
1125
1126
1127@register("getslice")
1128class GetSlice(AST):
1129    """
1130    AST node for getting a slice from a list or string object.
1131
1132    The object is loaded from the AST node :var:`obj` and the start and stop
1133    indices from the AST node :var:`index1` and :var:`index2`. :var:`index1`
1134    and :var:`index2` may also be :const:`None` (for missing slice indices,
1135    which default to the 0 for the start index and the length of the sequence
1136    for the end index).
1137    """
1138
1139    fields = AST.fields.union({"obj", "index1", "index2"})
1140
1141    def __init__(self, location=None, start=None, end=None, obj=None, index1=None, index2=None):
1142        super().__init__(location, start, end)
1143        self.obj = obj
1144        self.index1 = index1
1145        self.index2 = index2
1146
1147    def __repr__(self):
1148        return "<{0.__class__.__module__}.{0.__class__.__qualname__} obj={0.obj!r} index1={0.index1!r} index2={0.index2!r} at {1:#x}>".format(self, id(self))
1149
1150    def _repr_pretty_(self, p, cycle):
1151        if cycle:
1152            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1153        else:
1154            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1155                p.breakable()
1156                p.text("obj=")
1157                p.pretty(self.obj)
1158                p.breakable()
1159                p.text("index1=")
1160                p.pretty(self.index1)
1161                p.breakable()
1162                p.text("index2=")
1163                p.pretty(self.index2)
1164                p.breakable()
1165                p.text("at {:#x}".format(id(self)))
1166
1167    @handleeval
1168    def eval(self, vars):
1169        obj = (yield from self.obj.eval(vars))
1170        if self.index1 is not None:
1171            index1 = (yield from self.index1.eval(vars))
1172            if self.index2 is not None:
1173                index2 = (yield from self.index2.eval(vars))
1174                return obj[index1:index2]
1175            else:
1176                return obj[index1:]
1177        else:
1178            if self.index2 is not None:
1179                index2 = (yield from self.index2.eval(vars))
1180                return obj[:index2]
1181            else:
1182                return obj[:]
1183
1184    def ul4ondump(self, encoder):
1185        super().ul4ondump(encoder)
1186        encoder.dump(self.obj)
1187        encoder.dump(self.index1)
1188        encoder.dump(self.index2)
1189
1190    def ul4onload(self, decoder):
1191        super().ul4onload(decoder)
1192        self.obj = decoder.load()
1193        self.index1 = decoder.load()
1194        self.index2 = decoder.load()
1195
1196
1197class Unary(AST):
1198    """
1199    Base class for all AST nodes implementing unary operators.
1200    """
1201
1202    fields = AST.fields.union({"obj"})
1203
1204    def __init__(self, location=None, start=None, end=None, obj=None):
1205        super().__init__(location, start, end)
1206        self.obj = obj
1207
1208    def __repr__(self):
1209        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.obj!r} at {1:#x}>".format(self, id(self))
1210
1211    def _repr_pretty_(self, p, cycle):
1212        if cycle:
1213            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1214        else:
1215            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1216                p.breakable()
1217                p.pretty(self.obj)
1218                p.breakable()
1219                p.text("at {:#x}".format(id(self)))
1220
1221    def ul4ondump(self, encoder):
1222        super().ul4ondump(encoder)
1223        encoder.dump(self.obj)
1224
1225    def ul4onload(self, decoder):
1226        super().ul4onload(decoder)
1227        self.obj = decoder.load()
1228
1229    @handleeval
1230    def eval(self, vars):
1231        obj = (yield from self.obj.eval(vars))
1232        return self.evalfold(obj)
1233
1234    @classmethod
1235    def make(cls, location, start, end, obj):
1236        if isinstance(obj, Const):
1237            result = cls.evalfold(obj.value)
1238            if not isinstance(result, Undefined):
1239                return Const(location, start, end, result)
1240        return cls(location, start, end, obj)
1241
1242
1243@register("not")
1244class Not(Unary):
1245    """
1246    AST node for the unary ``not`` operator.
1247    """
1248
1249
1250    @classmethod
1251    def evalfold(cls, obj):
1252        return not obj
1253
1254
1255@register("neg")
1256class Neg(Unary):
1257    """
1258    AST node for the unary negation (i.e. "-") operator.
1259    """
1260
1261
1262    @classmethod
1263    def evalfold(cls, obj):
1264        return -obj
1265
1266
1267@register("print")
1268class Print(Unary):
1269    """
1270    AST node for a ``<?print?>`` tag.
1271    """
1272
1273    def _str(self):
1274        yield "print "
1275        yield from super()._str()
1276
1277    @handleeval
1278    def eval(self, vars):
1279        yield _str((yield from self.obj.eval(vars)))
1280
1281
1282@register("printx")
1283class PrintX(Unary):
1284    """
1285    AST node for a ``<?printx?>`` tag.
1286    """
1287
1288    def _str(self):
1289        yield "printx "
1290        yield from super()._str()
1291
1292    @handleeval
1293    def eval(self, vars):
1294        yield _xmlescape((yield from self.obj.eval(vars)))
1295
1296
1297@register("return")
1298class Return(Unary):
1299    """
1300    AST node for a ``<?return?>`` tag.
1301    """
1302
1303    def _str(self):
1304        yield "return "
1305        yield from super()._str()
1306
1307    @handleeval
1308    def eval(self, vars):
1309        value = (yield from self.obj.eval(vars))
1310        raise ReturnException(value)
1311
1312
1313class Binary(AST):
1314    """
1315    Base class for all AST nodes implementing binary operators.
1316    """
1317
1318    fields = AST.fields.union({"obj1", "obj2"})
1319
1320    def __init__(self, location=None, start=None, end=None, obj1=None, obj2=None):
1321        super().__init__(location, start, end)
1322        self.obj1 = obj1
1323        self.obj2 = obj2
1324
1325    def __repr__(self):
1326        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.obj1!r} {0.obj2!r} at {1:#x}>".format(self, id(self))
1327
1328    def _repr_pretty_(self, p, cycle):
1329        if cycle:
1330            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1331        else:
1332            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1333                p.breakable()
1334                p.pretty(self.obj1)
1335                p.breakable()
1336                p.pretty(self.obj2)
1337                p.breakable()
1338                p.text("at {:#x}".format(id(self)))
1339
1340    def ul4ondump(self, encoder):
1341        super().ul4ondump(encoder)
1342        encoder.dump(self.obj1)
1343        encoder.dump(self.obj2)
1344
1345    def ul4onload(self, decoder):
1346        super().ul4onload(decoder)
1347        self.obj1 = decoder.load()
1348        self.obj2 = decoder.load()
1349
1350    @handleeval
1351    def eval(self, vars):
1352        obj1 = (yield from self.obj1.eval(vars))
1353        obj2 = (yield from self.obj2.eval(vars))
1354        return self.evalfold(obj1, obj2)
1355
1356    @classmethod
1357    def make(cls, location, start, end, obj1, obj2):
1358        if isinstance(obj1, Const) and isinstance(obj2, Const):
1359            result = cls.evalfold(obj1.value, obj2.value)
1360            if not isinstance(result, Undefined):
1361                return Const(location, start, end, result)
1362        return cls(location, start, end, obj1, obj2)
1363
1364
1365@register("getitem")
1366class GetItem(Binary):
1367    """
1368    AST node for subscripting operator.
1369
1370    The object (which must be a list, string or dict) is loaded from the AST
1371    node :var:`obj1` and the index/key is loaded from the AST node :var:`obj2`.
1372    """
1373
1374
1375    @classmethod
1376    def evaluate(cls, obj1, obj2):
1377        return obj1[obj2]
1378
1379    @classmethod
1380    def evalfold(cls, obj1, obj2):
1381        try:
1382            return obj1[obj2]
1383        except KeyError:
1384            return UndefinedKey(obj2)
1385        except IndexError:
1386            return UndefinedIndex(obj2)
1387
1388
1389@register("eq")
1390class EQ(Binary):
1391    """
1392    AST node for the binary ``==`` comparison operator.
1393    """
1394
1395
1396    @classmethod
1397    def evalfold(cls, obj1, obj2):
1398        return obj1 == obj2
1399
1400
1401@register("ne")
1402class NE(Binary):
1403    """
1404    AST node for the binary ``!=`` comparison operator.
1405    """
1406
1407
1408    @classmethod
1409    def evalfold(cls, obj1, obj2):
1410        return obj1 != obj2
1411
1412
1413@register("lt")
1414class LT(Binary):
1415    """
1416    AST node for the binary ``<`` comparison operator.
1417    """
1418
1419
1420    @classmethod
1421    def evalfold(cls, obj1, obj2):
1422        return obj1 < obj2
1423
1424
1425@register("le")
1426class LE(Binary):
1427    """
1428    AST node for the binary ``<=`` comparison operator.
1429    """
1430
1431
1432    @classmethod
1433    def evalfold(cls, obj1, obj2):
1434        return obj1 <= obj2
1435
1436
1437@register("gt")
1438class GT(Binary):
1439    """
1440    AST node for the binary ``>`` comparison operator.
1441    """
1442
1443
1444    @classmethod
1445    def evalfold(cls, obj1, obj2):
1446        return obj1 > obj2
1447
1448
1449@register("ge")
1450class GE(Binary):
1451    """
1452    AST node for the binary ``>=`` comparison operator.
1453    """
1454
1455
1456    @classmethod
1457    def evalfold(cls, obj1, obj2):
1458        return obj1 >= obj2
1459
1460
1461@register("contains")
1462class Contains(Binary):
1463    """
1464    AST node for the binary containment testing operator.
1465
1466    The item/key object is loaded from the AST node :var:`obj1` and the container
1467    object (which must be a list, string or dict) is loaded from the AST node
1468    :var:`obj2`.
1469    """
1470
1471
1472    @classmethod
1473    def evalfold(cls, obj1, obj2):
1474        return obj1 in obj2
1475
1476
1477@register("notcontains")
1478class NotContains(Binary):
1479    """
1480    AST node for the inverted containment testing operator.
1481
1482    The item/key object is loaded from the AST node :var:`obj1` and the container
1483    object (which must be a list, string or dict) is loaded from the AST node
1484    :var:`obj2`.
1485    """
1486
1487
1488    @classmethod
1489    def evalfold(cls, obj1, obj2):
1490        return obj1 not in obj2
1491
1492
1493@register("add")
1494class Add(Binary):
1495    """
1496    AST node for the binary addition operator.
1497    """
1498
1499
1500    @classmethod
1501    def evalfold(cls, obj1, obj2):
1502        return obj1 + obj2
1503
1504
1505@register("sub")
1506class Sub(Binary):
1507    """
1508    AST node for the binary substraction operator.
1509    """
1510
1511
1512    @classmethod
1513    def evalfold(cls, obj1, obj2):
1514        return obj1 - obj2
1515
1516
1517@register("mul")
1518class Mul(Binary):
1519    """
1520    AST node for the binary multiplication operator.
1521    """
1522
1523
1524    @classmethod
1525    def evalfold(cls, obj1, obj2):
1526        return obj1 * obj2
1527
1528
1529@register("floordiv")
1530class FloorDiv(Binary):
1531    """
1532    AST node for the binary truncating division operator.
1533    """
1534
1535
1536    @classmethod
1537    def evalfold(cls, obj1, obj2):
1538        return obj1 // obj2
1539
1540
1541@register("truediv")
1542class TrueDiv(Binary):
1543    """
1544    AST node for the binary true division operator.
1545    """
1546
1547
1548    @classmethod
1549    def evalfold(cls, obj1, obj2):
1550        return obj1 / obj2
1551
1552
1553@register("and")
1554class And(Binary):
1555    """
1556    AST node for the binary ``and`` operator.
1557    """
1558
1559
1560    @classmethod
1561    def evalfold(cls, obj1, obj2):
1562        # This is not called from ``eval``, as it doesn't short-circuit
1563        return obj1 and obj2
1564
1565    @handleeval
1566    def eval(self, vars):
1567        obj1 = (yield from self.obj1.eval(vars))
1568        if not obj1:
1569            return obj1
1570        return (yield from self.obj2.eval(vars))
1571
1572
1573@register("or")
1574class Or(Binary):
1575    """
1576    AST node for the binary ``or`` operator.
1577    """
1578
1579
1580    @classmethod
1581    def evalfold(cls, obj1, obj2):
1582        # This is not called from ``eval``, as it doesn't short-circuit
1583        return obj1 or obj2
1584
1585    @handleeval
1586    def eval(self, vars):
1587        obj1 = (yield from self.obj1.eval(vars))
1588        if obj1:
1589            return obj1
1590        return (yield from self.obj2.eval(vars))
1591
1592
1593@register("mod")
1594class Mod(Binary):
1595    """
1596    AST node for the binary modulo operator.
1597    """
1598
1599
1600    @classmethod
1601    def evalfold(cls, obj1, obj2):
1602        return obj1 % obj2
1603
1604
1605class ChangeVar(AST):
1606    """
1607    Baseclass for all AST nodes that store or modify a variable.
1608
1609    The variable name is stored in the string :var:`varname` and the value that
1610    will be stored or be used to modify the stored value is loaded from the
1611    AST node :var:`value`.
1612    """
1613
1614    fields = AST.fields.union({"varname", "value"})
1615
1616    def __init__(self, location=None, start=None, end=None, varname=None, value=None):
1617        super().__init__(location, start, end)
1618        self.varname = varname
1619        self.value = value
1620
1621    def __repr__(self):
1622        return "<{0.__class__.__module__}.{0.__class__.__qualname__} varname={0.varname!r} value={0.value!r} at {1:#x}>".format(self, id(self))
1623
1624    def _repr_pretty_(self, p, cycle):
1625        if cycle:
1626            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1627        else:
1628            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1629                p.breakable()
1630                p.text("varname=")
1631                p.pretty(self.obj1)
1632                p.text("value=")
1633                p.breakable()
1634                p.pretty(self.obj2)
1635                p.breakable()
1636                p.text("at {:#x}".format(id(self)))
1637
1638    def ul4ondump(self, encoder):
1639        super().ul4ondump(encoder)
1640        encoder.dump(self.varname)
1641        encoder.dump(self.value)
1642
1643    def ul4onload(self, decoder):
1644        super().ul4onload(decoder)
1645        self.varname = decoder.load()
1646        self.value = decoder.load()
1647
1648
1649@register("storevar")
1650class StoreVar(ChangeVar):
1651    """
1652    AST node that stores a value into a variable.
1653    """
1654
1655    @handleeval
1656    def eval(self, vars):
1657        value = (yield from self.value.eval(vars))
1658        _unpackvar(vars, self.varname, value)
1659
1660
1661@register("addvar")
1662class AddVar(ChangeVar):
1663    """
1664    AST node that adds a value to a variable (i.e. the ``+=`` operator).
1665    """
1666
1667    @handleeval
1668    def eval(self, vars):
1669        value = (yield from self.value.eval(vars))
1670        vars[self.varname] += value
1671
1672
1673@register("subvar")
1674class SubVar(ChangeVar):
1675    """
1676    AST node that substracts a value from a variable (i.e. the ``-=`` operator).
1677    """
1678
1679    @handleeval
1680    def eval(self, vars):
1681        value = (yield from self.value.eval(vars))
1682        vars[self.varname] -= value
1683
1684
1685@register("mulvar")
1686class MulVar(ChangeVar):
1687    """
1688    AST node that multiplies a variable by a value (i.e. the ``*=`` operator).
1689    """
1690
1691    @handleeval
1692    def eval(self, vars):
1693        value = (yield from self.value.eval(vars))
1694        vars[self.varname] *= value
1695
1696
1697@register("floordivvar")
1698class FloorDivVar(ChangeVar):
1699    """
1700    AST node that divides a variable by a value (truncating to an integer value;
1701    i.e. the ``//=`` operator).
1702    """
1703
1704    @handleeval
1705    def eval(self, vars):
1706        value = (yield from self.value.eval(vars))
1707        vars[self.varname] //= value
1708
1709
1710@register("truedivvar")
1711class TrueDivVar(ChangeVar):
1712    """
1713    AST node that divides a variable by a value (i.e. the ``/=`` operator).
1714    """
1715
1716    @handleeval
1717    def eval(self, vars):
1718        value = (yield from self.value.eval(vars))
1719        vars[self.varname] /= value
1720
1721
1722@register("modvar")
1723class ModVar(ChangeVar):
1724    """
1725    AST node for the ``%=`` operator.
1726    """
1727
1728    @handleeval
1729    def eval(self, vars):
1730        value = (yield from self.value.eval(vars))
1731        vars[self.varname] %= value
1732
1733
1734@register("callfunc")
1735class CallFunc(AST):
1736    """
1737    AST node for calling an function.
1738
1739    The object to be called is stored in the attribute :var:`obj`. The list of
1740    positional arguments is loaded from the list of AST nodes :var:`args`.
1741    Keyword arguments are in :var:`kwargs`. `var`:remargs` is the AST node
1742    for the ``*`` argument (and may by ``None`` if there is no ``*`` argument).
1743    `var`:remkwargs` is the AST node for the ``**`` argument (and may by ``None``
1744    if there is no ``**`` argument)
1745    """
1746
1747    fields = AST.fields.union({"obj", "args", "kwargs", "remargs", "remkwargs"})
1748
1749    def __init__(self, location=None, start=None, end=None, obj=None):
1750        super().__init__(location, start, end)
1751        self.obj = obj
1752        self.args = []
1753        self.kwargs = []
1754        self.remargs = None
1755        self.remkwargs = None
1756
1757    def __repr__(self):
1758        return "<{0.__class__.__module__}.{0.__class__.__qualname__} obj={0.obj!r}{1}{2}{3}{4} at {5:#x}>".format(
1759            self,
1760            "".join(" {!r}".format(arg) for arg in self.args),
1761            "".join(" {}={!r}".format(argname, argvalue) for (argname, argvalue) in self.kwargs),
1762            " *{!r}".format(self.remargs) if self.remargs is not None else "",
1763            " **{!r}".format(self.remkwargs) if self.remargs is not None else "",
1764            id(self))
1765
1766    def _repr_pretty_(self, p, cycle):
1767        if cycle:
1768            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1769        else:
1770            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1771                p.breakable()
1772                p.text("obj=")
1773                p.pretty(self.obj)
1774                for arg in self.args:
1775                    p.breakable()
1776                    p.pretty(arg)
1777                for (argname, arg) in self.kwargs:
1778                    p.breakable()
1779                    p.text("{}=".format(argname))
1780                    p.pretty(arg)
1781                if self.remargs is not None:
1782                    p.breakable()
1783                    p.text("*")
1784                    p.pretty(self.remargs)
1785                if self.remkwargs is not None:
1786                    p.breakable()
1787                    p.text("**")
1788                    p.pretty(self.remkwargs)
1789                p.breakable()
1790                p.text("at {:#x}".format(id(self)))
1791
1792    @handleeval
1793    def eval(self, vars):
1794        obj = (yield from self.obj.eval(vars))
1795        args = []
1796        for arg in self.args:
1797            arg = (yield from arg.eval(vars))
1798            args.append(arg)
1799        kwargs = {}
1800        for (argname, arg) in self.kwargs:
1801            kwargs[argname] = (yield from arg.eval(vars))
1802        if self.remargs is not None:
1803            args.extend((yield from self.remargs.eval(vars)))
1804        if self.remkwargs is not None:
1805            kwargs.update((yield from self.remkwargs.eval(vars)))
1806        result = obj(*args, **kwargs)
1807        if isinstance(result, types.GeneratorType):
1808            return (yield from result)
1809        else:
1810            return result
1811
1812    def ul4ondump(self, encoder):
1813        super().ul4ondump(encoder)
1814        encoder.dump(self.obj)
1815        encoder.dump(self.args)
1816        encoder.dump(self.kwargs)
1817        encoder.dump(self.remargs)
1818        encoder.dump(self.remkwargs)
1819
1820    def ul4onload(self, decoder):
1821        super().ul4onload(decoder)
1822        self.obj = decoder.load()
1823        self.args = decoder.load()
1824        self.kwargs = [tuple(arg) for arg in decoder.load()]
1825        self.remargs = decoder.load()
1826        self.remkwargs = decoder.load()
1827
1828
1829@register("callmeth")
1830class CallMeth(AST):
1831    """
1832    AST node for calling a method.
1833
1834    The method name is stored in the string :var:`methname`. The object for which
1835    the method will be called is loaded from the AST node :var:`obj` and the list
1836    of arguments is loaded from the list of AST nodes :var:`args`. Keyword
1837    arguments are in :var:`kwargs`. `var`:remargs` is the AST node for the ``*``
1838    argument (and may by ``None`` if there is no ``*`` argument).
1839    `var`:remkwargs` is the AST node for the ``**`` argument (and may by ``None``
1840    if there is no ``**`` argument)
1841    """
1842
1843    fields = AST.fields.union({"obj", "methname", "args", "kwargs", "remargs", "remkwargs"})
1844
1845    def __init__(self, location=None, start=None, end=None, obj=None, methname=None):
1846        super().__init__(location, start, end)
1847        self.obj = obj
1848        self.methname = methname
1849        self.args = []
1850        self.kwargs = []
1851        self.remargs = None
1852        self.remkwargs = None
1853
1854    def __repr__(self):
1855        return "<{0.__class__.__module__}.{0.__class__.__qualname__} methname={0.methname!r} obj={0.obj!r}{1}{2}{3}{4} at {5:#x}>".format(
1856            self,
1857            "".join(" {!r}".format(arg) for arg in self.args),
1858            "".join(" {}={!r}".format(argname, argvalue) for (argname, argvalue) in self.kwargs),
1859            " *{!r}".format(self.remargs) if self.remargs is not None else "",
1860            " **{!r}".format(self.remkwargs) if self.remargs is not None else "",
1861            id(self))
1862
1863    def _repr_pretty_(self, p, cycle):
1864        if cycle:
1865            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1866        else:
1867            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1868                p.breakable()
1869                p.text("methname=")
1870                p.pretty(self.methname)
1871                p.breakable()
1872                p.text("obj=")
1873                p.pretty(self.obj)
1874                for arg in self.args:
1875                    p.breakable()
1876                    p.pretty(arg)
1877                for (argname, arg) in self.kwargs:
1878                    p.breakable()
1879                    p.text("{}=".format(argname))
1880                    p.pretty(arg)
1881                if self.remargs is not None:
1882                    p.breakable()
1883                    p.text("*")
1884                    p.pretty(self.remargs)
1885                if self.remkwargs is not None:
1886                    p.breakable()
1887                    p.text("**")
1888                    p.pretty(self.remkwargs)
1889                p.breakable()
1890                p.text("at {:#x}".format(id(self)))
1891
1892    @handleeval
1893    def eval(self, vars):
1894        obj = (yield from self.obj.eval(vars))
1895        args = []
1896        for arg in self.args:
1897            arg = (yield from arg.eval(vars))
1898            args.append(arg)
1899        kwargs = {}
1900        for (argname, arg) in self.kwargs:
1901            kwargs[argname] = (yield from arg.eval(vars))
1902        if self.remargs is not None:
1903            args.extend((yield from self.remargs.eval(vars)))
1904        if self.remkwargs is not None:
1905            kwargs.update((yield from self.remkwargs.eval(vars)))
1906        result = self.methods[self.methname](obj, *args, **kwargs)
1907        if isinstance(result, types.GeneratorType):
1908            return (yield from result)
1909        else:
1910            return result
1911
1912    def ul4ondump(self, encoder):
1913        super().ul4ondump(encoder)
1914        encoder.dump(self.methname)
1915        encoder.dump(self.obj)
1916        encoder.dump(self.args)
1917        encoder.dump(self.kwargs)
1918        encoder.dump(self.remargs)
1919        encoder.dump(self.remkwargs)
1920
1921    def ul4onload(self, decoder):
1922        super().ul4onload(decoder)
1923        self.methname = decoder.load()
1924        self.obj = decoder.load()
1925        self.args = decoder.load()
1926        self.kwargs = [tuple(arg) for arg in decoder.load()]
1927        self.remargs = decoder.load()
1928        self.remkwargs = decoder.load()
1929
1930
1931@register("template")
1932class Template(Block):
1933    """
1934    A template object is normally created by passing the template source to the
1935    constructor. It can also be loaded from the compiled format via the class
1936    methods :meth:`load` (from a stream) or :meth:`loads` (from a string).
1937
1938    The compiled format can be generated with the methods :meth:`dump` (which
1939    dumps the format to a stream) or :meth:`dumps` (which returns a string with
1940    the compiled format).
1941
1942    Rendering the template can be done with the methods :meth:`render` (which
1943    is a generator) or :meth:`renders` (which returns a string).
1944
1945    A :class:`Template` object is itself an AST node. Evaluating it will store
1946    the template object under its name in the local variables.
1947
1948    A :class:`Template` can also be called as a function (returning the result
1949    of the first ``<?return?>`` tag encountered. In this case all output of the
1950    template will be ignored.
1951    """
1952    fields = Block.fields.union({"source", "name", "keepws", "startdelim", "enddelim"})
1953
1954    version = "24"
1955
1956    def __init__(self, source=None, name=None, keepws=True, startdelim="<?", enddelim="?>"):
1957        """
1958        Create a :class:`Template` object. If :var:`source` is ``None``, the
1959        :class:`Template` remains uninitialized, otherwise :var:`source` will be
1960        compiled (using :var:`startdelim` and :var:`enddelim` as the tag
1961        delimiters). :var:`name` is the name of the template. It will be used in
1962        exception messages and should be a valid Python identifier. If
1963        :var:`keepws` is false linefeeds and indentation will be ignored in the
1964        literal text in templates (i.e. the text between the tags). However
1965        trailing whitespace at the end of the line will be honored regardless of
1966        the value of :var:`keepws`. Output will always be ignored when calling
1967        a template as a function.
1968        """
1969        # ``location``/``endlocation`` will remain ``None`` for a top level template
1970        # For a subtemplate/subfunction ``location`` will be set to the location of the ``<?def?>`` tag in :meth:`_compile`
1971        # and ``endlocation`` will be the location of the ``<?end def?>`` tag
1972        super().__init__(None, 0, 0)
1973        self.keepws = keepws
1974        self.startdelim = startdelim
1975        self.enddelim = enddelim
1976        self.name = name
1977        self.source = None
1978
1979        # If we have source code compile it
1980        if source is not None:
1981            self._compile(source, name, startdelim, enddelim)
1982
1983    def __repr__(self):
1984        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} name={0.name!r} keepws={0.keepws!r}".format(self)
1985        if self.startdelim != "<?":
1986            s += " startdelim={0.startdelim!r}".format(self)
1987        if self.enddelim != "?>":
1988            s += " enddelim={0.enddelim!r}".format(self)
1989        if self.content:
1990            s + " ..."
1991        return s + " at {:#x}>".format(id(self))
1992
1993    def _str(self):
1994        yield "def "
1995        yield self.name if self.name is not None else "unnamed"
1996        yield ":"
1997        yield None
1998        yield +1
1999        yield from super()._str()
2000        yield -1
2001
2002    def _repr_pretty_(self, p, cycle):
2003        if cycle:
2004            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
2005        else:
2006            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
2007                p.breakable()
2008                p.text("name=")
2009                p.pretty(self.name)
2010                p.breakable()
2011                p.text("keepws=")
2012                p.pretty(self.keepws)
2013                if self.startdelim != "<?":
2014                    p.breakable()
2015                    p.text("startdelim=")
2016                    p.pretty(self.startdelim)
2017                if self.enddelim != "?>":
2018                    p.breakable()
2019                    p.text("enddelim=")
2020                    p.pretty(self.enddelim)
2021                for node in self.content:
2022                    p.breakable()
2023                    p.pretty(node)
2024                p.breakable()
2025                p.text("at {:#x}".format(id(self)))
2026
2027    def ul4ondump(self, encoder):
2028        # Don't call ``super().ul4ondump()``, as we want the version to be first
2029        encoder.dump(self.version)
2030        encoder.dump(self.source)
2031        encoder.dump(self.name)
2032        encoder.dump(self.keepws)
2033        encoder.dump(self.startdelim)
2034        encoder.dump(self.enddelim)
2035        encoder.dump(self.location)
2036        encoder.dump(self.endlocation)
2037        encoder.dump(self.content)
2038
2039    def ul4onload(self, decoder):
2040        version = decoder.load()
2041        if version != self.version:
2042            raise ValueError("invalid version, expected {!r}, got {!r}".format(self.version, version))
2043        self.source = decoder.load()
2044        self.name = decoder.load()
2045        self.keepws = decoder.load()
2046        self.startdelim = decoder.load()
2047        self.enddelim = decoder.load()
2048        self.location = decoder.load()
2049        self.endlocation = decoder.load()
2050        self.content = decoder.load()
2051
2052    @classmethod
2053    def loads(cls, data):
2054        """
2055        The class method :meth:`loads` loads the template/function from string
2056        :var:`data`. :var:`data` must contain the template/function in compiled
2057        UL4ON format.
2058        """
2059        from ll import ul4on
2060        return ul4on.loads(data)
2061
2062    @classmethod
2063    def load(cls, stream):
2064        """
2065        The class method :meth:`load` loads the template/function from the stream
2066        :var:`stream`. The stream must contain the template/function in compiled
2067        UL4ON format.
2068        """
2069        from ll import ul4on
2070        return ul4on.load(stream)
2071
2072    def dump(self, stream):
2073        """
2074        :meth:`dump` dumps the template/function in compiled UL4ON format to the
2075        stream :var:`stream`.
2076        """
2077        from ll import ul4on
2078        ul4on.dump(self, stream)
2079
2080    def dumps(self):
2081        """
2082        :meth:`dumps` returns the template/function in compiled UL4ON format
2083        (as a string).
2084        """
2085        from ll import ul4on
2086        return ul4on.dumps(self)
2087
2088    def render(self, **vars):
2089        """
2090        Render the template iteratively (i.e. this is a generator).
2091        :var:`vars` contains the top level variables available to the
2092        template code.
2093        """
2094        yield from super().eval(vars) # Bypass ``self.eval()`` which simply stores the object as a local variable
2095
2096    def renders(self, **vars):
2097        """
2098        Render the template as a string. :var:`vars` contains the top level
2099        variables available to the template code.
2100        """
2101        return "".join(self.render(**vars))
2102
2103    def __call__(self, **vars):
2104        """
2105        Call the template as a function and return the resulting value.
2106        :var:`vars` contains the top level variables available to the template code.
2107        """
2108        try:
2109            for output in super().eval(vars): # Bypass ``self.eval()`` which simply stores the object as a local variable
2110                pass # Ignore all output
2111        except ReturnException as ex:
2112            return ex.value
2113
2114    def jssource(self):
2115        """
2116        Return the template as the source code of a Javascript function.
2117        """
2118        return "ul4.Template.loads({})".format(_asjson(self.dumps()))
2119
2120    def javasource(self):
2121        """
2122        Return the template as Java source code.
2123        """
2124        return "com.livinglogic.ul4.InterpretedTemplate.loads({})".format(misc.javaexpr(self.dumps()))
2125
2126    def _tokenize(self, source, startdelim, enddelim):
2127        """
2128        Tokenize the template/function source code :var:`source` into tags and
2129        non-tag text. :var:`startdelim` and :var:`enddelim` are used as the tag
2130        delimiters.
2131
2132        This is a generator which produces :class:`Location` objects for each tag
2133        or non-tag text. It will be called by :meth:`_compile` internally.
2134        """
2135        pattern = "{}(printx|print|code|for|if|elif|else|end|break|continue|def|return|note)(\s*((.|\\n)*?)\s*)?{}".format(re.escape(startdelim), re.escape(enddelim))
2136        pos = 0
2137        for match in re.finditer(pattern, source):
2138            if match.start() != pos:
2139                yield Location(self, source, None, pos, match.start(), pos, match.start())
2140            type = source[match.start(1):match.end(1)]
2141            if type != "note":
2142                yield Location(self, source, type, match.start(), match.end(), match.start(3), match.end(3))
2143            pos = match.end()
2144        end = len(source)
2145        if pos != end:
2146            yield Location(self, source, None, pos, end, pos, end)
2147
2148    def _parser(self, location, error):
2149        from ll import UL4Lexer, UL4Parser
2150        source = location.code
2151        if not source:
2152            raise ValueError(error)
2153        stream = antlr3.ANTLRStringStream(source)
2154        lexer = UL4Lexer.UL4Lexer(stream)
2155        lexer.location = location
2156        tokens = antlr3.CommonTokenStream(lexer)
2157        parser = UL4Parser.UL4Parser(tokens)
2158        parser.location = location
2159        return parser
2160
2161    def _compile(self, source, name, startdelim, enddelim):
2162        """
2163        Compile the template source code :var:`source` into an AST.
2164        :var:`startdelim` and :var:`enddelim` are used as the tag delimiters.
2165        """
2166        self.name = name
2167        self.startdelim = startdelim
2168        self.enddelim = enddelim
2169
2170        # This stack stores the nested for/if/elif/else/def blocks
2171        stack = [self]
2172
2173        self.source = source
2174
2175        if source is None:
2176            return
2177
2178        def parseexpr(location):
2179            return self._parser(location, "expression required").expression()
2180
2181        def parsestmt(location):
2182            return self._parser(location, "statement required").statement()
2183
2184        def parsefor(location):
2185            return self._parser(location, "loop expression required").for_()
2186
2187        for location in self._tokenize(source, startdelim, enddelim):
2188            try:
2189                if location.type is None:
2190                    stack[-1].append(Text(location, location.startcode, location.endcode))
2191                elif location.type == "print":
2192                    stack[-1].append(Print(location, location.startcode, location.endcode, parseexpr(location)))
2193                elif location.type == "printx":
2194                    stack[-1].append(PrintX(location, location.startcode, location.endcode, parseexpr(location)))
2195                elif location.type == "code":
2196                    stack[-1].append(parsestmt(location))
2197                elif location.type == "if":
2198                    block = IfElIfElse(location, location.startcode, location.endcode, parseexpr(location))
2199                    stack[-1].append(block)
2200                    stack.append(block)
2201                elif location.type == "elif":
2202                    if not isinstance(stack[-1], IfElIfElse):
2203                        raise BlockError("elif doesn't match and if")
2204                    elif isinstance(stack[-1].content[-1], Else):
2205                        raise BlockError("else already seen in if")
2206                    stack[-1].newblock(ElIf(location, location.startcode, location.endcode, parseexpr(location)))
2207                elif location.type == "else":
2208                    if not isinstance(stack[-1], IfElIfElse):
2209                        raise BlockError("else doesn't match any if")
2210                    elif isinstance(stack[-1].content[-1], Else):
2211                        raise BlockError("else already seen in if")
2212                    stack[-1].newblock(Else(location, location.startcode, location.endcode))
2213                elif location.type == "end":
2214                    if len(stack) <= 1:
2215                        raise BlockError("not in any block")
2216                    code = location.code
2217                    if code:
2218                        if code == "if":
2219                            if not isinstance(stack[-1], IfElIfElse):
2220                                raise BlockError("endif doesn't match any if")
2221                        elif code == "for":
2222                            if not isinstance(stack[-1], For):
2223                                raise BlockError("endfor doesn't match any for")
2224                        elif code == "def":
2225                            if not isinstance(stack[-1], Template):
2226                                raise BlockError("enddef doesn't match any def")
2227                        else:
2228                            raise BlockError("illegal end value {!r}".format(code))
2229                    last = stack.pop()
2230                    # Set ``endlocation`` of block
2231                    last.endlocation = location
2232                    if isinstance(last, IfElIfElse):
2233                        last.content[-1].endlocation = location
2234                elif location.type == "for":
2235                    block = parsefor(location)
2236                    stack[-1].append(block)
2237                    stack.append(block)
2238                elif location.type == "break":
2239                    for block in reversed(stack):
2240                        if isinstance(block, For):
2241                            break
2242                        elif isinstance(block, Template):
2243                            raise BlockError("break outside of for loop")
2244                    stack[-1].append(Break(location, location.startcode, location.endcode))
2245                elif location.type == "continue":
2246                    for block in reversed(stack):
2247                        if isinstance(block, For):
2248                            break
2249                        elif isinstance(block, Template):
2250                            raise BlockError("continue outside of for loop")
2251                    stack[-1].append(Continue(location, location.startcode, location.endcode))
2252                elif location.type == "def":
2253                    block = Template(None, location.code, self.keepws, self.startdelim, self.enddelim)
2254                    block.location = location # Set start ``location`` of sub template
2255                    block.source = self.source # The source of the top level template (so that the offsets in :class:`Location` are correct)
2256                    block.start = location.startcode
2257                    block.end = location.endcode
2258                    stack[-1].append(block)
2259                    stack.append(block)
2260                elif location.type == "return":
2261                    stack[-1].append(Return(location, location.startcode, location.endcode, parseexpr(location)))
2262                else: # Can't happen
2263                    raise ValueError("unknown tag {!r}".format(location.type))
2264            except Exception as exc:
2265                raise Error(self) from exc
2266        if len(stack) > 1:
2267            raise Error(stack[-1]) from BlockError("block unclosed")
2268
2269    @handleeval
2270    def eval(self, vars):
2271        yield from ()
2272        vars[self.name] = TemplateClosure(self, vars)
2273
2274
2275###
2276### Functions & methods
2277###
2278
2279@AST.makefunction
2280def _print(*values):
2281    for (i, value) in enumerate(values):
2282        if i:
2283            yield " "
2284        yield _str(value)
2285
2286
2287@AST.makefunction
2288def _printx(*values):
2289    for (i, value) in enumerate(values):
2290        if i:
2291            yield " "
2292        yield _xmlescape(value)
2293
2294
2295@AST.makefunction
2296def _str(obj=""):
2297    if obj is None:
2298        return ""
2299    elif isinstance(obj, Undefined):
2300        return ""
2301    else:
2302        return str(obj)
2303
2304
2305@AST.makefunction
2306def _repr(obj):
2307    if isinstance(obj, str):
2308        return repr(obj)
2309    elif isinstance(obj, datetime.datetime):
2310        s = str(obj.isoformat())
2311        if s.endswith("T00:00:00"):
2312            s = s[:-9]
2313        return "@({})".format(s)
2314    elif isinstance(obj, datetime.date):
2315        return "@({})".format(obj.isoformat())
2316    elif isinstance(obj, datetime.timedelta):
2317        return repr(obj).partition(".")[-1]
2318    elif isinstance(obj, color.Color):
2319        if obj[3] == 0xff:
2320            s = "#{:02x}{:02x}{:02x}".format(obj[0], obj[1], obj[2])
2321            if s[1]==s[2] and s[3]==s[4] and s[5]==s[6]:
2322                return "#{}{}{}".format(s[1], s[3], s[5])
2323            return s
2324        else:
2325            s = "#{:02x}{:02x}{:02x}{:02x}".format(*obj)
2326            if s[1]==s[2] and s[3]==s[4] and s[5]==s[6] and s[7]==s[8]:
2327                return "#{}{}{}{}".format(s[1], s[3], s[5], s[7])
2328            return s
2329    elif isinstance(obj, collections.Sequence):
2330        return "[{}]".format(", ".join(_repr(item) for item in obj))
2331    elif isinstance(obj, collections.Mapping):
2332        return "{{{}}}".format(", ".join("{}: {}".format(_repr(key), _repr(value)) for (key, value) in obj.items()))
2333    else:
2334        return repr(obj)
2335
2336
2337@AST.makefunction
2338def _now():
2339    return datetime.datetime.now()
2340
2341
2342@AST.makefunction
2343def _utcnow():
2344    return datetime.datetime.utcnow()
2345
2346
2347@AST.makefunction
2348def _date(year, month, day, hour=0, minute=0, second=0, microsecond=0):
2349    return datetime.datetime(year, month, day, hour, minute, second, microsecond)
2350
2351
2352@AST.makefunction
2353def _timedelta(days=0, seconds=0, microseconds=0):
2354    return datetime.timedelta(days, seconds, microseconds)
2355
2356
2357@AST.makefunction
2358def _monthdelta(months=0):
2359    return misc.monthdelta(months)
2360
2361
2362@AST.makefunction
2363def _random():
2364    return random.random()
2365
2366
2367@AST.makefunction
2368def _xmlescape(obj):
2369    if obj is None:
2370        return ""
2371    elif isinstance(obj, Undefined):
2372        return ""
2373    else:
2374        return misc.xmlescape(str(obj))
2375
2376
2377@AST.makefunction
2378def _csv(obj):
2379    if obj is None:
2380        return ""
2381    elif isinstance(obj, Undefined):
2382        return ""
2383    elif not isinstance(obj, str):
2384        obj = _repr(obj)
2385    if any(c in obj for c in ',"\n'):
2386        return '"{}"'.format(obj.replace('"', '""'))
2387    return obj
2388
2389
2390@AST.makefunction
2391def _asjson(obj):
2392    if obj is None:
2393        return "null"
2394    elif isinstance(obj, Undefined):
2395        return "{}.undefined"
2396    if isinstance(obj, (bool, int, float, str)):
2397        return json.dumps(obj)
2398    elif isinstance(obj, datetime.datetime):
2399        return "new Date({}, {}, {}, {}, {}, {}, {})".format(obj.year, obj.month-1, obj.day, obj.hour, obj.minute, obj.second, obj.microsecond//1000)
2400    elif isinstance(obj, datetime.date):
2401        return "new Date({}, {}, {})".format(obj.year, obj.month-1, obj.day)
2402    elif isinstance(obj, datetime.timedelta):
2403        return "ul4.TimeDelta.create({}, {}, {})".format(obj.days, obj.seconds, obj.microseconds)
2404    elif isinstance(obj, misc.monthdelta):
2405        return "ul4.MonthDelta.create({})".format(obj.months)
2406    elif isinstance(obj, color.Color):
2407        return "ul4.Color.create({}, {}, {}, {})".format(*obj)
2408    elif isinstance(obj, collections.Mapping):
2409        return "{{{}}}".format(", ".join("{}: {}".format(_asjson(key), _asjson(value)) for (key, value) in obj.items()))
2410    elif isinstance(obj, collections.Sequence):
2411        return "[{}]".format(", ".join(_asjson(item) for item in obj))
2412    elif isinstance(obj, Template):
2413        return obj.jssource()
2414    else:
2415        raise TypeError("can't handle object of type {}".format(type(obj)))
2416
2417
2418@AST.makefunction
2419def _fromjson(string):
2420    from ll import ul4on
2421    return json.loads(string)
2422
2423
2424@AST.makefunction
2425def _asul4on(obj):
2426    from ll import ul4on
2427    return ul4on.dumps(obj)
2428
2429
2430@AST.makefunction
2431def _fromul4on(string):
2432    from ll import ul4on
2433    return ul4on.loads(string)
2434
2435
2436@AST.makefunction
2437def _int(obj=0, base=None):
2438    if base is None:
2439        return int(obj)
2440    else:
2441        return int(obj, base)
2442
2443
2444@AST.makefunction
2445def _float(obj=0.0):
2446    return float(obj)
2447
2448
2449@AST.makefunction
2450def _bool(obj=False):
2451    return bool(obj)
2452
2453
2454@AST.makefunction
2455def _len(sequence):
2456    return len(sequence)
2457
2458
2459@AST.makefunction
2460def _abs(number):
2461    return abs(number)
2462
2463
2464@AST.makefunction
2465def _any(iterable):
2466    return any(iterable)
2467
2468
2469@AST.makefunction
2470def _all(iterable):
2471    return all(iterable)
2472
2473
2474@AST.makefunction
2475def _enumerate(iterable, start=0):
2476    yield from ()
2477    return enumerate(iterable, start)
2478
2479
2480@AST.makefunction
2481def _enumfl(iterable, start=0):
2482    yield from ()
2483    def result(iterable):
2484        lastitem = None
2485        first = True
2486        i = start
2487        it = iter(iterable)
2488        try:
2489            item = next(it)
2490        except StopIteration:
2491            return
2492        while True:
2493            try:
2494                (lastitem, item) = (item, next(it))
2495            except StopIteration:
2496                yield (i, first, True, item) # Items haven't been swapped yet
2497                return
2498            else:
2499                yield (i, first, False, lastitem)
2500                first = False
2501            i += 1
2502    return result(iterable)
2503
2504
2505@AST.makefunction
2506def _isfirstlast(iterable):
2507    yield from ()
2508    def result(iterable):
2509        lastitem = None
2510        first = True
2511        it = iter(iterable)
2512        try:
2513            item = next(it)
2514        except StopIteration:
2515            return
2516        while True:
2517            try:
2518                (lastitem, item) = (item, next(it))
2519            except StopIteration:
2520                yield (first, True, item) # Items haven't been swapped yet
2521                return
2522            else:
2523                yield (first, False, lastitem)
2524                first = False
2525    return result(iterable)
2526
2527
2528@AST.makefunction
2529def _isfirst(iterable):
2530    yield from ()
2531    def result(iterable):
2532        first = True
2533        for item in iterable:
2534            yield (first, item)
2535            first = False
2536    return result(iterable)
2537
2538
2539@AST.makefunction
2540def _islast(iterable):
2541    yield from ()
2542    def result(iterable):
2543        lastitem = None
2544        it = iter(iterable)
2545        try:
2546            item = next(it)
2547        except StopIteration:
2548            return
2549        while True:
2550            try:
2551                (lastitem, item) = (item, next(it))
2552            except StopIteration:
2553                yield (True, item) # Items haven't been swapped yet
2554                return
2555            else:
2556                yield (False, lastitem)
2557    return result(iterable)
2558
2559
2560@AST.makefunction
2561def _isundefined(obj):
2562    return isinstance(obj, Undefined)
2563
2564
2565@AST.makefunction
2566def _isdefined(obj):
2567    return not isinstance(obj, Undefined)
2568
2569
2570@AST.makefunction
2571def _isnone(obj):
2572    return obj is None
2573
2574
2575@AST.makefunction
2576def _isstr(obj):
2577    return isinstance(obj, str)
2578
2579
2580@AST.makefunction
2581def _isint(obj):
2582    return isinstance(obj, int) and not isinstance(obj, bool)
2583
2584
2585@AST.makefunction
2586def _isfloat(obj):
2587    return isinstance(obj, float)
2588
2589
2590@AST.makefunction
2591def _isbool(obj):
2592    return isinstance(obj, bool)
2593
2594
2595@AST.makefunction
2596def _isdate(obj):
2597    return isinstance(obj, (datetime.datetime, datetime.date))
2598
2599
2600@AST.makefunction
2601def _istimedelta(obj):
2602    return isinstance(obj, datetime.timedelta)
2603
2604
2605@AST.makefunction
2606def _ismonthdelta(obj):
2607    return isinstance(obj, misc.monthdelta)
2608
2609
2610@AST.makefunction
2611def _islist(obj):
2612    return isinstance(obj, collections.Sequence) and not isinstance(obj, str) and not isinstance(obj, color.Color)
2613
2614
2615@AST.makefunction
2616def _isdict(obj):
2617    return isinstance(obj, collections.Mapping) and not isinstance(obj, Template)
2618
2619
2620@AST.makefunction
2621def _iscolor(obj):
2622    return isinstance(obj, color.Color)
2623
2624
2625@AST.makefunction
2626def _istemplate(obj):
2627    return isinstance(obj, (Template, TemplateClosure))
2628
2629
2630@AST.makefunction
2631def _isfunction(obj):
2632    return callable(obj)
2633
2634
2635@AST.makefunction
2636def _chr(i):
2637    return chr(i)
2638
2639
2640@AST.makefunction
2641def _ord(c):
2642    return ord(c)
2643
2644
2645@AST.makefunction
2646def _hex(number):
2647    return hex(number)
2648
2649
2650@AST.makefunction
2651def _oct(number):
2652    return oct(number)
2653
2654
2655@AST.makefunction
2656def _bin(number):
2657    return bin(number)
2658
2659
2660@AST.makefunction
2661def _min(*args):
2662    return min(*args)
2663
2664
2665@AST.makefunction
2666def _max(*args):
2667    return max(*args)
2668
2669
2670@AST.makefunction
2671def _sorted(iterable):
2672    return sorted(iterable)
2673
2674
2675@AST.makefunction
2676def _range(*args):
2677    return range(*args)
2678
2679
2680@AST.makefunction
2681def _type(obj):
2682    if obj is None:
2683        return "none"
2684    elif isinstance(obj, Undefined):
2685        return "undefined"
2686    elif isinstance(obj, str):
2687        return "str"
2688    elif isinstance(obj, bool):
2689        return "bool"
2690    elif isinstance(obj, int):
2691        return "int"
2692    elif isinstance(obj, float):
2693        return "float"
2694    elif isinstance(obj, (datetime.datetime, datetime.date)):
2695        return "date"
2696    elif isinstance(obj, datetime.timedelta):
2697        return "timedelta"
2698    elif isinstance(obj, misc.monthdelta):
2699        return "monthdelta"
2700    elif isinstance(obj, color.Color):
2701        return "color"
2702    elif isinstance(obj, (Template, TemplateClosure)):
2703        return "template"
2704    elif isinstance(obj, collections.Mapping):
2705        return "dict"
2706    elif isinstance(obj, color.Color):
2707        return "color"
2708    elif isinstance(obj, collections.Sequence):
2709        return "list"
2710    elif callable(obj):
2711        return "function"
2712    return None
2713
2714
2715@AST.makefunction
2716def _reversed(sequence):
2717    yield from ()
2718    return reversed(sequence)
2719
2720
2721@AST.makefunction
2722def _randrange(*args):
2723    return random.randrange(*args)
2724
2725
2726@AST.makefunction
2727def _randchoice(sequence):
2728    return random.choice(sequence)
2729
2730
2731@AST.makefunction
2732def _format(obj, fmt, lang=None):
2733    if isinstance(obj, (datetime.date, datetime.time, datetime.timedelta)):
2734        if lang is None:
2735            lang = "en"
2736        oldlocale = locale.getlocale()
2737        try:
2738            for candidate in (locale.normalize(lang), locale.normalize("en"), ""):
2739                try:
2740                    locale.setlocale(locale.LC_ALL, candidate)
2741                    return format(obj, fmt)
2742                except locale.Error:
2743                    if not candidate:
2744                        return format(obj, fmt)
2745        finally:
2746            try:
2747                locale.setlocale(locale.LC_ALL, oldlocale)
2748            except locale.Error:
2749                pass
2750    else:
2751        return format(obj, fmt)
2752
2753
2754@AST.makefunction
2755def _zip(*iterables):
2756    return zip(*iterables)
2757
2758
2759@AST.makefunction
2760def _urlquote(string):
2761    return urlparse.quote_plus(string)
2762
2763
2764@AST.makefunction
2765def _urlunquote(string):
2766    return urlparse.unquote_plus(string)
2767
2768
2769@AST.makefunction
2770def _rgb(r, g, b, a=1.0):
2771    return color.Color.fromrgb(r, g, b, a)
2772
2773
2774@AST.makefunction
2775def _hls(h, l, s, a=1.0):
2776    return color.Color.fromhls(h, l, s, a)
2777
2778
2779@AST.makefunction
2780def _hsv(h, s, v, a=1.0):
2781    return color.Color.fromhsv(h, s, v, a)
2782
2783
2784@AST.makemethod
2785def _split(obj, sep=None, count=None):
2786    return obj.split(sep, count if count is not None else -1)
2787
2788
2789@AST.makemethod
2790def _rsplit(obj, sep=None, count=None):
2791    return obj.rsplit(sep, count if count is not None else -1)
2792
2793
2794@AST.makemethod
2795def _strip(obj, chars=None):
2796    return obj.strip(chars)
2797
2798
2799@AST.makemethod
2800def _lstrip(obj, chars=None):
2801    return obj.lstrip(chars)
2802
2803
2804@AST.makemethod
2805def _rstrip(obj, chars=None):
2806    return obj.rstrip(chars)
2807
2808
2809@AST.makemethod
2810def _find(obj, sub, start=None, end=None):
2811    if isinstance(obj, str):
2812        return obj.find(sub, start, end)
2813    else:
2814        try:
2815            if end is None:
2816                if start is None:
2817                    return obj.index(sub)
2818                return obj.index(sub, start)
2819            return obj.index(sub, start, end)
2820        except ValueError:
2821            return -1
2822
2823
2824@AST.makemethod
2825def _rfind(obj, sub, start=None, end=None):
2826    if isinstance(obj, str):
2827        return obj.rfind(sub, start, end)
2828    else:
2829        for i in reversed(range(*slice(start, end).indices(len(obj)))):
2830            if obj[i] == sub:
2831                return i
2832        return -1
2833
2834
2835@AST.makemethod
2836def _startswith(obj, prefix):
2837    return obj.startswith(prefix)
2838
2839
2840@AST.makemethod
2841def _endswith(obj, suffix):
2842    return obj.endswith(suffix)
2843
2844
2845@AST.makemethod
2846def _upper(obj):
2847    return obj.upper()
2848
2849
2850@AST.makemethod
2851def _lower(obj):
2852    return obj.lower()
2853
2854
2855@AST.makemethod
2856def _capitalize(obj):
2857    return obj.capitalize()
2858
2859
2860@AST.makemethod
2861def _replace(obj, old, new, count=None):
2862    if count is None:
2863        return obj.replace(old, new)
2864    else:
2865        return obj.replace(old, new, count)
2866
2867
2868@AST.makemethod
2869def _r(obj):
2870    return obj.r()
2871
2872
2873@AST.makemethod
2874def _g(obj):
2875    return obj.g()
2876
2877
2878@AST.makemethod
2879def _b(obj):
2880    return obj.b()
2881
2882
2883@AST.makemethod
2884def _a(obj):
2885    return obj.a()
2886
2887
2888@AST.makemethod
2889def _hls(obj):
2890    return obj.hls()
2891
2892
2893@AST.makemethod
2894def _hlsa(obj):
2895    return obj.hlsa()
2896
2897
2898@AST.makemethod
2899def _hsv(obj):
2900    return obj.hsv()
2901
2902
2903@AST.makemethod
2904def _hsva(obj):
2905    return obj.hsva()
2906
2907
2908@AST.makemethod
2909def _lum(obj):
2910    return obj.lum()
2911
2912
2913@AST.makemethod
2914def _weekday(obj):
2915    return obj.weekday()
2916
2917
2918@AST.makemethod
2919def _week(obj, firstweekday=None):
2920    if firstweekday is None:
2921        firstweekday = 0
2922    else:
2923        firstweekday %= 7
2924    jan1 = obj.__class__(obj.year, 1, 1)
2925    yearday = (obj - jan1).days+7
2926    jan1weekday = jan1.weekday()
2927    while jan1weekday != firstweekday:
2928        yearday -= 1
2929        jan1weekday += 1
2930        if jan1weekday == 7:
2931            jan1weekday = 0
2932    return yearday//7
2933
2934
2935@AST.makemethod
2936def _items(obj):
2937    yield from ()
2938    return obj.items()
2939
2940
2941@AST.makemethod
2942def _values(obj):
2943    yield from ()
2944    return obj.values()
2945
2946
2947@AST.makemethod
2948def _join(obj, iterable):
2949    return obj.join(iterable)
2950
2951
2952@AST.makemethod
2953def _render(obj, **vars):
2954    yield from obj.render(**vars)
2955
2956
2957@AST.makemethod
2958def _renders(obj, **vars):
2959    return obj.renders(**vars)
2960
2961
2962@AST.makemethod
2963def _mimeformat(obj):
2964    weekdayname = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
2965    monthname = (None, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
2966    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])
2967
2968
2969@AST.makemethod
2970def _isoformat(obj):
2971    result = obj.isoformat()
2972    suffix = "T00:00:00"
2973    if result.endswith(suffix):
2974        return result[:-len(suffix)]
2975    return result
2976
2977
2978@AST.makemethod
2979def _yearday(obj):
2980    return (obj - obj.__class__(obj.year, 1, 1)).days+1
2981
2982
2983@AST.makemethod
2984def _get(obj, key, default=None):
2985    return obj.get(key, default)
2986
2987
2988@AST.makemethod
2989def _withlum(obj, lum):
2990    return obj.withlum(lum)
2991
2992
2993@AST.makemethod
2994def _witha(obj, a):
2995    return obj.witha(a)
2996
2997
2998@AST.makemethod
2999def _day(obj):
3000    return obj.day
3001
3002
3003@AST.makemethod
3004def _month(obj):
3005    return obj.month
3006
3007
3008@AST.makemethod
3009def _year(obj):
3010    return obj.year
3011
3012
3013@AST.makemethod
3014def _hour(obj):
3015    return obj.hour
3016
3017
3018@AST.makemethod
3019def _minute(obj):
3020    return obj.minute
3021
3022
3023@AST.makemethod
3024def _second(obj):
3025    return obj.second
3026
3027
3028@AST.makemethod
3029def _microsecond(obj):
3030    return obj.microsecond
3031
3032
3033@AST.makemethod
3034def _days(obj):
3035    return obj.days
3036
3037
3038@AST.makemethod
3039def _seconds(obj):
3040    return obj.seconds
3041
3042
3043@AST.makemethod
3044def _microseconds(obj):
3045    return obj.microseconds
3046
3047
3048@AST.makemethod
3049def _months(obj):
3050    return obj.months
3051
3052
3053@AST.makemethod
3054def _append(obj, *items):
3055    obj.extend(items)
3056
3057
3058@AST.makemethod
3059def _insert(obj, pos, *items):
3060    obj[pos:pos] = items
3061
3062
3063@AST.makemethod
3064def _pop(obj, pos=-1):
3065    return obj.pop(pos)
3066
3067
3068@AST.makemethod
3069def _update(obj, *others, **kwargs):
3070    for other in others:
3071        obj.update(other)
3072    obj.update(**kwargs)
3073
3074
3075class TemplateClosure(Object):
3076    fields = {"location", "endlocation", "name", "source", "startdelim", "enddelim", "content"}
3077
3078    def __init__(self, template, vars):
3079        self.template = template
3080        # Freeze variables of the currently running templates/functions
3081        self.vars = vars.copy()
3082
3083    def render(self, **vars):
3084        return self.template.render(**collections.ChainMap(vars, self.vars))
3085
3086    def renders(self, **vars):
3087        return self.template.renders(**collections.ChainMap(vars, self.vars))
3088
3089    def __call__(self, **vars):
3090        return self.template(**collections.ChainMap(vars, self.vars))
3091
3092    def __getattr__(self, name):
3093        return getattr(self.template, name)
3094
3095    def __repr__(self):
3096        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} name={0.name!r} keepws={0.keepws!r}".format(self)
3097        if self.startdelim != "<?":
3098            s += " startdelim={0.startdelim!r}".format(self)
3099        if self.enddelim != "?>":
3100            s += " enddelim={0.enddelim!r}".format(self)
3101        if self.content:
3102            s + " ..."
3103        return s + " at {:#x}>".format(id(self))
3104
3105    def _repr_pretty_(self, p, cycle):
3106        if cycle:
3107            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
3108        else:
3109            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
3110                p.breakable()
3111                p.text("name=")
3112                p.pretty(self.name)
3113                p.breakable()
3114                p.text("keepws=")
3115                p.pretty(self.keepws)
3116                if self.startdelim != "<?":
3117                    p.breakable()
3118                    p.text("startdelim=")
3119                    p.pretty(self.startdelim)
3120                if self.enddelim != "?>":
3121                    p.breakable()
3122                    p.text("enddelim=")
3123                    p.pretty(self.enddelim)
3124                for node in self.content:
3125                    p.breakable()
3126                    p.pretty(node)
3127                p.breakable()
3128                p.text("at {:#x}".format(id(self)))
Note: See TracBrowser for help on using the browser.