1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright 2017, Data61
5# Commonwealth Scientific and Industrial Research Organisation (CSIRO)
6# ABN 41 687 119 230.
7#
8# This software may be distributed and modified according to the terms of
9# the BSD 2-Clause license. Note that NO WARRANTY is provided.
10# See "LICENSE_BSD2.txt" for details.
11#
12# @TAG(DATA61_BSD)
13#
14
15from __future__ import absolute_import, division, print_function, \
16    unicode_literals
17from camkes.internal.seven import cmp, filter, map, zip
18
19from .base import ASTObject
20from .objects import Assembly
21from .traversal import TraversalAction
22import collections
23
24class LiftedAST(ASTObject, collections.Iterable):
25    child_fields = ('items',)
26
27    no_hash = ASTObject.no_hash + ('_assembly',)
28
29    def __init__(self, items):
30        assert items is None or isinstance(items, (list, tuple))
31        super(LiftedAST, self).__init__()
32        self._items = list(items or [])
33        self._assembly = None
34        self.claim_children()
35
36    @property
37    def items(self):
38        return self._items
39    @items.setter
40    def items(self, value):
41        assert isinstance(value, (list, tuple))
42        if self.frozen:
43            raise TypeError('you cannot change the items in a frozen lifted '
44                'AST')
45        self._items = value
46
47    def freeze(self):
48        self.items = tuple(self.items)
49        super(LiftedAST, self).freeze()
50
51    def claim_children(self):
52        [self.adopt(i) for i in self.items]
53
54    @property
55    def assembly(self):
56        if self._assembly is None:
57            for i in self.items:
58                if isinstance(i, Assembly):
59                    if self.frozen:
60                        self._assembly = i
61                    return i
62        return self._assembly
63
64    def filter(self, function=None):
65        if function is None:
66            function = lambda x: x is not None
67        self.items = [x for x in self.items if function(x)]
68
69    def __iter__(self):
70        c = Collector()
71        self.postorder(c)
72        return iter(c.contents)
73
74class Collector(TraversalAction):
75    def __init__(self):
76        self.contents = []
77
78    def __call__(self, item):
79        self.contents.append(item)
80        return item
81