ovld 0.4.3__py3-none-any.whl → 0.4.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ovld/__init__.py +1 -0
- ovld/abc.py +48 -0
- ovld/core.py +16 -28
- ovld/dependent.py +131 -55
- ovld/mro.py +30 -60
- ovld/recode.py +63 -50
- ovld/typemap.py +9 -31
- ovld/types.py +282 -72
- ovld/utils.py +36 -0
- ovld/version.py +1 -1
- {ovld-0.4.3.dist-info → ovld-0.4.4.dist-info}/METADATA +1 -1
- ovld-0.4.4.dist-info/RECORD +14 -0
- ovld-0.4.3.dist-info/RECORD +0 -13
- {ovld-0.4.3.dist-info → ovld-0.4.4.dist-info}/WHEEL +0 -0
- {ovld-0.4.3.dist-info → ovld-0.4.4.dist-info}/licenses/LICENSE +0 -0
ovld/recode.py
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
import ast
|
2
2
|
import inspect
|
3
3
|
import linecache
|
4
|
+
import re
|
4
5
|
import textwrap
|
5
6
|
from ast import _splitlines_no_ff as splitlines
|
6
7
|
from functools import reduce
|
7
8
|
from itertools import count
|
8
9
|
from types import CodeType, FunctionType
|
9
10
|
|
10
|
-
from .
|
11
|
-
from .utils import Unusable, UsageError
|
11
|
+
from .utils import MISSING, Unusable, UsageError, subtler_type
|
12
12
|
|
13
13
|
recurse = Unusable(
|
14
14
|
"recurse() can only be used from inside an @ovld-registered function."
|
@@ -19,12 +19,8 @@ call_next = Unusable(
|
|
19
19
|
|
20
20
|
|
21
21
|
dispatch_template = """
|
22
|
-
from ovld.utils import MISSING
|
23
|
-
|
24
22
|
def __DISPATCH__(self, {args}):
|
25
|
-
{inits}
|
26
23
|
{body}
|
27
|
-
{call}
|
28
24
|
"""
|
29
25
|
|
30
26
|
|
@@ -55,6 +51,35 @@ def instantiate_code(symbol, code, inject={}):
|
|
55
51
|
# return rval
|
56
52
|
|
57
53
|
|
54
|
+
class NameDatabase:
|
55
|
+
def __init__(self, default_name):
|
56
|
+
self.default_name = default_name
|
57
|
+
self.count = count()
|
58
|
+
self.variables = {}
|
59
|
+
self.names = {}
|
60
|
+
self.registered = set()
|
61
|
+
|
62
|
+
def register(self, name):
|
63
|
+
self.registered.add(name)
|
64
|
+
|
65
|
+
def __getitem__(self, value):
|
66
|
+
if isinstance(value, (int, float, str)):
|
67
|
+
return repr(value)
|
68
|
+
if id(value) in self.names:
|
69
|
+
return self.names[id(value)]
|
70
|
+
name = orig_name = getattr(value, "__name__", self.default_name)
|
71
|
+
if not re.match(string=name, pattern=r"[a-zA-Z_][a-zA-Z0-9_]+"):
|
72
|
+
name = self.default_name
|
73
|
+
i = 1
|
74
|
+
while name in self.registered:
|
75
|
+
name = f"{orig_name}{i}"
|
76
|
+
i += 1
|
77
|
+
self.variables[name] = value
|
78
|
+
self.names[id(value)] = name
|
79
|
+
self.registered.add(name)
|
80
|
+
return name
|
81
|
+
|
82
|
+
|
58
83
|
def generate_dispatch(arganal):
|
59
84
|
def join(li, sep=", ", trail=False):
|
60
85
|
li = [x for x in li if x]
|
@@ -76,6 +101,13 @@ def generate_dispatch(arganal):
|
|
76
101
|
lookup = []
|
77
102
|
|
78
103
|
i = 0
|
104
|
+
ndb = NameDatabase(default_name="INJECT")
|
105
|
+
|
106
|
+
def lookup_for(x):
|
107
|
+
return ndb[arganal.lookup_for(x)]
|
108
|
+
|
109
|
+
for name in spr + spo + pr + po + kr:
|
110
|
+
ndb.register(name)
|
79
111
|
|
80
112
|
for name in spr + spo:
|
81
113
|
if name in spr:
|
@@ -83,7 +115,7 @@ def generate_dispatch(arganal):
|
|
83
115
|
else:
|
84
116
|
args.append(f"{name}=MISSING")
|
85
117
|
posargs.append(name)
|
86
|
-
lookup.append(f"{
|
118
|
+
lookup.append(f"{lookup_for(i)}({name})")
|
87
119
|
i += 1
|
88
120
|
|
89
121
|
if len(po) <= 1:
|
@@ -99,7 +131,7 @@ def generate_dispatch(arganal):
|
|
99
131
|
else:
|
100
132
|
args.append(f"{name}=MISSING")
|
101
133
|
posargs.append(name)
|
102
|
-
lookup.append(f"{
|
134
|
+
lookup.append(f"{lookup_for(i)}({name})")
|
103
135
|
i += 1
|
104
136
|
|
105
137
|
if len(po) > 1:
|
@@ -109,14 +141,9 @@ def generate_dispatch(arganal):
|
|
109
141
|
args.append("*")
|
110
142
|
|
111
143
|
for name in kr:
|
112
|
-
lookup_fn = (
|
113
|
-
"self.map.transform"
|
114
|
-
if name in arganal.complex_transforms
|
115
|
-
else "type"
|
116
|
-
)
|
117
144
|
args.append(f"{name}")
|
118
145
|
posargs.append(f"{name}={name}")
|
119
|
-
lookup.append(f"({name!r}, {
|
146
|
+
lookup.append(f"({name!r}, {lookup_for(name)}({name}))")
|
120
147
|
|
121
148
|
for name in ko:
|
122
149
|
args.append(f"{name}=MISSING")
|
@@ -126,9 +153,7 @@ def generate_dispatch(arganal):
|
|
126
153
|
inits.add("TARGS = []")
|
127
154
|
body.append(f"if {name} is not MISSING:")
|
128
155
|
body.append(f" KWARGS[{name!r}] = {name}")
|
129
|
-
body.append(
|
130
|
-
f" TARGS.append(({name!r}, {arganal.lookup_for(name)}({name})))"
|
131
|
-
)
|
156
|
+
body.append(f" TARGS.append(({name!r}, {lookup_for(name)}({name})))")
|
132
157
|
|
133
158
|
posargs.append(kwargsstar)
|
134
159
|
lookup.append(targsstar)
|
@@ -150,30 +175,19 @@ def generate_dispatch(arganal):
|
|
150
175
|
calls.append(f"\nif {arg} is MISSING:{call}")
|
151
176
|
calls.append(fullcall)
|
152
177
|
|
178
|
+
lines = [*inits, *body, textwrap.indent("".join(calls), " ")]
|
153
179
|
code = dispatch_template.format(
|
154
|
-
inits=join(inits, sep="\n "),
|
155
180
|
args=join(args),
|
156
|
-
body=join(
|
157
|
-
|
181
|
+
body=join(lines, sep="\n ").lstrip(),
|
182
|
+
)
|
183
|
+
return instantiate_code(
|
184
|
+
"__DISPATCH__", code, inject={"MISSING": MISSING, **ndb.variables}
|
158
185
|
)
|
159
|
-
return instantiate_code("__DISPATCH__", code)
|
160
|
-
|
161
|
-
|
162
|
-
class GenSym:
|
163
|
-
def __init__(self, prefix):
|
164
|
-
self.prefix = prefix
|
165
|
-
self.count = count()
|
166
|
-
self.variables = {}
|
167
|
-
|
168
|
-
def add(self, value):
|
169
|
-
if isinstance(value, (int, float, str)):
|
170
|
-
return repr(value)
|
171
|
-
id = f"{self.prefix}{next(self.count)}"
|
172
|
-
self.variables[id] = value
|
173
|
-
return id
|
174
186
|
|
175
187
|
|
176
188
|
def generate_dependent_dispatch(tup, handlers, next_call, slf, name, err, nerr):
|
189
|
+
from .dependent import generate_checking_code, is_dependent
|
190
|
+
|
177
191
|
def to_dict(tup):
|
178
192
|
return dict(
|
179
193
|
entry if isinstance(entry, tuple) else (i, entry)
|
@@ -187,14 +201,14 @@ def generate_dependent_dispatch(tup, handlers, next_call, slf, name, err, nerr):
|
|
187
201
|
return f"ARG{x}" if isinstance(x, int) else f"{x}={x}"
|
188
202
|
|
189
203
|
def codegen(typ, arg):
|
190
|
-
cg = typ
|
204
|
+
cg = generate_checking_code(typ)
|
191
205
|
return cg.template.format(
|
192
|
-
arg=arg, **{k:
|
206
|
+
arg=arg, **{k: ndb[v] for k, v in cg.substitutions.items()}
|
193
207
|
)
|
194
208
|
|
195
209
|
tup = to_dict(tup)
|
196
210
|
handlers = [(h, to_dict(types)) for h, types in handlers]
|
197
|
-
|
211
|
+
ndb = NameDatabase(default_name="INJECT")
|
198
212
|
conjs = []
|
199
213
|
|
200
214
|
exclusive = False
|
@@ -227,7 +241,7 @@ def generate_dependent_dispatch(tup, handlers, next_call, slf, name, err, nerr):
|
|
227
241
|
exclusive = getattr(focus, "exclusive_type", False)
|
228
242
|
|
229
243
|
for i, (h, types) in enumerate(handlers):
|
230
|
-
relevant = [k for k in tup if
|
244
|
+
relevant = [k for k in tup if is_dependent(types[k])]
|
231
245
|
if len(relevant) > 1:
|
232
246
|
# The keyexpr method only works if there is only one condition to check.
|
233
247
|
keyexpr = keyed = None
|
@@ -243,7 +257,7 @@ def generate_dependent_dispatch(tup, handlers, next_call, slf, name, err, nerr):
|
|
243
257
|
|
244
258
|
body = []
|
245
259
|
if keyexpr:
|
246
|
-
body.append(f"HANDLER = {
|
260
|
+
body.append(f"HANDLER = {ndb[keyed]}.get({keyexpr}, FALLTHROUGH)")
|
247
261
|
body.append(f"return HANDLER({slf}{argcall})")
|
248
262
|
|
249
263
|
elif exclusive:
|
@@ -263,12 +277,12 @@ def generate_dependent_dispatch(tup, handlers, next_call, slf, name, err, nerr):
|
|
263
277
|
body.append("elif SUMMATION == 0:")
|
264
278
|
body.append(f" return FALLTHROUGH({slf}{argcall})")
|
265
279
|
body.append("else:")
|
266
|
-
body.append(f" raise {
|
280
|
+
body.append(f" raise {ndb[err]}")
|
267
281
|
|
268
282
|
body_text = textwrap.indent("\n".join(body), " ")
|
269
283
|
code = f"def __DEPENDENT_DISPATCH__({slf}{argspec}):\n{body_text}"
|
270
284
|
|
271
|
-
inject =
|
285
|
+
inject = ndb.variables
|
272
286
|
for i, (h, types) in enumerate(handlers):
|
273
287
|
inject[f"HANDLER{i}"] = h
|
274
288
|
|
@@ -400,18 +414,16 @@ class NameConverter(ast.NodeTransformer):
|
|
400
414
|
tmp = f"__TMP{next(self.count)}_"
|
401
415
|
|
402
416
|
def _make_lookup_call(key, arg):
|
417
|
+
name = (
|
418
|
+
"__SUBTLER_TYPE"
|
419
|
+
if self.analysis.lookup_for(key) is subtler_type
|
420
|
+
else "type"
|
421
|
+
)
|
403
422
|
value = ast.NamedExpr(
|
404
423
|
target=ast.Name(id=f"{tmp}{key}", ctx=ast.Store()),
|
405
424
|
value=self.visit(arg),
|
406
425
|
)
|
407
|
-
|
408
|
-
func = ast.Attribute(
|
409
|
-
value=ast.Name(id=f"{tmp}M", ctx=ast.Load()),
|
410
|
-
attr="transform",
|
411
|
-
ctx=ast.Load(),
|
412
|
-
)
|
413
|
-
else:
|
414
|
-
func = ast.Name(id="type", ctx=ast.Load())
|
426
|
+
func = ast.Name(id=name, ctx=ast.Load())
|
415
427
|
return ast.Call(
|
416
428
|
func=func,
|
417
429
|
args=[value],
|
@@ -579,6 +591,7 @@ def recode(fn, ovld, recurse_sym, call_next_sym, newname):
|
|
579
591
|
new_fn.__kwdefaults__ = fn.__kwdefaults__
|
580
592
|
new_fn.__annotations__ = fn.__annotations__
|
581
593
|
new_fn = rename_function(new_fn, newname)
|
594
|
+
new_fn.__globals__["__SUBTLER_TYPE"] = subtler_type
|
582
595
|
new_fn.__globals__[ovld_mangled] = ovld
|
583
596
|
new_fn.__globals__[code_mangled] = new_fn.__code__
|
584
597
|
return new_fn
|
ovld/typemap.py
CHANGED
@@ -1,27 +1,12 @@
|
|
1
1
|
import inspect
|
2
2
|
import math
|
3
|
-
import typing
|
4
3
|
from dataclasses import dataclass
|
5
4
|
from itertools import count
|
6
5
|
from types import CodeType
|
7
6
|
|
8
|
-
from .dependent import DependentType
|
9
7
|
from .mro import sort_types
|
10
8
|
from .recode import generate_dependent_dispatch
|
11
|
-
from .utils import MISSING
|
12
|
-
|
13
|
-
|
14
|
-
class GenericAliasMC(type):
|
15
|
-
def __instancecheck__(cls, obj):
|
16
|
-
return hasattr(obj, "__origin__")
|
17
|
-
|
18
|
-
|
19
|
-
class GenericAlias(metaclass=GenericAliasMC):
|
20
|
-
pass
|
21
|
-
|
22
|
-
|
23
|
-
def is_type_of_type(t):
|
24
|
-
return getattr(t, "__origin__", None) is type
|
9
|
+
from .utils import MISSING, subtler_type
|
25
10
|
|
26
11
|
|
27
12
|
class TypeMap(dict):
|
@@ -123,16 +108,6 @@ class MultiTypeMap(dict):
|
|
123
108
|
self.all = {}
|
124
109
|
self.errors = {}
|
125
110
|
|
126
|
-
def transform(self, obj):
|
127
|
-
if isinstance(obj, GenericAlias):
|
128
|
-
return type[obj]
|
129
|
-
elif obj is typing.Any:
|
130
|
-
return type[object]
|
131
|
-
elif isinstance(obj, type):
|
132
|
-
return type[obj]
|
133
|
-
else:
|
134
|
-
return type(obj)
|
135
|
-
|
136
111
|
def mro(self, obj_t_tup):
|
137
112
|
specificities = {}
|
138
113
|
candidates = None
|
@@ -229,6 +204,8 @@ class MultiTypeMap(dict):
|
|
229
204
|
sig: A Signature object.
|
230
205
|
handler: A function to handle the tuple.
|
231
206
|
"""
|
207
|
+
from .dependent import is_dependent
|
208
|
+
|
232
209
|
self.clear()
|
233
210
|
|
234
211
|
obj_t_tup = sig.types
|
@@ -240,8 +217,7 @@ class MultiTypeMap(dict):
|
|
240
217
|
self.tiebreaks[handler] = sig.tiebreak
|
241
218
|
self.type_tuples[handler] = obj_t_tup
|
242
219
|
self.dependent[handler] = any(
|
243
|
-
|
244
|
-
for t in obj_t_tup
|
220
|
+
is_dependent(t[1] if isinstance(t, tuple) else t) for t in obj_t_tup
|
245
221
|
)
|
246
222
|
|
247
223
|
for i, cls in enumerate(obj_t_tup):
|
@@ -266,19 +242,21 @@ class MultiTypeMap(dict):
|
|
266
242
|
print(f"{'':{width-2}} @ {co.co_filename}:{co.co_firstlineno}")
|
267
243
|
|
268
244
|
def display_resolution(self, *args, **kwargs):
|
245
|
+
from .dependent import is_dependent
|
246
|
+
|
269
247
|
def dependent_match(tup, args):
|
270
248
|
for t, a in zip(tup, args):
|
271
249
|
if isinstance(t, tuple):
|
272
250
|
t = t[1]
|
273
251
|
a = a[1]
|
274
|
-
if
|
252
|
+
if is_dependent(t) and not isinstance(a, t):
|
275
253
|
return False
|
276
254
|
return True
|
277
255
|
|
278
256
|
message = "No method will be called."
|
279
257
|
argt = [
|
280
|
-
*map(
|
281
|
-
*[(k,
|
258
|
+
*map(subtler_type, args),
|
259
|
+
*[(k, subtler_type(v)) for k, v in kwargs.items()],
|
282
260
|
]
|
283
261
|
finished = False
|
284
262
|
rank = 1
|