@greenlabs/ppx-spice 0.1.8 → 0.1.9-rc1

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 (106) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +4 -0
  3. package/docs/GUIDE.md +139 -0
  4. package/package.json +1 -1
  5. package/ppx-windows.exe +0 -0
  6. package/.github/workflows/build_linux.yml +0 -41
  7. package/.github/workflows/build_macos.yml +0 -41
  8. package/.github/workflows/build_windows.yml +0 -41
  9. package/.github/workflows/print_esy_cache.js +0 -13
  10. package/.github/workflows/publish.yml +0 -161
  11. package/.github/workflows/publish_prerelease.yml +0 -177
  12. package/.vscode/settings.json +0 -6
  13. package/src/.ocamlformat +0 -0
  14. package/src/bin/bin.ml +0 -1
  15. package/src/bin/dune +0 -5
  16. package/src/dune +0 -1
  17. package/src/dune-project +0 -2
  18. package/src/dune-workspace +0 -3
  19. package/src/esy.lock/.gitattributes +0 -3
  20. package/src/esy.lock/.gitignore +0 -3
  21. package/src/esy.lock/index.json +0 -1196
  22. package/src/esy.lock/opam/astring.0.8.5/opam +0 -37
  23. package/src/esy.lock/opam/base-bytes.base/opam +0 -9
  24. package/src/esy.lock/opam/base-threads.base/opam +0 -6
  25. package/src/esy.lock/opam/base-unix.base/opam +0 -6
  26. package/src/esy.lock/opam/base.v0.14.1/opam +0 -36
  27. package/src/esy.lock/opam/biniou.1.2.1/opam +0 -45
  28. package/src/esy.lock/opam/cmdliner.1.0.4/opam +0 -36
  29. package/src/esy.lock/opam/cppo.1.6.8/opam +0 -37
  30. package/src/esy.lock/opam/csexp.1.5.1/opam +0 -60
  31. package/src/esy.lock/opam/dot-merlin-reader.4.1/opam +0 -30
  32. package/src/esy.lock/opam/dune-build-info.2.9.1/opam +0 -42
  33. package/src/esy.lock/opam/dune-configurator.2.9.1/opam +0 -47
  34. package/src/esy.lock/opam/dune.2.9.1/opam +0 -58
  35. package/src/esy.lock/opam/easy-format.1.3.2/opam +0 -46
  36. package/src/esy.lock/opam/fix.20201120/opam +0 -24
  37. package/src/esy.lock/opam/fpath.0.7.3/opam +0 -36
  38. package/src/esy.lock/opam/menhir.20211012/opam +0 -28
  39. package/src/esy.lock/opam/menhirLib.20211012/opam +0 -29
  40. package/src/esy.lock/opam/menhirSdk.20211012/opam +0 -29
  41. package/src/esy.lock/opam/ocaml-compiler-libs.v0.12.4/opam +0 -39
  42. package/src/esy.lock/opam/ocaml-lsp-server.1.8.3/opam +0 -54
  43. package/src/esy.lock/opam/ocamlbuild.0.14.0/opam +0 -36
  44. package/src/esy.lock/opam/ocamlfind.1.9.1/opam +0 -44
  45. package/src/esy.lock/opam/ocamlformat-rpc-lib.0.18.0/opam +0 -40
  46. package/src/esy.lock/opam/ocamlformat.0.19.0/opam +0 -55
  47. package/src/esy.lock/opam/ocp-indent.1.8.1/opam +0 -57
  48. package/src/esy.lock/opam/odoc-parser.0.9.0/opam +0 -45
  49. package/src/esy.lock/opam/pp.1.1.2/opam +0 -58
  50. package/src/esy.lock/opam/ppx_derivers.1.2.1/opam +0 -23
  51. package/src/esy.lock/opam/ppx_yojson_conv_lib.v0.14.0/opam +0 -24
  52. package/src/esy.lock/opam/ppxlib.0.23.0/opam +0 -62
  53. package/src/esy.lock/opam/re.1.10.3/opam +0 -46
  54. package/src/esy.lock/opam/result.1.5/opam +0 -22
  55. package/src/esy.lock/opam/seq.base/files/META.seq +0 -4
  56. package/src/esy.lock/opam/seq.base/files/seq.install +0 -3
  57. package/src/esy.lock/opam/seq.base/opam +0 -15
  58. package/src/esy.lock/opam/sexplib0.v0.14.0/opam +0 -26
  59. package/src/esy.lock/opam/stdio.v0.14.0/opam +0 -27
  60. package/src/esy.lock/opam/stdlib-shims.0.3.0/opam +0 -31
  61. package/src/esy.lock/opam/topkg.1.0.4/opam +0 -44
  62. package/src/esy.lock/opam/uchar.0.0.2/opam +0 -36
  63. package/src/esy.lock/opam/uucp.14.0.0/opam +0 -41
  64. package/src/esy.lock/opam/uuseg.14.0.0/opam +0 -43
  65. package/src/esy.lock/opam/uutf.1.0.2/opam +0 -40
  66. package/src/esy.lock/opam/yojson.1.7.0/opam +0 -38
  67. package/src/esy.lock/overrides/opam__s__ocamlbuild_opam__c__0.14.0_opam_override/files/ocamlbuild-0.14.0.patch +0 -463
  68. package/src/esy.lock/overrides/opam__s__ocamlbuild_opam__c__0.14.0_opam_override/package.json +0 -27
  69. package/src/esy.lock/overrides/opam__s__ocamlfind_opam__c__1.9.1_opam_override/files/findlib-1.9.1.patch +0 -471
  70. package/src/esy.lock/overrides/opam__s__ocamlfind_opam__c__1.9.1_opam_override/package.json +0 -61
  71. package/src/ppx/codecs.ml +0 -120
  72. package/src/ppx/decode_cases.ml +0 -18
  73. package/src/ppx/dune +0 -9
  74. package/src/ppx/polyvariants.ml +0 -288
  75. package/src/ppx/ppx_spice.ml +0 -19
  76. package/src/ppx/records.ml +0 -163
  77. package/src/ppx/signature.ml +0 -86
  78. package/src/ppx/structure.ml +0 -109
  79. package/src/ppx/tuple.ml +0 -68
  80. package/src/ppx/utils.ml +0 -117
  81. package/src/ppx/variants.ml +0 -257
  82. package/src/ppx_spice.opam +0 -21
  83. package/test/__tests__/test_optional_field_records.js +0 -91
  84. package/test/__tests__/test_optional_field_records.res +0 -98
  85. package/test/__tests__/test_polyvariants.js +0 -57
  86. package/test/__tests__/test_polyvariants.res +0 -41
  87. package/test/__tests__/test_records.js +0 -100
  88. package/test/__tests__/test_records.res +0 -111
  89. package/test/__tests__/test_variants.js +0 -85
  90. package/test/__tests__/test_variants.res +0 -63
  91. package/test/bsconfig.json +0 -27
  92. package/test/package.json +0 -18
  93. package/test/src/OptionalFieldRecords.js +0 -237
  94. package/test/src/OptionalFieldRecords.res +0 -23
  95. package/test/src/Polyvariants.js +0 -94
  96. package/test/src/Polyvariants.res +0 -5
  97. package/test/src/Polyvariants.resi +0 -5
  98. package/test/src/Records.js +0 -186
  99. package/test/src/Records.res +0 -17
  100. package/test/src/Records.resi +0 -17
  101. package/test/src/Spice.js +0 -448
  102. package/test/src/Spice_Codecs.js +0 -57
  103. package/test/src/Variants.js +0 -115
  104. package/test/src/Variants.res +0 -11
  105. package/test/src/Variants.resi +0 -11
  106. package/test/yarn.lock +0 -4194
@@ -1,288 +0,0 @@
1
- open Parsetree
2
- open Ast_helper
3
- open Utils
4
-
5
- (* Polyvariants arguments are wrapped inside a Tuple, meaning that if there's only
6
- one arg it's the coreType, but if there's more than one arg it's a tuple of one tuple with those args.
7
- This function abstract this particuliarity from polyvariants (It's different from Variants). *)
8
-
9
- type parsed_field = {
10
- name : string;
11
- alias : expression;
12
- has_attr_as : bool;
13
- row_field : Parsetree.row_field;
14
- }
15
-
16
- let get_args_from_polyvars ~loc coreTypes =
17
- match coreTypes with
18
- | [] -> []
19
- | [ coreType ] -> (
20
- match coreType.ptyp_desc with
21
- (* If it's a tuple, return the args *)
22
- | Ptyp_tuple coreTypes -> coreTypes
23
- (* If it's any other coreType, return it *)
24
- | _ -> [ coreType ])
25
- | _ ->
26
- fail loc
27
- "This error shoudn't happen, means that the AST of your polyvariant is \
28
- wrong"
29
-
30
- let generate_encoder_case generator_settings unboxed has_attr_as row =
31
- let { name; alias; row_field = { prf_desc } } = row in
32
- match prf_desc with
33
- | Rtag (_, _attributes, core_types) ->
34
- let alias_name, _, delimit = get_string_from_expression alias in
35
- let constructor_expr =
36
- Exp.constant (Pconst_string (alias_name, Location.none, delimit))
37
- in
38
- let args = get_args_from_polyvars ~loc core_types in
39
-
40
- let lhs_vars =
41
- match args with
42
- | [] -> None
43
- | [ _ ] -> Some (Pat.var (mknoloc "v0"))
44
- | _ ->
45
- args
46
- |> List.mapi (fun i _ ->
47
- mkloc ("v" ^ string_of_int i) loc |> Pat.var)
48
- |> Pat.tuple
49
- |> fun v -> Some v
50
- in
51
-
52
- let rhs_list =
53
- args
54
- |> List.map (Codecs.generate_codecs generator_settings)
55
- |> List.map (fun (encoder, _) -> Option.get encoder)
56
- |> List.mapi (fun i e ->
57
- Exp.apply ~loc e
58
- [ (Asttypes.Nolabel, make_ident_expr ("v" ^ string_of_int i)) ])
59
- |> List.append [ [%expr Js.Json.string [%e constructor_expr]] ]
60
- in
61
-
62
- {
63
- pc_lhs = Pat.variant name lhs_vars;
64
- pc_guard = None;
65
- pc_rhs =
66
- (if unboxed then List.tl rhs_list |> List.hd (* diff *)
67
- else if has_attr_as then [%expr Js.Json.string [%e constructor_expr]]
68
- else [%expr Js.Json.array [%e rhs_list |> Exp.array]]);
69
- }
70
- (* We don't have enough information to generate a encoder *)
71
- | Rinherit arg ->
72
- fail arg.ptyp_loc "This syntax is not yet implemented by spice"
73
-
74
- let generate_decode_success_case num_args constructor_name =
75
- {
76
- pc_lhs =
77
- Array.init num_args (fun i ->
78
- mknoloc ("v" ^ string_of_int i) |> Pat.var |> fun p ->
79
- [%pat? Belt.Result.Ok [%p p]])
80
- |> Array.to_list
81
- |> tuple_or_singleton Pat.tuple;
82
- pc_guard = None;
83
- pc_rhs =
84
- ( Array.init num_args (fun i -> make_ident_expr ("v" ^ string_of_int i))
85
- |> Array.to_list
86
- |> tuple_or_singleton Exp.tuple
87
- |> fun v ->
88
- Some v |> Exp.variant constructor_name |> fun e ->
89
- [%expr Belt.Result.Ok [%e e]] );
90
- }
91
-
92
- let generate_arg_decoder generator_settings args constructor_name =
93
- let num_args = List.length args in
94
- args
95
- |> List.mapi (Decode_cases.generate_error_case num_args)
96
- |> List.append [ generate_decode_success_case num_args constructor_name ]
97
- |> Exp.match_
98
- (args
99
- |> List.map (Codecs.generate_codecs generator_settings)
100
- |> List.mapi (fun i (_, decoder) ->
101
- Exp.apply (Option.get decoder)
102
- [
103
- ( Asttypes.Nolabel,
104
- (* +1 because index 0 is the constructor *)
105
- let idx =
106
- Pconst_integer (string_of_int (i + 1), None)
107
- |> Exp.constant
108
- in
109
- [%expr Belt.Array.getExn json_arr [%e idx]] );
110
- ])
111
- |> tuple_or_singleton Exp.tuple)
112
-
113
- let generate_decoder_case generator_settings { prf_desc } =
114
- match prf_desc with
115
- | Rtag ({ txt }, _, core_types) ->
116
- let args = get_args_from_polyvars ~loc core_types in
117
- let arg_len =
118
- Pconst_integer (string_of_int (List.length args + 1), None)
119
- |> Exp.constant
120
- in
121
- let decoded =
122
- match args with
123
- | [] ->
124
- let resultant_exp = Exp.variant txt None in
125
- [%expr Belt.Result.Ok [%e resultant_exp]]
126
- | _ -> generate_arg_decoder generator_settings args txt
127
- in
128
-
129
- {
130
- pc_lhs =
131
- ( Pconst_string (txt, Location.none, None) |> Pat.constant |> fun v ->
132
- Some v |> Pat.construct (lid "Js.Json.JSONString") );
133
- pc_guard = None;
134
- pc_rhs =
135
- [%expr
136
- if Js.Array.length tagged != [%e arg_len] then
137
- Spice.error
138
- "Invalid number of arguments to polyvariant constructor" v
139
- else [%e decoded]];
140
- }
141
- | Rinherit core_type ->
142
- fail core_type.ptyp_loc "This syntax is not yet implemented by spice"
143
-
144
- let generate_decoder_case_attr generator_settings row =
145
- let { alias; row_field = { prf_desc } } = row in
146
- match prf_desc with
147
- | Rtag ({ txt }, _, core_types) ->
148
- let args = get_args_from_polyvars ~loc core_types in
149
- let alias_name, loc, delimit = get_string_from_expression alias in
150
- let decoded =
151
- match args with
152
- | [] ->
153
- let resultant_exp = Exp.variant txt None in
154
- [%expr Belt.Result.Ok [%e resultant_exp]]
155
- | _ -> generate_arg_decoder generator_settings args txt
156
- in
157
-
158
- let if' =
159
- Exp.apply (make_ident_expr "=")
160
- [
161
- ( Asttypes.Nolabel,
162
- Pconst_string (alias_name, Location.none, delimit) |> Exp.constant
163
- );
164
- (Asttypes.Nolabel, [%expr str]);
165
- ]
166
- in
167
- let then' = [%expr [%e decoded]] in
168
-
169
- (if', then')
170
- | Rinherit core_type ->
171
- fail core_type.ptyp_loc "This syntax is not yet implemented by spice"
172
-
173
- let generate_unboxed_decode generator_settings { prf_desc } =
174
- match prf_desc with
175
- | Rtag ({ txt; loc }, _, args) -> (
176
- match args with
177
- | [ a ] -> (
178
- let _, d = Codecs.generate_codecs generator_settings a in
179
- match d with
180
- | Some d ->
181
- let constructor = Exp.construct (lid txt) (Some [%expr v]) in
182
-
183
- Some
184
- [%expr
185
- fun v ->
186
- Belt.Result.map ([%e d] v) (fun v -> [%e constructor])]
187
- | None -> None)
188
- | _ -> fail loc "Expected exactly one type argument")
189
- | Rinherit coreType ->
190
- fail coreType.ptyp_loc "This syntax is not yet implemented by spice"
191
-
192
- let parse_decl ({ prf_desc; prf_loc; prf_attributes } as row_field) =
193
- let txt =
194
- match prf_desc with
195
- | Rtag ({ txt }, _, _) -> txt
196
- | _ -> failwith "cannot get polymorphic variant constructor"
197
- in
198
-
199
- let alias, has_attr_as =
200
- match get_attribute_by_name prf_attributes "spice.as" with
201
- | Ok (Some attribute) -> (get_expression_from_payload attribute, true)
202
- | Ok None -> (Exp.constant (Pconst_string (txt, Location.none, None)), false)
203
- | Error s -> (fail prf_loc s, false)
204
- in
205
-
206
- { name = txt; alias; has_attr_as; row_field }
207
-
208
- let generate_codecs ({ do_encode; do_decode } as generator_settings) row_fields
209
- unboxed =
210
- let parsed_fields = List.map parse_decl row_fields in
211
- let count_has_attr =
212
- parsed_fields |> List.filter (fun v -> v.has_attr_as) |> List.length
213
- in
214
- let has_attr_as =
215
- if count_has_attr > 0 then
216
- if count_has_attr = List.length parsed_fields then true
217
- else failwith "Partial @spice.as usage is not allowed"
218
- else false
219
- in
220
-
221
- let encoder =
222
- some_if_true do_encode
223
- (List.map
224
- (generate_encoder_case generator_settings unboxed has_attr_as)
225
- parsed_fields
226
- |> Exp.match_ [%expr v]
227
- |> Exp.fun_ Asttypes.Nolabel None [%pat? v])
228
- in
229
-
230
- let decoder =
231
- match not do_decode with
232
- | true -> None
233
- | false ->
234
- if unboxed then
235
- generate_unboxed_decode generator_settings (List.hd row_fields)
236
- else if has_attr_as then
237
- let rec make_ifthenelse cases =
238
- match cases with
239
- | [] -> [%expr Spice.error "Not matched" v]
240
- | hd :: tl ->
241
- let if_, then_ = hd in
242
- Exp.ifthenelse if_ then_ (Some (make_ifthenelse tl))
243
- in
244
-
245
- let decoder_switch =
246
- parsed_fields
247
- |> List.map (generate_decoder_case_attr generator_settings)
248
- |> make_ifthenelse
249
- in
250
-
251
- Some
252
- [%expr
253
- fun v ->
254
- match Js.Json.classify v with
255
- | Js.Json.JSONString str -> [%e decoder_switch]
256
- | _ -> Spice.error "Not a JSONString" v]
257
- else
258
- let decoder_default_case =
259
- {
260
- pc_lhs = [%pat? _];
261
- pc_guard = None;
262
- pc_rhs =
263
- [%expr
264
- Spice.error "Invalid polymorphic constructor"
265
- (Belt.Array.getExn json_arr 0)];
266
- }
267
- in
268
-
269
- let decoder_switch =
270
- row_fields |> List.map (generate_decoder_case generator_settings)
271
- |> fun l ->
272
- l @ [ decoder_default_case ]
273
- |> Exp.match_ [%expr Belt.Array.getExn tagged 0]
274
- in
275
-
276
- Some
277
- [%expr
278
- fun v ->
279
- match Js.Json.classify v with
280
- | Js.Json.JSONArray [||] ->
281
- Spice.error "Expected polyvariant, found empty array" v
282
- | Js.Json.JSONArray json_arr ->
283
- let tagged = Js.Array.map Js.Json.classify json_arr in
284
- [%e decoder_switch]
285
- | _ -> Spice.error "Not a polyvariant" v]
286
- in
287
-
288
- (encoder, decoder)
@@ -1,19 +0,0 @@
1
- open Ppxlib
2
-
3
- class mapper =
4
- object (self)
5
- inherit Ast_traverse.map
6
-
7
- method! signature sign =
8
- sign |> List.map (Signature.map_signature_item self) |> List.concat
9
-
10
- method! structure strt =
11
- strt |> List.map (Structure.map_structure_item self) |> List.concat
12
- end
13
-
14
- let signature_mapper = (new mapper)#signature
15
-
16
- let structure_mapper = (new mapper)#structure;;
17
-
18
- Ppxlib.Driver.register_transformation ~preprocess_impl:structure_mapper
19
- ~preprocess_intf:signature_mapper "spice"
@@ -1,163 +0,0 @@
1
- open Ppxlib
2
- open Parsetree
3
- open Ast_helper
4
- open Utils
5
-
6
- type parsed_decl = {
7
- name : string;
8
- (* "NAME" *)
9
- key : expression;
10
- (* v.NAME *)
11
- field : expression;
12
- codecs : expression option * expression option;
13
- default : expression option;
14
- is_optional : bool;
15
- }
16
-
17
- let optional_attr : Ppxlib.Parsetree.attribute =
18
- {
19
- attr_name = { txt = "ns.optional"; loc = Location.none };
20
- attr_payload = PStr [];
21
- attr_loc = Location.none;
22
- }
23
-
24
- let generate_encoder decls unboxed =
25
- match unboxed with
26
- | true ->
27
- let { codecs; field } = List.hd decls in
28
- let e, _ = codecs in
29
- [%expr fun v -> [%e Option.get e] [%e field]]
30
- | false ->
31
- let arrExpr =
32
- decls
33
- |> List.map (fun { key; field; codecs = encoder, _; is_optional } ->
34
- let is_optional =
35
- if is_optional then [%expr true] else [%expr false]
36
- in
37
- [%expr
38
- [%e key], [%e is_optional], [%e Option.get encoder] [%e field]])
39
- |> Exp.array
40
- in
41
- [%expr
42
- [%e arrExpr] |> Spice.filterOptional |> Js.Dict.fromArray
43
- |> Js.Json.object_]
44
- |> Exp.fun_ Asttypes.Nolabel None [%pat? v]
45
-
46
- let generate_dict_get { key; codecs = _, decoder; default } =
47
- let decoder = Option.get decoder in
48
- match default with
49
- | Some default ->
50
- [%expr
51
- Belt.Option.getWithDefault
52
- (Belt.Option.map (Js.Dict.get dict [%e key]) [%e decoder])
53
- (Belt.Result.Ok [%e default])]
54
- | None ->
55
- [%expr
56
- Belt.Option.getWithDefault (Js.Dict.get dict [%e key]) Js.Json.null
57
- |> [%e decoder]]
58
-
59
- let generate_dict_gets decls =
60
- decls |> List.map generate_dict_get |> tuple_or_singleton Exp.tuple
61
-
62
- let generate_error_case { key } =
63
- {
64
- pc_lhs = [%pat? Belt.Result.Error (e : Spice.decodeError)];
65
- pc_guard = None;
66
- pc_rhs = [%expr Belt.Result.Error { e with path = "." ^ [%e key] ^ e.path }];
67
- }
68
-
69
- let generate_final_record_expr decls =
70
- decls
71
- |> List.map (fun { name; is_optional } ->
72
- let attrs = if is_optional then [ optional_attr ] else [] in
73
- (lid name, make_ident_expr ~attrs name))
74
- |> fun l -> [%expr Belt.Result.Ok [%e Exp.record l None]]
75
-
76
- let generate_success_case { name } success_expr =
77
- {
78
- pc_lhs = (mknoloc name |> Pat.var |> fun p -> [%pat? Belt.Result.Ok [%p p]]);
79
- pc_guard = None;
80
- pc_rhs = success_expr;
81
- }
82
-
83
- let rec generate_nested_switches_recurse all_decls remaining_decls =
84
- let current, success_expr =
85
- match remaining_decls with
86
- | [] -> failwith "Spice internal error: [] not expected"
87
- | [ last ] -> (last, generate_final_record_expr all_decls)
88
- | first :: tail -> (first, generate_nested_switches_recurse all_decls tail)
89
- in
90
- [ generate_error_case current ]
91
- |> List.append [ generate_success_case current success_expr ]
92
- |> Exp.match_ (generate_dict_get current)
93
- [@@ocaml.doc
94
- " Recursively generates an expression containing nested switches, first\n\
95
- \ * decoding the first record items, then (if successful) the second, \
96
- etc. "]
97
-
98
- let generate_nested_switches decls =
99
- generate_nested_switches_recurse decls decls
100
-
101
- let generate_decoder decls unboxed =
102
- match unboxed with
103
- | true ->
104
- let { codecs; name } = List.hd decls in
105
- let _, d = codecs in
106
-
107
- let record_expr = Exp.record [ (lid name, make_ident_expr "v") ] None in
108
-
109
- [%expr
110
- fun v ->
111
- Belt.Result.map ([%e Option.get d] v) (fun v -> [%e record_expr])]
112
- | false ->
113
- [%expr
114
- fun v ->
115
- match Js.Json.classify v with
116
- | Js.Json.JSONObject dict -> [%e generate_nested_switches decls]
117
- | _ -> Spice.error "Not an object" v]
118
-
119
- let parse_decl generator_settings
120
- { pld_name = { txt }; pld_loc; pld_type; pld_attributes } =
121
- let default =
122
- match get_attribute_by_name pld_attributes "spice.default" with
123
- | Ok (Some attribute) -> Some (get_expression_from_payload attribute)
124
- | Ok None -> None
125
- | Error s -> fail pld_loc s
126
- in
127
- let key =
128
- match get_attribute_by_name pld_attributes "spice.key" with
129
- | Ok (Some attribute) -> get_expression_from_payload attribute
130
- | Ok None -> Exp.constant (Pconst_string (txt, Location.none, None))
131
- | Error s -> fail pld_loc s
132
- in
133
- let optional_attrs = [ "ns.optional"; "res.optional" ] in
134
- let is_optional =
135
- optional_attrs
136
- |> List.map (fun attr -> get_attribute_by_name pld_attributes attr)
137
- |> List.exists (function Ok (Some _) -> true | _ -> false)
138
- in
139
- let codecs = Codecs.generate_codecs generator_settings pld_type in
140
- let codecs =
141
- if is_optional then
142
- match codecs with
143
- | Some encode, Some decode ->
144
- ( Some [%expr Spice.optionToJson [%e encode]],
145
- Some [%expr Spice.optionFromJson [%e decode]] )
146
- | _ -> codecs
147
- else codecs
148
- in
149
-
150
- {
151
- name = txt;
152
- key;
153
- field = Exp.field [%expr v] (lid txt);
154
- codecs;
155
- default;
156
- is_optional;
157
- }
158
-
159
- let generate_codecs ({ do_encode; do_decode } as generator_settings) decls
160
- unboxed =
161
- let parsed_decls = List.map (parse_decl generator_settings) decls in
162
- ( some_if_true do_encode (generate_encoder parsed_decls unboxed),
163
- some_if_true do_decode (generate_decoder parsed_decls unboxed) )
@@ -1,86 +0,0 @@
1
- open Ppxlib
2
- open Parsetree
3
- open Utils
4
-
5
- let rec add_encoder_params param_names result_type =
6
- match param_names with
7
- | [] -> result_type
8
- | hd :: tl ->
9
- [%type: ([%t Ast_helper.Typ.var hd] -> Js.Json.t) -> [%t result_type]]
10
- |> add_encoder_params tl
11
-
12
- let make_result_type value_type =
13
- [%type: ([%t value_type], Spice.decodeError) Belt.Result.t]
14
-
15
- let rec add_decoder_params param_names result_type =
16
- match param_names with
17
- | [] -> result_type
18
- | hd :: tl ->
19
- let decoder_param =
20
- [%type: Js.Json.t -> [%t make_result_type (Ast_helper.Typ.var hd)]]
21
- in
22
- [%type: [%t decoder_param] -> [%t result_type]] |> add_decoder_params tl
23
-
24
- let generate_sig_decls { do_encode; do_decode } type_name param_names =
25
- let encoder_pat = type_name ^ Utils.encoder_func_suffix in
26
- let decoder_pat = type_name ^ Utils.decoder_func_suffix in
27
- let value_type =
28
- param_names
29
- |> List.map Ast_helper.Typ.var
30
- |> Ast_helper.Typ.constr (lid type_name)
31
- in
32
-
33
- let decls = [] in
34
-
35
- let decls =
36
- match do_encode with
37
- | true ->
38
- decls
39
- @ [
40
- [%type: [%t value_type] -> Js.Json.t]
41
- |> add_encoder_params (List.rev param_names)
42
- |> Ast_helper.Val.mk (mknoloc encoder_pat)
43
- |> Ast_helper.Sig.value;
44
- ]
45
- | false -> decls
46
- in
47
- let decls =
48
- match do_decode with
49
- | true ->
50
- decls
51
- @ [
52
- [%type: Js.Json.t -> [%t make_result_type value_type]]
53
- |> add_decoder_params (List.rev param_names)
54
- |> Ast_helper.Val.mk (mknoloc decoder_pat)
55
- |> Ast_helper.Sig.value;
56
- ]
57
- | false -> decls
58
- in
59
-
60
- decls
61
-
62
- let map_type_decl decl =
63
- let {
64
- ptype_attributes;
65
- ptype_name = { txt = type_name };
66
- ptype_params;
67
- ptype_loc;
68
- } =
69
- decl
70
- in
71
-
72
- match get_generator_settings_from_attributes ptype_attributes with
73
- | Error s -> fail ptype_loc s
74
- | Ok None -> []
75
- | Ok (Some generator_settings) ->
76
- generate_sig_decls generator_settings type_name
77
- (get_param_names ptype_params)
78
-
79
- let map_signature_item mapper ({ psig_desc } as signature_item) =
80
- match psig_desc with
81
- | Psig_type (_, decls) ->
82
- let generated_sig_items =
83
- decls |> List.map map_type_decl |> List.concat
84
- in
85
- mapper#signature_item signature_item :: generated_sig_items
86
- | _ -> [ mapper#signature_item signature_item ]
@@ -1,109 +0,0 @@
1
- open Ppxlib
2
- open Parsetree
3
- open Ast_helper
4
- open Codecs
5
- open Utils
6
-
7
- let add_params param_names expr =
8
- List.fold_right
9
- (fun s acc ->
10
- let pat = Pat.var (mknoloc s) in
11
- Exp.fun_ Asttypes.Nolabel None pat acc)
12
- param_names
13
- [%expr fun v -> [%e expr] v]
14
-
15
- let generate_codec_decls type_name param_names (encoder, decoder) =
16
- let encoder_pat = Pat.var (mknoloc (type_name ^ Utils.encoder_func_suffix)) in
17
- let encoder_param_names =
18
- List.map (fun s -> encoder_var_prefix ^ s) param_names
19
- in
20
-
21
- let decoder_pat = Pat.var (mknoloc (type_name ^ Utils.decoder_func_suffix)) in
22
- let decoder_param_names =
23
- List.map (fun s -> decoder_var_prefix ^ s) param_names
24
- in
25
-
26
- let vbs = [] in
27
-
28
- let vbs =
29
- match encoder with
30
- | None -> vbs
31
- | Some encoder ->
32
- vbs
33
- @ [
34
- Vb.mk
35
- ~attrs:[ attr_warning [%expr "-39"] ]
36
- encoder_pat
37
- (add_params encoder_param_names encoder);
38
- ]
39
- in
40
-
41
- let vbs =
42
- match decoder with
43
- | None -> vbs
44
- | Some decoder ->
45
- vbs
46
- @ [
47
- Vb.mk
48
- ~attrs:[ attr_warning [%expr "-4"]; attr_warning [%expr "-39"] ]
49
- decoder_pat
50
- (add_params decoder_param_names decoder);
51
- ]
52
- in
53
-
54
- vbs
55
-
56
- let map_type_decl decl =
57
- let {
58
- ptype_attributes;
59
- ptype_name = { txt = type_name };
60
- ptype_manifest;
61
- ptype_params;
62
- ptype_loc;
63
- ptype_kind;
64
- } =
65
- decl
66
- in
67
-
68
- let is_unboxed =
69
- match Utils.get_attribute_by_name ptype_attributes "unboxed" with
70
- | Ok (Some _) -> true
71
- | _ -> false
72
- in
73
-
74
- match get_generator_settings_from_attributes ptype_attributes with
75
- | Ok None -> []
76
- | Ok (Some generator_settings) -> (
77
- match (ptype_manifest, ptype_kind) with
78
- | None, Ptype_abstract ->
79
- fail ptype_loc "Can't generate codecs for unspecified type"
80
- | Some { ptyp_desc = Ptyp_variant (row_fields, _, _) }, Ptype_abstract ->
81
- generate_codec_decls type_name
82
- (get_param_names ptype_params)
83
- (Polyvariants.generate_codecs generator_settings row_fields
84
- is_unboxed)
85
- | Some manifest, _ ->
86
- generate_codec_decls type_name
87
- (get_param_names ptype_params)
88
- (generate_codecs generator_settings manifest)
89
- | None, Ptype_variant decls ->
90
- generate_codec_decls type_name
91
- (get_param_names ptype_params)
92
- (Variants.generate_codecs generator_settings decls is_unboxed)
93
- | None, Ptype_record decls ->
94
- generate_codec_decls type_name
95
- (get_param_names ptype_params)
96
- (Records.generate_codecs generator_settings decls is_unboxed)
97
- | _ -> fail ptype_loc "This type is not handled by spice")
98
- | Error s -> fail ptype_loc s
99
-
100
- let map_structure_item mapper ({ pstr_desc } as structure_item) =
101
- match pstr_desc with
102
- | Pstr_type (rec_flag, decls) -> (
103
- let value_bindings = decls |> List.map map_type_decl |> List.concat in
104
- [ mapper#structure_item structure_item ]
105
- @
106
- match List.length value_bindings > 0 with
107
- | true -> [ Str.value rec_flag value_bindings ]
108
- | false -> [])
109
- | _ -> [ mapper#structure_item structure_item ]