root/livinglogic.python.xist/src/ll/ul4c.py @ 5335:2eac802a9505

Revision 5335:2eac802a9505, 82.1 KB (checked in by Walter Doerwald <walter@…>, 7 years ago)

Add str method to AST (using True for keepws). Enhance Error message.

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