morphir-python 0.0.1__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.
- morphir/__init__.py +14 -0
- morphir/ir/__init__.py +110 -0
- morphir/ir/access_controlled.py +15 -0
- morphir/ir/decorations.py +19 -0
- morphir/ir/diagnostics.py +105 -0
- morphir/ir/distribution.py +21 -0
- morphir/ir/document.py +37 -0
- morphir/ir/documented.py +11 -0
- morphir/ir/format_version.py +483 -0
- morphir/ir/fqname.py +9 -0
- morphir/ir/json.py +11 -0
- morphir/ir/literal.py +25 -0
- morphir/ir/meta.py +11 -0
- morphir/ir/migrate.py +1267 -0
- morphir/ir/module.py +17 -0
- morphir/ir/name.py +27 -0
- morphir/ir/package.py +15 -0
- morphir/ir/path.py +25 -0
- morphir/ir/qname.py +9 -0
- morphir/ir/ref.py +17 -0
- morphir/ir/type.py +37 -0
- morphir/ir/type_constraints.py +33 -0
- morphir/ir/type_def.py +19 -0
- morphir/ir/type_spec.py +25 -0
- morphir/ir/v3/__init__.py +64 -0
- morphir/ir/v3/_legacy_value.py +201 -0
- morphir/ir/v3/access_controlled.py +31 -0
- morphir/ir/v3/codec.py +1275 -0
- morphir/ir/v3/codec_v1.py +491 -0
- morphir/ir/v3/codec_v2.py +187 -0
- morphir/ir/v3/distribution.py +42 -0
- morphir/ir/v3/documented.py +13 -0
- morphir/ir/v3/fqname.py +30 -0
- morphir/ir/v3/literal.py +46 -0
- morphir/ir/v3/module.py +32 -0
- morphir/ir/v3/name.py +42 -0
- morphir/ir/v3/package.py +23 -0
- morphir/ir/v3/path.py +29 -0
- morphir/ir/v3/qname.py +16 -0
- morphir/ir/v3/type.py +126 -0
- morphir/ir/v3/value.py +235 -0
- morphir/ir/v4/__init__.py +160 -0
- morphir/ir/v4/access_controlled.py +17 -0
- morphir/ir/v4/annotation.py +75 -0
- morphir/ir/v4/codec.py +2161 -0
- morphir/ir/v4/decorations.py +88 -0
- morphir/ir/v4/distribution.py +56 -0
- morphir/ir/v4/document.py +69 -0
- morphir/ir/v4/documented.py +10 -0
- morphir/ir/v4/fqname.py +69 -0
- morphir/ir/v4/incompleteness.py +78 -0
- morphir/ir/v4/json.py +103 -0
- morphir/ir/v4/literal.py +51 -0
- morphir/ir/v4/meta.py +27 -0
- morphir/ir/v4/module.py +30 -0
- morphir/ir/v4/name.py +69 -0
- morphir/ir/v4/package.py +19 -0
- morphir/ir/v4/path.py +50 -0
- morphir/ir/v4/qname.py +34 -0
- morphir/ir/v4/ref.py +35 -0
- morphir/ir/v4/type.py +140 -0
- morphir/ir/v4/type_constraints.py +91 -0
- morphir/ir/v4/type_def.py +38 -0
- morphir/ir/v4/type_spec.py +64 -0
- morphir/ir/v4/value.py +480 -0
- morphir/ir/value.py +81 -0
- morphir/py.typed +0 -0
- morphir/sdk/__init__.py +110 -0
- morphir/sdk/_compare.py +187 -0
- morphir/sdk/aggregate.py +421 -0
- morphir/sdk/basics.py +504 -0
- morphir/sdk/char.py +110 -0
- morphir/sdk/decimal.py +311 -0
- morphir/sdk/dict.py +336 -0
- morphir/sdk/instant.py +118 -0
- morphir/sdk/int.py +86 -0
- morphir/sdk/key.py +522 -0
- morphir/sdk/list.py +356 -0
- morphir/sdk/local_date.py +436 -0
- morphir/sdk/local_time.py +267 -0
- morphir/sdk/maybe.py +135 -0
- morphir/sdk/number.py +237 -0
- morphir/sdk/regex.py +287 -0
- morphir/sdk/result.py +162 -0
- morphir/sdk/result_list.py +169 -0
- morphir/sdk/rule.py +103 -0
- morphir/sdk/set.py +214 -0
- morphir/sdk/stateful_app.py +49 -0
- morphir/sdk/string.py +427 -0
- morphir/sdk/tuple.py +43 -0
- morphir/sdk/uuid.py +209 -0
- morphir_python-0.0.1.dist-info/METADATA +269 -0
- morphir_python-0.0.1.dist-info/RECORD +99 -0
- morphir_python-0.0.1.dist-info/WHEEL +4 -0
- morphir_python-0.0.1.dist-info/entry_points.txt +2 -0
- morphir_python-0.0.1.dist-info/licenses/LICENSE +201 -0
- morphir_tools/__init__.py +13 -0
- morphir_tools/cli.py +223 -0
- morphir_tools/py.typed +0 -0
morphir/ir/migrate.py
ADDED
|
@@ -0,0 +1,1267 @@
|
|
|
1
|
+
"""Migrations between Morphir IR format 3 and IR v4.
|
|
2
|
+
|
|
3
|
+
`v3_to_v4` always succeeds for a valid v3 Library or Specs. `v4_to_v3` collects
|
|
4
|
+
every construct format 3 cannot represent in one pass and fails with all of them,
|
|
5
|
+
so users fix every problem at once. A v4 Specs becomes a v3 Specs (format 3.1.0);
|
|
6
|
+
a v4 Application has no v3 form. Nothing is invented or dropped, except:
|
|
7
|
+
|
|
8
|
+
- the package release version, which v3 cannot hold (``package_version_dropped``);
|
|
9
|
+
- value source locations, only when ``drop_source_locations=True``
|
|
10
|
+
(``source_location_dropped``);
|
|
11
|
+
- value-definition input attributes, only when ``drop_input_attributes=True`` or
|
|
12
|
+
through `drop_input_attributes` (``input_attributes_dropped``). v4 JSON spells
|
|
13
|
+
an input as a bare type, so an input whose attributes hold more than its
|
|
14
|
+
declared type cannot be encoded without this drop.
|
|
15
|
+
|
|
16
|
+
The mapping follows morphir-moonbit ``migration/v3/migration.mbt``, adjusted for
|
|
17
|
+
the Python v4 model. Diagnostic codes are defined in `morphir.ir.diagnostics` and
|
|
18
|
+
may be renamed when finos bead ``morphir-diwy`` settles the ecosystem rules.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
>>> from morphir.ir import v3
|
|
22
|
+
>>> lib = v3.Library(v3.Path(()), v3.package.Definition())
|
|
23
|
+
>>> result = v3_to_v4(lib, package_version="1.2.0")
|
|
24
|
+
>>> result.value.package.version
|
|
25
|
+
'1.2.0'
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import dataclasses
|
|
31
|
+
import re
|
|
32
|
+
from dataclasses import dataclass, field
|
|
33
|
+
from typing import cast, overload
|
|
34
|
+
|
|
35
|
+
from . import diagnostics as d
|
|
36
|
+
from .diagnostics import Diagnostic, Location
|
|
37
|
+
from .v3 import access_controlled as ac3
|
|
38
|
+
from .v3 import distribution as dist3
|
|
39
|
+
from .v3 import documented as doc3
|
|
40
|
+
from .v3 import fqname as fq3
|
|
41
|
+
from .v3 import literal as lit3
|
|
42
|
+
from .v3 import module as mod3
|
|
43
|
+
from .v3 import name as name3
|
|
44
|
+
from .v3 import package as pkg3
|
|
45
|
+
from .v3 import path as path3
|
|
46
|
+
from .v3 import type as t3
|
|
47
|
+
from .v3 import value as v3
|
|
48
|
+
from .v4 import access_controlled as ac4
|
|
49
|
+
from .v4 import annotation as ann4
|
|
50
|
+
from .v4 import distribution as dist4
|
|
51
|
+
from .v4 import documented as doc4
|
|
52
|
+
from .v4 import fqname as fq4
|
|
53
|
+
from .v4 import literal as lit4
|
|
54
|
+
from .v4 import module as mod4
|
|
55
|
+
from .v4 import name as name4
|
|
56
|
+
from .v4 import package as pkg4
|
|
57
|
+
from .v4 import path as path4
|
|
58
|
+
from .v4 import type as t4
|
|
59
|
+
from .v4 import type_def as td4
|
|
60
|
+
from .v4 import type_spec as ts4
|
|
61
|
+
from .v4 import value as v4
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass(frozen=True)
|
|
65
|
+
class Ok[T]:
|
|
66
|
+
"""A successful migration, with any warnings about dropped information."""
|
|
67
|
+
|
|
68
|
+
value: T
|
|
69
|
+
warnings: tuple[Diagnostic, ...] = ()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass(frozen=True)
|
|
73
|
+
class Err:
|
|
74
|
+
"""A failed migration holding every diagnostic found."""
|
|
75
|
+
|
|
76
|
+
diagnostics: tuple[Diagnostic, ...]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
type MigrationResult[T] = Ok[T] | Err
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# --- v3 -> v4 ---
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _name_up(n: name3.Name) -> name4.Name:
|
|
86
|
+
return name4.Name(tuple(n))
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _path_up(p: path3.Path) -> path4.Path:
|
|
90
|
+
return path4.Path(tuple(_name_up(n) for n in p))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _fqname_up(f: fq3.FQName) -> fq4.FQName:
|
|
94
|
+
return fq4.FQName(
|
|
95
|
+
_path_up(f.package_path), _path_up(f.module_path), _name_up(f.local_name)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _access_up[A, B](
|
|
100
|
+
item: ac3.AccessControlled[A], value: B
|
|
101
|
+
) -> ac4.AccessControlled[B]:
|
|
102
|
+
if item.access is ac3.Access.PUBLIC:
|
|
103
|
+
return ac4.Public(value)
|
|
104
|
+
return ac4.Private(value)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _literal_up(literal: lit3.Literal) -> lit4.Literal:
|
|
108
|
+
match literal:
|
|
109
|
+
case lit3.BoolLiteral(b):
|
|
110
|
+
return lit4.BoolLiteral(b)
|
|
111
|
+
case lit3.CharLiteral(c):
|
|
112
|
+
return lit4.CharLiteral(c)
|
|
113
|
+
case lit3.StringLiteral(s):
|
|
114
|
+
return lit4.StringLiteral(s)
|
|
115
|
+
case lit3.WholeNumberLiteral(i):
|
|
116
|
+
return lit4.IntegerLiteral(i)
|
|
117
|
+
case lit3.FloatLiteral(f):
|
|
118
|
+
return lit4.FloatLiteral(f)
|
|
119
|
+
case lit3.DecimalLiteral(x):
|
|
120
|
+
return lit4.DecimalLiteral(x)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _type_up(tpe: t3.Type[None]) -> t4.Type:
|
|
124
|
+
a = t4.TypeAttributes()
|
|
125
|
+
match tpe:
|
|
126
|
+
case t3.Variable(_, n):
|
|
127
|
+
return t4.Variable(a, _name_up(n))
|
|
128
|
+
case t3.Reference(_, f, args):
|
|
129
|
+
return t4.Reference(a, _fqname_up(f), [_type_up(x) for x in args])
|
|
130
|
+
case t3.Tuple(_, elements):
|
|
131
|
+
return t4.Tuple(a, [_type_up(x) for x in elements])
|
|
132
|
+
case t3.Record(_, fields):
|
|
133
|
+
return t4.Record(
|
|
134
|
+
a, [t4.Field(_name_up(f.name), _type_up(f.tpe)) for f in fields]
|
|
135
|
+
)
|
|
136
|
+
case t3.ExtensibleRecord(_, var, fields):
|
|
137
|
+
return t4.ExtensibleRecord(
|
|
138
|
+
a,
|
|
139
|
+
_name_up(var),
|
|
140
|
+
[t4.Field(_name_up(f.name), _type_up(f.tpe)) for f in fields],
|
|
141
|
+
)
|
|
142
|
+
case t3.Function(_, arg, ret):
|
|
143
|
+
return t4.Function(a, _type_up(arg), _type_up(ret))
|
|
144
|
+
case t3.Unit(_):
|
|
145
|
+
return t4.Unit(a)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _ctors_up(ctors: t3.Constructors[None]) -> ts4.Constructors:
|
|
149
|
+
return {
|
|
150
|
+
_name_up(n): [(_name_up(an), _type_up(at)) for an, at in args]
|
|
151
|
+
for n, args in ctors.items()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _params_up(params: tuple[name3.Name, ...]) -> list[name4.Name]:
|
|
156
|
+
return [_name_up(p) for p in params]
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _type_spec_up(spec: t3.Specification[None]) -> ts4.Specification:
|
|
160
|
+
match spec:
|
|
161
|
+
case t3.TypeAliasSpecification(params, tpe):
|
|
162
|
+
return ts4.TypeAliasSpecification(_params_up(params), _type_up(tpe))
|
|
163
|
+
case t3.OpaqueTypeSpecification(params):
|
|
164
|
+
return ts4.OpaqueTypeSpecification(_params_up(params))
|
|
165
|
+
case t3.CustomTypeSpecification(params, ctors):
|
|
166
|
+
return ts4.CustomTypeSpecification(_params_up(params), _ctors_up(ctors))
|
|
167
|
+
case t3.DerivedTypeSpecification(params, base, from_base, to_base):
|
|
168
|
+
return ts4.DerivedTypeSpecification(
|
|
169
|
+
_params_up(params),
|
|
170
|
+
ts4.DerivedTypeSpecificationDetails(
|
|
171
|
+
_type_up(base), _fqname_up(from_base), _fqname_up(to_base)
|
|
172
|
+
),
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _type_def_up(defn: t3.Definition[None]) -> td4.Definition:
|
|
177
|
+
match defn:
|
|
178
|
+
case t3.TypeAliasDefinition(params, tpe):
|
|
179
|
+
return td4.TypeAliasDefinition(_params_up(params), _type_up(tpe))
|
|
180
|
+
case t3.CustomTypeDefinition(params, ctors):
|
|
181
|
+
return td4.CustomTypeDefinition(
|
|
182
|
+
_params_up(params), _access_up(ctors, _ctors_up(ctors.value))
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _va_up(tpe: t3.Type[None]) -> v4.ValueAttributes:
|
|
187
|
+
return v4.ValueAttributes(inferred_type=_type_up(tpe))
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
type TypedValue3 = v3.Value[None, t3.Type[None]]
|
|
191
|
+
type TypedPattern3 = v3.Pattern[t3.Type[None]]
|
|
192
|
+
type TypedDefinition3 = v3.Definition[None, t3.Type[None]]
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _pattern_up(p: TypedPattern3) -> v4.Pattern:
|
|
196
|
+
a = _va_up(p.attributes)
|
|
197
|
+
match p:
|
|
198
|
+
case v3.WildcardPattern(_):
|
|
199
|
+
return v4.WildcardPattern(a)
|
|
200
|
+
case v3.AsPattern(_, inner, n):
|
|
201
|
+
return v4.AsPattern(a, _pattern_up(inner), _name_up(n))
|
|
202
|
+
case v3.TuplePattern(_, elements):
|
|
203
|
+
return v4.TuplePattern(a, [_pattern_up(x) for x in elements])
|
|
204
|
+
case v3.ConstructorPattern(_, f, args):
|
|
205
|
+
return v4.ConstructorPattern(
|
|
206
|
+
a, _fqname_up(f), [_pattern_up(x) for x in args]
|
|
207
|
+
)
|
|
208
|
+
case v3.EmptyListPattern(_):
|
|
209
|
+
return v4.EmptyListPattern(a)
|
|
210
|
+
case v3.HeadTailPattern(_, head, tail):
|
|
211
|
+
return v4.HeadTailPattern(a, _pattern_up(head), _pattern_up(tail))
|
|
212
|
+
case v3.LiteralPattern(_, literal):
|
|
213
|
+
return v4.LiteralPattern(a, _literal_up(literal))
|
|
214
|
+
case v3.UnitPattern(_):
|
|
215
|
+
return v4.UnitPattern(a)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _value_up(val: TypedValue3) -> v4.Value:
|
|
219
|
+
a = _va_up(val.attributes)
|
|
220
|
+
match val:
|
|
221
|
+
case v3.LiteralValue(_, literal):
|
|
222
|
+
return v4.LiteralValue(a, _literal_up(literal))
|
|
223
|
+
case v3.Constructor(_, f):
|
|
224
|
+
return v4.Constructor(a, _fqname_up(f))
|
|
225
|
+
case v3.Tuple(_, elements):
|
|
226
|
+
return v4.Tuple(a, [_value_up(x) for x in elements])
|
|
227
|
+
case v3.List(_, items):
|
|
228
|
+
return v4.List(a, [_value_up(x) for x in items])
|
|
229
|
+
case v3.Record(_, fields):
|
|
230
|
+
return v4.Record(
|
|
231
|
+
a, [(_name_up(n), _value_up(x)) for n, x in fields.items()]
|
|
232
|
+
)
|
|
233
|
+
case v3.Variable(_, n):
|
|
234
|
+
return v4.Variable(a, _name_up(n))
|
|
235
|
+
case v3.Reference(_, f):
|
|
236
|
+
return v4.Reference(a, _fqname_up(f))
|
|
237
|
+
case v3.Field(_, subject, n):
|
|
238
|
+
return v4.Field(a, _value_up(subject), _name_up(n))
|
|
239
|
+
case v3.FieldFunction(_, n):
|
|
240
|
+
return v4.FieldFunction(a, _name_up(n))
|
|
241
|
+
case v3.Apply(_, function, argument):
|
|
242
|
+
return v4.Apply(a, _value_up(function), _value_up(argument))
|
|
243
|
+
case v3.Lambda(_, pattern, body):
|
|
244
|
+
return v4.Lambda(a, _pattern_up(pattern), _value_up(body))
|
|
245
|
+
case v3.LetDefinition(_, n, defn, in_value):
|
|
246
|
+
return v4.LetDefinition(
|
|
247
|
+
a, _name_up(n), _value_def_up(defn), _value_up(in_value)
|
|
248
|
+
)
|
|
249
|
+
case v3.LetRecursion(_, defs, in_value):
|
|
250
|
+
return v4.LetRecursion(
|
|
251
|
+
a,
|
|
252
|
+
{_name_up(n): _value_def_up(x) for n, x in defs.items()},
|
|
253
|
+
_value_up(in_value),
|
|
254
|
+
)
|
|
255
|
+
case v3.Destructure(_, pattern, subject, in_value):
|
|
256
|
+
return v4.Destructure(
|
|
257
|
+
a, _pattern_up(pattern), _value_up(subject), _value_up(in_value)
|
|
258
|
+
)
|
|
259
|
+
case v3.IfThenElse(_, cond, then_branch, else_branch):
|
|
260
|
+
return v4.IfThenElse(
|
|
261
|
+
a, _value_up(cond), _value_up(then_branch), _value_up(else_branch)
|
|
262
|
+
)
|
|
263
|
+
case v3.PatternMatch(_, subject, cases):
|
|
264
|
+
return v4.PatternMatch(
|
|
265
|
+
a,
|
|
266
|
+
_value_up(subject),
|
|
267
|
+
[(_pattern_up(p), _value_up(b)) for p, b in cases],
|
|
268
|
+
)
|
|
269
|
+
case v3.UpdateRecord(_, subject, fields):
|
|
270
|
+
return v4.UpdateRecord(
|
|
271
|
+
a,
|
|
272
|
+
_value_up(subject),
|
|
273
|
+
[(_name_up(n), _value_up(x)) for n, x in fields.items()],
|
|
274
|
+
)
|
|
275
|
+
case v3.Unit(_):
|
|
276
|
+
return v4.Unit(a)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def _value_def_up(defn: TypedDefinition3) -> v4.Definition:
|
|
280
|
+
return v4.Definition(
|
|
281
|
+
[(_name_up(n), _va_up(va), _type_up(tpe)) for n, va, tpe in defn.input_types],
|
|
282
|
+
_type_up(defn.output_type),
|
|
283
|
+
_value_up(defn.body),
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _value_spec_up(spec: v3.Specification[None]) -> v4.Specification:
|
|
288
|
+
return v4.Specification(
|
|
289
|
+
[(_name_up(n), _type_up(tp)) for n, tp in spec.inputs], _type_up(spec.output)
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _documented_up[A, B](item: doc3.Documented[A], value: B) -> doc4.Documented[B]:
|
|
294
|
+
return doc4.Documented(item.doc, value)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def _module_spec_up(spec: mod3.Specification[None]) -> mod4.Specification:
|
|
298
|
+
return mod4.Specification(
|
|
299
|
+
types={
|
|
300
|
+
_name_up(n): _documented_up(x, _type_spec_up(x.value))
|
|
301
|
+
for n, x in spec.types.items()
|
|
302
|
+
},
|
|
303
|
+
values={
|
|
304
|
+
_name_up(n): _documented_up(x, _value_spec_up(x.value))
|
|
305
|
+
for n, x in spec.values.items()
|
|
306
|
+
},
|
|
307
|
+
doc=spec.doc,
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _module_def_up(defn: mod3.Definition[None, t3.Type[None]]) -> mod4.Definition:
|
|
312
|
+
return mod4.Definition(
|
|
313
|
+
types={
|
|
314
|
+
_name_up(n): _access_up(
|
|
315
|
+
x, _documented_up(x.value, _type_def_up(x.value.value))
|
|
316
|
+
)
|
|
317
|
+
for n, x in defn.types.items()
|
|
318
|
+
},
|
|
319
|
+
values={
|
|
320
|
+
_name_up(n): _access_up(
|
|
321
|
+
x, _documented_up(x.value, _value_def_up(x.value.value))
|
|
322
|
+
)
|
|
323
|
+
for n, x in defn.values.items()
|
|
324
|
+
},
|
|
325
|
+
doc=defn.doc,
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def _package_spec_up(spec: pkg3.Specification[None]) -> pkg4.Specification:
|
|
330
|
+
return pkg4.Specification(
|
|
331
|
+
{_path_up(p): _module_spec_up(m) for p, m in spec.modules.items()}
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _package_def_up(defn: pkg3.Definition[None, t3.Type[None]]) -> pkg4.Definition:
|
|
336
|
+
return pkg4.Definition(
|
|
337
|
+
{
|
|
338
|
+
_path_up(p): _access_up(m, _module_def_up(m.value))
|
|
339
|
+
for p, m in defn.modules.items()
|
|
340
|
+
}
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
@overload
|
|
345
|
+
def v3_to_v4(
|
|
346
|
+
dist: dist3.Library,
|
|
347
|
+
*,
|
|
348
|
+
package_version: str | None = None,
|
|
349
|
+
drop_input_attributes: bool = False,
|
|
350
|
+
) -> Ok[dist4.LibraryDistribution]: ...
|
|
351
|
+
@overload
|
|
352
|
+
def v3_to_v4(
|
|
353
|
+
dist: dist3.Specs,
|
|
354
|
+
*,
|
|
355
|
+
package_version: str | None = None,
|
|
356
|
+
drop_input_attributes: bool = False,
|
|
357
|
+
) -> Ok[dist4.SpecsDistribution]: ...
|
|
358
|
+
def v3_to_v4(
|
|
359
|
+
dist: dist3.Distribution,
|
|
360
|
+
*,
|
|
361
|
+
package_version: str | None = None,
|
|
362
|
+
drop_input_attributes: bool = False,
|
|
363
|
+
) -> Ok[dist4.LibraryDistribution] | Ok[dist4.SpecsDistribution]:
|
|
364
|
+
"""Migrate a format-3 Library or Specs to the same v4 distribution kind.
|
|
365
|
+
|
|
366
|
+
Unit type attributes become empty `TypeAttributes`; each value attribute type
|
|
367
|
+
becomes ``inferred_type``; ``WholeNumberLiteral`` becomes ``IntegerLiteral``.
|
|
368
|
+
A Specs maps its package specification as a Library maps its dependencies.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
dist: The v3 Library or Specs.
|
|
372
|
+
package_version: Optional release version for the v4 package identity.
|
|
373
|
+
Without it the version is absent; nothing is invented.
|
|
374
|
+
drop_input_attributes: Reset each value-definition input's attributes to
|
|
375
|
+
its declared type, as `drop_input_attributes` does, so the result can
|
|
376
|
+
be encoded as v4 JSON. Each input that loses information is reported.
|
|
377
|
+
|
|
378
|
+
Returns:
|
|
379
|
+
``Ok`` with the v4 Library or Specs and any ``input_attributes_dropped``
|
|
380
|
+
warnings. Forward migration has no failure paths.
|
|
381
|
+
"""
|
|
382
|
+
package = dist4.PackageInfo(_path_up(dist.package_name), package_version)
|
|
383
|
+
dependencies = {
|
|
384
|
+
_path_up(p): _package_spec_up(s) for p, s in dist.dependencies.items()
|
|
385
|
+
}
|
|
386
|
+
if isinstance(dist, dist3.Specs):
|
|
387
|
+
specs = dist4.SpecsDistribution(
|
|
388
|
+
package=package,
|
|
389
|
+
specification=_package_spec_up(dist.specification),
|
|
390
|
+
dependencies=dependencies,
|
|
391
|
+
)
|
|
392
|
+
if drop_input_attributes:
|
|
393
|
+
return _drop_input_attributes(specs)
|
|
394
|
+
return Ok(specs)
|
|
395
|
+
library = dist4.LibraryDistribution(
|
|
396
|
+
package=package,
|
|
397
|
+
definition=_package_def_up(dist.definition),
|
|
398
|
+
dependencies=dependencies,
|
|
399
|
+
)
|
|
400
|
+
if drop_input_attributes:
|
|
401
|
+
return _drop_input_attributes(library)
|
|
402
|
+
return Ok(library)
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
# --- Per-input attributes ---
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
class _InputDrop:
|
|
409
|
+
"""Resets value-definition input attributes, recording each loss."""
|
|
410
|
+
|
|
411
|
+
def __init__(self) -> None:
|
|
412
|
+
self.warnings: list[Diagnostic] = []
|
|
413
|
+
|
|
414
|
+
def definition(
|
|
415
|
+
self, defn: v4.ValueDefinitionBody, loc: Location
|
|
416
|
+
) -> v4.ValueDefinitionBody:
|
|
417
|
+
match defn:
|
|
418
|
+
case v4.Definition():
|
|
419
|
+
return self.expression(defn, loc)
|
|
420
|
+
case v4.ExternalBody(inputs, output, externals, fallback):
|
|
421
|
+
here = (*loc, "ExternalBody", "body")
|
|
422
|
+
return v4.ExternalBody(
|
|
423
|
+
inputs,
|
|
424
|
+
output,
|
|
425
|
+
externals,
|
|
426
|
+
None if fallback is None else self.value(fallback, here),
|
|
427
|
+
)
|
|
428
|
+
case v4.IncompleteBody(inputs, incompleteness, output, partial):
|
|
429
|
+
here = (*loc, "IncompleteBody", "partial_body")
|
|
430
|
+
return v4.IncompleteBody(
|
|
431
|
+
inputs,
|
|
432
|
+
incompleteness,
|
|
433
|
+
output,
|
|
434
|
+
None if partial is None else self.value(partial, here),
|
|
435
|
+
)
|
|
436
|
+
case v4.NativeBody():
|
|
437
|
+
return defn
|
|
438
|
+
|
|
439
|
+
def expression(self, defn: v4.Definition, loc: Location) -> v4.Definition:
|
|
440
|
+
inputs: list[tuple[name4.Name, v4.ValueAttributes, t4.Type]] = []
|
|
441
|
+
for n, attrs, tpe in defn.input_types:
|
|
442
|
+
declared = v4.ValueAttributes(inferred_type=tpe)
|
|
443
|
+
if attrs not in (v4.ValueAttributes(), declared):
|
|
444
|
+
self.warnings.append(
|
|
445
|
+
Diagnostic(
|
|
446
|
+
d.INPUT_ATTRIBUTES_DROPPED,
|
|
447
|
+
"ValueDefinitionInput",
|
|
448
|
+
(*loc, "input_types", name4.to_string(n)),
|
|
449
|
+
f"input {name4.to_string(n)!r} kept only its declared type; "
|
|
450
|
+
"v4 JSON spells an input as a bare type",
|
|
451
|
+
)
|
|
452
|
+
)
|
|
453
|
+
inputs.append((n, declared, tpe))
|
|
454
|
+
return v4.Definition(
|
|
455
|
+
inputs, defn.output_type, self.value(defn.body, (*loc, "body"))
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
def value(self, val: v4.Value, loc: Location) -> v4.Value:
|
|
459
|
+
here = (*loc, type(val).__name__)
|
|
460
|
+
a = val.attributes
|
|
461
|
+
match val:
|
|
462
|
+
case v4.Tuple(_, elements):
|
|
463
|
+
return v4.Tuple(
|
|
464
|
+
a, [self.value(x, (*here, i)) for i, x in enumerate(elements)]
|
|
465
|
+
)
|
|
466
|
+
case v4.List(_, items):
|
|
467
|
+
return v4.List(
|
|
468
|
+
a, [self.value(x, (*here, i)) for i, x in enumerate(items)]
|
|
469
|
+
)
|
|
470
|
+
case v4.Record(_, fields):
|
|
471
|
+
return v4.Record(a, self.fields(fields, here))
|
|
472
|
+
case v4.Field(_, subject, n):
|
|
473
|
+
return v4.Field(a, self.value(subject, (*here, "subject")), n)
|
|
474
|
+
case v4.Apply(_, function, argument):
|
|
475
|
+
return v4.Apply(
|
|
476
|
+
a,
|
|
477
|
+
self.value(function, (*here, "function")),
|
|
478
|
+
self.value(argument, (*here, "argument")),
|
|
479
|
+
)
|
|
480
|
+
case v4.Lambda(_, pattern, body):
|
|
481
|
+
return v4.Lambda(a, pattern, self.value(body, (*here, "body")))
|
|
482
|
+
case v4.LetDefinition(_, n, defn, in_value):
|
|
483
|
+
return v4.LetDefinition(
|
|
484
|
+
a,
|
|
485
|
+
n,
|
|
486
|
+
self.definition(defn, (*here, "definition")),
|
|
487
|
+
self.value(in_value, (*here, "in_value")),
|
|
488
|
+
)
|
|
489
|
+
case v4.LetRecursion(_, defs, in_value):
|
|
490
|
+
return v4.LetRecursion(
|
|
491
|
+
a,
|
|
492
|
+
{
|
|
493
|
+
k: self.definition(
|
|
494
|
+
x, (*here, "definitions", name4.to_string(k))
|
|
495
|
+
)
|
|
496
|
+
for k, x in defs.items()
|
|
497
|
+
},
|
|
498
|
+
self.value(in_value, (*here, "in_value")),
|
|
499
|
+
)
|
|
500
|
+
case v4.Destructure(_, pattern, subject, in_value):
|
|
501
|
+
return v4.Destructure(
|
|
502
|
+
a,
|
|
503
|
+
pattern,
|
|
504
|
+
self.value(subject, (*here, "value_to_destructure")),
|
|
505
|
+
self.value(in_value, (*here, "in_value")),
|
|
506
|
+
)
|
|
507
|
+
case v4.IfThenElse(_, cond, then_branch, else_branch):
|
|
508
|
+
return v4.IfThenElse(
|
|
509
|
+
a,
|
|
510
|
+
self.value(cond, (*here, "condition")),
|
|
511
|
+
self.value(then_branch, (*here, "then_branch")),
|
|
512
|
+
self.value(else_branch, (*here, "else_branch")),
|
|
513
|
+
)
|
|
514
|
+
case v4.PatternMatch(_, subject, cases):
|
|
515
|
+
return v4.PatternMatch(
|
|
516
|
+
a,
|
|
517
|
+
self.value(subject, (*here, "branch_on")),
|
|
518
|
+
[
|
|
519
|
+
(p, self.value(b, (*here, "cases", i)))
|
|
520
|
+
for i, (p, b) in enumerate(cases)
|
|
521
|
+
],
|
|
522
|
+
)
|
|
523
|
+
case v4.UpdateRecord(_, subject, fields):
|
|
524
|
+
return v4.UpdateRecord(
|
|
525
|
+
a,
|
|
526
|
+
self.value(subject, (*here, "value_to_update")),
|
|
527
|
+
self.fields(fields, here),
|
|
528
|
+
)
|
|
529
|
+
case _:
|
|
530
|
+
return val
|
|
531
|
+
|
|
532
|
+
def fields(
|
|
533
|
+
self, items: list[tuple[name4.Name, v4.Value]], loc: Location
|
|
534
|
+
) -> list[tuple[name4.Name, v4.Value]]:
|
|
535
|
+
return [(k, self.value(x, (*loc, name4.to_string(k)))) for k, x in items]
|
|
536
|
+
|
|
537
|
+
def package_def(self, defn: pkg4.Definition, loc: Location) -> pkg4.Definition:
|
|
538
|
+
modules: dict[path4.Path, ac4.AccessControlled[mod4.Definition]] = {}
|
|
539
|
+
for p, m in defn.modules.items():
|
|
540
|
+
here = (*loc, path4.to_string(p))
|
|
541
|
+
values = {
|
|
542
|
+
k: _with_access(
|
|
543
|
+
x,
|
|
544
|
+
doc4.Documented(
|
|
545
|
+
x.value.doc,
|
|
546
|
+
self.definition(
|
|
547
|
+
x.value.value, (*here, "values", name4.to_string(k))
|
|
548
|
+
),
|
|
549
|
+
),
|
|
550
|
+
)
|
|
551
|
+
for k, x in m.value.values.items()
|
|
552
|
+
}
|
|
553
|
+
modules[p] = _with_access(
|
|
554
|
+
m, mod4.Definition(m.value.types, values, m.value.doc)
|
|
555
|
+
)
|
|
556
|
+
return pkg4.Definition(modules)
|
|
557
|
+
|
|
558
|
+
# Specifications: annotation arguments are expressions too.
|
|
559
|
+
|
|
560
|
+
def annotations(
|
|
561
|
+
self, items: list[ann4.Annotation], loc: Location
|
|
562
|
+
) -> list[ann4.Annotation]:
|
|
563
|
+
result: list[ann4.Annotation] = []
|
|
564
|
+
for i, item in enumerate(items):
|
|
565
|
+
here = (*loc, "annotations", i)
|
|
566
|
+
if isinstance(item, ann4.CompactAnnotation):
|
|
567
|
+
result.append(item)
|
|
568
|
+
continue
|
|
569
|
+
arguments: list[ann4.AnnotationArgument] = []
|
|
570
|
+
for j, arg in enumerate(item.arguments):
|
|
571
|
+
at = (*here, "arguments", j)
|
|
572
|
+
match arg:
|
|
573
|
+
case ann4.PositionalArgument(value):
|
|
574
|
+
arguments.append(ann4.PositionalArgument(self.value(value, at)))
|
|
575
|
+
case ann4.NamedArgument(name, value):
|
|
576
|
+
arguments.append(
|
|
577
|
+
ann4.NamedArgument(name, self.value(value, (*at, "value")))
|
|
578
|
+
)
|
|
579
|
+
result.append(ann4.StructuredAnnotation(item.name, arguments))
|
|
580
|
+
return result
|
|
581
|
+
|
|
582
|
+
def module_spec(
|
|
583
|
+
self, spec: mod4.Specification, loc: Location
|
|
584
|
+
) -> mod4.Specification:
|
|
585
|
+
types = {
|
|
586
|
+
k: doc4.Documented(
|
|
587
|
+
x.doc,
|
|
588
|
+
dataclasses.replace(
|
|
589
|
+
x.value,
|
|
590
|
+
annotations=self.annotations(
|
|
591
|
+
x.value.annotations, (*loc, "types", name4.to_string(k))
|
|
592
|
+
),
|
|
593
|
+
),
|
|
594
|
+
)
|
|
595
|
+
for k, x in spec.types.items()
|
|
596
|
+
}
|
|
597
|
+
values = {
|
|
598
|
+
k: doc4.Documented(
|
|
599
|
+
x.doc,
|
|
600
|
+
dataclasses.replace(
|
|
601
|
+
x.value,
|
|
602
|
+
annotations=self.annotations(
|
|
603
|
+
x.value.annotations, (*loc, "values", name4.to_string(k))
|
|
604
|
+
),
|
|
605
|
+
),
|
|
606
|
+
)
|
|
607
|
+
for k, x in spec.values.items()
|
|
608
|
+
}
|
|
609
|
+
return mod4.Specification(
|
|
610
|
+
types, values, spec.doc, self.annotations(spec.annotations, loc)
|
|
611
|
+
)
|
|
612
|
+
|
|
613
|
+
def package_spec(
|
|
614
|
+
self, spec: pkg4.Specification, loc: Location
|
|
615
|
+
) -> pkg4.Specification:
|
|
616
|
+
return pkg4.Specification(
|
|
617
|
+
{
|
|
618
|
+
p: self.module_spec(m, (*loc, path4.to_string(p)))
|
|
619
|
+
for p, m in spec.modules.items()
|
|
620
|
+
}
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def _with_access[A, B](
|
|
625
|
+
item: ac4.AccessControlled[A], value: B
|
|
626
|
+
) -> ac4.AccessControlled[B]:
|
|
627
|
+
return ac4.Public(value) if isinstance(item, ac4.Public) else ac4.Private(value)
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
def drop_input_attributes[D: dist4.Distribution](dist: D) -> Ok[D]:
|
|
631
|
+
"""Reset every value-definition input's attributes to its declared type.
|
|
632
|
+
|
|
633
|
+
v4 JSON spells an input as a bare type (kit case ``definitions-0027``), so
|
|
634
|
+
the draft codec refuses an input whose attributes hold anything else, such as
|
|
635
|
+
the resolved types morphir-elm writes for typed inputs. This drop makes such
|
|
636
|
+
a distribution encodable. Module-level and let-bound definitions are covered.
|
|
637
|
+
|
|
638
|
+
Args:
|
|
639
|
+
dist: Any v4 distribution. Dependencies and the expressions in
|
|
640
|
+
specification annotation arguments are covered too.
|
|
641
|
+
|
|
642
|
+
Returns:
|
|
643
|
+
``Ok`` with the distribution and one ``input_attributes_dropped`` warning
|
|
644
|
+
per input whose attributes were neither empty nor its declared type.
|
|
645
|
+
"""
|
|
646
|
+
return _drop_input_attributes(dist)
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def _drop_input_attributes[D: dist4.Distribution](dist: D) -> Ok[D]:
|
|
650
|
+
job = _InputDrop()
|
|
651
|
+
loc: Location = ("distribution", "modules")
|
|
652
|
+
|
|
653
|
+
def dep(p: path4.Path) -> Location:
|
|
654
|
+
return ("distribution", "dependencies", path4.to_string(p))
|
|
655
|
+
|
|
656
|
+
result: dist4.Distribution
|
|
657
|
+
match dist:
|
|
658
|
+
case dist4.SpecsDistribution(package, specification, deps):
|
|
659
|
+
result = dist4.SpecsDistribution(
|
|
660
|
+
package,
|
|
661
|
+
job.package_spec(specification, loc),
|
|
662
|
+
{p: job.package_spec(s, dep(p)) for p, s in deps.items()},
|
|
663
|
+
)
|
|
664
|
+
case dist4.LibraryDistribution(package, definition, deps):
|
|
665
|
+
result = dist4.LibraryDistribution(
|
|
666
|
+
package,
|
|
667
|
+
job.package_def(definition, loc),
|
|
668
|
+
{p: job.package_spec(s, dep(p)) for p, s in deps.items()},
|
|
669
|
+
)
|
|
670
|
+
case dist4.ApplicationDistribution(package, definition, deps, entry_points):
|
|
671
|
+
result = dist4.ApplicationDistribution(
|
|
672
|
+
package,
|
|
673
|
+
job.package_def(definition, loc),
|
|
674
|
+
{p: job.package_def(x, dep(p)) for p, x in deps.items()},
|
|
675
|
+
entry_points,
|
|
676
|
+
)
|
|
677
|
+
return Ok(cast("D", result), tuple(job.warnings))
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
# --- v4 -> v3 ---
|
|
681
|
+
|
|
682
|
+
_CLASSIC_WORD = re.compile(r"^[a-z0-9]+$")
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
@dataclass
|
|
686
|
+
class _Downgrade:
|
|
687
|
+
drop_source_locations: bool
|
|
688
|
+
errors: list[Diagnostic] = field(default_factory=list)
|
|
689
|
+
dropped_sources: int = 0
|
|
690
|
+
|
|
691
|
+
def error(self, code: str, construct: str, loc: Location, message: str) -> None:
|
|
692
|
+
self.errors.append(Diagnostic(code, construct, loc, message))
|
|
693
|
+
|
|
694
|
+
# Names
|
|
695
|
+
|
|
696
|
+
def name(self, n: name4.Name, loc: Location) -> name3.Name:
|
|
697
|
+
for word in n:
|
|
698
|
+
if not _CLASSIC_WORD.match(word):
|
|
699
|
+
self.error(
|
|
700
|
+
d.INVALID_NAME,
|
|
701
|
+
"Name",
|
|
702
|
+
loc,
|
|
703
|
+
f"name word {word!r} has no classic (v3) form",
|
|
704
|
+
)
|
|
705
|
+
return name3.Name(tuple(n))
|
|
706
|
+
|
|
707
|
+
def path(self, p: path4.Path, loc: Location) -> path3.Path:
|
|
708
|
+
return path3.Path(tuple(self.name(n, loc) for n in p))
|
|
709
|
+
|
|
710
|
+
def fqname(self, f: fq4.FQName, loc: Location) -> fq3.FQName:
|
|
711
|
+
return fq3.FQName(
|
|
712
|
+
self.path(f.package_path, loc),
|
|
713
|
+
self.path(f.module_path, loc),
|
|
714
|
+
self.name(f.local_name, loc),
|
|
715
|
+
)
|
|
716
|
+
|
|
717
|
+
def access[A, B](
|
|
718
|
+
self, item: ac4.AccessControlled[A], value: B
|
|
719
|
+
) -> ac3.AccessControlled[B]:
|
|
720
|
+
if isinstance(item, ac4.Public):
|
|
721
|
+
return ac3.public(value)
|
|
722
|
+
return ac3.private(value)
|
|
723
|
+
|
|
724
|
+
def documented[A, B](
|
|
725
|
+
self, item: doc4.Documented[A], value: B, construct: str, loc: Location
|
|
726
|
+
) -> doc3.Documented[B]:
|
|
727
|
+
if item.doc is None:
|
|
728
|
+
self.error(
|
|
729
|
+
d.UNSUPPORTED_DOCUMENTATION_DOWNGRADE,
|
|
730
|
+
construct,
|
|
731
|
+
loc,
|
|
732
|
+
f"{construct} has no documentation; v3 member documentation is a "
|
|
733
|
+
"required string",
|
|
734
|
+
)
|
|
735
|
+
return doc3.Documented("", value)
|
|
736
|
+
return doc3.Documented(item.doc, value)
|
|
737
|
+
|
|
738
|
+
# Attributes
|
|
739
|
+
|
|
740
|
+
def type_attributes(self, a: t4.TypeAttributes, loc: Location) -> None:
|
|
741
|
+
present = [
|
|
742
|
+
label
|
|
743
|
+
for label, on in (
|
|
744
|
+
("source", a.source is not None),
|
|
745
|
+
("constraints", a.constraints is not None),
|
|
746
|
+
("extensions", bool(a.extensions)),
|
|
747
|
+
)
|
|
748
|
+
if on
|
|
749
|
+
]
|
|
750
|
+
if present:
|
|
751
|
+
self.error(
|
|
752
|
+
d.UNSUPPORTED_ATTRIBUTES_DOWNGRADE,
|
|
753
|
+
"TypeAttributes",
|
|
754
|
+
loc,
|
|
755
|
+
f"type attributes carry {', '.join(present)}, which v3 cannot hold",
|
|
756
|
+
)
|
|
757
|
+
|
|
758
|
+
def value_attributes(
|
|
759
|
+
self, a: v4.ValueAttributes, construct: str, loc: Location
|
|
760
|
+
) -> t3.Type[None]:
|
|
761
|
+
if a.extensions:
|
|
762
|
+
self.error(
|
|
763
|
+
d.UNSUPPORTED_ATTRIBUTES_DOWNGRADE,
|
|
764
|
+
construct,
|
|
765
|
+
loc,
|
|
766
|
+
"value attributes carry extensions, which v3 cannot hold",
|
|
767
|
+
)
|
|
768
|
+
if a.source is not None:
|
|
769
|
+
if self.drop_source_locations:
|
|
770
|
+
self.dropped_sources += 1
|
|
771
|
+
else:
|
|
772
|
+
self.error(
|
|
773
|
+
d.UNSUPPORTED_ATTRIBUTES_DOWNGRADE,
|
|
774
|
+
construct,
|
|
775
|
+
loc,
|
|
776
|
+
"value attributes carry a source location; pass "
|
|
777
|
+
"drop_source_locations=True to drop it",
|
|
778
|
+
)
|
|
779
|
+
if a.inferred_type is None:
|
|
780
|
+
self.error(
|
|
781
|
+
d.MISSING_INFERRED_TYPE,
|
|
782
|
+
construct,
|
|
783
|
+
loc,
|
|
784
|
+
f"{construct} has no inferred_type; v3 value attributes are types",
|
|
785
|
+
)
|
|
786
|
+
return t3.Unit(None)
|
|
787
|
+
return self.type(a.inferred_type, (*loc, "inferred_type"))
|
|
788
|
+
|
|
789
|
+
# Types
|
|
790
|
+
|
|
791
|
+
def type(self, tpe: t4.Type, loc: Location) -> t3.Type[None]:
|
|
792
|
+
self.type_attributes(tpe.attributes, loc)
|
|
793
|
+
here = (*loc, type(tpe).__name__)
|
|
794
|
+
match tpe:
|
|
795
|
+
case t4.Variable(_, n):
|
|
796
|
+
return t3.Variable(None, self.name(n, here))
|
|
797
|
+
case t4.Reference(_, f, args):
|
|
798
|
+
return t3.Reference(
|
|
799
|
+
None,
|
|
800
|
+
self.fqname(f, here),
|
|
801
|
+
tuple(self.type(x, (*here, i)) for i, x in enumerate(args)),
|
|
802
|
+
)
|
|
803
|
+
case t4.Tuple(_, elements):
|
|
804
|
+
return t3.Tuple(
|
|
805
|
+
None,
|
|
806
|
+
tuple(self.type(x, (*here, i)) for i, x in enumerate(elements)),
|
|
807
|
+
)
|
|
808
|
+
case t4.Record(_, fields):
|
|
809
|
+
return t3.Record(None, self.fields(fields, here))
|
|
810
|
+
case t4.ExtensibleRecord(_, var, fields):
|
|
811
|
+
return t3.ExtensibleRecord(
|
|
812
|
+
None, self.name(var, here), self.fields(fields, here)
|
|
813
|
+
)
|
|
814
|
+
case t4.Function(_, arg, ret):
|
|
815
|
+
return t3.Function(
|
|
816
|
+
None,
|
|
817
|
+
self.type(arg, (*here, "argument_type")),
|
|
818
|
+
self.type(ret, (*here, "return_type")),
|
|
819
|
+
)
|
|
820
|
+
case t4.Unit(_):
|
|
821
|
+
return t3.Unit(None)
|
|
822
|
+
case t4.Union():
|
|
823
|
+
self.unsupported("Union", here)
|
|
824
|
+
return t3.Unit(None)
|
|
825
|
+
|
|
826
|
+
def fields(
|
|
827
|
+
self, fields: list[t4.Field], loc: Location
|
|
828
|
+
) -> tuple[t3.Field[None], ...]:
|
|
829
|
+
return tuple(
|
|
830
|
+
t3.Field(self.name(f.name, loc), self.type(f.tpe, (*loc, "fields", i)))
|
|
831
|
+
for i, f in enumerate(fields)
|
|
832
|
+
)
|
|
833
|
+
|
|
834
|
+
def ctors(self, ctors: ts4.Constructors, loc: Location) -> t3.Constructors[None]:
|
|
835
|
+
return {
|
|
836
|
+
self.name(n, loc): tuple(
|
|
837
|
+
(self.name(an, loc), self.type(at, (*loc, name4.to_string(n), i)))
|
|
838
|
+
for i, (an, at) in enumerate(args)
|
|
839
|
+
)
|
|
840
|
+
for n, args in ctors.items()
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
def params(self, params: list[name4.Name], loc: Location) -> tuple[name3.Name, ...]:
|
|
844
|
+
return tuple(self.name(p, loc) for p in params)
|
|
845
|
+
|
|
846
|
+
def annotations(self, items: list[ann4.Annotation], loc: Location) -> None:
|
|
847
|
+
if items:
|
|
848
|
+
self.unsupported("Annotations", (*loc, "annotations"))
|
|
849
|
+
|
|
850
|
+
def type_spec(
|
|
851
|
+
self, spec: ts4.Specification, loc: Location
|
|
852
|
+
) -> t3.Specification[None]:
|
|
853
|
+
self.annotations(spec.annotations, loc)
|
|
854
|
+
params = self.params(spec.type_params, loc)
|
|
855
|
+
match spec:
|
|
856
|
+
case ts4.TypeAliasSpecification(_, tpe):
|
|
857
|
+
return t3.TypeAliasSpecification(params, self.type(tpe, loc))
|
|
858
|
+
case ts4.OpaqueTypeSpecification(_):
|
|
859
|
+
return t3.OpaqueTypeSpecification(params)
|
|
860
|
+
case ts4.CustomTypeSpecification(_, ctors):
|
|
861
|
+
return t3.CustomTypeSpecification(params, self.ctors(ctors, loc))
|
|
862
|
+
case ts4.DerivedTypeSpecification(_, details):
|
|
863
|
+
return t3.DerivedTypeSpecification(
|
|
864
|
+
params,
|
|
865
|
+
self.type(details.base_type, loc),
|
|
866
|
+
self.fqname(details.from_base_type, loc),
|
|
867
|
+
self.fqname(details.to_base_type, loc),
|
|
868
|
+
)
|
|
869
|
+
|
|
870
|
+
def type_def(self, defn: td4.Definition, loc: Location) -> t3.Definition[None]:
|
|
871
|
+
params = self.params(defn.type_params, loc)
|
|
872
|
+
match defn:
|
|
873
|
+
case td4.TypeAliasDefinition(_, tpe):
|
|
874
|
+
return t3.TypeAliasDefinition(params, self.type(tpe, loc))
|
|
875
|
+
case td4.CustomTypeDefinition(_, ctors):
|
|
876
|
+
return t3.CustomTypeDefinition(
|
|
877
|
+
params, self.access(ctors, self.ctors(ctors.value, loc))
|
|
878
|
+
)
|
|
879
|
+
case td4.IncompleteTypeDefinition():
|
|
880
|
+
self.unsupported(
|
|
881
|
+
"IncompleteTypeDefinition", (*loc, "IncompleteTypeDefinition")
|
|
882
|
+
)
|
|
883
|
+
return t3.TypeAliasDefinition(params, t3.Unit(None))
|
|
884
|
+
|
|
885
|
+
# Values
|
|
886
|
+
|
|
887
|
+
def literal(self, literal: lit4.Literal, loc: Location) -> lit3.Literal:
|
|
888
|
+
match literal:
|
|
889
|
+
case lit4.BoolLiteral(b):
|
|
890
|
+
return lit3.BoolLiteral(b)
|
|
891
|
+
case lit4.CharLiteral(c):
|
|
892
|
+
return lit3.CharLiteral(c)
|
|
893
|
+
case lit4.StringLiteral(s):
|
|
894
|
+
return lit3.StringLiteral(s)
|
|
895
|
+
case lit4.IntegerLiteral(i):
|
|
896
|
+
return lit3.WholeNumberLiteral(i)
|
|
897
|
+
case lit4.FloatLiteral(f):
|
|
898
|
+
return lit3.FloatLiteral(f)
|
|
899
|
+
case lit4.DecimalLiteral(x):
|
|
900
|
+
return lit3.DecimalLiteral(x)
|
|
901
|
+
case lit4.DocumentLiteral():
|
|
902
|
+
self.unsupported("DocumentLiteral", loc)
|
|
903
|
+
return lit3.StringLiteral("")
|
|
904
|
+
|
|
905
|
+
def unsupported(self, construct: str, loc: Location) -> None:
|
|
906
|
+
self.error(
|
|
907
|
+
d.UNSUPPORTED_V4_DOWNGRADE,
|
|
908
|
+
construct,
|
|
909
|
+
loc,
|
|
910
|
+
f"{construct} exists only in IR v4 and cannot be written as format 3.0.0",
|
|
911
|
+
)
|
|
912
|
+
|
|
913
|
+
def pattern(self, p: v4.Pattern, loc: Location) -> TypedPattern3:
|
|
914
|
+
construct = type(p).__name__
|
|
915
|
+
here = (*loc, construct)
|
|
916
|
+
a = self.value_attributes(p.attributes, construct, here)
|
|
917
|
+
match p:
|
|
918
|
+
case v4.WildcardPattern(_):
|
|
919
|
+
return v3.WildcardPattern(a)
|
|
920
|
+
case v4.AsPattern(_, inner, n):
|
|
921
|
+
return v3.AsPattern(
|
|
922
|
+
a, self.pattern(inner, (*here, "pattern")), self.name(n, here)
|
|
923
|
+
)
|
|
924
|
+
case v4.TuplePattern(_, elements):
|
|
925
|
+
return v3.TuplePattern(
|
|
926
|
+
a,
|
|
927
|
+
tuple(self.pattern(x, (*here, i)) for i, x in enumerate(elements)),
|
|
928
|
+
)
|
|
929
|
+
case v4.ConstructorPattern(_, f, args):
|
|
930
|
+
return v3.ConstructorPattern(
|
|
931
|
+
a,
|
|
932
|
+
self.fqname(f, here),
|
|
933
|
+
tuple(self.pattern(x, (*here, i)) for i, x in enumerate(args)),
|
|
934
|
+
)
|
|
935
|
+
case v4.EmptyListPattern(_):
|
|
936
|
+
return v3.EmptyListPattern(a)
|
|
937
|
+
case v4.HeadTailPattern(_, head, tail):
|
|
938
|
+
return v3.HeadTailPattern(
|
|
939
|
+
a,
|
|
940
|
+
self.pattern(head, (*here, "head")),
|
|
941
|
+
self.pattern(tail, (*here, "tail")),
|
|
942
|
+
)
|
|
943
|
+
case v4.LiteralPattern(_, literal):
|
|
944
|
+
return v3.LiteralPattern(a, self.literal(literal, here))
|
|
945
|
+
case v4.UnitPattern(_):
|
|
946
|
+
return v3.UnitPattern(a)
|
|
947
|
+
|
|
948
|
+
def named_values(
|
|
949
|
+
self, items: list[tuple[name4.Name, v4.Value]], construct: str, loc: Location
|
|
950
|
+
) -> dict[name3.Name, TypedValue3]:
|
|
951
|
+
result: dict[name3.Name, TypedValue3] = {}
|
|
952
|
+
for n, x in items:
|
|
953
|
+
key = self.name(n, loc)
|
|
954
|
+
if key in result:
|
|
955
|
+
self.error(
|
|
956
|
+
d.DUPLICATE_MEMBER,
|
|
957
|
+
construct,
|
|
958
|
+
loc,
|
|
959
|
+
f"field {name4.to_string(n)!r} appears more than once; v3 record "
|
|
960
|
+
"fields are a dictionary",
|
|
961
|
+
)
|
|
962
|
+
result[key] = self.value(x, (*loc, name4.to_string(n)))
|
|
963
|
+
return result
|
|
964
|
+
|
|
965
|
+
def value(self, val: v4.Value, loc: Location) -> TypedValue3:
|
|
966
|
+
construct = type(val).__name__
|
|
967
|
+
here = (*loc, construct)
|
|
968
|
+
if isinstance(val, (v4.Hole, v4.Native, v4.External)):
|
|
969
|
+
self.unsupported(construct, here)
|
|
970
|
+
return v3.Unit(t3.Unit(None))
|
|
971
|
+
a = self.value_attributes(val.attributes, construct, here)
|
|
972
|
+
match val:
|
|
973
|
+
case v4.LiteralValue(_, literal):
|
|
974
|
+
return v3.LiteralValue(a, self.literal(literal, here))
|
|
975
|
+
case v4.Constructor(_, f):
|
|
976
|
+
return v3.Constructor(a, self.fqname(f, here))
|
|
977
|
+
case v4.Tuple(_, elements):
|
|
978
|
+
return v3.Tuple(
|
|
979
|
+
a, tuple(self.value(x, (*here, i)) for i, x in enumerate(elements))
|
|
980
|
+
)
|
|
981
|
+
case v4.List(_, items):
|
|
982
|
+
return v3.List(
|
|
983
|
+
a, tuple(self.value(x, (*here, i)) for i, x in enumerate(items))
|
|
984
|
+
)
|
|
985
|
+
case v4.Record(_, fields):
|
|
986
|
+
return v3.Record(a, self.named_values(fields, construct, here))
|
|
987
|
+
case v4.Variable(_, n):
|
|
988
|
+
return v3.Variable(a, self.name(n, here))
|
|
989
|
+
case v4.Reference(_, f):
|
|
990
|
+
return v3.Reference(a, self.fqname(f, here))
|
|
991
|
+
case v4.Field(_, subject, n):
|
|
992
|
+
return v3.Field(
|
|
993
|
+
a, self.value(subject, (*here, "subject")), self.name(n, here)
|
|
994
|
+
)
|
|
995
|
+
case v4.FieldFunction(_, n):
|
|
996
|
+
return v3.FieldFunction(a, self.name(n, here))
|
|
997
|
+
case v4.Apply(_, function, argument):
|
|
998
|
+
return v3.Apply(
|
|
999
|
+
a,
|
|
1000
|
+
self.value(function, (*here, "function")),
|
|
1001
|
+
self.value(argument, (*here, "argument")),
|
|
1002
|
+
)
|
|
1003
|
+
case v4.Lambda(_, pattern, body):
|
|
1004
|
+
return v3.Lambda(
|
|
1005
|
+
a,
|
|
1006
|
+
self.pattern(pattern, (*here, "pattern")),
|
|
1007
|
+
self.value(body, (*here, "body")),
|
|
1008
|
+
)
|
|
1009
|
+
case v4.LetDefinition(_, n, defn, in_value):
|
|
1010
|
+
return v3.LetDefinition(
|
|
1011
|
+
a,
|
|
1012
|
+
self.name(n, here),
|
|
1013
|
+
self.value_def(defn, (*here, "definition")),
|
|
1014
|
+
self.value(in_value, (*here, "in_value")),
|
|
1015
|
+
)
|
|
1016
|
+
case v4.LetRecursion(_, defs, in_value):
|
|
1017
|
+
return v3.LetRecursion(
|
|
1018
|
+
a,
|
|
1019
|
+
{
|
|
1020
|
+
self.name(n, here): self.value_def(
|
|
1021
|
+
x, (*here, "definitions", name4.to_string(n))
|
|
1022
|
+
)
|
|
1023
|
+
for n, x in defs.items()
|
|
1024
|
+
},
|
|
1025
|
+
self.value(in_value, (*here, "in_value")),
|
|
1026
|
+
)
|
|
1027
|
+
case v4.Destructure(_, pattern, subject, in_value):
|
|
1028
|
+
return v3.Destructure(
|
|
1029
|
+
a,
|
|
1030
|
+
self.pattern(pattern, (*here, "pattern")),
|
|
1031
|
+
self.value(subject, (*here, "value_to_destructure")),
|
|
1032
|
+
self.value(in_value, (*here, "in_value")),
|
|
1033
|
+
)
|
|
1034
|
+
case v4.IfThenElse(_, cond, then_branch, else_branch):
|
|
1035
|
+
return v3.IfThenElse(
|
|
1036
|
+
a,
|
|
1037
|
+
self.value(cond, (*here, "condition")),
|
|
1038
|
+
self.value(then_branch, (*here, "then_branch")),
|
|
1039
|
+
self.value(else_branch, (*here, "else_branch")),
|
|
1040
|
+
)
|
|
1041
|
+
case v4.PatternMatch(_, subject, cases):
|
|
1042
|
+
return v3.PatternMatch(
|
|
1043
|
+
a,
|
|
1044
|
+
self.value(subject, (*here, "branch_on")),
|
|
1045
|
+
tuple(
|
|
1046
|
+
(
|
|
1047
|
+
self.pattern(p, (*here, "cases", i)),
|
|
1048
|
+
self.value(b, (*here, "cases", i)),
|
|
1049
|
+
)
|
|
1050
|
+
for i, (p, b) in enumerate(cases)
|
|
1051
|
+
),
|
|
1052
|
+
)
|
|
1053
|
+
case v4.UpdateRecord(_, subject, fields):
|
|
1054
|
+
return v3.UpdateRecord(
|
|
1055
|
+
a,
|
|
1056
|
+
self.value(subject, (*here, "value_to_update")),
|
|
1057
|
+
self.named_values(fields, construct, here),
|
|
1058
|
+
)
|
|
1059
|
+
case _:
|
|
1060
|
+
return v3.Unit(a)
|
|
1061
|
+
|
|
1062
|
+
def value_def(
|
|
1063
|
+
self, defn: v4.ValueDefinitionBody, loc: Location
|
|
1064
|
+
) -> TypedDefinition3:
|
|
1065
|
+
if not isinstance(defn, v4.Definition):
|
|
1066
|
+
construct = type(defn).__name__
|
|
1067
|
+
self.unsupported(construct, (*loc, construct))
|
|
1068
|
+
return v3.Definition((), t3.Unit(None), v3.Unit(t3.Unit(None)))
|
|
1069
|
+
inputs = []
|
|
1070
|
+
for n, va, tpe in defn.input_types:
|
|
1071
|
+
here = (*loc, "input_types", name4.to_string(n))
|
|
1072
|
+
inputs.append(
|
|
1073
|
+
(
|
|
1074
|
+
self.name(n, here),
|
|
1075
|
+
self.value_attributes(va, "ValueDefinitionInput", here),
|
|
1076
|
+
self.type(tpe, here),
|
|
1077
|
+
)
|
|
1078
|
+
)
|
|
1079
|
+
return v3.Definition(
|
|
1080
|
+
tuple(inputs),
|
|
1081
|
+
self.type(defn.output_type, (*loc, "output_type")),
|
|
1082
|
+
self.value(defn.body, (*loc, "body")),
|
|
1083
|
+
)
|
|
1084
|
+
|
|
1085
|
+
def value_spec(
|
|
1086
|
+
self, spec: v4.Specification, loc: Location
|
|
1087
|
+
) -> v3.Specification[None]:
|
|
1088
|
+
self.annotations(spec.annotations, loc)
|
|
1089
|
+
return v3.Specification(
|
|
1090
|
+
tuple(
|
|
1091
|
+
(self.name(n, loc), self.type(tp, (*loc, "inputs", name4.to_string(n))))
|
|
1092
|
+
for n, tp in spec.inputs
|
|
1093
|
+
),
|
|
1094
|
+
self.type(spec.output, (*loc, "output")),
|
|
1095
|
+
)
|
|
1096
|
+
|
|
1097
|
+
# Modules and packages
|
|
1098
|
+
|
|
1099
|
+
def module_spec(
|
|
1100
|
+
self, spec: mod4.Specification, loc: Location
|
|
1101
|
+
) -> mod3.Specification[None]:
|
|
1102
|
+
self.annotations(spec.annotations, loc)
|
|
1103
|
+
types = {}
|
|
1104
|
+
for n, x in spec.types.items():
|
|
1105
|
+
here = (*loc, "types", name4.to_string(n))
|
|
1106
|
+
types[self.name(n, here)] = self.documented(
|
|
1107
|
+
x, self.type_spec(x.value, here), "TypeSpecification", here
|
|
1108
|
+
)
|
|
1109
|
+
values = {}
|
|
1110
|
+
for n, y in spec.values.items():
|
|
1111
|
+
here = (*loc, "values", name4.to_string(n))
|
|
1112
|
+
values[self.name(n, here)] = self.documented(
|
|
1113
|
+
y, self.value_spec(y.value, here), "ValueSpecification", here
|
|
1114
|
+
)
|
|
1115
|
+
return mod3.Specification(types, values, spec.doc)
|
|
1116
|
+
|
|
1117
|
+
def module_def(
|
|
1118
|
+
self, defn: mod4.Definition, loc: Location
|
|
1119
|
+
) -> mod3.Definition[None, t3.Type[None]]:
|
|
1120
|
+
types = {}
|
|
1121
|
+
for n, x in defn.types.items():
|
|
1122
|
+
here = (*loc, "types", name4.to_string(n))
|
|
1123
|
+
types[self.name(n, here)] = self.access(
|
|
1124
|
+
x,
|
|
1125
|
+
self.documented(
|
|
1126
|
+
x.value, self.type_def(x.value.value, here), "TypeDefinition", here
|
|
1127
|
+
),
|
|
1128
|
+
)
|
|
1129
|
+
values = {}
|
|
1130
|
+
for n, y in defn.values.items():
|
|
1131
|
+
here = (*loc, "values", name4.to_string(n))
|
|
1132
|
+
values[self.name(n, here)] = self.access(
|
|
1133
|
+
y,
|
|
1134
|
+
self.documented(
|
|
1135
|
+
y.value,
|
|
1136
|
+
self.value_def(y.value.value, here),
|
|
1137
|
+
"ValueDefinition",
|
|
1138
|
+
here,
|
|
1139
|
+
),
|
|
1140
|
+
)
|
|
1141
|
+
return mod3.Definition(types, values, defn.doc)
|
|
1142
|
+
|
|
1143
|
+
def package_spec(
|
|
1144
|
+
self, spec: pkg4.Specification, loc: Location
|
|
1145
|
+
) -> pkg3.Specification[None]:
|
|
1146
|
+
return pkg3.Specification(
|
|
1147
|
+
{
|
|
1148
|
+
self.path(p, loc): self.module_spec(m, (*loc, path4.to_string(p)))
|
|
1149
|
+
for p, m in spec.modules.items()
|
|
1150
|
+
}
|
|
1151
|
+
)
|
|
1152
|
+
|
|
1153
|
+
def package_def(
|
|
1154
|
+
self, defn: pkg4.Definition, loc: Location
|
|
1155
|
+
) -> pkg3.Definition[None, t3.Type[None]]:
|
|
1156
|
+
return pkg3.Definition(
|
|
1157
|
+
{
|
|
1158
|
+
self.path(p, loc): self.access(
|
|
1159
|
+
m, self.module_def(m.value, (*loc, path4.to_string(p)))
|
|
1160
|
+
)
|
|
1161
|
+
for p, m in defn.modules.items()
|
|
1162
|
+
}
|
|
1163
|
+
)
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
@overload
|
|
1167
|
+
def v4_to_v3(
|
|
1168
|
+
dist: dist4.LibraryDistribution, *, drop_source_locations: bool = False
|
|
1169
|
+
) -> MigrationResult[dist3.Library]: ...
|
|
1170
|
+
@overload
|
|
1171
|
+
def v4_to_v3(
|
|
1172
|
+
dist: dist4.SpecsDistribution, *, drop_source_locations: bool = False
|
|
1173
|
+
) -> MigrationResult[dist3.Specs]: ...
|
|
1174
|
+
@overload
|
|
1175
|
+
def v4_to_v3(
|
|
1176
|
+
dist: dist4.ApplicationDistribution, *, drop_source_locations: bool = False
|
|
1177
|
+
) -> Err: ...
|
|
1178
|
+
def v4_to_v3(
|
|
1179
|
+
dist: dist4.Distribution, *, drop_source_locations: bool = False
|
|
1180
|
+
) -> MigrationResult[dist3.Library] | MigrationResult[dist3.Specs]:
|
|
1181
|
+
"""Migrate a v4 Library or Specs to format 3, or report why it cannot.
|
|
1182
|
+
|
|
1183
|
+
Every unsupported construct is collected in one pass. A Specs becomes a v3
|
|
1184
|
+
Specs, which format 3.1.0 introduced; an Application has no format-3 form.
|
|
1185
|
+
|
|
1186
|
+
Args:
|
|
1187
|
+
dist: The v4 distribution.
|
|
1188
|
+
drop_source_locations: Drop value source locations instead of failing.
|
|
1189
|
+
This is the only opt-in loss.
|
|
1190
|
+
|
|
1191
|
+
Returns:
|
|
1192
|
+
``Ok`` with the v3 Library or Specs and any warnings, or ``Err`` with
|
|
1193
|
+
every diagnostic found.
|
|
1194
|
+
"""
|
|
1195
|
+
if isinstance(dist, dist4.ApplicationDistribution):
|
|
1196
|
+
return Err(
|
|
1197
|
+
(
|
|
1198
|
+
Diagnostic(
|
|
1199
|
+
d.UNSUPPORTED_V4_DOWNGRADE,
|
|
1200
|
+
"Application",
|
|
1201
|
+
("distribution",),
|
|
1202
|
+
"Application distributions cannot be written as format 3, "
|
|
1203
|
+
"which has no Application",
|
|
1204
|
+
),
|
|
1205
|
+
)
|
|
1206
|
+
)
|
|
1207
|
+
job = _Downgrade(drop_source_locations)
|
|
1208
|
+
loc: Location = ("distribution",)
|
|
1209
|
+
|
|
1210
|
+
def dependencies() -> dict[path3.Path, pkg3.Specification[None]]:
|
|
1211
|
+
return {
|
|
1212
|
+
job.path(p, loc): job.package_spec(
|
|
1213
|
+
s, (*loc, "dependencies", path4.to_string(p))
|
|
1214
|
+
)
|
|
1215
|
+
for p, s in dist.dependencies.items()
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
# Fields are migrated in declaration order, so diagnostics keep that order.
|
|
1219
|
+
result: dist3.Library | dist3.Specs
|
|
1220
|
+
if isinstance(dist, dist4.SpecsDistribution):
|
|
1221
|
+
result = dist3.Specs(
|
|
1222
|
+
package_name=job.path(dist.package.name, (*loc, "package")),
|
|
1223
|
+
specification=job.package_spec(dist.specification, (*loc, "modules")),
|
|
1224
|
+
dependencies=dependencies(),
|
|
1225
|
+
)
|
|
1226
|
+
else:
|
|
1227
|
+
result = dist3.Library(
|
|
1228
|
+
package_name=job.path(dist.package.name, (*loc, "package")),
|
|
1229
|
+
definition=job.package_def(dist.definition, (*loc, "modules")),
|
|
1230
|
+
dependencies=dependencies(),
|
|
1231
|
+
)
|
|
1232
|
+
if job.errors:
|
|
1233
|
+
return Err(tuple(job.errors))
|
|
1234
|
+
warnings: list[Diagnostic] = []
|
|
1235
|
+
if dist.package.version is not None:
|
|
1236
|
+
warnings.append(
|
|
1237
|
+
Diagnostic(
|
|
1238
|
+
d.PACKAGE_VERSION_DROPPED,
|
|
1239
|
+
"PackageInfo",
|
|
1240
|
+
(*loc, "package", "version"),
|
|
1241
|
+
f"package version {dist.package.version!r} was dropped; format 3 "
|
|
1242
|
+
"has no package version",
|
|
1243
|
+
)
|
|
1244
|
+
)
|
|
1245
|
+
if job.dropped_sources:
|
|
1246
|
+
warnings.append(
|
|
1247
|
+
Diagnostic(
|
|
1248
|
+
d.SOURCE_LOCATION_DROPPED,
|
|
1249
|
+
"ValueAttributes",
|
|
1250
|
+
loc,
|
|
1251
|
+
f"{job.dropped_sources} value source location(s) were dropped",
|
|
1252
|
+
)
|
|
1253
|
+
)
|
|
1254
|
+
# Ok is invariant, so each kind is returned under its own narrowed type.
|
|
1255
|
+
if isinstance(result, dist3.Specs):
|
|
1256
|
+
return Ok(result, tuple(warnings))
|
|
1257
|
+
return Ok(result, tuple(warnings))
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
__all__ = [
|
|
1261
|
+
"Err",
|
|
1262
|
+
"MigrationResult",
|
|
1263
|
+
"Ok",
|
|
1264
|
+
"drop_input_attributes",
|
|
1265
|
+
"v3_to_v4",
|
|
1266
|
+
"v4_to_v3",
|
|
1267
|
+
]
|