(*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *)

module type S = sig
  module L : Loc_sig.S

  type read_loc = L.t

  type write_loc =
    | Write of L.t Reason.virtual_reason
    | Uninitialized

  type write_locs = write_loc list

  type values = write_locs L.LMap.t

  val uninitialized : write_loc
end

module Make (L : Loc_sig.S) : S with module L = L = struct
  module L = L

  type read_loc = L.t

  type write_loc =
    | Write of L.t Reason.virtual_reason
    | Uninitialized

  type write_locs = write_loc list

  type values = write_locs L.LMap.t

  let uninitialized = Uninitialized
end

module With_Loc = Make (Loc_sig.LocS)
module With_ALoc = Make (Loc_sig.ALocS)
include With_Loc

let print_values =
  let print_write_loc write_loc =
    match write_loc with
    | Uninitialized -> "(uninitialized)"
    | Write reason ->
      let loc = Reason.loc_of_reason reason in
      Utils_js.spf
        "%s: (%s)"
        (Loc.debug_to_string loc)
        Reason.(desc_of_reason reason |> string_of_desc)
  in
  fun values ->
    let kvlist = Loc_collections.LocMap.bindings values in
    let strlist =
      Base.List.map
        ~f:(fun (read_loc, write_locs) ->
          Printf.sprintf
            "%s => { %s }"
            (L.debug_to_string read_loc)
            (String.concat ", " @@ Base.List.map ~f:print_write_loc write_locs))
        kvlist
    in
    Printf.sprintf "[ %s ]" (String.concat "; " strlist)
