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.
Files changed (99) hide show
  1. morphir/__init__.py +14 -0
  2. morphir/ir/__init__.py +110 -0
  3. morphir/ir/access_controlled.py +15 -0
  4. morphir/ir/decorations.py +19 -0
  5. morphir/ir/diagnostics.py +105 -0
  6. morphir/ir/distribution.py +21 -0
  7. morphir/ir/document.py +37 -0
  8. morphir/ir/documented.py +11 -0
  9. morphir/ir/format_version.py +483 -0
  10. morphir/ir/fqname.py +9 -0
  11. morphir/ir/json.py +11 -0
  12. morphir/ir/literal.py +25 -0
  13. morphir/ir/meta.py +11 -0
  14. morphir/ir/migrate.py +1267 -0
  15. morphir/ir/module.py +17 -0
  16. morphir/ir/name.py +27 -0
  17. morphir/ir/package.py +15 -0
  18. morphir/ir/path.py +25 -0
  19. morphir/ir/qname.py +9 -0
  20. morphir/ir/ref.py +17 -0
  21. morphir/ir/type.py +37 -0
  22. morphir/ir/type_constraints.py +33 -0
  23. morphir/ir/type_def.py +19 -0
  24. morphir/ir/type_spec.py +25 -0
  25. morphir/ir/v3/__init__.py +64 -0
  26. morphir/ir/v3/_legacy_value.py +201 -0
  27. morphir/ir/v3/access_controlled.py +31 -0
  28. morphir/ir/v3/codec.py +1275 -0
  29. morphir/ir/v3/codec_v1.py +491 -0
  30. morphir/ir/v3/codec_v2.py +187 -0
  31. morphir/ir/v3/distribution.py +42 -0
  32. morphir/ir/v3/documented.py +13 -0
  33. morphir/ir/v3/fqname.py +30 -0
  34. morphir/ir/v3/literal.py +46 -0
  35. morphir/ir/v3/module.py +32 -0
  36. morphir/ir/v3/name.py +42 -0
  37. morphir/ir/v3/package.py +23 -0
  38. morphir/ir/v3/path.py +29 -0
  39. morphir/ir/v3/qname.py +16 -0
  40. morphir/ir/v3/type.py +126 -0
  41. morphir/ir/v3/value.py +235 -0
  42. morphir/ir/v4/__init__.py +160 -0
  43. morphir/ir/v4/access_controlled.py +17 -0
  44. morphir/ir/v4/annotation.py +75 -0
  45. morphir/ir/v4/codec.py +2161 -0
  46. morphir/ir/v4/decorations.py +88 -0
  47. morphir/ir/v4/distribution.py +56 -0
  48. morphir/ir/v4/document.py +69 -0
  49. morphir/ir/v4/documented.py +10 -0
  50. morphir/ir/v4/fqname.py +69 -0
  51. morphir/ir/v4/incompleteness.py +78 -0
  52. morphir/ir/v4/json.py +103 -0
  53. morphir/ir/v4/literal.py +51 -0
  54. morphir/ir/v4/meta.py +27 -0
  55. morphir/ir/v4/module.py +30 -0
  56. morphir/ir/v4/name.py +69 -0
  57. morphir/ir/v4/package.py +19 -0
  58. morphir/ir/v4/path.py +50 -0
  59. morphir/ir/v4/qname.py +34 -0
  60. morphir/ir/v4/ref.py +35 -0
  61. morphir/ir/v4/type.py +140 -0
  62. morphir/ir/v4/type_constraints.py +91 -0
  63. morphir/ir/v4/type_def.py +38 -0
  64. morphir/ir/v4/type_spec.py +64 -0
  65. morphir/ir/v4/value.py +480 -0
  66. morphir/ir/value.py +81 -0
  67. morphir/py.typed +0 -0
  68. morphir/sdk/__init__.py +110 -0
  69. morphir/sdk/_compare.py +187 -0
  70. morphir/sdk/aggregate.py +421 -0
  71. morphir/sdk/basics.py +504 -0
  72. morphir/sdk/char.py +110 -0
  73. morphir/sdk/decimal.py +311 -0
  74. morphir/sdk/dict.py +336 -0
  75. morphir/sdk/instant.py +118 -0
  76. morphir/sdk/int.py +86 -0
  77. morphir/sdk/key.py +522 -0
  78. morphir/sdk/list.py +356 -0
  79. morphir/sdk/local_date.py +436 -0
  80. morphir/sdk/local_time.py +267 -0
  81. morphir/sdk/maybe.py +135 -0
  82. morphir/sdk/number.py +237 -0
  83. morphir/sdk/regex.py +287 -0
  84. morphir/sdk/result.py +162 -0
  85. morphir/sdk/result_list.py +169 -0
  86. morphir/sdk/rule.py +103 -0
  87. morphir/sdk/set.py +214 -0
  88. morphir/sdk/stateful_app.py +49 -0
  89. morphir/sdk/string.py +427 -0
  90. morphir/sdk/tuple.py +43 -0
  91. morphir/sdk/uuid.py +209 -0
  92. morphir_python-0.0.1.dist-info/METADATA +269 -0
  93. morphir_python-0.0.1.dist-info/RECORD +99 -0
  94. morphir_python-0.0.1.dist-info/WHEEL +4 -0
  95. morphir_python-0.0.1.dist-info/entry_points.txt +2 -0
  96. morphir_python-0.0.1.dist-info/licenses/LICENSE +201 -0
  97. morphir_tools/__init__.py +13 -0
  98. morphir_tools/cli.py +223 -0
  99. morphir_tools/py.typed +0 -0
@@ -0,0 +1,491 @@
1
+ """Read-only JSON decoders for morphir-elm IR format 1, into the 3.0.0 model.
2
+
3
+ Port of the decoders in morphir-elm ``src/Morphir/IR/*/CodecV1.elm`` at commit
4
+ bc99af69, which morphir-elm still uses to read ``"formatVersion": 1``. As in elm,
5
+ format 1 decodes into the same model as format 3.0.0, so decoding is the upgrade:
6
+ encode the result with `morphir.ir.v3.codec` to write format 3. The encoders are
7
+ not ported, because no writer emits format 1.
8
+
9
+ Format 1 differs from format 3.0.0 only in these spellings:
10
+
11
+ - every tag is snake_case: ``"library"``, ``"public"``, ``"variable"``,
12
+ ``"custom_type_definition"``, ``"let_definition"``, ``"wildcard_pattern"``;
13
+ - literal tags are ``"bool_literal"``, ``"char_literal"``, ``"string_literal"``,
14
+ ``"int_literal"``, ``"float_literal"`` and ``"decimal_literal"``;
15
+ - access control is ``["public", x]``, documentation is ``[doc, x]`` or the bare
16
+ ``x``, and a record field type is ``[name, type]``;
17
+ - package modules are ``{"name", "spec"}`` and ``{"name", "def"}`` objects;
18
+ - modules have no ``doc``; a ``doc`` member is ignored, as in elm.
19
+
20
+ Names, paths, and qualified names are spelled as in format 3.0.0; use the
21
+ `morphir.ir.v3.codec` decoders for them. elm's ``encodeSpecification`` writes a
22
+ derived type as ``"DerivedTypeSpecification"`` but ``decodeSpecification`` reads
23
+ only ``"derived_type_specification"``; this decoder follows the elm decoder.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ from .. import diagnostics as d
29
+ from ..diagnostics import DiagnosticError, Location, fail
30
+ from ..format_version import LegacyFormat, read_legacy_document
31
+ from . import _legacy_value, module, package
32
+ from . import literal as lit
33
+ from . import type as t
34
+ from . import value as v
35
+ from .access_controlled import Access, AccessControlled
36
+ from .codec import (
37
+ Decoder,
38
+ _expect_list,
39
+ _expect_object,
40
+ _field,
41
+ _index,
42
+ _list_of,
43
+ _pair_list_to_dict,
44
+ _tag,
45
+ _unknown,
46
+ decode_fqname,
47
+ decode_name,
48
+ decode_path,
49
+ decode_unit,
50
+ )
51
+ from .codec import decode_literal as decode_literal_3
52
+ from .distribution import Library
53
+ from .documented import Documented
54
+ from .name import Name
55
+ from .path import Path
56
+
57
+ # --- Literal ---
58
+
59
+ _LITERAL_TAGS = {
60
+ "bool_literal": "BoolLiteral",
61
+ "char_literal": "CharLiteral",
62
+ "string_literal": "StringLiteral",
63
+ "int_literal": "WholeNumberLiteral",
64
+ "float_literal": "FloatLiteral",
65
+ "decimal_literal": "DecimalLiteral",
66
+ }
67
+
68
+
69
+ def decode_literal(j: object, loc: Location = ()) -> lit.Literal:
70
+ """Decode a format-1 literal; the payloads are checked as in format 3.0.0."""
71
+ tag, items = _tag(j, loc, "Literal")
72
+ title = _LITERAL_TAGS.get(tag)
73
+ if title is None:
74
+ raise _unknown(tag, loc, "Literal")
75
+ return decode_literal_3([title, *items[1:]], loc)
76
+
77
+
78
+ # --- AccessControlled, Documented ---
79
+
80
+
81
+ _ACCESS = {"public": Access.PUBLIC, "private": Access.PRIVATE}
82
+
83
+
84
+ def decode_access_controlled[A](
85
+ decode_value: Decoder[A],
86
+ ) -> Decoder[AccessControlled[A]]:
87
+ """Decode ``["public", x]`` or ``["private", x]``."""
88
+
89
+ def decode(j: object, loc: Location = ()) -> AccessControlled[A]:
90
+ tag, items = _tag(j, loc, "AccessControlled")
91
+ access = _ACCESS.get(tag)
92
+ if access is None:
93
+ raise _unknown(tag, loc, "AccessControlled")
94
+ return AccessControlled(
95
+ access, decode_value(_index(items, 1, loc, tag), (*loc, 1))
96
+ )
97
+
98
+ return decode
99
+
100
+
101
+ def decode_documented[A](decode_value: Decoder[A]) -> Decoder[Documented[A]]:
102
+ """Decode ``[doc, x]``, or an undocumented ``x`` with doc ``""``.
103
+
104
+ As elm's ``Decode.oneOf``, the pair is tried first. When both readings fail,
105
+ the error holds the diagnostics of both.
106
+ """
107
+
108
+ def decode(j: object, loc: Location = ()) -> Documented[A]:
109
+ if isinstance(j, list) and len(j) > 1 and isinstance(j[0], str):
110
+ try:
111
+ return Documented(j[0], decode_value(j[1], (*loc, 1)))
112
+ except DiagnosticError as pair_error:
113
+ try:
114
+ return Documented("", decode_value(j, loc))
115
+ except DiagnosticError as bare_error:
116
+ raise DiagnosticError(
117
+ *pair_error.diagnostics, *bare_error.diagnostics
118
+ ) from None
119
+ return Documented("", decode_value(j, loc))
120
+
121
+ return decode
122
+
123
+
124
+ # --- Type ---
125
+
126
+
127
+ def decode_type[A](decode_attributes: Decoder[A]) -> Decoder[t.Type[A]]:
128
+ """Build a format-1 type decoder (elm ``decodeType``)."""
129
+
130
+ def decode(j: object, loc: Location = ()) -> t.Type[A]:
131
+ tag, items = _tag(j, loc, "Type")
132
+
133
+ def at(i: int) -> tuple[object, Location]:
134
+ return _index(items, i, loc, tag), (*loc, i)
135
+
136
+ def attrs() -> A:
137
+ return decode_attributes(*at(1))
138
+
139
+ match tag:
140
+ case "variable":
141
+ return t.Variable(attrs(), decode_name(*at(2)))
142
+ case "reference":
143
+ return t.Reference(
144
+ attrs(), decode_fqname(*at(2)), _list_of(decode, *at(3), "Type")
145
+ )
146
+ case "tuple":
147
+ return t.Tuple(attrs(), _list_of(decode, *at(2), "Type"))
148
+ case "record":
149
+ return t.Record(attrs(), _list_of(decode_field, *at(2), "Field"))
150
+ case "extensible_record":
151
+ return t.ExtensibleRecord(
152
+ attrs(),
153
+ decode_name(*at(2)),
154
+ _list_of(decode_field, *at(3), "Field"),
155
+ )
156
+ case "function":
157
+ return t.Function(attrs(), decode(*at(2)), decode(*at(3)))
158
+ case "unit":
159
+ return t.Unit(attrs())
160
+ case _:
161
+ raise _unknown(tag, loc, "Type")
162
+
163
+ def decode_field(j: object, loc: Location = ()) -> t.Field[A]:
164
+ pair = _expect_list(j, loc, "Field")
165
+ return t.Field(
166
+ decode_name(_index(pair, 0, loc, "Field"), (*loc, 0)),
167
+ decode(_index(pair, 1, loc, "Field"), (*loc, 1)),
168
+ )
169
+
170
+ return decode
171
+
172
+
173
+ def _decode_constructors[A](
174
+ decode_t: Decoder[t.Type[A]],
175
+ ) -> Decoder[t.Constructors[A]]:
176
+ def decode_arg(j: object, loc: Location) -> tuple[Name, t.Type[A]]:
177
+ pair = _expect_list(j, loc, "ConstructorArg")
178
+ return (
179
+ decode_name(_index(pair, 0, loc, "ConstructorArg"), (*loc, 0)),
180
+ decode_t(_index(pair, 1, loc, "ConstructorArg"), (*loc, 1)),
181
+ )
182
+
183
+ def decode_args(j: object, loc: Location) -> t.ConstructorArgs[A]:
184
+ return _list_of(decode_arg, j, loc, "Constructor")
185
+
186
+ def decode(j: object, loc: Location = ()) -> t.Constructors[A]:
187
+ return _pair_list_to_dict(decode_name, decode_args, j, loc, "Constructors")
188
+
189
+ return decode
190
+
191
+
192
+ def decode_type_specification[A](
193
+ decode_attributes: Decoder[A],
194
+ ) -> Decoder[t.Specification[A]]:
195
+ """Build a format-1 type specification decoder."""
196
+ decode_t = decode_type(decode_attributes)
197
+ decode_ctors = _decode_constructors(decode_t)
198
+
199
+ def decode(j: object, loc: Location = ()) -> t.Specification[A]:
200
+ tag, items = _tag(j, loc, "TypeSpecification")
201
+
202
+ def at(i: int) -> tuple[object, Location]:
203
+ return _index(items, i, loc, tag), (*loc, i)
204
+
205
+ def params() -> tuple[Name, ...]:
206
+ return _list_of(decode_name, *at(1), "Name")
207
+
208
+ match tag:
209
+ case "type_alias_specification":
210
+ return t.TypeAliasSpecification(params(), decode_t(*at(2)))
211
+ case "opaque_type_specification":
212
+ return t.OpaqueTypeSpecification(params())
213
+ case "custom_type_specification":
214
+ return t.CustomTypeSpecification(params(), decode_ctors(*at(2)))
215
+ case "derived_type_specification":
216
+ config_json, config_loc = at(2)
217
+ config = _expect_object(config_json, config_loc, tag)
218
+
219
+ def member(key: str) -> tuple[object, Location]:
220
+ return _field(config, key, config_loc, tag), (*config_loc, key)
221
+
222
+ return t.DerivedTypeSpecification(
223
+ params(),
224
+ decode_t(*member("baseType")),
225
+ decode_fqname(*member("fromBaseType")),
226
+ decode_fqname(*member("toBaseType")),
227
+ )
228
+ case _:
229
+ raise _unknown(tag, loc, "TypeSpecification")
230
+
231
+ return decode
232
+
233
+
234
+ def decode_type_definition[A](
235
+ decode_attributes: Decoder[A],
236
+ ) -> Decoder[t.Definition[A]]:
237
+ """Build a format-1 type definition decoder."""
238
+ decode_t = decode_type(decode_attributes)
239
+ decode_ctors = decode_access_controlled(_decode_constructors(decode_t))
240
+
241
+ def decode(j: object, loc: Location = ()) -> t.Definition[A]:
242
+ tag, items = _tag(j, loc, "TypeDefinition")
243
+
244
+ def at(i: int) -> tuple[object, Location]:
245
+ return _index(items, i, loc, tag), (*loc, i)
246
+
247
+ match tag:
248
+ case "type_alias_definition":
249
+ return t.TypeAliasDefinition(
250
+ _list_of(decode_name, *at(1), "Name"), decode_t(*at(2))
251
+ )
252
+ case "custom_type_definition":
253
+ return t.CustomTypeDefinition(
254
+ _list_of(decode_name, *at(1), "Name"), decode_ctors(*at(2))
255
+ )
256
+ case _:
257
+ raise _unknown(tag, loc, "TypeDefinition")
258
+
259
+ return decode
260
+
261
+
262
+ # --- Value ---
263
+
264
+
265
+ def decode_pattern[A](decode_attributes: Decoder[A]) -> Decoder[v.Pattern[A]]:
266
+ """Build a format-1 pattern decoder."""
267
+ return _legacy_value.decode_pattern(decode_literal, decode_attributes)
268
+
269
+
270
+ def decode_value[TA, VA](
271
+ decode_type_attributes: Decoder[TA], decode_value_attributes: Decoder[VA]
272
+ ) -> Decoder[v.Value[TA, VA]]:
273
+ """Build a format-1 value decoder."""
274
+ return _legacy_value.decode_value(
275
+ decode_literal, decode_type(decode_type_attributes), decode_value_attributes
276
+ )
277
+
278
+
279
+ def decode_value_specification[A](
280
+ decode_attributes: Decoder[A],
281
+ ) -> Decoder[v.Specification[A]]:
282
+ """Build a decoder for ``{"inputs", "output"}`` with format-1 types."""
283
+ decode_t = decode_type(decode_attributes)
284
+ construct = "ValueSpecification"
285
+
286
+ def decode_input(j: object, loc: Location) -> tuple[Name, t.Type[A]]:
287
+ pair = _expect_list(j, loc, "Input")
288
+ return (
289
+ decode_name(_index(pair, 0, loc, "Input"), (*loc, 0)),
290
+ decode_t(_index(pair, 1, loc, "Input"), (*loc, 1)),
291
+ )
292
+
293
+ def decode(j: object, loc: Location = ()) -> v.Specification[A]:
294
+ obj = _expect_object(j, loc, construct)
295
+ return v.Specification(
296
+ _list_of(
297
+ decode_input,
298
+ _field(obj, "inputs", loc, construct),
299
+ (*loc, "inputs"),
300
+ "Input",
301
+ ),
302
+ decode_t(_field(obj, "output", loc, construct), (*loc, "output")),
303
+ )
304
+
305
+ return decode
306
+
307
+
308
+ def decode_value_definition[TA, VA](
309
+ decode_type_attributes: Decoder[TA], decode_value_attributes: Decoder[VA]
310
+ ) -> Decoder[v.Definition[TA, VA]]:
311
+ """Build a format-1 value definition decoder."""
312
+ return _legacy_value.decode_value_definition(
313
+ decode_type(decode_type_attributes),
314
+ decode_value_attributes,
315
+ decode_value(decode_type_attributes, decode_value_attributes),
316
+ )
317
+
318
+
319
+ # --- Module ---
320
+
321
+
322
+ def _named[A](
323
+ decode_entry: Decoder[A],
324
+ obj: dict[str, object],
325
+ key: str,
326
+ loc: Location,
327
+ construct: str,
328
+ ) -> dict[Name, A]:
329
+ return _pair_list_to_dict(
330
+ decode_name,
331
+ decode_entry,
332
+ _field(obj, key, loc, construct),
333
+ (*loc, key),
334
+ key.capitalize(),
335
+ )
336
+
337
+
338
+ def decode_module_specification[TA](
339
+ decode_type_attributes: Decoder[TA],
340
+ ) -> Decoder[module.Specification[TA]]:
341
+ """Build a format-1 module specification decoder; ``doc`` is always None."""
342
+ decode_ts = decode_documented(decode_type_specification(decode_type_attributes))
343
+ decode_vs = decode_documented(decode_value_specification(decode_type_attributes))
344
+
345
+ def decode(j: object, loc: Location = ()) -> module.Specification[TA]:
346
+ construct = "ModuleSpecification"
347
+ obj = _expect_object(j, loc, construct)
348
+ return module.Specification(
349
+ _named(decode_ts, obj, "types", loc, construct),
350
+ _named(decode_vs, obj, "values", loc, construct),
351
+ )
352
+
353
+ return decode
354
+
355
+
356
+ def decode_module_definition[TA, VA](
357
+ decode_type_attributes: Decoder[TA], decode_value_attributes: Decoder[VA]
358
+ ) -> Decoder[module.Definition[TA, VA]]:
359
+ """Build a format-1 module definition decoder; ``doc`` is always None."""
360
+ decode_td = decode_access_controlled(
361
+ decode_documented(decode_type_definition(decode_type_attributes))
362
+ )
363
+ decode_vd = decode_access_controlled(
364
+ decode_documented(
365
+ decode_value_definition(decode_type_attributes, decode_value_attributes)
366
+ )
367
+ )
368
+
369
+ def decode(j: object, loc: Location = ()) -> module.Definition[TA, VA]:
370
+ construct = "ModuleDefinition"
371
+ obj = _expect_object(j, loc, construct)
372
+ return module.Definition(
373
+ _named(decode_td, obj, "types", loc, construct),
374
+ _named(decode_vd, obj, "values", loc, construct),
375
+ )
376
+
377
+ return decode
378
+
379
+
380
+ # --- Package ---
381
+
382
+
383
+ def _modules[A](
384
+ decode_module: Decoder[A], member: str, j: object, loc: Location, construct: str
385
+ ) -> dict[Path, A]:
386
+ obj = _expect_object(j, loc, construct)
387
+ result: dict[Path, A] = {}
388
+ entries = _field(obj, "modules", loc, construct)
389
+ for i, entry in enumerate(_expect_list(entries, (*loc, "modules"), "Modules")):
390
+ here = (*loc, "modules", i)
391
+ named = _expect_object(entry, here, "Module")
392
+ name = decode_path(_field(named, "name", here, "Module"), (*here, "name"))
393
+ result[name] = decode_module(
394
+ _field(named, member, here, "Module"), (*here, member)
395
+ )
396
+ return result
397
+
398
+
399
+ def decode_package_specification[TA](
400
+ decode_type_attributes: Decoder[TA],
401
+ ) -> Decoder[package.Specification[TA]]:
402
+ """Build a decoder for ``{"modules": [{"name", "spec"}]}``."""
403
+ decode_m = decode_module_specification(decode_type_attributes)
404
+
405
+ def decode(j: object, loc: Location = ()) -> package.Specification[TA]:
406
+ return package.Specification(
407
+ _modules(decode_m, "spec", j, loc, "PackageSpecification")
408
+ )
409
+
410
+ return decode
411
+
412
+
413
+ def decode_package_definition[TA, VA](
414
+ decode_type_attributes: Decoder[TA], decode_value_attributes: Decoder[VA]
415
+ ) -> Decoder[package.Definition[TA, VA]]:
416
+ """Build a decoder for ``{"modules": [{"name", "def": ["public", ...]}]}``."""
417
+ decode_m = decode_access_controlled(
418
+ decode_module_definition(decode_type_attributes, decode_value_attributes)
419
+ )
420
+
421
+ def decode(j: object, loc: Location = ()) -> package.Definition[TA, VA]:
422
+ return package.Definition(
423
+ _modules(decode_m, "def", j, loc, "PackageDefinition")
424
+ )
425
+
426
+ return decode
427
+
428
+
429
+ # --- Distribution ---
430
+
431
+ _decode_dependency = decode_package_specification(decode_unit)
432
+ _decode_library_def = decode_package_definition(decode_unit, decode_type(decode_unit))
433
+
434
+
435
+ def decode_distribution(j: object, loc: Location = ()) -> Library:
436
+ """Decode ``["library", name, dependencies, definition]``."""
437
+ tag, items = _tag(j, loc, "Distribution")
438
+ if tag != "library":
439
+ raise fail(
440
+ d.UNKNOWN_NODE,
441
+ "Distribution",
442
+ (*loc, 0),
443
+ f"unknown distribution kind {tag!r}; format 1 has only library",
444
+ )
445
+
446
+ def at(i: int) -> tuple[object, Location]:
447
+ return _index(items, i, loc, tag), (*loc, i)
448
+
449
+ return Library(
450
+ package_name=decode_path(*at(1)),
451
+ dependencies=_pair_list_to_dict(
452
+ decode_path, _decode_dependency, *at(2), "Dependencies"
453
+ ),
454
+ definition=_decode_library_def(*at(3)),
455
+ )
456
+
457
+
458
+ def decode_versioned_distribution(document: str | object) -> Library:
459
+ """Decode a ``"formatVersion": 1`` document into the format 3.0.0 model.
460
+
461
+ Args:
462
+ document: JSON text or an already-decoded JSON value.
463
+
464
+ Raises:
465
+ DiagnosticError: With ``unsupported_format_version_major`` for any format
466
+ other than 1, or with a decoding diagnostic.
467
+ """
468
+ root = read_legacy_document(document, LegacyFormat.V1)
469
+ return decode_distribution(
470
+ _field(root, "distribution", (), "document"), ("distribution",)
471
+ )
472
+
473
+
474
+ __all__ = [
475
+ "decode_access_controlled",
476
+ "decode_distribution",
477
+ "decode_documented",
478
+ "decode_literal",
479
+ "decode_module_definition",
480
+ "decode_module_specification",
481
+ "decode_package_definition",
482
+ "decode_package_specification",
483
+ "decode_pattern",
484
+ "decode_type",
485
+ "decode_type_definition",
486
+ "decode_type_specification",
487
+ "decode_value",
488
+ "decode_value_definition",
489
+ "decode_value_specification",
490
+ "decode_versioned_distribution",
491
+ ]
@@ -0,0 +1,187 @@
1
+ """Read-only JSON decoders for morphir-elm IR format 2, into the 3.0.0 model.
2
+
3
+ morphir-elm wrote format 2 from commit 8e0e729d (2021-10-08) to commit 02aa36af
4
+ (2023-05-18). Format 3 changed one thing: value and pattern tags went from
5
+ snake_case (``"let_definition"``, ``"wildcard_pattern"``) to TitleCase. Every
6
+ other shape, including TitleCase literals and types, ``{"access", "value"}``,
7
+ ``{"doc", "value"}``, and ``[path, module]`` package entries, is the format 3.0.0
8
+ shape, so this module reuses `morphir.ir.v3.codec` for everything except values,
9
+ patterns, and the containers that hold them.
10
+
11
+ The value and pattern decoders port ``Value/CodecV2.elm`` from morphir-elm commit
12
+ 02aa36af. morphir-elm removed that module in commit 7cb7b300, and today refuses
13
+ format 2; reading it here is a deliberate divergence, so that old files can be
14
+ upgraded. As in elm, format 2 decodes into the format 3.0.0 model; encode the
15
+ result with `morphir.ir.v3.codec` to write format 3. No writer emits format 2.
16
+
17
+ The finos/morphir v2 schema documentation says that format 2 literals stay
18
+ snake_case. morphir-elm wrote them in TitleCase from the first format-2 commit
19
+ (e742a620), and morphir-elm is normative.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from .. import diagnostics as d
25
+ from ..diagnostics import Location, fail
26
+ from ..format_version import LegacyFormat, read_legacy_document
27
+ from . import _legacy_value, module, package
28
+ from . import value as v
29
+ from .codec import (
30
+ Decoder,
31
+ _expect_object,
32
+ _field,
33
+ _index,
34
+ _pair_list_to_dict,
35
+ _tag,
36
+ decode_access_controlled,
37
+ decode_documented,
38
+ decode_literal,
39
+ decode_name,
40
+ decode_package_specification,
41
+ decode_path,
42
+ decode_type,
43
+ decode_type_definition,
44
+ decode_unit,
45
+ )
46
+ from .codec import _decode_doc as decode_module_doc
47
+ from .distribution import Library
48
+
49
+
50
+ def decode_pattern[A](decode_attributes: Decoder[A]) -> Decoder[v.Pattern[A]]:
51
+ """Build a format-2 pattern decoder: snake_case tags, format-3 literals."""
52
+ return _legacy_value.decode_pattern(decode_literal, decode_attributes)
53
+
54
+
55
+ def decode_value[TA, VA](
56
+ decode_type_attributes: Decoder[TA], decode_value_attributes: Decoder[VA]
57
+ ) -> Decoder[v.Value[TA, VA]]:
58
+ """Build a format-2 value decoder: snake_case tags, format-3 types and literals."""
59
+ return _legacy_value.decode_value(
60
+ decode_literal, decode_type(decode_type_attributes), decode_value_attributes
61
+ )
62
+
63
+
64
+ def decode_value_definition[TA, VA](
65
+ decode_type_attributes: Decoder[TA], decode_value_attributes: Decoder[VA]
66
+ ) -> Decoder[v.Definition[TA, VA]]:
67
+ """Build a format-2 value definition decoder."""
68
+ return _legacy_value.decode_value_definition(
69
+ decode_type(decode_type_attributes),
70
+ decode_value_attributes,
71
+ decode_value(decode_type_attributes, decode_value_attributes),
72
+ )
73
+
74
+
75
+ def decode_module_definition[TA, VA](
76
+ decode_type_attributes: Decoder[TA], decode_value_attributes: Decoder[VA]
77
+ ) -> Decoder[module.Definition[TA, VA]]:
78
+ """Build a format-2 module definition decoder, with the optional ``doc``."""
79
+ decode_td = decode_access_controlled(
80
+ decode_documented(decode_type_definition(decode_type_attributes))
81
+ )
82
+ decode_vd = decode_access_controlled(
83
+ decode_documented(
84
+ decode_value_definition(decode_type_attributes, decode_value_attributes)
85
+ )
86
+ )
87
+ construct = "ModuleDefinition"
88
+
89
+ def decode(j: object, loc: Location = ()) -> module.Definition[TA, VA]:
90
+ obj = _expect_object(j, loc, construct)
91
+ return module.Definition(
92
+ _pair_list_to_dict(
93
+ decode_name,
94
+ decode_td,
95
+ _field(obj, "types", loc, construct),
96
+ (*loc, "types"),
97
+ "Types",
98
+ ),
99
+ _pair_list_to_dict(
100
+ decode_name,
101
+ decode_vd,
102
+ _field(obj, "values", loc, construct),
103
+ (*loc, "values"),
104
+ "Values",
105
+ ),
106
+ decode_module_doc(obj),
107
+ )
108
+
109
+ return decode
110
+
111
+
112
+ def decode_package_definition[TA, VA](
113
+ decode_type_attributes: Decoder[TA], decode_value_attributes: Decoder[VA]
114
+ ) -> Decoder[package.Definition[TA, VA]]:
115
+ """Build a decoder for ``{"modules": [[path, {"access", "value"}]]}``."""
116
+ decode_m = decode_access_controlled(
117
+ decode_module_definition(decode_type_attributes, decode_value_attributes)
118
+ )
119
+ construct = "PackageDefinition"
120
+
121
+ def decode(j: object, loc: Location = ()) -> package.Definition[TA, VA]:
122
+ obj = _expect_object(j, loc, construct)
123
+ return package.Definition(
124
+ _pair_list_to_dict(
125
+ decode_path,
126
+ decode_m,
127
+ _field(obj, "modules", loc, construct),
128
+ (*loc, "modules"),
129
+ "Modules",
130
+ )
131
+ )
132
+
133
+ return decode
134
+
135
+
136
+ _decode_dependency = decode_package_specification(decode_unit)
137
+ _decode_library_def = decode_package_definition(decode_unit, decode_type(decode_unit))
138
+
139
+
140
+ def decode_distribution(j: object, loc: Location = ()) -> Library:
141
+ """Decode ``["Library", name, dependencies, definition]``."""
142
+ tag, items = _tag(j, loc, "Distribution")
143
+ if tag != "Library":
144
+ raise fail(
145
+ d.UNKNOWN_NODE,
146
+ "Distribution",
147
+ (*loc, 0),
148
+ f"unknown distribution kind {tag!r}; format 2 has only Library",
149
+ )
150
+
151
+ def at(i: int) -> tuple[object, Location]:
152
+ return _index(items, i, loc, tag), (*loc, i)
153
+
154
+ return Library(
155
+ package_name=decode_path(*at(1)),
156
+ dependencies=_pair_list_to_dict(
157
+ decode_path, _decode_dependency, *at(2), "Dependencies"
158
+ ),
159
+ definition=_decode_library_def(*at(3)),
160
+ )
161
+
162
+
163
+ def decode_versioned_distribution(document: str | object) -> Library:
164
+ """Decode a ``"formatVersion": 2`` document into the format 3.0.0 model.
165
+
166
+ Args:
167
+ document: JSON text or an already-decoded JSON value.
168
+
169
+ Raises:
170
+ DiagnosticError: With ``unsupported_format_version_major`` for any format
171
+ other than 2, or with a decoding diagnostic.
172
+ """
173
+ root = read_legacy_document(document, LegacyFormat.V2)
174
+ return decode_distribution(
175
+ _field(root, "distribution", (), "document"), ("distribution",)
176
+ )
177
+
178
+
179
+ __all__ = [
180
+ "decode_distribution",
181
+ "decode_module_definition",
182
+ "decode_package_definition",
183
+ "decode_pattern",
184
+ "decode_value",
185
+ "decode_value_definition",
186
+ "decode_versioned_distribution",
187
+ ]