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
|
@@ -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
|
+
]
|