(****************************************************************************)
(*     Sail                                                                 *)
(*                                                                          *)
(*  Sail and the Sail architecture models here, comprising all files and    *)
(*  directories except the ASL-derived Sail code in the aarch64 directory,  *)
(*  are subject to the BSD two-clause licence below.                        *)
(*                                                                          *)
(*  The ASL derived parts of the ARMv8.3 specification in                   *)
(*  aarch64/no_vector and aarch64/full are copyright ARM Ltd.               *)
(*                                                                          *)
(*  Copyright (c) 2013-2025                                                 *)
(*    Kathyrn Gray                                                          *)
(*    Shaked Flur                                                           *)
(*    Stephen Kell                                                          *)
(*    Gabriel Kerneis                                                       *)
(*    Robert Norton-Wright                                                  *)
(*    Christopher Pulte                                                     *)
(*    Peter Sewell                                                          *)
(*    Alasdair Armstrong                                                    *)
(*    Brian Campbell                                                        *)
(*    Thomas Bauereiss                                                      *)
(*    Anthony Fox                                                           *)
(*    Jon French                                                            *)
(*    Dominic Mulligan                                                      *)
(*    Stephen Kell                                                          *)
(*    Mark Wassell                                                          *)
(*    Alastair Reid (Arm Ltd)                                               *)
(*                                                                          *)
(*  All rights reserved.                                                    *)
(*                                                                          *)
(*  This work was partially supported by EPSRC grant EP/K008528/1 <a        *)
(*  href="http://www.cl.cam.ac.uk/users/pes20/rems">REMS: Rigorous          *)
(*  Engineering for Mainstream Systems</a>, an ARM iCASE award, EPSRC IAA   *)
(*  KTF funding, and donations from Arm.  This project has received         *)
(*  funding from the European Research Council (ERC) under the European     *)
(*  Union’s Horizon 2020 research and innovation programme (grant           *)
(*  agreement No 789108, ELVER).                                            *)
(*                                                                          *)
(*  This software was developed by SRI International and the University of  *)
(*  Cambridge Computer Laboratory (Department of Computer Science and       *)
(*  Technology) under DARPA/AFRL contracts FA8650-18-C-7809 ("CIFV")        *)
(*  and FA8750-10-C-0237 ("CTSRD").                                         *)
(*                                                                          *)
(*  SPDX-License-Identifier: BSD-2-Clause                                   *)
(****************************************************************************)

open Ast_util

let parse_override obj =
  let open Util.Option_monad in
  let* id = Option.bind (List.assoc_opt "id" obj) attribute_data_string in
  let* target = Option.bind (List.assoc_opt "target" obj) attribute_data_string in
  let* prefix =
    match List.assoc_opt "prefix" obj with Some (AD_aux (AD_string s, _)) -> Some s | Some _ -> None | None -> Some ""
  in
  let* suffix =
    match List.assoc_opt "prefix" obj with Some (AD_aux (AD_string s, _)) -> Some s | Some _ -> None | None -> Some ""
  in
  Some ((prefix, id, suffix), target)

module Overrides = Map.Make (struct
  type t = string * string * string

  let compare (p1, n1, s1) (p2, n2, s2) = Util.lex_ord_list String.compare [p1; n1; s1] [p2; n2; s2]
end)

module type CONFIG = sig
  type style

  val allowed : string -> bool
  val pretty : style -> string -> string
  val mangle : style -> string -> string
  val variant : string -> int -> string
  val overrides : string Overrides.t
end

module Make (Config : CONFIG) () = struct
  let names = Hashtbl.create 1024
  let generated = Hashtbl.create 1024

  let translate ?(prefix = "") ?(suffix = "") style orig_str =
    match Overrides.find_opt (prefix, orig_str, suffix) Config.overrides with
    | Some result -> result
    | None -> (
        match Hashtbl.find_opt names (prefix, orig_str, suffix) with
        | Some result -> result
        | None ->
            let str = if Config.allowed orig_str then Config.pretty style orig_str else Config.mangle style orig_str in
            let str = prefix ^ str ^ suffix in
            let rec variant_str n =
              let modified = Config.variant str n in
              if Hashtbl.mem generated modified then variant_str (n + 1)
              else (
                Hashtbl.add generated modified ();
                Hashtbl.add names (prefix, orig_str, suffix) modified;
                modified
              )
            in
            variant_str 0
      )

  let to_string ?(prefix = "") ?(suffix = "") style id = translate ~prefix ~suffix style (string_of_id id)
end
