root/livinglogic.python.xist/src/ll/ul4c.py @ 5321:fbc274119efb

Revision 5321:fbc274119efb, 81.5 KB (checked in by Walter Doerwald <walter@…>, 7 years ago)

Add UL4 methods days(), seconds(), microseconds() and months() for timedelta/monthdelta objects.

Line 
1# -*- coding: utf-8 -*-
2
3## Copyright 2009-2013 by LivingLogic AG, Bayreuth/Germany
4## Copyright 2009-2013 by Walter Dörwald
5##
6## All Rights Reserved
7##
8## See ll/xist/__init__.py for the license
9
10
11"""
12:mod:`ll.ul4c` provides templating for XML/HTML as well as any other text-based
13format. A template defines placeholders for data output and basic logic (like
14loops and conditional blocks), that define how the final rendered output will
15look.
16
17:mod:`ll.ul4c` compiles a template to an internal format, which makes it
18possible to implement template renderers in multiple programming languages.
19"""
20
21
22__docformat__ = "reStructuredText"
23
24
25import re, types, datetime, urllib.parse as urlparse, json, collections, locale, itertools, random, datetime, unicodedata
26
27import antlr3
28
29from ll import color, misc
30
31
32# Regular expression used for splitting dates in isoformat
33datesplitter = re.compile("[-T:.]")
34
35
36def register(name):
37    from ll import ul4on
38    def registration(cls):
39        ul4on.register("de.livinglogic.ul4." + name)(cls)
40        cls.type = name
41        return cls
42    return registration
43
44
45class Object:
46    fields = {}
47
48    def __getitem__(self, key):
49        if key in self.fields:
50            return getattr(self, key)
51        raise KeyError(key)
52
53
54###
55### Location information
56###
57
58@register("location")
59class Location(Object):
60    """
61    A :class:`Location` object contains information about the location of a
62    template tag.
63    """
64    __slots__ = ("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("print")
1299class Print(UnaryTag):
1300    """
1301    AST node for a ``<?print?>`` tag.
1302    """
1303
1304    def _str(self, indent, keepws):
1305        yield indent*"\t"
1306        yield "print "
1307        yield from self.obj._str(indent, keepws)
1308        yield "\n"
1309
1310    def eval(self, keepws, vars):
1311        yield _str((yield from self.obj.eval(keepws, vars)))
1312
1313
1314@register("printx")
1315class PrintX(UnaryTag):
1316    """
1317    AST node for a ``<?printx?>`` tag.
1318    """
1319
1320    def _str(self, indent, keepws):
1321        yield indent*"\t"
1322        yield "printx "
1323        yield from self.obj._str(indent, keepws)
1324        yield "\n"
1325
1326    def eval(self, keepws, vars):
1327        yield _xmlescape((yield from self.obj.eval(keepws, vars)))
1328
1329
1330@register("return")
1331class Return(UnaryTag):
1332    """
1333    AST node for a ``<?return?>`` tag.
1334    """
1335
1336    def _str(self, indent, keepws):
1337        yield indent*"\t"
1338        yield "return "
1339        yield from self.obj._str(indent, keepws)
1340        yield "\n"
1341
1342    def eval(self, keepws, vars):
1343        value = (yield from self.obj.eval(keepws, vars))
1344        raise ReturnException(value)
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        result = obj(*args, **kwargs)
2020        if isinstance(result, types.GeneratorType):
2021            return (yield from result)
2022        else:
2023            return result
2024
2025    def ul4ondump(self, encoder):
2026        encoder.dump(self.obj)
2027        encoder.dump(self.args)
2028        encoder.dump(self.kwargs)
2029        encoder.dump(self.remargs)
2030        encoder.dump(self.remkwargs)
2031
2032    def ul4onload(self, decoder):
2033        self.obj = decoder.load()
2034        self.args = decoder.load()
2035        self.kwargs = [tuple(arg) for arg in decoder.load()]
2036        self.remargs = decoder.load()
2037        self.remkwargs = decoder.load()
2038
2039
2040@register("callmeth")
2041class CallMeth(AST):
2042    """
2043    AST node for calling a method.
2044
2045    The method name is stored in the string :var:`methname`. The object for which
2046    the method will be called is loaded from the AST node :var:`obj` and the list
2047    of arguments is loaded from the list of AST nodes :var:`args`. Keyword
2048    arguments are in :var:`kwargs`. `var`:remargs` is the AST node for the ``*``
2049    argument (and may by ``None`` if there is no ``*`` argument).
2050    `var`:remkwargs` is the AST node for the ``**`` argument (and may by ``None``
2051    if there is no ``**`` argument)
2052    """
2053
2054    precedence = 9
2055    associative = False
2056    fields = AST.fields.union({"obj", "methname", "args", "kwargs", "remargs", "remkwargs"})
2057
2058    def __init__(self, obj=None, methname=None):
2059        self.obj = obj
2060        self.methname = methname
2061        self.args = []
2062        self.kwargs = []
2063        self.remargs = None
2064        self.remkwargs = None
2065
2066    def __repr__(self):
2067        return "<{0.__class__.__module__}.{0.__class__.__qualname__} methname={0.methname!r} obj={0.obj!r}{1}{2}{3}{4} at {5:#x}>".format(
2068            self,
2069            "".join(" {!r}".format(arg) for arg in self.args),
2070            "".join(" {}={!r}".format(argname, argvalue) for (argname, argvalue) in self.kwargs),
2071            " *{!r}".format(self.remargs) if self.remargs is not None else "",
2072            " **{!r}".format(self.remkwargs) if self.remargs is not None else "",
2073            id(self))
2074
2075    def _repr_pretty_(self, p, cycle):
2076        if cycle:
2077            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
2078        else:
2079            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
2080                p.breakable()
2081                p.text("methname=")
2082                p.pretty(self.methname)
2083                p.breakable()
2084                p.text("obj=")
2085                p.pretty(self.obj)
2086                for arg in self.args:
2087                    p.breakable()
2088                    p.pretty(arg)
2089                for (argname, arg) in self.kwargs:
2090                    p.breakable()
2091                    p.text("{}=".format(argname))
2092                    p.pretty(arg)
2093                if self.remargs is not None:
2094                    p.breakable()
2095                    p.text("*")
2096                    p.pretty(self.remargs)
2097                if self.remkwargs is not None:
2098                    p.breakable()
2099                    p.text("**")
2100                    p.pretty(self.remkwargs)
2101                p.breakable()
2102                p.text("at {:#x}".format(id(self)))
2103
2104    def _str(self, indent, keepws):
2105        yield from self._formatop(self.obj)
2106        yield ".("
2107        first = True
2108        for arg in self.args:
2109            if first:
2110                first = False
2111            else:
2112                yield ", "
2113            yield from arg._str(indent, keepws)
2114        for (argname, argvalue) in self.kwargs:
2115            if first:
2116                first = False
2117            else:
2118                yield ", "
2119            yield argname
2120            yield "="
2121            yield from argvalue._str(indent, keepws)
2122        if self.remargs is not None:
2123            if first:
2124                first = False
2125            else:
2126                yield ", "
2127            yield "*"
2128            yield from self.remargs._str(indent, keepws)
2129        if self.remkwargs is not None:
2130            if first:
2131                first = False
2132            else:
2133                yield ", "
2134            yield "**"
2135            yield from self.remkwargs._str(indent, keepws)
2136        yield ")"
2137
2138    def eval(self, keepws, vars):
2139        obj = (yield from self.obj.eval(keepws, vars))
2140        args = []
2141        for arg in self.args:
2142            arg = (yield from arg.eval(keepws, vars))
2143            args.append(arg)
2144        kwargs = {}
2145        for (argname, arg) in self.kwargs:
2146            kwargs[argname] = (yield from arg.eval(keepws, vars))
2147        if self.remargs is not None:
2148            args.extend((yield from self.remargs.eval(keepws, vars)))
2149        if self.remkwargs is not None:
2150            kwargs.update((yield from self.remkwargs.eval(keepws, vars)))
2151        result = self.methods[self.methname](obj, *args, **kwargs)
2152        if isinstance(result, types.GeneratorType):
2153            return (yield from result)
2154        else:
2155            return result
2156
2157    def ul4ondump(self, encoder):
2158        encoder.dump(self.methname)
2159        encoder.dump(self.obj)
2160        encoder.dump(self.args)
2161        encoder.dump(self.kwargs)
2162        encoder.dump(self.remargs)
2163        encoder.dump(self.remkwargs)
2164
2165    def ul4onload(self, decoder):
2166        self.methname = decoder.load()
2167        self.obj = decoder.load()
2168        self.args = decoder.load()
2169        self.kwargs = [tuple(arg) for arg in decoder.load()]
2170        self.remargs = decoder.load()
2171        self.remkwargs = decoder.load()
2172
2173
2174@register("template")
2175class Template(Block):
2176    """
2177    A template object is normally created by passing the template source to the
2178    constructor. It can also be loaded from the compiled format via the class
2179    methods :meth:`load` (from a stream) or :meth:`loads` (from a string).
2180
2181    The compiled format can be generated with the methods :meth:`dump` (which
2182    dumps the format to a stream) or :meth:`dumps` (which returns a string with
2183    the compiled format).
2184
2185    Rendering the template can be done with the methods :meth:`render` (which
2186    is a generator) or :meth:`renders` (which returns a string).
2187
2188    A :class:`Template` object is itself an AST node. Evaluating it will store
2189    the template object under its name in the local variables.
2190
2191    A :class:`Template` can also be called as a function (returning the result
2192    of the first ``<?return?>`` tag encountered. In this case all output of the
2193    template will be ignored.
2194    """
2195    fields = Block.fields.union({"source", "name", "keepws", "startdelim", "enddelim", "endlocation"})
2196
2197    version = "24"
2198
2199    def __init__(self, source=None, name=None, keepws=True, startdelim="<?", enddelim="?>"):
2200        """
2201        Create a :class:`Template` object. If :var:`source` is ``None``, the
2202        :class:`Template` remains uninitialized, otherwise :var:`source` will be
2203        compiled (using :var:`startdelim` and :var:`enddelim` as the tag
2204        delimiters). :var:`name` is the name of the template. It will be used in
2205        exception messages and should be a valid Python identifier. If
2206        :var:`keepws` is false linefeeds and indentation will be ignored in the
2207        literal text in templates (i.e. the text between the tags). However
2208        trailing whitespace at the end of the line will be honored regardless of
2209        the value of :var:`keepws`. Output will always be ignored when calling
2210        a template as a function.
2211        """
2212        # ``location``/``endlocation`` will remain ``None`` for a top level template
2213        # For a subtemplate/subfunction ``location`` will be set to the location of the ``<?template?>`` tag
2214        # in :meth:`_compile` and ``endlocation`` will be the location of the ``<?end template?>`` tag
2215        super().__init__(None)
2216        self.keepws = keepws
2217        self.startdelim = startdelim
2218        self.enddelim = enddelim
2219        self.name = name
2220        self.source = None
2221
2222        # If we have source code compile it
2223        if source is not None:
2224            self._compile(source, name, startdelim, enddelim)
2225
2226    def __repr__(self):
2227        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} name={0.name!r} keepws={0.keepws!r}".format(self)
2228        if self.startdelim != "<?":
2229            s += " startdelim={0.startdelim!r}".format(self)
2230        if self.enddelim != "?>":
2231            s += " enddelim={0.enddelim!r}".format(self)
2232        if self.content:
2233            s + " ..."
2234        return s + " at {:#x}>".format(id(self))
2235
2236    def _str(self, indent, keepws):
2237        yield indent*"\t"
2238        yield "def "
2239        yield self.name if self.name is not None else "unnamed"
2240        yield ":\n"
2241        indent += 1
2242        yield from super()._str(indent, keepws)
2243
2244    def __str__(self):
2245        return "".join(self._str(0, self.keepws))
2246
2247    def _repr_pretty_(self, p, cycle):
2248        if cycle:
2249            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
2250        else:
2251            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
2252                p.breakable()
2253                p.text("name=")
2254                p.pretty(self.name)
2255                p.breakable()
2256                p.text("keepws=")
2257                p.pretty(self.keepws)
2258                if self.startdelim != "<?":
2259                    p.breakable()
2260                    p.text("startdelim=")
2261                    p.pretty(self.startdelim)
2262                if self.enddelim != "?>":
2263                    p.breakable()
2264                    p.text("enddelim=")
2265                    p.pretty(self.enddelim)
2266                for node in self.content:
2267                    p.breakable()
2268                    p.pretty(node)
2269                p.breakable()
2270                p.text("at {:#x}".format(id(self)))
2271
2272    def ul4ondump(self, encoder):
2273        encoder.dump(self.version)
2274        encoder.dump(self.source)
2275        encoder.dump(self.name)
2276        encoder.dump(self.keepws)
2277        encoder.dump(self.startdelim)
2278        encoder.dump(self.enddelim)
2279        encoder.dump(self.location)
2280        encoder.dump(self.endlocation)
2281        encoder.dump(self.content)
2282
2283    def ul4onload(self, decoder):
2284        version = decoder.load()
2285        if version != self.version:
2286            raise ValueError("invalid version, expected {!r}, got {!r}".format(self.version, version))
2287        self.source = decoder.load()
2288        self.name = decoder.load()
2289        self.keepws = decoder.load()
2290        self.startdelim = decoder.load()
2291        self.enddelim = decoder.load()
2292        self.location = decoder.load()
2293        self.endlocation = decoder.load()
2294        self.content = decoder.load()
2295
2296    @classmethod
2297    def loads(cls, data):
2298        """
2299        The class method :meth:`loads` loads the template/function from string
2300        :var:`data`. :var:`data` must contain the template/function in compiled
2301        UL4ON format.
2302        """
2303        from ll import ul4on
2304        return ul4on.loads(data)
2305
2306    @classmethod
2307    def load(cls, stream):
2308        """
2309        The class method :meth:`load` loads the template/function from the stream
2310        :var:`stream`. The stream must contain the template/function in compiled
2311        UL4ON format.
2312        """
2313        from ll import ul4on
2314        return ul4on.load(stream)
2315
2316    def dump(self, stream):
2317        """
2318        :meth:`dump` dumps the template/function in compiled UL4ON format to the
2319        stream :var:`stream`.
2320        """
2321        from ll import ul4on
2322        ul4on.dump(self, stream)
2323
2324    def dumps(self):
2325        """
2326        :meth:`dumps` returns the template/function in compiled UL4ON format
2327        (as a string).
2328        """
2329        from ll import ul4on
2330        return ul4on.dumps(self)
2331
2332    def render(self, **vars):
2333        """
2334        Render the template iteratively (i.e. this is a generator).
2335        :var:`vars` contains the top level variables available to the
2336        template code.
2337        """
2338        yield from super().eval(self.keepws, vars) # Bypass ``self.eval()`` which simply stores the object as a local variable
2339
2340    def renders(self, **vars):
2341        """
2342        Render the template as a string. :var:`vars` contains the top level
2343        variables available to the template code.
2344        """
2345        return "".join(self.render(**vars))
2346
2347    def __call__(self, **vars):
2348        """
2349        Call the template as a function and return the resulting value.
2350        :var:`vars` contains the top level variables available to the template code.
2351        """
2352        try:
2353            for output in super().eval(self.keepws, vars): # Bypass ``self.eval()`` which simply stores the object as a local variable
2354                pass # Ignore all output
2355        except ReturnException as ex:
2356            return ex.value
2357
2358    def jssource(self):
2359        """
2360        Return the template as the source code of a Javascript function.
2361        """
2362        return "ul4.Template.loads({})".format(_asjson(self.dumps()))
2363
2364    def javasource(self):
2365        """
2366        Return the template as Java source code.
2367        """
2368        return "com.livinglogic.ul4.InterpretedTemplate.loads({})".format(misc.javaexpr(self.dumps()))
2369
2370    def _tokenize(self, source, startdelim, enddelim):
2371        """
2372        Tokenize the template/function source code :var:`source` into tags and
2373        non-tag text. :var:`startdelim` and :var:`enddelim` are used as the tag
2374        delimiters.
2375
2376        This is a generator which produces :class:`Location` objects for each tag
2377        or non-tag text. It will be called by :meth:`_compile` internally.
2378        """
2379        pattern = "{}(printx|print|exe|for|if|elif|else|end|break|continue|def|return|note)(\s*((.|\\n)*?)\s*)?{}".format(re.escape(startdelim), re.escape(enddelim))
2380        pos = 0
2381        for match in re.finditer(pattern, source):
2382            if match.start() != pos:
2383                yield Location(source, None, pos, match.start(), pos, match.start())
2384            type = source[match.start(1):match.end(1)]
2385            if type != "note":
2386                yield Location(source, type, match.start(), match.end(), match.start(3), match.end(3))
2387            pos = match.end()
2388        end = len(source)
2389        if pos != end:
2390            yield Location(source, None, pos, end, pos, end)
2391
2392    def _parser(self, location, error):
2393        from ll import UL4Lexer, UL4Parser
2394        source = location.code
2395        if not source:
2396            raise ValueError(error)
2397        stream = antlr3.ANTLRStringStream(source)
2398        lexer = UL4Lexer.UL4Lexer(stream)
2399        lexer.location = location
2400        tokens = antlr3.CommonTokenStream(lexer)
2401        parser = UL4Parser.UL4Parser(tokens)
2402        parser.location = location
2403        return parser
2404
2405    def _compile(self, source, name, startdelim, enddelim):
2406        """
2407        Compile the template source code :var:`source` into an AST.
2408        :var:`startdelim` and :var:`enddelim` are used as the tag delimiters.
2409        """
2410        self.name = name
2411        self.startdelim = startdelim
2412        self.enddelim = enddelim
2413
2414        # This stack stores the nested for/if/elif/else/def blocks
2415        stack = [self]
2416
2417        self.source = source
2418
2419        if source is None:
2420            return
2421
2422        def parseexpr(location):
2423            return self._parser(location, "expression required").expression()
2424
2425        def parsestmt(location):
2426            return self._parser(location, "statement required").statement()
2427
2428        def parsefor(location):
2429            return self._parser(location, "loop expression required").for_()
2430
2431        for location in self._tokenize(source, startdelim, enddelim):
2432            try:
2433                if location.type is None:
2434                    stack[-1].append(Text(location))
2435                elif location.type == "print":
2436                    stack[-1].append(Print(location, parseexpr(location)))
2437                elif location.type == "printx":
2438                    stack[-1].append(PrintX(location, parseexpr(location)))
2439                elif location.type == "exe":
2440                    stack[-1].append(parsestmt(location))
2441                elif location.type == "if":
2442                    block = IfElIfElse(location, parseexpr(location))
2443                    stack[-1].append(block)
2444                    stack.append(block)
2445                elif location.type == "elif":
2446                    if not isinstance(stack[-1], IfElIfElse):
2447                        raise BlockError("elif doesn't match and if")
2448                    elif isinstance(stack[-1].content[-1], Else):
2449                        raise BlockError("else already seen in if")
2450                    stack[-1].newblock(ElIf(location, parseexpr(location)))
2451                elif location.type == "else":
2452                    if not isinstance(stack[-1], IfElIfElse):
2453                        raise BlockError("else doesn't match any if")
2454                    elif isinstance(stack[-1].content[-1], Else):
2455                        raise BlockError("else already seen in if")
2456                    stack[-1].newblock(Else(location))
2457                elif location.type == "end":
2458                    if len(stack) <= 1:
2459                        raise BlockError("not in any block")
2460                    code = location.code
2461                    if code:
2462                        if code == "if":
2463                            if not isinstance(stack[-1], IfElIfElse):
2464                                raise BlockError("endif doesn't match any if")
2465                        elif code == "for":
2466                            if not isinstance(stack[-1], For):
2467                                raise BlockError("endfor doesn't match any for")
2468                        elif code == "def":
2469                            if not isinstance(stack[-1], Template):
2470                                raise BlockError("enddef doesn't match any def")
2471                        else:
2472                            raise BlockError("illegal end value {!r}".format(code))
2473                    last = stack.pop()
2474                    # Set ``endlocation`` of block
2475                    last.endlocation = location
2476                    if isinstance(last, IfElIfElse):
2477                        last.content[-1].endlocation = location
2478                elif location.type == "for":
2479                    block = parsefor(location)
2480                    stack[-1].append(block)
2481                    stack.append(block)
2482                elif location.type == "break":
2483                    for block in reversed(stack):
2484                        if isinstance(block, For):
2485                            break
2486                        elif isinstance(block, Template):
2487                            raise BlockError("break outside of for loop")
2488                    stack[-1].append(Break(location))
2489                elif location.type == "continue":
2490                    for block in reversed(stack):
2491                        if isinstance(block, For):
2492                            break
2493                        elif isinstance(block, Template):
2494                            raise BlockError("continue outside of for loop")
2495                    stack[-1].append(Continue(location))
2496                elif location.type == "def":
2497                    block = Template(None, location.code, self.keepws, self.startdelim, self.enddelim)
2498                    block.location = location # Set start ``location`` of sub template
2499                    block.source = self.source # The source of the top level template (so that the offsets in :class:`Location` are correct)
2500                    stack[-1].append(block)
2501                    stack.append(block)
2502                elif location.type == "return":
2503                    stack[-1].append(Return(location, parseexpr(location)))
2504                else: # Can't happen
2505                    raise ValueError("unknown tag {!r}".format(location.type))
2506            except Exception as exc:
2507                raise Error(location) from exc
2508        if len(stack) > 1:
2509            raise Error(stack[-1].location) from BlockError("block unclosed")
2510
2511    def eval(self, keepws, vars):
2512        yield from ()
2513        vars[self.name] = TemplateClosure(self, vars)
2514
2515
2516###
2517### Functions & methods
2518###
2519
2520@AST.makefunction
2521def _print(*values):
2522    for (i, value) in enumerate(values):
2523        if i:
2524            yield " "
2525        yield _str(value)
2526
2527
2528@AST.makefunction
2529def _printx(*values):
2530    for (i, value) in enumerate(values):
2531        if i:
2532            yield " "
2533        yield _xmlescape(value)
2534
2535
2536@AST.makefunction
2537def _str(obj=""):
2538    if obj is None:
2539        return ""
2540    elif isinstance(obj, Undefined):
2541        return ""
2542    else:
2543        return str(obj)
2544
2545
2546@AST.makefunction
2547def _repr(obj):
2548    if isinstance(obj, str):
2549        return repr(obj)
2550    elif isinstance(obj, datetime.datetime):
2551        s = str(obj.isoformat())
2552        if s.endswith("T00:00:00"):
2553            s = s[:-9]
2554        return "@({})".format(s)
2555    elif isinstance(obj, datetime.date):
2556        return "@({})".format(obj.isoformat())
2557    elif isinstance(obj, datetime.timedelta):
2558        return repr(obj).partition(".")[-1]
2559    elif isinstance(obj, color.Color):
2560        if obj[3] == 0xff:
2561            s = "#{:02x}{:02x}{:02x}".format(obj[0], obj[1], obj[2])
2562            if s[1]==s[2] and s[3]==s[4] and s[5]==s[6]:
2563                return "#{}{}{}".format(s[1], s[3], s[5])
2564            return s
2565        else:
2566            s = "#{:02x}{:02x}{:02x}{:02x}".format(*obj)
2567            if s[1]==s[2] and s[3]==s[4] and s[5]==s[6] and s[7]==s[8]:
2568                return "#{}{}{}{}".format(s[1], s[3], s[5], s[7])
2569            return s
2570    elif isinstance(obj, collections.Sequence):
2571        return "[{}]".format(", ".join(_repr(item) for item in obj))
2572    elif isinstance(obj, collections.Mapping):
2573        return "{{{}}}".format(", ".join("{}: {}".format(_repr(key), _repr(value)) for (key, value) in obj.items()))
2574    else:
2575        return repr(obj)
2576
2577
2578@AST.makefunction
2579def _now():
2580    return datetime.datetime.now()
2581
2582
2583@AST.makefunction
2584def _utcnow():
2585    return datetime.datetime.utcnow()
2586
2587
2588@AST.makefunction
2589def _date(year, month, day, hour=0, minute=0, second=0, microsecond=0):
2590    return datetime.datetime(year, month, day, hour, minute, second, microsecond)
2591
2592
2593@AST.makefunction
2594def _timedelta(days=0, seconds=0, microseconds=0):
2595    return datetime.timedelta(days, seconds, microseconds)
2596
2597
2598@AST.makefunction
2599def _monthdelta(months=0):
2600    return misc.monthdelta(months)
2601
2602
2603@AST.makefunction
2604def _random():
2605    return random.random()
2606
2607
2608@AST.makefunction
2609def _xmlescape(obj):
2610    if obj is None:
2611        return ""
2612    elif isinstance(obj, Undefined):
2613        return ""
2614    else:
2615        return misc.xmlescape(str(obj))
2616
2617
2618@AST.makefunction
2619def _csv(obj):
2620    if obj is None:
2621        return ""
2622    elif isinstance(obj, Undefined):
2623        return ""
2624    elif not isinstance(obj, str):
2625        obj = _repr(obj)
2626    if any(c in obj for c in ',"\n'):
2627        return '"{}"'.format(obj.replace('"', '""'))
2628    return obj
2629
2630
2631@AST.makefunction
2632def _asjson(obj):
2633    if obj is None:
2634        return "null"
2635    elif isinstance(obj, Undefined):
2636        return "{}.undefined"
2637    if isinstance(obj, (bool, int, float, str)):
2638        return json.dumps(obj)
2639    elif isinstance(obj, datetime.datetime):
2640        return "new Date({}, {}, {}, {}, {}, {}, {})".format(obj.year, obj.month-1, obj.day, obj.hour, obj.minute, obj.second, obj.microsecond//1000)
2641    elif isinstance(obj, datetime.date):
2642        return "new Date({}, {}, {})".format(obj.year, obj.month-1, obj.day)
2643    elif isinstance(obj, datetime.timedelta):
2644        return "ul4.TimeDelta.create({}, {}, {})".format(obj.days, obj.seconds, obj.microseconds)
2645    elif isinstance(obj, misc.monthdelta):
2646        return "ul4.MonthDelta.create({})".format(obj.months)
2647    elif isinstance(obj, color.Color):
2648        return "ul4.Color.create({}, {}, {}, {})".format(*obj)
2649    elif isinstance(obj, collections.Mapping):
2650        return "{{{}}}".format(", ".join("{}: {}".format(_asjson(key), _asjson(value)) for (key, value) in obj.items()))
2651    elif isinstance(obj, collections.Sequence):
2652        return "[{}]".format(", ".join(_asjson(item) for item in obj))
2653    elif isinstance(obj, Template):
2654        return obj.jssource()
2655    else:
2656        raise TypeError("can't handle object of type {}".format(type(obj)))
2657
2658
2659@AST.makefunction
2660def _fromjson(string):
2661    from ll import ul4on
2662    return json.loads(string)
2663
2664
2665@AST.makefunction
2666def _asul4on(obj):
2667    from ll import ul4on
2668    return ul4on.dumps(obj)
2669
2670
2671@AST.makefunction
2672def _fromul4on(string):
2673    from ll import ul4on
2674    return ul4on.loads(string)
2675
2676
2677@AST.makefunction
2678def _int(obj=0, base=None):
2679    if base is None:
2680        return int(obj)
2681    else:
2682        return int(obj, base)
2683
2684
2685@AST.makefunction
2686def _float(obj=0.0):
2687    return float(obj)
2688
2689
2690@AST.makefunction
2691def _bool(obj=False):
2692    return bool(obj)
2693
2694
2695@AST.makefunction
2696def _len(sequence):
2697    return len(sequence)
2698
2699
2700@AST.makefunction
2701def _abs(number):
2702    return abs(number)
2703
2704
2705@AST.makefunction
2706def _any(iterable):
2707    return any(iterable)
2708
2709
2710@AST.makefunction
2711def _all(iterable):
2712    return all(iterable)
2713
2714
2715@AST.makefunction
2716def _enumerate(iterable, start=0):
2717    yield from ()
2718    return enumerate(iterable, start)
2719
2720
2721@AST.makefunction
2722def _enumfl(iterable, start=0):
2723    yield from ()
2724    def result(iterable):
2725        lastitem = None
2726        first = True
2727        i = start
2728        it = iter(iterable)
2729        try:
2730            item = next(it)
2731        except StopIteration:
2732            return
2733        while True:
2734            try:
2735                (lastitem, item) = (item, next(it))
2736            except StopIteration:
2737                yield (i, first, True, item) # Items haven't been swapped yet
2738                return
2739            else:
2740                yield (i, first, False, lastitem)
2741                first = False
2742            i += 1
2743    return result(iterable)
2744
2745
2746@AST.makefunction
2747def _isfirstlast(iterable):
2748    yield from ()
2749    def result(iterable):
2750        lastitem = None
2751        first = True
2752        it = iter(iterable)
2753        try:
2754            item = next(it)
2755        except StopIteration:
2756            return
2757        while True:
2758            try:
2759                (lastitem, item) = (item, next(it))
2760            except StopIteration:
2761                yield (first, True, item) # Items haven't been swapped yet
2762                return
2763            else:
2764                yield (first, False, lastitem)
2765                first = False
2766    return result(iterable)
2767
2768
2769@AST.makefunction
2770def _isfirst(iterable):
2771    yield from ()
2772    def result(iterable):
2773        first = True
2774        for item in iterable:
2775            yield (first, item)
2776            first = False
2777    return result(iterable)
2778
2779
2780@AST.makefunction
2781def _islast(iterable):
2782    yield from ()
2783    def result(iterable):
2784        lastitem = None
2785        it = iter(iterable)
2786        try:
2787            item = next(it)
2788        except StopIteration:
2789            return
2790        while True:
2791            try:
2792                (lastitem, item) = (item, next(it))
2793            except StopIteration:
2794                yield (True, item) # Items haven't been swapped yet
2795                return
2796            else:
2797                yield (False, lastitem)
2798    return result(iterable)
2799
2800
2801@AST.makefunction
2802def _isundefined(obj):
2803    return isinstance(obj, Undefined)
2804
2805
2806@AST.makefunction
2807def _isdefined(obj):
2808    return not isinstance(obj, Undefined)
2809
2810
2811@AST.makefunction
2812def _isnone(obj):
2813    return obj is None
2814
2815
2816@AST.makefunction
2817def _isstr(obj):
2818    return isinstance(obj, str)
2819
2820
2821@AST.makefunction
2822def _isint(obj):
2823    return isinstance(obj, int) and not isinstance(obj, bool)
2824
2825
2826@AST.makefunction
2827def _isfloat(obj):
2828    return isinstance(obj, float)
2829
2830
2831@AST.makefunction
2832def _isbool(obj):
2833    return isinstance(obj, bool)
2834
2835
2836@AST.makefunction
2837def _isdate(obj):
2838    return isinstance(obj, (datetime.datetime, datetime.date))
2839
2840
2841@AST.makefunction
2842def _istimedelta(obj):
2843    return isinstance(obj, datetime.timedelta)
2844
2845
2846@AST.makefunction
2847def _ismonthdelta(obj):
2848    return isinstance(obj, misc.monthdelta)
2849
2850
2851@AST.makefunction
2852def _islist(obj):
2853    return isinstance(obj, collections.Sequence) and not isinstance(obj, str) and not isinstance(obj, color.Color)
2854
2855
2856@AST.makefunction
2857def _isdict(obj):
2858    return isinstance(obj, collections.Mapping) and not isinstance(obj, Template)
2859
2860
2861@AST.makefunction
2862def _iscolor(obj):
2863    return isinstance(obj, color.Color)
2864
2865
2866@AST.makefunction
2867def _istemplate(obj):
2868    return isinstance(obj, (Template, TemplateClosure))
2869
2870
2871@AST.makefunction
2872def _isfunction(obj):
2873    return callable(obj)
2874
2875
2876@AST.makefunction
2877def _chr(i):
2878    return chr(i)
2879
2880
2881@AST.makefunction
2882def _ord(c):
2883    return ord(c)
2884
2885
2886@AST.makefunction
2887def _hex(number):
2888    return hex(number)
2889
2890
2891@AST.makefunction
2892def _oct(number):
2893    return oct(number)
2894
2895
2896@AST.makefunction
2897def _bin(number):
2898    return bin(number)
2899
2900
2901@AST.makefunction
2902def _min(*args):
2903    return min(*args)
2904
2905
2906@AST.makefunction
2907def _max(*args):
2908    return max(*args)
2909
2910
2911@AST.makefunction
2912def _sorted(iterable):
2913    return sorted(iterable)
2914
2915
2916@AST.makefunction
2917def _range(*args):
2918    return range(*args)
2919
2920
2921@AST.makefunction
2922def _type(obj):
2923    if obj is None:
2924        return "none"
2925    elif isinstance(obj, Undefined):
2926        return "undefined"
2927    elif isinstance(obj, str):
2928        return "str"
2929    elif isinstance(obj, bool):
2930        return "bool"
2931    elif isinstance(obj, int):
2932        return "int"
2933    elif isinstance(obj, float):
2934        return "float"
2935    elif isinstance(obj, (datetime.datetime, datetime.date)):
2936        return "date"
2937    elif isinstance(obj, datetime.timedelta):
2938        return "timedelta"
2939    elif isinstance(obj, misc.monthdelta):
2940        return "monthdelta"
2941    elif isinstance(obj, color.Color):
2942        return "color"
2943    elif isinstance(obj, (Template, TemplateClosure)):
2944        return "template"
2945    elif isinstance(obj, collections.Mapping):
2946        return "dict"
2947    elif isinstance(obj, color.Color):
2948        return "color"
2949    elif isinstance(obj, collections.Sequence):
2950        return "list"
2951    elif callable(obj):
2952        return "function"
2953    return None
2954
2955
2956@AST.makefunction
2957def _reversed(sequence):
2958    yield from ()
2959    return reversed(sequence)
2960
2961
2962@AST.makefunction
2963def _randrange(*args):
2964    return random.randrange(*args)
2965
2966
2967@AST.makefunction
2968def _randchoice(sequence):
2969    return random.choice(sequence)
2970
2971
2972@AST.makefunction
2973def _format(obj, fmt, lang=None):
2974    if isinstance(obj, (datetime.date, datetime.time, datetime.timedelta)):
2975        if lang is None:
2976            lang = "en"
2977        oldlocale = locale.getlocale()
2978        try:
2979            for candidate in (locale.normalize(lang), locale.normalize("en"), ""):
2980                try:
2981                    locale.setlocale(locale.LC_ALL, candidate)
2982                    return format(obj, fmt)
2983                except locale.Error:
2984                    if not candidate:
2985                        return format(obj, fmt)
2986        finally:
2987            try:
2988                locale.setlocale(locale.LC_ALL, oldlocale)
2989            except locale.Error:
2990                pass
2991    else:
2992        return format(obj, fmt)
2993
2994
2995@AST.makefunction
2996def _zip(*iterables):
2997    return zip(*iterables)
2998
2999
3000@AST.makefunction
3001def _urlquote(string):
3002    return urlparse.quote_plus(string)
3003
3004
3005@AST.makefunction
3006def _urlunquote(string):
3007    return urlparse.unquote_plus(string)
3008
3009
3010@AST.makefunction
3011def _rgb(r, g, b, a=1.0):
3012    return color.Color.fromrgb(r, g, b, a)
3013
3014
3015@AST.makefunction
3016def _hls(h, l, s, a=1.0):
3017    return color.Color.fromhls(h, l, s, a)
3018
3019
3020@AST.makefunction
3021def _hsv(h, s, v, a=1.0):
3022    return color.Color.fromhsv(h, s, v, a)
3023
3024
3025@AST.makemethod
3026def _split(obj, sep=None, count=None):
3027    return obj.split(sep, count if count is not None else -1)
3028
3029
3030@AST.makemethod
3031def _rsplit(obj, sep=None, count=None):
3032    return obj.rsplit(sep, count if count is not None else -1)
3033
3034
3035@AST.makemethod
3036def _strip(obj, chars=None):
3037    return obj.strip(chars)
3038
3039
3040@AST.makemethod
3041def _lstrip(obj, chars=None):
3042    return obj.lstrip(chars)
3043
3044
3045@AST.makemethod
3046def _rstrip(obj, chars=None):
3047    return obj.rstrip(chars)
3048
3049
3050@AST.makemethod
3051def _find(obj, sub, start=None, end=None):
3052    if isinstance(obj, str):
3053        return obj.find(sub, start, end)
3054    else:
3055        try:
3056            if end is None:
3057                if start is None:
3058                    return obj.index(sub)
3059                return obj.index(sub, start)
3060            return obj.index(sub, start, end)
3061        except ValueError:
3062            return -1
3063
3064
3065@AST.makemethod
3066def _rfind(obj, sub, start=None, end=None):
3067    if isinstance(obj, str):
3068        return obj.rfind(sub, start, end)
3069    else:
3070        for i in reversed(range(*slice(start, end).indices(len(obj)))):
3071            if obj[i] == sub:
3072                return i
3073        return -1
3074
3075
3076@AST.makemethod
3077def _startswith(obj, prefix):
3078    return obj.startswith(prefix)
3079
3080
3081@AST.makemethod
3082def _endswith(obj, suffix):
3083    return obj.endswith(suffix)
3084
3085
3086@AST.makemethod
3087def _upper(obj):
3088    return obj.upper()
3089
3090
3091@AST.makemethod
3092def _lower(obj):
3093    return obj.lower()
3094
3095
3096@AST.makemethod
3097def _capitalize(obj):
3098    return obj.capitalize()
3099
3100
3101@AST.makemethod
3102def _replace(obj, old, new, count=None):
3103    if count is None:
3104        return obj.replace(old, new)
3105    else:
3106        return obj.replace(old, new, count)
3107
3108
3109@AST.makemethod
3110def _r(obj):
3111    return obj.r()
3112
3113
3114@AST.makemethod
3115def _g(obj):
3116    return obj.g()
3117
3118
3119@AST.makemethod
3120def _b(obj):
3121    return obj.b()
3122
3123
3124@AST.makemethod
3125def _a(obj):
3126    return obj.a()
3127
3128
3129@AST.makemethod
3130def _hls(obj):
3131    return obj.hls()
3132
3133
3134@AST.makemethod
3135def _hlsa(obj):
3136    return obj.hlsa()
3137
3138
3139@AST.makemethod
3140def _hsv(obj):
3141    return obj.hsv()
3142
3143
3144@AST.makemethod
3145def _hsva(obj):
3146    return obj.hsva()
3147
3148
3149@AST.makemethod
3150def _lum(obj):
3151    return obj.lum()
3152
3153
3154@AST.makemethod
3155def _weekday(obj):
3156    return obj.weekday()
3157
3158
3159@AST.makemethod
3160def _week(obj, firstweekday=None):
3161    if firstweekday is None:
3162        firstweekday = 0
3163    else:
3164        firstweekday %= 7
3165    jan1 = obj.__class__(obj.year, 1, 1)
3166    yearday = (obj - jan1).days+7
3167    jan1weekday = jan1.weekday()
3168    while jan1weekday != firstweekday:
3169        yearday -= 1
3170        jan1weekday += 1
3171        if jan1weekday == 7:
3172            jan1weekday = 0
3173    return yearday//7
3174
3175
3176@AST.makemethod
3177def _items(obj):
3178    yield from ()
3179    return obj.items()
3180
3181
3182@AST.makemethod
3183def _values(obj):
3184    yield from ()
3185    return obj.values()
3186
3187
3188@AST.makemethod
3189def _join(obj, iterable):
3190    return obj.join(iterable)
3191
3192
3193@AST.makemethod
3194def _render(obj, **vars):
3195    yield from obj.render(**vars)
3196
3197
3198@AST.makemethod
3199def _renders(obj, **vars):
3200    return obj.renders(**vars)
3201
3202
3203@AST.makemethod
3204def _mimeformat(obj):
3205    weekdayname = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
3206    monthname = (None, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
3207    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])
3208
3209
3210@AST.makemethod
3211def _isoformat(obj):
3212    result = obj.isoformat()
3213    suffix = "T00:00:00"
3214    if result.endswith(suffix):
3215        return result[:-len(suffix)]
3216    return result
3217
3218
3219@AST.makemethod
3220def _yearday(obj):
3221    return (obj - obj.__class__(obj.year, 1, 1)).days+1
3222
3223
3224@AST.makemethod
3225def _get(obj, key, default=None):
3226    return obj.get(key, default)
3227
3228
3229@AST.makemethod
3230def _withlum(obj, lum):
3231    return obj.withlum(lum)
3232
3233
3234@AST.makemethod
3235def _witha(obj, a):
3236    return obj.witha(a)
3237
3238
3239@AST.makemethod
3240def _day(obj):
3241    return obj.day
3242
3243
3244@AST.makemethod
3245def _month(obj):
3246    return obj.month
3247
3248
3249@AST.makemethod
3250def _year(obj):
3251    return obj.year
3252
3253
3254@AST.makemethod
3255def _hour(obj):
3256    return obj.hour
3257
3258
3259@AST.makemethod
3260def _minute(obj):
3261    return obj.minute
3262
3263
3264@AST.makemethod
3265def _second(obj):
3266    return obj.second
3267
3268
3269@AST.makemethod
3270def _microsecond(obj):
3271    return obj.microsecond
3272
3273
3274@AST.makemethod
3275def _days(obj):
3276    return obj.days
3277
3278
3279@AST.makemethod
3280def _seconds(obj):
3281    return obj.seconds
3282
3283
3284@AST.makemethod
3285def _microseconds(obj):
3286    return obj.microseconds
3287
3288
3289@AST.makemethod
3290def _months(obj):
3291    return obj.months
3292
3293
3294class TemplateClosure(Object):
3295    fields = {"location", "endlocation", "name", "source", "startdelim", "enddelim", "content"}
3296
3297    def __init__(self, template, vars):
3298        self.template = template
3299        # Freeze variables of the currently running templates/functions
3300        self.vars = vars.copy()
3301
3302    def render(self, **vars):
3303        return self.template.render(**collections.ChainMap(vars, self.vars))
3304
3305    def renders(self, **vars):
3306        return self.template.renders(**collections.ChainMap(vars, self.vars))
3307
3308    def __call__(self, **vars):
3309        return self.template(**collections.ChainMap(vars, self.vars))
3310
3311    def __getattr__(self, name):
3312        return getattr(self.template, name)
3313
3314    def __repr__(self):
3315        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} name={0.name!r} keepws={0.keepws!r}".format(self)
3316        if self.startdelim != "<?":
3317            s += " startdelim={0.startdelim!r}".format(self)
3318        if self.enddelim != "?>":
3319            s += " enddelim={0.enddelim!r}".format(self)
3320        if self.content:
3321            s + " ..."
3322        return s + " at {:#x}>".format(id(self))
3323
3324    def _repr_pretty_(self, p, cycle):
3325        if cycle:
3326            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
3327        else:
3328            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
3329                p.breakable()
3330                p.text("name=")
3331                p.pretty(self.name)
3332                p.breakable()
3333                p.text("keepws=")
3334                p.pretty(self.keepws)
3335                if self.startdelim != "<?":
3336                    p.breakable()
3337                    p.text("startdelim=")
3338                    p.pretty(self.startdelim)
3339                if self.enddelim != "?>":
3340                    p.breakable()
3341                    p.text("enddelim=")
3342                    p.pretty(self.enddelim)
3343                for node in self.content:
3344                    p.breakable()
3345                    p.pretty(node)
3346                p.breakable()
3347                p.text("at {:#x}".format(id(self)))
3348
3349
3350###
3351### Helper classes/functions used at runtime
3352###
3353
3354def _makedict(*items):
3355    result = {}
3356    for item in items:
3357        if len(item) == 1:
3358            result.update(item[0])
3359        else:
3360            result[item[0]] = item[1]
3361    return result
3362
3363
3364def _formatnestednameul4(name):
3365    if isinstance(name, str):
3366        return name
3367    elif len(name) == 1:
3368        return "({},)".format(_formatnestednameul4(name[0]))
3369    else:
3370        return "({})".format(", ".join(_formatnestednameul4(name) for name in name))
3371
3372
3373def _unpackvar(vars, name, value):
3374    if isinstance(name, str):
3375        vars[name] = value
3376    else:
3377        if len(name) > len(value):
3378            raise TypeError("too many values to unpack (expected {})".format(len(name)))
3379        elif len(name) < len(value):
3380            raise TypeError("need more than {} value{} to unpack)".format(len(values), "ss" if len(values) != 1 else ""))
3381        for (name, value) in zip(name, value):
3382            _unpackvar(vars, name, value)
Note: See TracBrowser for help on using the browser.