root/livinglogic.python.xist/src/ll/ul4c.py @ 5336:fe802c9b09e9

Revision 5336:fe802c9b09e9, 81.9 KB (checked in by Walter Doerwald <walter@…>, 7 years ago)

Merge AST and Tag again.

Expressions are now allowed as the content of <?code tag?>, so they may sit at
the top level in tags.

Have the location object point back to the root template. With this we don't
have to pass along the keepws flag in eval().

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