root/livinglogic.python.xist/src/ll/ul4c.py @ 5312:9a98178e4483

Revision 5312:9a98178e4483, 81.0 KB (checked in by Walter Doerwald <walter@…>, 7 years ago)

Merge UL4 templates and functions again.

Templates call be called as functions. All ouput will be ignored in this case.

Executing templates is now done by interpreting the AST directly (via the eval()
method), instead of generating Python source code from it first.

AST nodes can both produce output and return results via enhanced generators.

Constant folding has been removed.

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