root/livinglogic.python.xist/src/ll/ul4c.py @ 5311:75467b6660f9

Revision 5311:75467b6660f9, 96.2 KB (checked in by Walter Doerwald <walter@…>, 7 years ago)

Prevent local variables from leaking into the surrounding scope in UL4 templates.

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