root/livinglogic.python.xist/src/ll/ul4c.py @ 5326:c2604b2d5f08

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

Reintroduce constant folding.

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