root/livinglogic.python.xist/src/ll/ul4c.py @ 5349:f6fd7e51b446

Revision 5349:f6fd7e51b446, 77.4 KB (checked in by Walter Doerwald <walter@…>, 7 years ago)

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