This repository was archived by the owner on Jun 23, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtypes.py
More file actions
132 lines (107 loc) · 4.22 KB
/
types.py
File metadata and controls
132 lines (107 loc) · 4.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
from collections import namedtuple
id_ = lambda i: i
const = lambda i: lambda x: i
class SumBase(object):
pass
class RecordBase(object):
pass
class NStackTypeInputMixin(object):
@classmethod
def _nstackFromBase(cls, base):
raise NotImplementedError("_nstackFromBase not implemented")
class NStackTypeOutputMixin(object):
def _nstackToBase(self):
raise NotImplementedError("_nstackToBase not implemented")
def createlist(name, preprocfunc=None, optional=False):
class ListProxy(list):
def __new__(cls, a=None):
if a is None and optional:
return None
return list.__new__(cls, a)
def __init__(self, a):
if preprocfunc:
a = preprocfunc(a)
super(ListProxy, self).__init__(a)
return type(name, (ListProxy, ), {})
def createtuple(name, length, preprocfunc=None, optional=False):
class TupleProxy(tuple):
def __new__(cls, a=None):
if a is None and optional:
# python's tuple type supports `tuple()`
# which returns the empty tuple. we lose
# that semantics because of ambiguity
# with an optional empty tuple
return None
if preprocfunc:
a = preprocfunc(a)
r = tuple.__new__(cls, a)
if len(r) < length:
raise TypeError("tuple type too small")
return r
return type(name, (TupleProxy, ), {})
def createrecord(name, fields, preprocfunc=None, optional=False):
# fields is a mapping of name to constructor
nt = namedtuple(name, fields)
class TupleProxy(nt, RecordBase):
def __new__(cls, a):
# intermediate class needed for use of super
if a is None and optional:
return None
if preprocfunc:
a = preprocfunc(a)
return super(TupleProxy, cls).__new__(cls, *a)
return type(name, (TupleProxy, ), {})
def createsum(name, constrs, preprocfuncs=None, optional=False):
# constrs is a mapping of constr name to constructor
subclasses = []
raiseOnTypeError = object()
class Sum(SumBase, NStackTypeInputMixin, NStackTypeOutputMixin):
def __init__(self, value):
raise RuntimeError("Calling constructor of sum type base-class")
@classmethod
def new(cls, v):
if v is None and optional:
return None
branch_idx, value = v
return subclasses[branch_idx](value)
def match(self, *args):
return self._church(args)
@property
def value(self):
return self.match(*(id_ for i in subclasses))
def valueWithIndex(self):
return self.match(*((lambda i: lambda v: (i, v))(i)
for i, j in enumerate(subclasses)))
@property
def _branch(self):
return self.match(*(const(i) for i in range(len(subclasses))))
def _getAs(self, cls, default=raiseOnTypeError):
err = raiseTypeError(cls.__name__) if default is raiseOnTypeError else const(default)
return self.match(*((id_ if cls is j else err) for j in subclasses))
def __repr__(self):
return "<{}: {}({})>".format(name, self._constructor_name, self.value)
@classmethod
def _nstackFromBase(cls, v):
return cls.new(v)
def _nstackToBase(self):
return self.valueWithIndex()
def raiseTypeError(name):
def inner(v):
raise TypeError("Not a " + name)
return inner
def makeconstructor(i):
def constructor(self, value):
if preprocfuncs:
value = preprocfuncs[i](value)
self._church = lambda args: args[i](value)
return constructor
base_ = type(name, (Sum, ), {})
for i, j in enumerate(constrs):
branch = type(j, (base_, ), {
'__init__': makeconstructor(i),
'_constructor_name': j})
subclasses.append(branch)
setattr(base_, j, branch)
setattr(base_, "get" + j, (lambda branch_:
lambda self, default=raiseOnTypeError: self._getAs(branch_, default=default))(branch))
return base_