1
|
|
|
"""Base classes for defining abstract data types. |
2
|
|
|
|
3
|
|
|
This module provides three public members, which are used together. |
4
|
|
|
|
5
|
|
|
Given a structure, possibly a choice of different structures, that you'd like |
6
|
|
|
to associate with a type: |
7
|
|
|
|
8
|
|
|
- First, create a class, that subclasses the Sum class. |
9
|
|
|
- Then, for each possible structure, add an attribute annotation to the class |
10
|
|
|
with the desired name of the constructor, and a type of ``Ctor``, with the |
11
|
|
|
types within the constructor as arguments. |
12
|
|
|
|
13
|
|
|
To look inside an ADT instance, use the functions from the |
14
|
|
|
:mod:`structured_data.match` module. |
15
|
|
|
|
16
|
|
|
Putting it together: |
17
|
|
|
|
18
|
|
|
>>> from structured_data import match |
19
|
|
|
>>> class Example(Sum): |
20
|
|
|
... FirstConstructor: Ctor[int, str] |
21
|
|
|
... SecondConstructor: Ctor[bytes] |
22
|
|
|
... ThirdConstructor: Ctor |
23
|
|
|
... def __iter__(self): |
24
|
|
|
... matchable = match.Matchable(self) |
25
|
|
|
... if matchable(Example.FirstConstructor(match.pat.count, match.pat.string)): |
26
|
|
|
... count, string = matchable[match.pat.count, match.pat.string] |
27
|
|
|
... for _ in range(count): |
28
|
|
|
... yield string |
29
|
|
|
... elif matchable(Example.SecondConstructor(match.pat.bytes)): |
30
|
|
|
... bytes_ = matchable[match.pat.bytes] |
31
|
|
|
... for byte in bytes_: |
32
|
|
|
... yield chr(byte) |
33
|
|
|
... elif matchable(Example.ThirdConstructor()): |
34
|
|
|
... yield "Third" |
35
|
|
|
... yield "Constructor" |
36
|
|
|
>>> list(Example.FirstConstructor(5, "abc")) |
37
|
|
|
['abc', 'abc', 'abc', 'abc', 'abc'] |
38
|
|
|
>>> list(Example.SecondConstructor(b"abc")) |
39
|
|
|
['a', 'b', 'c'] |
40
|
|
|
>>> list(Example.ThirdConstructor()) |
41
|
|
|
['Third', 'Constructor'] |
42
|
|
|
""" |
43
|
|
|
|
44
|
|
|
import typing |
45
|
|
|
|
46
|
|
|
from ._adt.product_type import Product |
47
|
|
|
from ._adt.sum_type import Sum |
48
|
|
|
|
49
|
|
|
if typing.TYPE_CHECKING: # pragma: nocover |
50
|
|
|
|
51
|
|
|
T = typing.TypeVar("T") |
52
|
|
|
|
53
|
|
|
class Ctor: |
54
|
|
|
"""Dummy class for type-checking purposes.""" |
55
|
|
|
|
56
|
|
|
class ConcreteCtor(typing.Generic[T]): |
|
|
|
|
57
|
|
|
"""Wrapper class for type-checking purposes. |
58
|
|
|
|
59
|
|
|
The type parameter should be a Tuple type of fixed size. |
60
|
|
|
Classes containing this annotation (meaning they haven't been |
61
|
|
|
processed by the ``adt`` decorator) should not be instantiated. |
62
|
|
|
""" |
63
|
|
|
|
64
|
|
|
|
65
|
|
|
else: |
66
|
|
|
from ._adt.ctor import Ctor |
67
|
|
|
|
68
|
|
|
|
69
|
|
|
__all__ = ["Ctor", "Product", "Sum"] |
70
|
|
|
|