ovld 0.4.2__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/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 .dependent import DependentType
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"{arganal.lookup_for(i)}({name})")
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"{arganal.lookup_for(i)}({name})")
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}, {lookup_fn}({name}))")
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(body, sep="\n "),
157
- call=textwrap.indent("".join(calls), " "),
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.codegen()
204
+ cg = generate_checking_code(typ)
191
205
  return cg.template.format(
192
- arg=arg, **{k: gen.add(v) for k, v in cg.substitutions.items()}
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
- gen = GenSym(prefix="INJECT")
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 isinstance(types[k], DependentType)]
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 = {gen.add(keyed)}.get({keyexpr}, FALLTHROUGH)")
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 {gen.add(err)}")
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 = gen.variables
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
- if self.analysis.lookup_for(key) == "self.map.transform":
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
- isinstance(t[1] if isinstance(t, tuple) else t, DependentType)
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 isinstance(t, DependentType) and not t.check(a):
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(self.transform, args),
281
- *[(k, self.transform(v)) for k, v in kwargs.items()],
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