Passed
Push — master ( d1ffd3...062c67 )
by Max
50s
created

TupleDestructurer.destructure()   A

Complexity

Conditions 3

Size

Total Lines 4
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
from ._adt_constructor import ADTConstructor
2
from ._match_failure import MatchFailure
3
from ._not_in import not_in
4
from ._patterns import AsPattern
5
from ._patterns import Pattern
6
from ._unpack import unpack
7
8
9
class Destructurer:
10
11
    def __init__(self, target):
12
        self.target = target
13
14
    def __call__(self, value):
15
        return self.destructure(value)
16
17
    def destructure(self, value):
18
        raise NotImplementedError
19
20
    type = None
21
22
23
class AsPatternDestructurer(Destructurer):
24
25
    def destructure(self, value):
26
        if self.target is value:
27
            return reversed(self.target)
28
        return (value, value)
29
30
    type = AsPattern
31
32
33
class ADTDestructurer(Destructurer):
34
35
    def destructure(self, value):
36
        if value.__class__ is not self.target.__class__:
37
            raise MatchFailure
38
        return reversed(unpack(value))
39
40
    type = ADTConstructor
41
42
43
class TupleDestructurer(Destructurer):
44
45
    def destructure(self, value):
46
        if isinstance(value, self.target.__class__) and len(self.target) == len(value):
47
            return reversed(value)
48
        raise MatchFailure
49
50
    type = tuple
51
52
53
class DestructurerList:
54
55
    def __init__(self, *destructurers):
56
        self.destructurers = tuple(destructurers)
57
58
    def get_destructurer(self, item):
59
        for destructurer in self.destructurers:
60
            if isinstance(item, destructurer.type):
61
                return destructurer(item)
62
        return None
63
64
    @classmethod
65
    def custom(cls, *destructurers):
66
        return cls(AsPatternDestructurer, ADTDestructurer, *destructurers, TupleDestructurer)
67
68
    def names(self, target):
69
        name_list = []
70
        names_seen = set()
71
        to_process = [target]
72
        while to_process:
73
            item = to_process.pop()
74
            if isinstance(item, Pattern):
75
                not_in(names_seen, item.name)
76
                names_seen.add(item.name)
77
                name_list.append(item.name)
78
            else:
79
                destructurer = self.get_destructurer(item)
80
                if destructurer:
81
                    to_process.extend(destructurer(item))
82
        return name_list
83
84
85
DESTRUCTURERS = DestructurerList.custom()
86