1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
(* Copyright 2022-2023 Kotoi-Xie Consultancy, Inc. This file is a part of the

==== Bindoj (https://kxc.dev/bindoj) ====

software project that is developed, maintained, and distributed by
Kotoi-Xie Consultancy, Inc. (https://kxc.inc) which is also known as KXC.

Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
                                                                              *)
(* Acknowledgements  --- AnchorZ Inc. ---  The current/initial version or a
significant portion of this file is developed under the funding provided by
AnchorZ Inc. to satisfy its needs in its product development workflow.
                                                                              *)
include Utils

open Kxclib.Json

type 'camlrepr external_format = ..
type ('tag, 'datatype_expr) foreign_language = ..

type external_format_label = External_format : _ external_format -> external_format_label
type foreign_language_label = Foreign_language : _ foreign_language -> foreign_language_label

module External_format = struct
  module LabelOrdered = struct
    type t = external_format_label
    let compare x y = compare x y
  end
  module LabelSet = Set.Make(LabelOrdered)
  module LabelMap = Map.Make(LabelOrdered)
  type label_set = LabelSet.t
  type 'x label_map = 'x LabelMap.t

  type ('t, 'ext) codec = {
      encode : 't -> 'ext;
      decode : 'ext -> 't option;
    }
  type 't codec' =
    Codec : 'ext external_format*('t, 'ext) codec -> 't codec'
  type 't codecs = 't codec' LabelMap.t
end

module rec Refl : sig
  type 't constructor =
    | InlineRecord of {
        get: 't -> Expr'.t StringMap.t;
        mk: Expr'.t StringMap.t -> 't option;
      }
    | TupleLike of {
        get: 't -> Expr'.t list;
        mk: Expr'.t list -> 't option;
      }
    | NoParam of {
        value: 't
      }
    | ReusedInlineRecord of {
      get: 't -> Expr'.t StringMap.t;
      mk: Expr'.t StringMap.t -> 't option;
    }

  type 't result =
    | Record of {
        get: 't -> Expr'.t StringMap.t;
        mk: Expr'.t StringMap.t -> 't option;
      }
    | Variant of {
        constructors: 't constructor StringMap.t;
        classify: 't -> (string * 't constructor);
      }
    | Alias of {
        get: 't -> Expr'.t;
        mk: Expr'.t -> 't option;
      }

  and 'a t = 'a result Lazy.t
end = Refl

and Expr' : sig
  type t =
    | Unit
    | Bool of bool
    | Int of int
    | Int53p of int53p
    | Float of float
    | String of string
    | Uchar of Uchar.t
    | Byte of char
    | Bytes of Bytes.t
    | Some of t
    | None
    | Tuple of t list
    | List of t list
    | Map of (string * t) list
    | StringEnum of string
    | Refl : 'a Refl.t * 'a -> t
end = Expr'

module Expr = struct
  include Expr'
  open Option.Ops_monad

  let of_unit () = Unit
  let to_unit = function Unit -> some () | _ -> none
  let of_bool b = Bool b
  let to_bool = function Bool b -> some b | _ -> none
  let of_int i = Int i
  let to_int = function Int i -> some i | _ -> none
  let of_int53p i = Int53p i
  let to_int53p = function Int53p i -> some i | _ -> none
  let of_float f = Float f
  let to_float = function Float f -> some f | _ -> none
  let of_string s = String s
  let to_string = function String s -> some s | _ -> none
  let of_uchar c = Uchar c
  let to_uchar = function Uchar c -> some c | _ -> none
  let of_byte b = Byte b
  let to_byte = function Byte b -> some b | _ -> none
  let of_bytes s = Bytes s
  let to_bytes = function Bytes s -> some s | _ -> none
  let of_option of_a = function
    | Option.Some a -> Some (of_a a)
    | Option.None -> None
  let to_option to_a e =
    match e with
    | Some x -> to_a x |> Option.map (fun x -> some x)
    | None -> some none
    | _ -> none
  let of_list of_a xs = List (xs |> List.map of_a)
  let to_list to_a =
    function
    | List xs -> xs |> List.map to_a |> sequence_list
    | _ -> none
  let of_map of_a xs = Map (xs |> List.map (fun (k, v) -> k, of_a v))
  let to_map to_a = function
    | Map xs ->
      xs |> List.map (fun (k, v) ->
        to_a v |> Option.map (fun v -> k, v)
      ) |> sequence_list
    | _ -> none
  let of_refl refl x = Refl (refl, x)
  let to_refl (type a) (refl: a Refl.t) : t -> a option = function
    | Refl (refl', x) ->
      if Lazy.force refl == Obj.magic (Lazy.force refl') then Some (Obj.magic x)
      else None
    | _ -> None
end

module type Generic_typed_type_decl = sig
  type type_decl
  type t
  val decl : type_decl
  val reflect : t Refl.t
end
type ('type_decl, 't) generic_typed_type_decl =
  (module Generic_typed_type_decl with
            type type_decl = 'type_decl
          and type t = 't)

type _ boxed_generic_typed_type_decl =
  | Boxed_generic_typed_type_decl :
      ('type_decl, _) generic_typed_type_decl -> ('type_decl) boxed_generic_typed_type_decl

let mk_generic_typed_type_decl
    : type type_decl t. type_decl -> t Refl.t
           -> (type_decl, t) generic_typed_type_decl =
  fun decl refl -> (
    module struct
      type nonrec type_decl = type_decl
      type nonrec t = t
      let decl = decl
      let reflect = refl
    end)

let box_generic_typed_type_decl :
  ('type_decl, 't) generic_typed_type_decl
  -> ('type_decl) boxed_generic_typed_type_decl
  = fun ttd -> Boxed_generic_typed_type_decl ttd

let mk_boxed_generic_typed_type_decl :
  'type_decl -> 't Refl.t
  -> ('type_decl) boxed_generic_typed_type_decl
  = fun decl refl ->
  mk_generic_typed_type_decl decl refl |> box_generic_typed_type_decl

module Reflects = struct
  open Refl

  let reflect_of_alias get mk : _ Refl.t =
    lazy (Alias { get; mk })

  let unit_reflect =
    Expr.(reflect_of_alias
            of_unit to_unit)
  let bool_reflect =
    Expr.(reflect_of_alias
            of_bool to_bool)
  let int_reflect =
    Expr.(reflect_of_alias
            of_int to_int)
  let int53p_reflect =
    Expr.(reflect_of_alias
            of_int53p to_int53p)
  let float_reflect =
    Expr.(reflect_of_alias
            of_float to_float)
  let string_reflect =
    Expr.(reflect_of_alias
            of_string to_string)
  let uchar_reflect =
    Expr.(reflect_of_alias
            of_uchar to_uchar)
  let byte_reflect =
    Expr.(reflect_of_alias
            of_byte to_byte)
  let bytes_reflect =
    Expr.(reflect_of_alias
            of_bytes to_bytes)
end

module Wellknown = struct
  type _ external_format +=
     | External_format_json : jv external_format
  let json_format = External_format_json
  let json_format' = External_format json_format
end

module Json_shape = struct
  let pp_jv = pp_unparse

  type shape_explanation = [
    | `self
    | `named of string*shape_explanation
    | `special of string*shape_explanation
    | `with_warning of string*shape_explanation
    | `exactly of jv
    | `any_json_value
    | `unresolved of string
    | `anyone_of of shape_explanation list
    | `string_enum of string list
    | `nullable of shape_explanation
    | `boolean
    | `numeric
    | `integral | `proper_int53p | `proper_float
    | `string | `base64str
    | `array_of of shape_explanation
    | `tuple_of of shape_explanation list
    | `record_of of shape_explanation
    | `object_of of field_shape_explanation list
    ]
  [@@deriving show]
  and field_shape_explanation = [
    | `mandatory_field of string*shape_explanation
    | `optional_field of string*shape_explanation
    ]
  [@@deriving show]

  let string_of_shape_explanation = show_shape_explanation
  let string_of_field_shape_explanation = show_field_shape_explanation
end

type json_shape_explanation = Json_shape.shape_explanation
type json_field_shape_explanation = Json_shape.field_shape_explanation

let string_of_json_shape_explanation = Json_shape.string_of_shape_explanation
let string_of_json_field_shape_explanation = Json_shape.string_of_field_shape_explanation


module type Json_shape_explaner = sig
  type shape
  type field_shape
  val shape_of_json_shape_explanation : json_shape_explanation -> shape
  val self : shape
  val named : string * shape -> shape
  val special : string * shape -> shape
  val with_warning : string * shape -> shape
  val exactly : jv -> shape
  val any_json_value : shape
  val unresolved : string -> shape
  val anyone_of : shape list -> shape
  val string_enum : string list -> shape
  val nullable : shape -> shape
  val boolean : shape
  val numeric : shape
  val integral : shape
  val proper_int53p : shape
  val proper_float : shape
  val string : shape
  val base64str : shape
  val array_of : shape -> shape
  val tuple_of : shape list -> shape
  val record_of : shape -> shape
  val object_of : field_shape list -> shape
  val mandatory_field : string * shape -> field_shape
  val optional_field : string * shape -> field_shape
end

type ('shape, 'field_shape) json_shape_explaner =
(module Json_shape_explaner
  with type shape = 'shape
  and type field_shape = 'field_shape)

let json_shape_explanation : (json_shape_explanation, json_field_shape_explanation) json_shape_explaner =
  (module struct
    type shape = json_shape_explanation
    type field_shape = json_field_shape_explanation
    let shape_of_json_shape_explanation : json_shape_explanation -> shape = identity
    let self : shape = `self
    let named : string * shape -> shape = fun x -> `named x
    let special : string * shape -> shape = fun x -> `special x
    let with_warning : string * shape -> shape = fun x -> `with_warning x
    let exactly : jv -> shape = fun x -> `exactly x
    let any_json_value : shape = `any_json_value
    let unresolved : string -> shape = fun x -> `unresolved x
    let anyone_of : shape list -> shape = fun x -> `anyone_of x
    let string_enum : string list -> shape = fun x -> `string_enum x
    let nullable : shape -> shape = fun x -> `nullable x
    let boolean : shape = `boolean
    let numeric : shape = `numeric
    let integral : shape = `integral
    let proper_int53p : shape = `proper_int53p
    let proper_float : shape = `proper_float
    let string : shape = `string
    let base64str : shape = `base64str
    let array_of : shape -> shape = fun x -> `array_of x
    let tuple_of : shape list -> shape = fun x -> `tuple_of x
    let record_of : shape -> shape = fun x -> `record_of x
    let object_of : field_shape list -> shape = fun x ->  `object_of x
    let mandatory_field : string * shape -> field_shape = fun x -> `mandatory_field x
    let optional_field : string * shape -> field_shape = fun x -> `optional_field x
  end)

module OfJsonResult = struct
  module Err = struct
    type t = string * jvpath * json_shape_explanation
    let to_string (msg, path, _) =
      match path with
      | [] -> sprintf "%s at root" msg
      | path -> sprintf "%s at path %s" msg ((path |> List.rev) |> Json.unparse_jvpath)
    let message (msg, _, _) = msg
    let path (_, path, _) = path
    let shape (_, _, shape) = shape
  end

  module R0 = ResultOf'(struct
                  type nonrec err = Err.t
                  let string_of_err = Err.to_string &> Option.some
                end)
  include R0
  module Ops_monad = MonadOps(R0)
end

type 'a json_full_decoder =
  ?path:Kxclib.Json.jvpath
  -> Kxclib.Json.jv
  -> 'a OfJsonResult.t