root/livinglogic.python.xist/src/ll/ul4c.py @ 5345:d6cc4c625482

Revision 5345:d6cc4c625482, 80.5 KB (checked in by Walter Doerwald <walter@…>, 7 years ago)

Move stuff around.

Line 
1# -*- coding: utf-8 -*-
2
3## Copyright 2009-2013 by LivingLogic AG, Bayreuth/Germany
4## Copyright 2009-2013 by Walter Dörwald
5##
6## All Rights Reserved
7##
8## See ll/xist/__init__.py for the license
9
10
11"""
12:mod:`ll.ul4c` provides templating for XML/HTML as well as any other text-based
13format. A template defines placeholders for data output and basic logic (like
14loops and conditional blocks), that define how the final rendered output will
15look.
16
17:mod:`ll.ul4c` compiles a template to an internal format, which makes it
18possible to implement template renderers in multiple programming languages.
19"""
20
21
22__docformat__ = "reStructuredText"
23
24
25import re, types, datetime, urllib.parse as urlparse, json, collections, locale, itertools, random, datetime, unicodedata
26
27import antlr3
28
29from ll import color, misc
30
31
32# Regular expression used for splitting dates in isoformat
33datesplitter = re.compile("[-T:.]")
34
35
36def register(name):
37    from ll import ul4on
38    def registration(cls):
39        ul4on.register("de.livinglogic.ul4." + name)(cls)
40        cls.type = name
41        return cls
42    return registration
43
44
45class Object:
46    fields = {}
47
48    def __getitem__(self, key):
49        if key in self.fields:
50            return getattr(self, key)
51        raise KeyError(key)
52
53
54###
55### Location information
56###
57
58@register("location")
59class Location(Object):
60    """
61    A :class:`Location` object contains information about the location of a
62    template tag.
63    """
64    __slots__ = ("root", "source", "type", "starttag", "endtag", "startcode", "endcode")
65    fields = {"root", "source", "type", "starttag", "endtag", "startcode", "endcode", "tag", "code"}
66
67    def __init__(self, root=None, source=None, type=None, starttag=None, endtag=None, startcode=None, endcode=None):
68        """
69        Create a new :class:`Location` object. The arguments have the following
70        meaning:
71
72            :var:`root`
73                The :class:`Template` object
74
75            :var:`source`
76                The complete source string
77
78            :var:`type`
79                The tag type (i.e. ``"for"``, ``"if"``, etc. or ``None`` for
80                literal text)
81
82            :var:`starttag`
83                The start position of the start delimiter.
84
85            :var:`endtag`
86                The end position of the end delimiter.
87
88            :var:`startcode`
89                The start position of the tag code.
90
91            :var:`endcode`
92                The end position of the tag code.
93        """
94        self.root = root
95        self.source = source
96        self.type = type
97        self.starttag = starttag
98        self.endtag = endtag
99        self.startcode = startcode
100        self.endcode = endcode
101
102    @property
103    def code(self):
104        return self.source[self.startcode:self.endcode]
105
106    @property
107    def tag(self):
108        return self.source[self.starttag:self.endtag]
109
110    def __repr__(self):
111        return "<{}.{} {} at {:#x}>".format(self.__class__.__module__, self.__class__.__name__, self, id(self))
112
113    def pos(self):
114        lastlinefeed = self.source.rfind("\n", 0, self.starttag)
115        if lastlinefeed >= 0:
116            return (self.source.count("\n", 0, self.starttag)+1, self.starttag-lastlinefeed)
117        else:
118            return (1, self.starttag + 1)
119
120    def __str__(self):
121        (line, col) = self.pos()
122        return "{!r} at {}:{} (line {}, col {})".format(self.tag, self.starttag, self.endtag, line, col)
123
124    def ul4ondump(self, encoder):
125        encoder.dump(self.root)
126        encoder.dump(self.source)
127        encoder.dump(self.type)
128        encoder.dump(self.starttag)
129        encoder.dump(self.endtag)
130        encoder.dump(self.startcode)
131        encoder.dump(self.endcode)
132
133    def ul4onload(self, decoder):
134        self.root = decoder.load()
135        self.source = decoder.load()
136        self.type = decoder.load()
137        self.starttag = decoder.load()
138        self.endtag = decoder.load()
139        self.startcode = decoder.load()
140        self.endcode = decoder.load()
141
142
143###
144### Exceptions
145###
146
147class Error(Exception):
148    """
149    Exception class that wraps another exception and provides a location.
150    """
151    def __init__(self, location):
152        self.location = location
153
154    def __repr__(self):
155        return "<{}.{} in {} at {:#x}>".format(self.__class__.__module__, self.__class__.__name__, self.location, id(self))
156
157    def __str__(self):
158        if isinstance(self.location, (Template, TemplateClosure)):
159            if self.location.name is not None:
160                return "in template named {}".format(self.location.name)
161            else:
162                return "in unnamed template"
163        elif isinstance(self.location, AST):
164            return "in expression {}".format(self.location)
165        else:
166            return "in {}".format(self.location)
167
168
169class BlockError(Exception):
170    """
171    Exception that is raised by the compiler when an illegal block structure is
172    detected (e.g. an ``<?end if?>`` without a previous ``<?if?>``).
173    """
174
175    def __init__(self, message):
176        self.message = message
177
178    def __str__(self):
179        return self.message
180
181
182###
183### Exceptions used by the interpreted code for flow control
184###
185
186class BreakException(Exception):
187    pass
188
189
190class ContinueException(Exception):
191    pass
192
193
194class ReturnException(Exception):
195    def __init__(self, value):
196        self.value = value
197
198
199###
200### Various versions of undefined objects
201###
202
203class Undefined(object):
204    def __bool__(self):
205        return False
206
207    def __iter__(self):
208        raise TypeError("{!r} doesn't support iteration".format(self))
209
210    def __len__(self):
211        raise AttributeError("{!r} has no len()".format(self))
212
213    def __getattr__(self, key):
214        raise AttributeError("{!r} has no attribute {!r}".format(self, key))
215
216    def __getitem__(self, key):
217        raise TypeError("{!r} doesn't support indexing (key={!r})".format(self, key))
218
219
220class UndefinedKey(Undefined):
221    def __init__(self, key):
222        self.__key = key
223
224    def __repr__(self):
225        return "undefined object for key {!r}".format(self.__key)
226
227
228class UndefinedVariable(Undefined):
229    def __init__(self, name):
230        self.__name = name
231
232    def __repr__(self):
233        return "undefined variable {!r}".format(self.__name)
234
235
236class UndefinedIndex(Undefined):
237    def __init__(self, index):
238        self.__index = index
239
240    def __repr__(self):
241        return "undefined object at index {!r}".format(self.__index)
242
243
244###
245### Helper functions
246###
247
248
249def handleeval(f):
250    def wrapped(self, vars):
251        try:
252            return (yield from f(self, vars))
253        except (BreakException, ContinueException, ReturnException) as ex:
254            raise
255        except Exception as ex:
256            raise Error(self) from ex
257    return wrapped
258
259
260def _formatnestednameul4(name):
261    if isinstance(name, str):
262        return name
263    elif len(name) == 1:
264        return "({},)".format(_formatnestednameul4(name[0]))
265    else:
266        return "({})".format(", ".join(_formatnestednameul4(name) for name in name))
267
268
269
270def _unpackvar(vars, name, value):
271    if isinstance(name, str):
272        vars[name] = value
273    else:
274        if len(name) > len(value):
275            raise TypeError("too many values to unpack (expected {})".format(len(name)))
276        elif len(name) < len(value):
277            raise TypeError("need more than {} value{} to unpack)".format(len(values), "ss" if len(values) != 1 else ""))
278        for (name, value) in zip(name, value):
279            _unpackvar(vars, name, value)
280
281
282###
283### Compiler stuff: Nodes for the AST
284###
285
286class AST(Object):
287    """
288    Base class for all syntax tree nodes.
289    """
290    # used in :meth:`format` to decide if we need brackets around an operator
291    precedence = None
292    associative = True
293
294    # Set of attributes available via :meth:`getitem`.
295    fields = {"type", "location"}
296
297    # "Global" functions and methods. Functions in ``functions`` will be exposed to UL4 code
298    functions = {}
299    methods = {}
300
301    def __init__(self, location=None):
302        self.location = location
303
304    def __getitem__(self, key):
305        if key in self.fields:
306            return getattr(self, key)
307        raise KeyError(key)
308
309    def __repr__(self):
310        return "<{0.__class__.__module__}.{0.__class__.__qualname__} at {1:#x}>".format(self, id(self))
311
312    def _repr_pretty_(self, p, cycle):
313        p.text(repr(self))
314
315    def __str__(self):
316        return "".join(self._str(0))
317
318    def _formatop(self, op):
319        bracket = False
320        if op.precedence < self.precedence:
321            bracket = True
322        elif op.precedence == self.precedence and (not isinstance(op, self.__class__) or not self.associative):
323            bracket = True
324        if bracket:
325            yield "("
326        yield from op._str(0)
327        if bracket:
328            yield ")"
329
330    @misc.notimplemented
331    def _str(self, level):
332        """
333        Format :var:`self` (with the indentation level :var:`level`).
334
335        This is used by :meth:`__str__.
336        """
337
338    @misc.notimplemented
339    def eval(self, vars):
340        """
341        This evaluates the node.
342
343        This is a generator, which yields the text output of the node. If the
344        node returns a value (as most nodes do), this is done as the value of a
345        :exc:`StopIteration` exception.
346        """
347
348    def ul4ondump(self, encoder):
349        encoder.dump(self.location)
350
351    def ul4onload(self, decoder):
352        self.location = decoder.load()
353
354    @classmethod
355    def makefunction(cls, f):
356        name = f.__name__
357        if name.startswith("_"):
358            name = name[1:]
359        cls.functions[name] = f
360        return f
361
362    @classmethod
363    def makemethod(cls, f):
364        name = f.__name__
365        if name.startswith("_"):
366            name = name[1:]
367        cls.methods[name] = f
368        return f
369
370
371@register("text")
372class Text(AST):
373    """
374    AST node for literal text.
375    """
376
377    def text(self):
378        # If ``keepws`` is true, we output the literal text from the location info.
379        # Otherwise we have to strip linefeeds and indentation
380        text = self.location.code
381        if not self.location.root.keepws:
382            text = "".join(line.lstrip() for line in text.splitlines())
383        return text
384
385    def __repr__(self):
386        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {1!r} at {2:#x}>".format(self, self.text(), id(self))
387
388    def _str(self, level):
389        yield "text {!r}\n".format(self.text())
390
391    def eval(self, vars):
392        yield self.text()
393
394
395@register("const")
396class Const(AST):
397    """
398    Load a constant
399    """
400    precedence = 11
401    fields = AST.fields.union({"value"})
402
403    def __init__(self, location=None, value=None):
404        super().__init__(location)
405        self.value = value
406
407    def _str(self, level):
408        yield _repr(self.value)
409
410    def eval(self, vars):
411        yield from ()
412        return self.value
413
414    def ul4ondump(self, encoder):
415        super().ul4ondump(encoder)
416        encoder.dump(self.value)
417
418    def ul4onload(self, decoder):
419        super().ul4onload(decoder)
420        self.value = decoder.load()
421
422    def __repr__(self):
423        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.value!r} at {1:#x}>".format(self, id(self))
424
425
426@register("list")
427class List(AST):
428    """
429    AST nodes for loading a list object.
430    """
431
432    precedence = 11
433    fields = AST.fields.union({"items"})
434
435    def __init__(self, location=None, *items):
436        super().__init__(location)
437        self.items = list(items)
438
439    def __repr__(self):
440        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.items!r} at {1:#x}>".format(self, id(self))
441
442    def _repr_pretty_(self, p, cycle):
443        if cycle:
444            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
445        else:
446            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
447                for (i, item) in enumerate(self.items):
448                    if i:
449                        p.breakable()
450                    else:
451                        p.breakable("")
452                    p.pretty(item)
453                p.breakable()
454                p.text("at {:#x}".format(id(self)))
455
456    def _str(self, level):
457        yield "["
458        for (i, item) in enumerate(self.items):
459            if i:
460                yield ", "
461            yield from item._str(level)
462        yield "]"
463
464    @handleeval
465    def eval(self, vars):
466        result = []
467        for item in self.items:
468            item = (yield from item.eval(vars))
469            result.append(item)
470        return result
471
472    def ul4ondump(self, encoder):
473        super().ul4ondump(encoder)
474        encoder.dump(self.items)
475
476    def ul4onload(self, decoder):
477        super().ul4onload(decoder)
478        self.items = decoder.load()
479
480
481@register("listcomp")
482class ListComp(AST):
483    """
484    AST node for list comprehension.
485    """
486
487    precedence = 11
488    fields = AST.fields.union({"item", "varname", "container", "condition"})
489
490
491    def __init__(self, location=None, item=None, varname=None, container=None, condition=None):
492        super().__init__(location)
493        self.item = item
494        self.varname = varname
495        self.container = container
496        self.condition = condition
497
498    def __repr__(self):
499        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} item={0.item!r} varname={0.varname!r} container={0.container!r}".format(self)
500        if self.condition is not None:
501            s += " condition={0.condition!r}".format(self)
502        return s + " at {:#x}>".format(id(self))
503
504    def _repr_pretty_(self, p, cycle):
505        if cycle:
506            p.text("{0.__class__.__module__}.{0.__class__.__qualname__}(...)".format(self))
507        else:
508            with p.group(4, "{0.__class__.__module__}.{0.__class__.__qualname__}(".format(self), ")"):
509                p.breakable("")
510                p.text("item=")
511                p.pretty(self.item)
512                p.text(",")
513                p.breakable()
514                p.text("varname=")
515                p.pretty(self.varname)
516                p.text(",")
517                p.breakable()
518                p.text("container=")
519                p.pretty(self.container)
520                if self.condition is not None:
521                    p.text(",")
522                    p.breakable()
523                    p.text("condition=")
524                    p.pretty(self.condition)
525                p.breakable()
526                p.text("at {:#x}".format(id(self)))
527
528    def _str(self, level):
529        yield "["
530        yield from self.item._str(level)
531        yield " for "
532        yield _formatnestednameul4(self.varname)
533        yield " in "
534        yield from self.container._str(level)
535        if self.condition is not None:
536            yield " if "
537            yield from self.condition._str(level)
538        yield "]"
539
540    @handleeval
541    def eval(self, vars):
542        container = (yield from self.container.eval(vars))
543        vars = collections.ChainMap({}, vars) # Don't let loop variables leak into the surrounding scope
544        result = []
545        for item in container:
546            _unpackvar(vars, self.varname, item)
547            if self.condition is None or (yield from self.condition.eval(vars)):
548                item = (yield from self.item.eval(vars))
549                result.append(item)
550        return result
551
552    def ul4ondump(self, encoder):
553        super().ul4ondump(encoder)
554        encoder.dump(self.item)
555        encoder.dump(self.varname)
556        encoder.dump(self.container)
557        encoder.dump(self.condition)
558
559    def ul4onload(self, decoder):
560        super().ul4onload(decoder)
561        self.item = decoder.load()
562        self.varname = decoder.load()
563        self.container = decoder.load()
564        self.condition = decoder.load()
565
566
567@register("dict")
568class Dict(AST):
569    """
570    AST node for loading a dict object.
571    """
572
573    precedence = 11
574    fields = AST.fields.union({"items"})
575
576    def __init__(self, location=None, *items):
577        super().__init__(location)
578        self.items = list(items)
579
580    def __repr__(self):
581        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.items!r} at {1:#x}>".format(self, id(self))
582
583    def _repr_pretty_(self, p, cycle):
584        if cycle:
585            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
586        else:
587            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
588                for item in self.items:
589                    p.breakable()
590                    p.pretty(item[0])
591                    p.text("=")
592                    p.pretty(item[1])
593                p.breakable()
594                p.text("at {:#x}".format(id(self)))
595
596    def _str(self, level):
597        yield "{"
598        for (i, item) in enumerate(self.items):
599            if i:
600                yield ", "
601            yield from item[0]._str(level)
602            yield ": "
603            yield from item[1]._str(level)
604        yield "}"
605
606    @handleeval
607    def eval(self, vars):
608        result = {}
609        for item in self.items:
610            key = (yield from item[0].eval(vars))
611            value = (yield from item[1].eval(vars))
612            result[key] = value
613        return result
614
615    def ul4ondump(self, encoder):
616        super().ul4ondump(encoder)
617        encoder.dump(self.items)
618
619    def ul4onload(self, decoder):
620        super().ul4onload(decoder)
621        self.items = [tuple(item) for item in decoder.load()]
622
623
624@register("dictcomp")
625class DictComp(AST):
626    """
627    AST node for dictionary comprehension.
628    """
629
630    precedence = 11
631    fields = AST.fields.union({"key", "value", "varname", "container", "condition"})
632
633    def __init__(self, location=None, key=None, value=None, varname=None, container=None, condition=None):
634        super().__init__(location)
635        self.key = key
636        self.value = value
637        self.varname = varname
638        self.container = container
639        self.condition = condition
640
641    def __repr__(self):
642        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)
643        if self.condition is not None:
644            s += " {0.condition!r}".format(self)
645        return s + " at {:#x}>".format(id(self))
646
647    def _repr_pretty_(self, p, cycle):
648        if cycle:
649            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
650        else:
651            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
652                p.breakable()
653                p.text("key=")
654                p.pretty(self.key)
655                p.breakable()
656                p.text("value=")
657                p.pretty(self.value)
658                p.breakable()
659                p.text("varname=")
660                p.pretty(self.varname)
661                p.breakable()
662                p.text("container=")
663                p.pretty(self.container)
664                if self.condition is not None:
665                    p.breakable()
666                    p.text("condition=")
667                    p.pretty(self.condition)
668                p.breakable()
669                p.text("at {:#x}".format(id(self)))
670
671    def _str(self, level):
672        yield "{"
673        yield from self.key._str(level)
674        yield " : "
675        yield from self.value._str(level)
676        yield " for "
677        yield _formatnestednameul4(self.varname)
678        yield " in "
679        yield from self.container._str(level)
680        if self.condition is not None:
681            yield " if "
682            yield from self.condition._str(level)
683        yield "]"
684
685    @handleeval
686    def eval(self, vars):
687        container = (yield from self.container.eval(vars))
688        vars = collections.ChainMap({}, vars) # Don't let loop variables leak into the surrounding scope
689        result = {}
690        for item in container:
691            _unpackvar(vars, self.varname, item)
692            if self.condition is None or (yield from self.condition.eval(vars)):
693                key = (yield from self.key.eval(vars))
694                value = (yield from self.value.eval(vars))
695                result[key] = value
696        return result
697
698    def ul4ondump(self, encoder):
699        super().ul4ondump(encoder)
700        encoder.dump(self.key)
701        encoder.dump(self.value)
702        encoder.dump(self.varname)
703        encoder.dump(self.container)
704        encoder.dump(self.condition)
705
706    def ul4onload(self, decoder):
707        super().ul4onload(decoder)
708        self.key = decoder.load()
709        self.value = decoder.load()
710        self.varname = decoder.load()
711        self.container = decoder.load()
712        self.condition = decoder.load()
713
714
715@register("genexpr")
716class GenExpr(AST):
717    """
718    AST node for a generator expression.
719    """
720
721    precedence = 11
722    fields = AST.fields.union({"item", "varname", "container", "condition"})
723
724    def __init__(self, location=None, item=None, varname=None, container=None, condition=None):
725        super().__init__(location)
726        self.item = item
727        self.varname = varname
728        self.container = container
729        self.condition = condition
730
731    def __repr__(self):
732        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} item={0.item!r} varname={0.varname!r} container={0.container!r}".format(self)
733        if self.condition is not None:
734            s += " condition={0.condition!r}".format(self)
735        return s + " at {:#x}>".format(id(self))
736
737    def _repr_pretty_(self, p, cycle):
738        if cycle:
739            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
740        else:
741            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
742                p.breakable()
743                p.text("item=")
744                p.pretty(self.item)
745                p.breakable()
746                p.text("varname=")
747                p.pretty(self.varname)
748                p.breakable()
749                p.text("container=")
750                p.pretty(self.container)
751                if self.condition is not None:
752                    p.breakable()
753                    p.text("condition=")
754                    p.pretty(self.condition)
755                p.breakable()
756                p.text("at {:#x}".format(id(self)))
757
758    def _str(self, level):
759        yield "("
760        yield from self.item._str(level)
761        yield " for "
762        yield _formatnestednameul4(self.varname)
763        yield " in "
764        yield from self.container._str(level)
765        if self.condition is not None:
766            yield " if "
767            yield from self.condition._str(level)
768        yield ")"
769
770    @handleeval
771    def eval(self, vars):
772        container = (yield from self.container.eval(vars))
773        vars = collections.ChainMap({}, vars) # Don't let loop variables leak into the surrounding scope
774        def result():
775            for item in container:
776                _unpackvar(vars, self.varname, item)
777                if self.condition is None or (yield from self.condition.eval(vars)):
778                    item = (yield from self.item.eval(vars))
779                    yield item
780        return result()
781
782    def ul4ondump(self, encoder):
783        super().ul4ondump(encoder)
784        encoder.dump(self.item)
785        encoder.dump(self.varname)
786        encoder.dump(self.container)
787        encoder.dump(self.condition)
788
789    def ul4onload(self, decoder):
790        super().ul4onload(decoder)
791        self.item = decoder.load()
792        self.varname = decoder.load()
793        self.container = decoder.load()
794        self.condition = decoder.load()
795
796
797@register("var")
798class Var(AST):
799    """
800    AST nodes for loading a variable.
801    """
802
803    precedence = 11
804    fields = AST.fields.union({"name"})
805
806    def __init__(self, location=None, name=None):
807        super().__init__(location)
808        self.name = name
809
810    def __repr__(self):
811        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.name!r} at {1:#x}>".format(self, id(self))
812
813    def _str(self, level):
814        yield self.name
815
816    @handleeval
817    def eval(self, vars):
818        yield from ()
819        try:
820            return vars[self.name]
821        except KeyError:
822            try:
823                return self.functions[self.name]
824            except KeyError:
825                return UndefinedVariable(self.name)
826
827    def ul4ondump(self, encoder):
828        super().ul4ondump(encoder)
829        encoder.dump(self.name)
830
831    def ul4onload(self, decoder):
832        super().ul4onload(decoder)
833        self.name = decoder.load()
834
835
836class Block(AST):
837    """
838    Base class for all AST nodes that are blocks.
839
840    A block contains a sequence of AST nodes that are executed sequencially.
841    A block may execute its content zero (e.g. an ``<?if?>`` block) or more times
842    (e.g. a ``<?for?>`` block).
843    """
844
845    fields = AST.fields.union({"endlocation", "content"})
846
847    def __init__(self, location=None):
848        super().__init__(location)
849        self.endlocation = None
850        self.content = []
851
852    def append(self, item):
853        self.content.append(item)
854
855    def _str(self, level):
856        if self.content:
857            for node in self.content:
858                yield level*"\t"
859                yield from node._str(level)
860                yield "\n"
861        else:
862            yield level*"\t"
863            yield "pass\n"
864
865    @handleeval
866    def eval(self, vars):
867        for node in self.content:
868            yield from node.eval(vars)
869
870    def ul4ondump(self, encoder):
871        super().ul4ondump(encoder)
872        encoder.dump(self.endlocation)
873        encoder.dump(self.content)
874
875    def ul4onload(self, decoder):
876        super().ul4onload(decoder)
877        self.endlocation = decoder.load()
878        self.content = decoder.load()
879
880
881@register("ieie")
882class IfElIfElse(Block):
883    """
884    AST node for an conditional block.
885
886    The content of the :class:`IfElIfElse` block is one :class:`If` block
887    followed by zero or more :class:`ElIf` blocks followed by zero or one
888    :class:`Else` block.
889    """
890    def __init__(self, location=None, condition=None):
891        super().__init__(location)
892        if condition is not None:
893            self.newblock(If(location, condition))
894
895    def __repr__(self):
896        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {1} at {2:#x}>".format(self, repr(self.content)[1:-1], id(self))
897
898    def _repr_pretty_(self, p, cycle):
899        if cycle:
900            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
901        else:
902            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
903                for node in self.content:
904                    p.breakable()
905                    p.pretty(node)
906                p.breakable()
907                p.text("at {:#x}".format(id(self)))
908
909    def append(self, item):
910        self.content[-1].append(item)
911
912    def newblock(self, block):
913        if self.content:
914            self.content[-1].endlocation = block.location
915        self.content.append(block)
916
917    @handleeval
918    def eval(self, vars):
919        for node in self.content:
920            if isinstance(node, Else) or (yield from node.condition.eval(vars)):
921                yield from node.eval(vars)
922                break
923
924
925@register("if")
926class If(Block):
927    """
928    AST node for an ``<?if?>`` block.
929    """
930
931    fields = Block.fields.union({"condition"})
932
933    def __init__(self, location=None, condition=None):
934        super().__init__(location)
935        self.condition = condition
936
937    def __repr__(self):
938        return "<{0.__class__.__module__}.{0.__class__.__qualname__} condition={0.condition!r} {1} at {2:#x}>".format(self, " ..." if self.content else "", id(self))
939
940    def _repr_pretty_(self, p, cycle):
941        if cycle:
942            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
943        else:
944            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
945                p.breakable()
946                p.text("condition=")
947                p.pretty(self.condition)
948                for node in self.content:
949                    p.breakable()
950                    p.pretty(node)
951                p.breakable()
952                p.text("at {:#x}".format(id(self)))
953
954    def _str(self, level):
955        yield "if "
956        yield from self.condition._str(level)
957        yield ":\n"
958        yield from super()._str(level+1)
959
960    def ul4ondump(self, encoder):
961        super().ul4ondump(encoder)
962        encoder.dump(self.condition)
963
964    def ul4onload(self, decoder):
965        super().ul4onload(decoder)
966        self.condition = decoder.load()
967
968
969@register("elif")
970class ElIf(Block):
971    """
972    AST node for an ``<?elif?>`` block.
973    """
974
975    fields = Block.fields.union({"condition"})
976
977    def __init__(self, location=None, condition=None):
978        super().__init__(location)
979        self.condition = condition
980
981    def __repr__(self):
982        return "<{0.__class__.__module__}.{0.__class__.__qualname__} condition={0.condition!r} {1} at {2:#x}>".format(self, " ..." if self.content else "", id(self))
983
984    def _repr_pretty_(self, p, cycle):
985        if cycle:
986            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
987        else:
988            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
989                p.breakable()
990                p.text("condition=")
991                p.pretty(self.condition)
992                for node in self.content:
993                    p.breakable()
994                    p.pretty(node)
995                p.breakable()
996                p.text("at {:#x}".format(id(self)))
997
998    def _str(self, level):
999        yield "elif "
1000        yield from self.condition._str(level)
1001        yield ":\n"
1002        yield from super()._str(level+1)
1003
1004    def ul4ondump(self, encoder):
1005        super().ul4ondump(encoder)
1006        encoder.dump(self.condition)
1007
1008    def ul4onload(self, decoder):
1009        super().ul4onload(decoder)
1010        self.condition = decoder.load()
1011
1012
1013@register("else")
1014class Else(Block):
1015    """
1016    AST node for an ``<?else?>`` block.
1017    """
1018
1019    def __repr__(self):
1020        return "<{0.__class__.__module__}.{0.__class__.__qualname__} condition={0.condition!r} at {1:#x}>".format(self, id(self))
1021
1022    def _repr_pretty_(self, p, cycle):
1023        if cycle:
1024            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1025        else:
1026            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
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 _str(self, level):
1034        yield "else:\n"
1035        yield from super()._str(level+1)
1036
1037
1038@register("for")
1039class For(Block):
1040    """
1041    AST node for a ``<?for?>`` loop variable.
1042    """
1043
1044    fields = Block.fields.union({"varname", "container"})
1045
1046    def __init__(self, location=None, varname=None, container=None):
1047        super().__init__(location)
1048        self.varname = varname
1049        self.container = container
1050
1051    def __repr__(self):
1052        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))
1053
1054    def _repr_pretty_(self, p, cycle):
1055        if cycle:
1056            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1057        else:
1058            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1059                p.breakable()
1060                p.text("varname=")
1061                p.pretty(self.varname)
1062                p.breakable()
1063                p.text("container=")
1064                p.pretty(self.container)
1065                for node in self.content:
1066                    p.breakable()
1067                    p.pretty(node)
1068                p.breakable()
1069                p.text("at {:#x}".format(id(self)))
1070
1071    def ul4ondump(self, encoder):
1072        super().ul4ondump(encoder)
1073        encoder.dump(self.varname)
1074        encoder.dump(self.container)
1075
1076    def ul4onload(self, decoder):
1077        super().ul4onload(decoder)
1078        self.varname = decoder.load()
1079        self.container = decoder.load()
1080
1081    def _str(self, level):
1082        yield "for "
1083        yield _formatnestednameul4(self.varname)
1084        yield " in "
1085        yield from self.container._str(level)
1086        yield ":\n"
1087        yield from super()._str(level+1)
1088
1089    @handleeval
1090    def eval(self, vars):
1091        container = (yield from self.container.eval(vars))
1092        vars = collections.ChainMap({}, vars) # Don't let loop variables leak into the surrounding scope
1093        for item in container:
1094            _unpackvar(vars, self.varname, item)
1095            try:
1096                yield from super().eval(vars)
1097            except BreakException:
1098                break
1099            except ContinueException:
1100                pass
1101
1102
1103@register("break")
1104class Break(AST):
1105    """
1106    AST node for a ``<?break?>`` inside a ``<?for?>`` block.
1107    """
1108
1109    def _str(self, level):
1110        yield "break\n"
1111
1112    def eval(self, vars):
1113        yield from ()
1114        raise BreakException()
1115
1116
1117@register("continue")
1118class Continue(AST):
1119    """
1120    AST node for a ``<?continue?>`` inside a ``<?for?>`` block.
1121    """
1122
1123    def _str(self, level):
1124        yield "continue\n"
1125
1126    def eval(self, vars):
1127        yield from ()
1128        raise ContinueException()
1129
1130
1131@register("getattr")
1132class GetAttr(AST):
1133    """
1134    AST node for getting an attribute from an object.
1135
1136    The object is loaded from the AST node :var:`obj` and the attribute name
1137    is stored in the string :var:`attrname`.
1138    """
1139    precedence = 9
1140    associative = False
1141    fields = AST.fields.union({"obj", "attrname"})
1142
1143    def __init__(self, location=None, obj=None, attrname=None):
1144        super().__init__(location)
1145        self.obj = obj
1146        self.attrname = attrname
1147
1148    def __repr__(self):
1149        return "<{0.__class__.__module__}.{0.__class__.__qualname__} obj={0.obj!r}, attrname={0.attrname!r} at {1:#x}>".format(self, id(self))
1150
1151    def _repr_pretty_(self, p, cycle):
1152        if cycle:
1153            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1154        else:
1155            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1156                p.breakable()
1157                p.text("obj=")
1158                p.pretty(self.obj)
1159                p.breakable()
1160                p.text("attrname=")
1161                p.pretty(self.attrname)
1162                p.breakable()
1163                p.text("at {:#x}".format(id(self)))
1164
1165    def _str(self, level):
1166        yield from self._formatop(self.obj)
1167        yield "."
1168        yield self.attrname
1169
1170    @handleeval
1171    def eval(self, vars):
1172        obj = (yield from self.obj.eval(vars))
1173        try:
1174            return obj[self.attrname]
1175        except KeyError:
1176            return UndefinedKey(self.attrname)
1177
1178    def ul4ondump(self, encoder):
1179        super().ul4ondump(encoder)
1180        encoder.dump(self.obj)
1181        encoder.dump(self.attrname)
1182
1183    def ul4onload(self, decoder):
1184        super().ul4onload(decoder)
1185        self.obj = decoder.load()
1186        self.attrname = decoder.load()
1187
1188
1189@register("getslice")
1190class GetSlice(AST):
1191    """
1192    AST node for getting a slice from a list or string object.
1193
1194    The object is loaded from the AST node :var:`obj` and the start and stop
1195    indices from the AST node :var:`index1` and :var:`index2`. :var:`index1`
1196    and :var:`index2` may also be :const:`None` (for missing slice indices,
1197    which default to the 0 for the start index and the length of the sequence
1198    for the end index).
1199    """
1200
1201    precedence = 8
1202    associative = False
1203    fields = AST.fields.union({"obj", "index1", "index2"})
1204
1205    def __init__(self, location=None, obj=None, index1=None, index2=None):
1206        super().__init__(location)
1207        self.obj = obj
1208        self.index1 = index1
1209        self.index2 = index2
1210
1211    def __repr__(self):
1212        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))
1213
1214    def _repr_pretty_(self, p, cycle):
1215        if cycle:
1216            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1217        else:
1218            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1219                p.breakable()
1220                p.text("obj=")
1221                p.pretty(self.obj)
1222                p.breakable()
1223                p.text("index1=")
1224                p.pretty(self.index1)
1225                p.breakable()
1226                p.text("index2=")
1227                p.pretty(self.index2)
1228                p.breakable()
1229                p.text("at {:#x}".format(id(self)))
1230
1231    def _str(self, level):
1232        yield from self._formatop(self.obj)
1233        yield "["
1234        if self.index1 is not None:
1235            yield from self.index1._str(level)
1236        yield ":"
1237        if self.index2 is not None:
1238            yield from self.index2._str(level)
1239        yield "]"
1240
1241    @handleeval
1242    def eval(self, vars):
1243        obj = (yield from self.obj.eval(vars))
1244        if self.index1 is not None:
1245            index1 = (yield from self.index1.eval(vars))
1246            if self.index2 is not None:
1247                index2 = (yield from self.index2.eval(vars))
1248                return obj[index1:index2]
1249            else:
1250                return obj[index1:]
1251        else:
1252            if self.index2 is not None:
1253                index2 = (yield from self.index2.eval(vars))
1254                return obj[:index2]
1255            else:
1256                return obj[:]
1257
1258    def ul4ondump(self, encoder):
1259        super().ul4ondump(encoder)
1260        encoder.dump(self.obj)
1261        encoder.dump(self.index1)
1262        encoder.dump(self.index2)
1263
1264    def ul4onload(self, decoder):
1265        super().ul4onload(decoder)
1266        self.obj = decoder.load()
1267        self.index1 = decoder.load()
1268        self.index2 = decoder.load()
1269
1270
1271class Unary(AST):
1272    """
1273    Base class for all AST nodes implementing unary operators.
1274    """
1275
1276    fields = AST.fields.union({"obj"})
1277
1278    def __init__(self, location=None, obj=None):
1279        super().__init__(location)
1280        self.obj = obj
1281
1282    def __repr__(self):
1283        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.obj!r} at {1:#x}>".format(self, id(self))
1284
1285    def _repr_pretty_(self, p, cycle):
1286        if cycle:
1287            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1288        else:
1289            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1290                p.breakable()
1291                p.pretty(self.obj)
1292                p.breakable()
1293                p.text("at {:#x}".format(id(self)))
1294
1295    def ul4ondump(self, encoder):
1296        super().ul4ondump(encoder)
1297        encoder.dump(self.obj)
1298
1299    def ul4onload(self, decoder):
1300        super().ul4onload(decoder)
1301        self.obj = decoder.load()
1302
1303    @handleeval
1304    def eval(self, vars):
1305        obj = (yield from self.obj.eval(vars))
1306        return self.evalfold(obj)
1307
1308    @classmethod
1309    def make(cls, location, obj):
1310        if isinstance(obj, Const):
1311            result = cls.evalfold(obj.value)
1312            if not isinstance(result, Undefined):
1313                return Const(location, result)
1314        return cls(location, obj)
1315
1316
1317@register("not")
1318class Not(Unary):
1319    """
1320    AST node for the unary ``not`` operator.
1321    """
1322
1323    precedence = 2
1324
1325    def _str(self, level):
1326        yield "not "
1327        yield from self._formatop(self.obj)
1328
1329    @classmethod
1330    def evalfold(cls, obj):
1331        return not obj
1332
1333
1334@register("neg")
1335class Neg(Unary):
1336    """
1337    AST node for the unary negation (i.e. "-") operator.
1338    """
1339
1340    precedence = 7
1341
1342    def _str(self, level):
1343        yield "-"
1344        yield from self._formatop(self.obj)
1345
1346    @classmethod
1347    def evalfold(cls, obj):
1348        return -obj
1349
1350
1351@register("print")
1352class Print(Unary):
1353    """
1354    AST node for a ``<?print?>`` tag.
1355    """
1356
1357    def _str(self, level):
1358        yield "print "
1359        yield from self.obj._str(level)
1360
1361    @handleeval
1362    def eval(self, vars):
1363        yield _str((yield from self.obj.eval(vars)))
1364
1365
1366@register("printx")
1367class PrintX(Unary):
1368    """
1369    AST node for a ``<?printx?>`` tag.
1370    """
1371
1372    def _str(self, level):
1373        yield "printx "
1374        yield from self.obj._str(level)
1375
1376    @handleeval
1377    def eval(self, vars):
1378        yield _xmlescape((yield from self.obj.eval(vars)))
1379
1380
1381@register("return")
1382class Return(Unary):
1383    """
1384    AST node for a ``<?return?>`` tag.
1385    """
1386
1387    def _str(self, level):
1388        yield "return "
1389        yield from self.obj._str(level)
1390
1391    @handleeval
1392    def eval(self, vars):
1393        value = (yield from self.obj.eval(vars))
1394        raise ReturnException(value)
1395
1396
1397class Binary(AST):
1398    """
1399    Base class for all AST nodes implementing binary operators.
1400    """
1401
1402    fields = AST.fields.union({"obj1", "obj2"})
1403
1404    def __init__(self, location=None, obj1=None, obj2=None):
1405        super().__init__(location)
1406        self.obj1 = obj1
1407        self.obj2 = obj2
1408
1409    def __repr__(self):
1410        return "<{0.__class__.__module__}.{0.__class__.__qualname__} {0.obj1!r} {0.obj2!r} at {1:#x}>".format(self, id(self))
1411
1412    def _repr_pretty_(self, p, cycle):
1413        if cycle:
1414            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1415        else:
1416            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1417                p.breakable()
1418                p.pretty(self.obj1)
1419                p.breakable()
1420                p.pretty(self.obj2)
1421                p.breakable()
1422                p.text("at {:#x}".format(id(self)))
1423
1424    def ul4ondump(self, encoder):
1425        super().ul4ondump(encoder)
1426        encoder.dump(self.obj1)
1427        encoder.dump(self.obj2)
1428
1429    def ul4onload(self, decoder):
1430        super().ul4onload(decoder)
1431        self.obj1 = decoder.load()
1432        self.obj2 = decoder.load()
1433
1434    @handleeval
1435    def eval(self, vars):
1436        obj1 = (yield from self.obj1.eval(vars))
1437        obj2 = (yield from self.obj2.eval(vars))
1438        return self.evalfold(obj1, obj2)
1439
1440    @classmethod
1441    def make(cls, location, obj1, obj2):
1442        if isinstance(obj1, Const) and isinstance(obj2, Const):
1443            result = cls.evalfold(obj1.value, obj2.value)
1444            if not isinstance(result, Undefined):
1445                return Const(location, result)
1446        return cls(location, obj1, obj2)
1447
1448
1449@register("getitem")
1450class GetItem(Binary):
1451    """
1452    AST node for subscripting operator.
1453
1454    The object (which must be a list, string or dict) is loaded from the AST
1455    node :var:`obj1` and the index/key is loaded from the AST node :var:`obj2`.
1456    """
1457
1458    precedence = 9
1459    associative = False
1460
1461    @classmethod
1462    def evaluate(cls, obj1, obj2):
1463        return obj1[obj2]
1464
1465    def _str(self, level):
1466        yield from self.obj1._str(level)
1467        yield "["
1468        yield from self.obj2._str(level)
1469        yield "]"
1470
1471    @classmethod
1472    def evalfold(cls, obj1, obj2):
1473        try:
1474            return obj1[obj2]
1475        except KeyError:
1476            return UndefinedKey(obj2)
1477        except IndexError:
1478            return UndefinedIndex(obj2)
1479
1480
1481@register("eq")
1482class EQ(Binary):
1483    """
1484    AST node for the binary ``==`` comparison operator.
1485    """
1486
1487    precedence = 4
1488    associative = False
1489
1490    def _str(self, level):
1491        yield from self._formatop(self.obj1)
1492        yield " == "
1493        yield from self._formatop(self.obj2)
1494
1495    @classmethod
1496    def evalfold(cls, obj1, obj2):
1497        return obj1 == obj2
1498
1499
1500@register("ne")
1501class NE(Binary):
1502    """
1503    AST node for the binary ``!=`` comparison operator.
1504    """
1505
1506    precedence = 4
1507    associative = False
1508
1509    def _str(self, level):
1510        yield from self._formatop(self.obj1)
1511        yield " != "
1512        yield from self._formatop(self.obj2)
1513
1514    @classmethod
1515    def evalfold(cls, obj1, obj2):
1516        return obj1 != obj2
1517
1518
1519@register("lt")
1520class LT(Binary):
1521    """
1522    AST node for the binary ``<`` comparison operator.
1523    """
1524
1525    precedence = 4
1526    associative = False
1527
1528    def _str(self, level):
1529        yield from self._formatop(self.obj1)
1530        yield " < "
1531        yield from self._formatop(self.obj2)
1532
1533    @classmethod
1534    def evalfold(cls, obj1, obj2):
1535        return obj1 < obj2
1536
1537
1538@register("le")
1539class LE(Binary):
1540    """
1541    AST node for the binary ``<=`` comparison operator.
1542    """
1543
1544    precedence = 4
1545    associative = False
1546
1547    def _str(self, level):
1548        yield from self._formatop(self.obj1)
1549        yield " <= "
1550        yield from self._formatop(self.obj2)
1551
1552    @classmethod
1553    def evalfold(cls, obj1, obj2):
1554        return obj1 <= obj2
1555
1556
1557@register("gt")
1558class GT(Binary):
1559    """
1560    AST node for the binary ``>`` comparison operator.
1561    """
1562
1563    precedence = 4
1564    associative = False
1565
1566    def _str(self, level):
1567        yield from self._formatop(self.obj1)
1568        yield " > "
1569        yield from self._formatop(self.obj2)
1570
1571    @classmethod
1572    def evalfold(cls, obj1, obj2):
1573        return obj1 > obj2
1574
1575
1576@register("ge")
1577class GE(Binary):
1578    """
1579    AST node for the binary ``>=`` comparison operator.
1580    """
1581
1582    precedence = 4
1583    associative = False
1584
1585    def _str(self, level):
1586        yield from self._formatop(self.obj1)
1587        yield " >= "
1588        yield from self._formatop(self.obj2)
1589
1590    @classmethod
1591    def evalfold(cls, obj1, obj2):
1592        return obj1 >= obj2
1593
1594
1595@register("contains")
1596class Contains(Binary):
1597    """
1598    AST node for the binary containment testing operator.
1599
1600    The item/key object is loaded from the AST node :var:`obj1` and the container
1601    object (which must be a list, string or dict) is loaded from the AST node
1602    :var:`obj2`.
1603    """
1604
1605    precedence = 3
1606    associative = False
1607
1608    def _str(self, level):
1609        yield from self._formatop(self.obj1)
1610        yield " in "
1611        yield from self._formatop(self.obj2)
1612
1613    @classmethod
1614    def evalfold(cls, obj1, obj2):
1615        return obj1 in obj2
1616
1617
1618@register("notcontains")
1619class NotContains(Binary):
1620    """
1621    AST node for the inverted containment testing operator.
1622
1623    The item/key object is loaded from the AST node :var:`obj1` and the container
1624    object (which must be a list, string or dict) is loaded from the AST node
1625    :var:`obj2`.
1626    """
1627
1628    precedence = 3
1629    associative = False
1630
1631    def _str(self, level):
1632        yield from self._formatop(self.obj1)
1633        yield " not in "
1634        yield from self._formatop(self.obj2)
1635
1636    @classmethod
1637    def evalfold(cls, obj1, obj2):
1638        return obj1 not in obj2
1639
1640
1641@register("add")
1642class Add(Binary):
1643    """
1644    AST node for the binary addition operator.
1645    """
1646
1647    precedence = 5
1648
1649    def _str(self, level):
1650        yield from self._formatop(self.obj1)
1651        yield "+"
1652        yield from self._formatop(self.obj2)
1653
1654    @classmethod
1655    def evalfold(cls, obj1, obj2):
1656        return obj1 + obj2
1657
1658
1659@register("sub")
1660class Sub(Binary):
1661    """
1662    AST node for the binary substraction operator.
1663    """
1664
1665    precedence = 5
1666    associative = False
1667
1668    def _str(self, level):
1669        yield from self._formatop(self.obj1)
1670        yield "-"
1671        yield from self._formatop(self.obj2)
1672
1673    @classmethod
1674    def evalfold(cls, obj1, obj2):
1675        return obj1 - obj2
1676
1677
1678@register("mul")
1679class Mul(Binary):
1680    """
1681    AST node for the binary multiplication operator.
1682    """
1683
1684    precedence = 6
1685
1686    def _str(self, level):
1687        yield from self._formatop(self.obj1)
1688        yield "*"
1689        yield from self._formatop(self.obj2)
1690
1691    @classmethod
1692    def evalfold(cls, obj1, obj2):
1693        return obj1 * obj2
1694
1695
1696@register("floordiv")
1697class FloorDiv(Binary):
1698    """
1699    AST node for the binary truncating division operator.
1700    """
1701
1702    precedence = 6
1703    associative = False
1704
1705    def _str(self, level):
1706        yield from self._formatop(self.obj1)
1707        yield "//"
1708        yield from self._formatop(self.obj2)
1709
1710    @classmethod
1711    def evalfold(cls, obj1, obj2):
1712        return obj1 // obj2
1713
1714
1715@register("truediv")
1716class TrueDiv(Binary):
1717    """
1718    AST node for the binary true division operator.
1719    """
1720
1721    precedence = 6
1722    associative = False
1723
1724    def _str(self, level):
1725        yield from self._formatop(self.obj1)
1726        yield "/"
1727        yield from self._formatop(self.obj2)
1728
1729    @classmethod
1730    def evalfold(cls, obj1, obj2):
1731        return obj1 / obj2
1732
1733
1734@register("and")
1735class And(Binary):
1736    """
1737    AST node for the binary ``and`` operator.
1738    """
1739
1740    precedence = 1
1741
1742    def _str(self, level):
1743        yield from self._formatop(self.obj1)
1744        yield " and "
1745        yield from self._formatop(self.obj2)
1746
1747    @classmethod
1748    def evalfold(cls, obj1, obj2):
1749        # This is not called from ``eval``, as it doesn't short-circuit
1750        return obj1 and obj2
1751
1752    @handleeval
1753    def eval(self, vars):
1754        obj1 = (yield from self.obj1.eval(vars))
1755        if not obj1:
1756            return obj1
1757        return (yield from self.obj2.eval(vars))
1758
1759
1760
1761@register("or")
1762class Or(Binary):
1763    """
1764    AST node for the binary ``or`` operator.
1765    """
1766
1767    precedence = 0
1768
1769    def _str(self, level):
1770        yield from self._formatop(self.obj1)
1771        yield " or "
1772        yield from self._formatop(self.obj2)
1773
1774    @classmethod
1775    def evalfold(cls, obj1, obj2):
1776        # This is not called from ``eval``, as it doesn't short-circuit
1777        return obj1 or obj2
1778
1779    @handleeval
1780    def eval(self, vars):
1781        obj1 = (yield from self.obj1.eval(vars))
1782        if obj1:
1783            return obj1
1784        return (yield from self.obj2.eval(vars))
1785
1786
1787@register("mod")
1788class Mod(Binary):
1789    """
1790    AST node for the binary modulo operator.
1791    """
1792
1793    precedence = 6
1794    associative = False
1795
1796    def _str(self, level):
1797        yield from self._formatop(self.obj1)
1798        yield "%"
1799        yield from self._formatop(self.obj2)
1800
1801    @classmethod
1802    def evalfold(cls, obj1, obj2):
1803        return obj1 % obj2
1804
1805
1806class ChangeVar(AST):
1807    """
1808    Baseclass for all AST nodes that store or modify a variable.
1809
1810    The variable name is stored in the string :var:`varname` and the value that
1811    will be stored or be used to modify the stored value is loaded from the
1812    AST node :var:`value`.
1813    """
1814
1815    fields = AST.fields.union({"varname", "value"})
1816
1817    def __init__(self, location=None, varname=None, value=None):
1818        super().__init__(location)
1819        self.varname = varname
1820        self.value = value
1821
1822    def __repr__(self):
1823        return "<{0.__class__.__module__}.{0.__class__.__qualname__} varname={0.varname!r} value={0.value!r} at {1:#x}>".format(self, id(self))
1824
1825    def _repr_pretty_(self, p, cycle):
1826        if cycle:
1827            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
1828        else:
1829            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
1830                p.breakable()
1831                p.text("varname=")
1832                p.pretty(self.obj1)
1833                p.text("value=")
1834                p.breakable()
1835                p.pretty(self.obj2)
1836                p.breakable()
1837                p.text("at {:#x}".format(id(self)))
1838
1839    def ul4ondump(self, encoder):
1840        super().ul4ondump(encoder)
1841        encoder.dump(self.varname)
1842        encoder.dump(self.value)
1843
1844    def ul4onload(self, decoder):
1845        super().ul4onload(decoder)
1846        self.varname = decoder.load()
1847        self.value = decoder.load()
1848
1849
1850@register("storevar")
1851class StoreVar(ChangeVar):
1852    """
1853    AST node that stores a value into a variable.
1854    """
1855
1856    def _str(self, level):
1857        yield _formatnestednameul4(self.varname)
1858        yield " = "
1859        yield from self.value._str(level)
1860
1861    @handleeval
1862    def eval(self, vars):
1863        value = (yield from self.value.eval(vars))
1864        _unpackvar(vars, self.varname, value)
1865
1866
1867@register("addvar")
1868class AddVar(ChangeVar):
1869    """
1870    AST node that adds a value to a variable (i.e. the ``+=`` operator).
1871    """
1872
1873    def _str(self, level):
1874        yield _formatnestednameul4(self.varname)
1875        yield " += "
1876        yield from self.value._str(level)
1877
1878    @handleeval
1879    def eval(self, vars):
1880        value = (yield from self.value.eval(vars))
1881        vars[self.varname] += value
1882
1883
1884@register("subvar")
1885class SubVar(ChangeVar):
1886    """
1887    AST node that substracts a value from a variable (i.e. the ``-=`` operator).
1888    """
1889
1890    def _str(self, level):
1891        yield _formatnestednameul4(self.varname)
1892        yield " -= "
1893        yield from self.value._str(level)
1894
1895    @handleeval
1896    def eval(self, vars):
1897        value = (yield from self.value.eval(vars))
1898        vars[self.varname] -= value
1899
1900
1901@register("mulvar")
1902class MulVar(ChangeVar):
1903    """
1904    AST node that multiplies a variable by a value (i.e. the ``*=`` operator).
1905    """
1906
1907    def _str(self, level):
1908        yield _formatnestednameul4(self.varname)
1909        yield " *= "
1910        yield from self.value._str(level)
1911
1912    @handleeval
1913    def eval(self, vars):
1914        value = (yield from self.value.eval(vars))
1915        vars[self.varname] *= value
1916
1917
1918@register("floordivvar")
1919class FloorDivVar(ChangeVar):
1920    """
1921    AST node that divides a variable by a value (truncating to an integer value;
1922    i.e. the ``//=`` operator).
1923    """
1924
1925    def _str(self, level):
1926        yield _formatnestednameul4(self.varname)
1927        yield " //= "
1928        yield from self.value._str(level)
1929
1930    @handleeval
1931    def eval(self, vars):
1932        value = (yield from self.value.eval(vars))
1933        vars[self.varname] //= value
1934
1935
1936@register("truedivvar")
1937class TrueDivVar(ChangeVar):
1938    """
1939    AST node that divides a variable by a value (i.e. the ``/=`` operator).
1940    """
1941
1942    def _str(self, level):
1943        yield _formatnestednameul4(self.varname)
1944        yield " /= "
1945        yield from self.value._str(level)
1946
1947    @handleeval
1948    def eval(self, vars):
1949        value = (yield from self.value.eval(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, level):
1960        yield _formatnestednameul4(self.varname)
1961        yield " %= "
1962        yield from self.value._str(level)
1963
1964    @handleeval
1965    def eval(self, vars):
1966        value = (yield from self.value.eval(vars))
1967        vars[self.varname] %= value
1968
1969
1970@register("callfunc")
1971class CallFunc(AST):
1972    """
1973    AST node for calling an function.
1974
1975    The object to be called is stored in the attribute :var:`obj`. The list of
1976    positional arguments is loaded from the list of AST nodes :var:`args`.
1977    Keyword arguments are in :var:`kwargs`. `var`:remargs` is the AST node
1978    for the ``*`` argument (and may by ``None`` if there is no ``*`` argument).
1979    `var`:remkwargs` is the AST node for the ``**`` argument (and may by ``None``
1980    if there is no ``**`` argument)
1981    """
1982
1983    precedence = 10
1984    associative = False
1985    fields = AST.fields.union({"obj", "args", "kwargs", "remargs", "remkwargs"})
1986
1987    def __init__(self, location=None, obj=None):
1988        super().__init__(location)
1989        self.obj = obj
1990        self.args = []
1991        self.kwargs = []
1992        self.remargs = None
1993        self.remkwargs = None
1994
1995    def __repr__(self):
1996        return "<{0.__class__.__module__}.{0.__class__.__qualname__} obj={0.obj!r}{1}{2}{3}{4} at {5:#x}>".format(
1997            self,
1998            "".join(" {!r}".format(arg) for arg in self.args),
1999            "".join(" {}={!r}".format(argname, argvalue) for (argname, argvalue) in self.kwargs),
2000            " *{!r}".format(self.remargs) if self.remargs is not None else "",
2001            " **{!r}".format(self.remkwargs) if self.remargs is not None else "",
2002            id(self))
2003
2004    def _repr_pretty_(self, p, cycle):
2005        if cycle:
2006            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
2007        else:
2008            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
2009                p.breakable()
2010                p.text("obj=")
2011                p.pretty(self.obj)
2012                for arg in self.args:
2013                    p.breakable()
2014                    p.pretty(arg)
2015                for (argname, arg) in self.kwargs:
2016                    p.breakable()
2017                    p.text("{}=".format(argname))
2018                    p.pretty(arg)
2019                if self.remargs is not None:
2020                    p.breakable()
2021                    p.text("*")
2022                    p.pretty(self.remargs)
2023                if self.remkwargs is not None:
2024                    p.breakable()
2025                    p.text("**")
2026                    p.pretty(self.remkwargs)
2027                p.breakable()
2028                p.text("at {:#x}".format(id(self)))
2029
2030    def _str(self, level):
2031        yield from self.obj._str(level)
2032        yield "("
2033        first = True
2034        for arg in self.args:
2035            if first:
2036                first = False
2037            else:
2038                yield ", "
2039            yield from arg._str(level)
2040        for (argname, argvalue) in self.kwargs:
2041            if first:
2042                first = False
2043            else:
2044                yield ", "
2045            yield argname
2046            yield "="
2047            yield from argvalue._str(level)
2048        if self.remargs is not None:
2049            if first:
2050                first = False
2051            else:
2052                yield ", "
2053            yield "*"
2054            yield from self.remargs._str(level)
2055        if self.remkwargs is not None:
2056            if first:
2057                first = False
2058            else:
2059                yield ", "
2060            yield "**"
2061            yield from self.remkwargs._str(level)
2062        yield ")"
2063
2064    @handleeval
2065    def eval(self, vars):
2066        obj = (yield from self.obj.eval(vars))
2067        args = []
2068        for arg in self.args:
2069            arg = (yield from arg.eval(vars))
2070            args.append(arg)
2071        kwargs = {}
2072        for (argname, arg) in self.kwargs:
2073            kwargs[argname] = (yield from arg.eval(vars))
2074        if self.remargs is not None:
2075            args.extend((yield from self.remargs.eval(vars)))
2076        if self.remkwargs is not None:
2077            kwargs.update((yield from self.remkwargs.eval(vars)))
2078        result = obj(*args, **kwargs)
2079        if isinstance(result, types.GeneratorType):
2080            return (yield from result)
2081        else:
2082            return result
2083
2084    def ul4ondump(self, encoder):
2085        super().ul4ondump(encoder)
2086        encoder.dump(self.obj)
2087        encoder.dump(self.args)
2088        encoder.dump(self.kwargs)
2089        encoder.dump(self.remargs)
2090        encoder.dump(self.remkwargs)
2091
2092    def ul4onload(self, decoder):
2093        super().ul4onload(decoder)
2094        self.obj = decoder.load()
2095        self.args = decoder.load()
2096        self.kwargs = [tuple(arg) for arg in decoder.load()]
2097        self.remargs = decoder.load()
2098        self.remkwargs = decoder.load()
2099
2100
2101@register("callmeth")
2102class CallMeth(AST):
2103    """
2104    AST node for calling a method.
2105
2106    The method name is stored in the string :var:`methname`. The object for which
2107    the method will be called is loaded from the AST node :var:`obj` and the list
2108    of arguments is loaded from the list of AST nodes :var:`args`. Keyword
2109    arguments are in :var:`kwargs`. `var`:remargs` is the AST node for the ``*``
2110    argument (and may by ``None`` if there is no ``*`` argument).
2111    `var`:remkwargs` is the AST node for the ``**`` argument (and may by ``None``
2112    if there is no ``**`` argument)
2113    """
2114
2115    precedence = 9
2116    associative = False
2117    fields = AST.fields.union({"obj", "methname", "args", "kwargs", "remargs", "remkwargs"})
2118
2119    def __init__(self, location=None, obj=None, methname=None):
2120        super().__init__(location)
2121        self.obj = obj
2122        self.methname = methname
2123        self.args = []
2124        self.kwargs = []
2125        self.remargs = None
2126        self.remkwargs = None
2127
2128    def __repr__(self):
2129        return "<{0.__class__.__module__}.{0.__class__.__qualname__} methname={0.methname!r} obj={0.obj!r}{1}{2}{3}{4} at {5:#x}>".format(
2130            self,
2131            "".join(" {!r}".format(arg) for arg in self.args),
2132            "".join(" {}={!r}".format(argname, argvalue) for (argname, argvalue) in self.kwargs),
2133            " *{!r}".format(self.remargs) if self.remargs is not None else "",
2134            " **{!r}".format(self.remkwargs) if self.remargs is not None else "",
2135            id(self))
2136
2137    def _repr_pretty_(self, p, cycle):
2138        if cycle:
2139            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
2140        else:
2141            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
2142                p.breakable()
2143                p.text("methname=")
2144                p.pretty(self.methname)
2145                p.breakable()
2146                p.text("obj=")
2147                p.pretty(self.obj)
2148                for arg in self.args:
2149                    p.breakable()
2150                    p.pretty(arg)
2151                for (argname, arg) in self.kwargs:
2152                    p.breakable()
2153                    p.text("{}=".format(argname))
2154                    p.pretty(arg)
2155                if self.remargs is not None:
2156                    p.breakable()
2157                    p.text("*")
2158                    p.pretty(self.remargs)
2159                if self.remkwargs is not None:
2160                    p.breakable()
2161                    p.text("**")
2162                    p.pretty(self.remkwargs)
2163                p.breakable()
2164                p.text("at {:#x}".format(id(self)))
2165
2166    def _str(self, level):
2167        yield from self._formatop(self.obj)
2168        yield "."
2169        yield self.methname
2170        yield "("
2171        first = True
2172        for arg in self.args:
2173            if first:
2174                first = False
2175            else:
2176                yield ", "
2177            yield from arg._str(level)
2178        for (argname, argvalue) in self.kwargs:
2179            if first:
2180                first = False
2181            else:
2182                yield ", "
2183            yield argname
2184            yield "="
2185            yield from argvalue._str(level)
2186        if self.remargs is not None:
2187            if first:
2188                first = False
2189            else:
2190                yield ", "
2191            yield "*"
2192            yield from self.remargs._str(level)
2193        if self.remkwargs is not None:
2194            if first:
2195                first = False
2196            else:
2197                yield ", "
2198            yield "**"
2199            yield from self.remkwargs._str(level)
2200        yield ")"
2201
2202    @handleeval
2203    def eval(self, vars):
2204        obj = (yield from self.obj.eval(vars))
2205        args = []
2206        for arg in self.args:
2207            arg = (yield from arg.eval(vars))
2208            args.append(arg)
2209        kwargs = {}
2210        for (argname, arg) in self.kwargs:
2211            kwargs[argname] = (yield from arg.eval(vars))
2212        if self.remargs is not None:
2213            args.extend((yield from self.remargs.eval(vars)))
2214        if self.remkwargs is not None:
2215            kwargs.update((yield from self.remkwargs.eval(vars)))
2216        result = self.methods[self.methname](obj, *args, **kwargs)
2217        if isinstance(result, types.GeneratorType):
2218            return (yield from result)
2219        else:
2220            return result
2221
2222    def ul4ondump(self, encoder):
2223        super().ul4ondump(encoder)
2224        encoder.dump(self.methname)
2225        encoder.dump(self.obj)
2226        encoder.dump(self.args)
2227        encoder.dump(self.kwargs)
2228        encoder.dump(self.remargs)
2229        encoder.dump(self.remkwargs)
2230
2231    def ul4onload(self, decoder):
2232        super().ul4onload(decoder)
2233        self.methname = decoder.load()
2234        self.obj = decoder.load()
2235        self.args = decoder.load()
2236        self.kwargs = [tuple(arg) for arg in decoder.load()]
2237        self.remargs = decoder.load()
2238        self.remkwargs = decoder.load()
2239
2240
2241@register("template")
2242class Template(Block):
2243    """
2244    A template object is normally created by passing the template source to the
2245    constructor. It can also be loaded from the compiled format via the class
2246    methods :meth:`load` (from a stream) or :meth:`loads` (from a string).
2247
2248    The compiled format can be generated with the methods :meth:`dump` (which
2249    dumps the format to a stream) or :meth:`dumps` (which returns a string with
2250    the compiled format).
2251
2252    Rendering the template can be done with the methods :meth:`render` (which
2253    is a generator) or :meth:`renders` (which returns a string).
2254
2255    A :class:`Template` object is itself an AST node. Evaluating it will store
2256    the template object under its name in the local variables.
2257
2258    A :class:`Template` can also be called as a function (returning the result
2259    of the first ``<?return?>`` tag encountered. In this case all output of the
2260    template will be ignored.
2261    """
2262    fields = Block.fields.union({"source", "name", "keepws", "startdelim", "enddelim"})
2263
2264    version = "24"
2265
2266    def __init__(self, source=None, name=None, keepws=True, startdelim="<?", enddelim="?>"):
2267        """
2268        Create a :class:`Template` object. If :var:`source` is ``None``, the
2269        :class:`Template` remains uninitialized, otherwise :var:`source` will be
2270        compiled (using :var:`startdelim` and :var:`enddelim` as the tag
2271        delimiters). :var:`name` is the name of the template. It will be used in
2272        exception messages and should be a valid Python identifier. If
2273        :var:`keepws` is false linefeeds and indentation will be ignored in the
2274        literal text in templates (i.e. the text between the tags). However
2275        trailing whitespace at the end of the line will be honored regardless of
2276        the value of :var:`keepws`. Output will always be ignored when calling
2277        a template as a function.
2278        """
2279        # ``location``/``endlocation`` will remain ``None`` for a top level template
2280        # For a subtemplate/subfunction ``location`` will be set to the location of the ``<?def?>`` tag in :meth:`_compile`
2281        # and ``endlocation`` will be the location of the ``<?end def?>`` tag
2282        super().__init__(None)
2283        self.keepws = keepws
2284        self.startdelim = startdelim
2285        self.enddelim = enddelim
2286        self.name = name
2287        self.source = None
2288
2289        # If we have source code compile it
2290        if source is not None:
2291            self._compile(source, name, startdelim, enddelim)
2292
2293    def __repr__(self):
2294        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} name={0.name!r} keepws={0.keepws!r}".format(self)
2295        if self.startdelim != "<?":
2296            s += " startdelim={0.startdelim!r}".format(self)
2297        if self.enddelim != "?>":
2298            s += " enddelim={0.enddelim!r}".format(self)
2299        if self.content:
2300            s + " ..."
2301        return s + " at {:#x}>".format(id(self))
2302
2303    def _str(self, level):
2304        yield "def "
2305        yield self.name if self.name is not None else "unnamed"
2306        yield ":\n"
2307        yield from super()._str(level+1)
2308
2309    def _repr_pretty_(self, p, cycle):
2310        if cycle:
2311            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
2312        else:
2313            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
2314                p.breakable()
2315                p.text("name=")
2316                p.pretty(self.name)
2317                p.breakable()
2318                p.text("keepws=")
2319                p.pretty(self.keepws)
2320                if self.startdelim != "<?":
2321                    p.breakable()
2322                    p.text("startdelim=")
2323                    p.pretty(self.startdelim)
2324                if self.enddelim != "?>":
2325                    p.breakable()
2326                    p.text("enddelim=")
2327                    p.pretty(self.enddelim)
2328                for node in self.content:
2329                    p.breakable()
2330                    p.pretty(node)
2331                p.breakable()
2332                p.text("at {:#x}".format(id(self)))
2333
2334    def ul4ondump(self, encoder):
2335        # Don't call ``super().ul4ondump()``, as we want the version to be first
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(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(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(self, source, None, pos, match.start(), pos, match.start())
2447            type = source[match.start(1):match.end(1)]
2448            if type != "note":
2449                yield Location(self, 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(self, 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, 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, *items):
3360    obj.extend(items)
3361
3362
3363@AST.makemethod
3364def _insert(obj, pos, *items):
3365    obj[pos:pos] = items
3366
3367
3368@AST.makemethod
3369def _pop(obj, pos=-1):
3370    return obj.pop(pos)
3371
3372
3373@AST.makemethod
3374def _update(obj, *others, **kwargs):
3375    for other in others:
3376        obj.update(other)
3377    obj.update(**kwargs)
3378
3379
3380class TemplateClosure(Object):
3381    fields = {"location", "endlocation", "name", "source", "startdelim", "enddelim", "content"}
3382
3383    def __init__(self, template, vars):
3384        self.template = template
3385        # Freeze variables of the currently running templates/functions
3386        self.vars = vars.copy()
3387
3388    def render(self, **vars):
3389        return self.template.render(**collections.ChainMap(vars, self.vars))
3390
3391    def renders(self, **vars):
3392        return self.template.renders(**collections.ChainMap(vars, self.vars))
3393
3394    def __call__(self, **vars):
3395        return self.template(**collections.ChainMap(vars, self.vars))
3396
3397    def __getattr__(self, name):
3398        return getattr(self.template, name)
3399
3400    def __repr__(self):
3401        s = "<{0.__class__.__module__}.{0.__class__.__qualname__} name={0.name!r} keepws={0.keepws!r}".format(self)
3402        if self.startdelim != "<?":
3403            s += " startdelim={0.startdelim!r}".format(self)
3404        if self.enddelim != "?>":
3405            s += " enddelim={0.enddelim!r}".format(self)
3406        if self.content:
3407            s + " ..."
3408        return s + " at {:#x}>".format(id(self))
3409
3410    def _repr_pretty_(self, p, cycle):
3411        if cycle:
3412            p.text("<{0.__class__.__module__}.{0.__class__.__qualname__} ... at {1:#x}>".format(self, id(self)))
3413        else:
3414            with p.group(4, "<{0.__class__.__module__}.{0.__class__.__qualname__}".format(self), ">"):
3415                p.breakable()
3416                p.text("name=")
3417                p.pretty(self.name)
3418                p.breakable()
3419                p.text("keepws=")
3420                p.pretty(self.keepws)
3421                if self.startdelim != "<?":
3422                    p.breakable()
3423                    p.text("startdelim=")
3424                    p.pretty(self.startdelim)
3425                if self.enddelim != "?>":
3426                    p.breakable()
3427                    p.text("enddelim=")
3428                    p.pretty(self.enddelim)
3429                for node in self.content:
3430                    p.breakable()
3431                    p.pretty(node)
3432                p.breakable()
3433                p.text("at {:#x}".format(id(self)))
Note: See TracBrowser for help on using the browser.