root/livinglogic.python.xist/src/ll/ul4c.py @ 5327:34b988b19c6d

Revision 5327:34b988b19c6d, 82.1 KB (checked in by Walter Doerwald <walter@…>, 7 years ago)

Add proper exception chaining, so that the user get's to see where the error happened.

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