open Prims
let string_compare (s1 : Prims.string) (s2 : Prims.string) : Prims.int=
  FStarC_String.compare s1 s2
type 'a heap =
  | EmptyHeap 
  | Heap of ('a * 'a heap Prims.list) 
let uu___is_EmptyHeap (projectee : 'a heap) : Prims.bool=
  match projectee with | EmptyHeap -> true | uu___ -> false
let uu___is_Heap (projectee : 'a heap) : Prims.bool=
  match projectee with | Heap _0 -> true | uu___ -> false
let __proj__Heap__item___0 (projectee : 'a heap) : ('a * 'a heap Prims.list)=
  match projectee with | Heap _0 -> _0
let heap_merge (cmp : 'uuuuu -> 'uuuuu -> Prims.int) (h1 : 'uuuuu heap)
  (h2 : 'uuuuu heap) : 'uuuuu heap=
  match (h1, h2) with
  | (EmptyHeap, h) -> h
  | (h, EmptyHeap) -> h
  | (Heap (v1, hh1), Heap (v2, hh2)) ->
      let uu___ = let uu___1 = cmp v1 v2 in uu___1 < Prims.int_zero in
      if uu___ then Heap (v1, (h2 :: hh1)) else Heap (v2, (h1 :: hh2))
let heap_insert (cmp : 'uuuuu -> 'uuuuu -> Prims.int) (h : 'uuuuu heap)
  (v : 'uuuuu) : 'uuuuu heap= heap_merge cmp (Heap (v, [])) h
let rec heap_merge_pairs :
  'uuuuu .
    ('uuuuu -> 'uuuuu -> Prims.int) -> 'uuuuu heap Prims.list -> 'uuuuu heap
  =
  fun cmp uu___ ->
    match uu___ with
    | [] -> EmptyHeap
    | h::[] -> h
    | h1::h2::hh ->
        let uu___1 = heap_merge cmp h1 h2 in
        let uu___2 = heap_merge_pairs cmp hh in heap_merge cmp uu___1 uu___2
let heap_peek (uu___ : 'uuuuu heap) : 'uuuuu FStar_Pervasives_Native.option=
  match uu___ with
  | EmptyHeap -> FStar_Pervasives_Native.None
  | Heap (v, uu___1) -> FStar_Pervasives_Native.Some v
let heap_pop (cmp : 'uuuuu -> 'uuuuu -> Prims.int) (uu___ : 'uuuuu heap) :
  ('uuuuu * 'uuuuu heap) FStar_Pervasives_Native.option=
  match uu___ with
  | EmptyHeap -> FStar_Pervasives_Native.None
  | Heap (v, hh) ->
      let uu___1 = let uu___2 = heap_merge_pairs cmp hh in (v, uu___2) in
      FStar_Pervasives_Native.Some uu___1
let heap_from_list (cmp : 'uuuuu -> 'uuuuu -> Prims.int)
  (values : 'uuuuu Prims.list) : 'uuuuu heap=
  FStarC_List.fold_left (heap_insert cmp) EmptyHeap values
let push_nodup (key_fn : 'uuuuu -> Prims.string) (x : 'uuuuu)
  (uu___ : 'uuuuu Prims.list) : 'uuuuu Prims.list=
  match uu___ with
  | [] -> [x]
  | h::t ->
      let uu___1 =
        let uu___2 =
          let uu___3 = key_fn x in
          let uu___4 = key_fn h in string_compare uu___3 uu___4 in
        uu___2 = Prims.int_zero in
      if uu___1 then h :: t else x :: h :: t
let rec add_priorities :
  'uuuuu .
    Prims.int ->
      (Prims.int * 'uuuuu) Prims.list ->
        'uuuuu Prims.list -> (Prims.int * 'uuuuu) Prims.list
  =
  fun n acc uu___ ->
    match uu___ with
    | [] -> acc
    | h::t -> add_priorities (n + Prims.int_one) ((n, h) :: acc) t
let merge_increasing_lists_rev (key_fn : 'a -> Prims.string)
  (lists : 'a Prims.list Prims.list) : 'a Prims.list=
  let cmp v1 v2 =
    match (v1, v2) with
    | ((uu___, []), uu___1) -> failwith "impossible"
    | (uu___, (uu___1, [])) -> failwith "impossible"
    | ((pr1, h1::uu___), (pr2, h2::uu___1)) ->
        let cmp_h =
          let uu___2 = key_fn h1 in
          let uu___3 = key_fn h2 in string_compare uu___2 uu___3 in
        if cmp_h <> Prims.int_zero then cmp_h else pr1 - pr2 in
  let rec aux lists1 acc =
    let uu___ = heap_pop cmp lists1 in
    match uu___ with
    | FStar_Pervasives_Native.None -> acc
    | FStar_Pervasives_Native.Some ((pr, []), uu___1) ->
        failwith "impossible"
    | FStar_Pervasives_Native.Some ((pr, v::[]), lists2) ->
        let uu___1 = push_nodup key_fn v acc in aux lists2 uu___1
    | FStar_Pervasives_Native.Some ((pr, v::tl), lists2) ->
        let uu___1 = heap_insert cmp lists2 (pr, tl) in
        let uu___2 = push_nodup key_fn v acc in aux uu___1 uu___2 in
  let lists1 = FStarC_List.filter (fun x -> x <> []) lists in
  match lists1 with
  | [] -> []
  | l::[] -> FStarC_List.rev l
  | uu___ ->
      let lists2 = add_priorities Prims.int_zero [] lists1 in
      let uu___1 = heap_from_list cmp lists2 in aux uu___1 []
type 'a btree =
  | StrEmpty 
  | StrBranch of (Prims.string * 'a * 'a btree * 'a btree) 
let uu___is_StrEmpty (projectee : 'a btree) : Prims.bool=
  match projectee with | StrEmpty -> true | uu___ -> false
let uu___is_StrBranch (projectee : 'a btree) : Prims.bool=
  match projectee with | StrBranch _0 -> true | uu___ -> false
let __proj__StrBranch__item___0 (projectee : 'a btree) :
  (Prims.string * 'a * 'a btree * 'a btree)=
  match projectee with | StrBranch _0 -> _0
let rec btree_to_list_rev :
  'a .
    'a btree ->
      (Prims.string * 'a) Prims.list -> (Prims.string * 'a) Prims.list
  =
  fun btree1 acc ->
    match btree1 with
    | StrEmpty -> acc
    | StrBranch (key, value, lbt, rbt) ->
        let uu___ =
          let uu___1 = btree_to_list_rev lbt acc in (key, value) :: uu___1 in
        btree_to_list_rev rbt uu___
let rec btree_from_list :
  'a .
    (Prims.string * 'a) Prims.list ->
      Prims.int -> ('a btree * (Prims.string * 'a) Prims.list)
  =
  fun nodes size ->
    if size = Prims.int_zero
    then (StrEmpty, nodes)
    else
      (let lbt_size = size / (Prims.of_int (2)) in
       let rbt_size = (size - lbt_size) - Prims.int_one in
       let uu___1 = btree_from_list nodes lbt_size in
       match uu___1 with
       | (lbt, nodes_left) ->
           (match nodes_left with
            | [] -> failwith "Invalid size passed to btree_from_list"
            | (k, v)::nodes_left1 ->
                let uu___2 = btree_from_list nodes_left1 rbt_size in
                (match uu___2 with
                 | (rbt, nodes_left2) ->
                     ((StrBranch (k, v, lbt, rbt)), nodes_left2))))
let rec btree_insert_replace :
  'a . 'a btree -> Prims.string -> 'a -> 'a btree =
  fun bt k v ->
    match bt with
    | StrEmpty -> StrBranch (k, v, StrEmpty, StrEmpty)
    | StrBranch (k', v', lbt, rbt) ->
        let cmp = string_compare k k' in
        if cmp < Prims.int_zero
        then
          let uu___ =
            let uu___1 = btree_insert_replace lbt k v in
            (k', v', uu___1, rbt) in
          StrBranch uu___
        else
          if cmp > Prims.int_zero
          then
            (let uu___1 =
               let uu___2 = btree_insert_replace rbt k v in
               (k', v', lbt, uu___2) in
             StrBranch uu___1)
          else StrBranch (k', v, lbt, rbt)
let rec btree_find_exact :
  'a . 'a btree -> Prims.string -> 'a FStar_Pervasives_Native.option =
  fun bt k ->
    match bt with
    | StrEmpty -> FStar_Pervasives_Native.None
    | StrBranch (k', v, lbt, rbt) ->
        let cmp = string_compare k k' in
        if cmp < Prims.int_zero
        then btree_find_exact lbt k
        else
          if cmp > Prims.int_zero
          then btree_find_exact rbt k
          else FStar_Pervasives_Native.Some v
let rec btree_extract_min :
  'a .
    'a btree -> (Prims.string * 'a * 'a btree) FStar_Pervasives_Native.option
  =
  fun bt ->
    match bt with
    | StrEmpty -> FStar_Pervasives_Native.None
    | StrBranch (k, v, StrEmpty, rbt) ->
        FStar_Pervasives_Native.Some (k, v, rbt)
    | StrBranch (uu___, uu___1, lbt, uu___2) -> btree_extract_min lbt
let rec btree_remove : 'a . 'a btree -> Prims.string -> 'a btree =
  fun bt k ->
    match bt with
    | StrEmpty -> StrEmpty
    | StrBranch (k', v, lbt, rbt) ->
        let cmp = string_compare k k' in
        if cmp < Prims.int_zero
        then
          let uu___ = let uu___1 = btree_remove lbt k in (k', v, uu___1, rbt) in
          StrBranch uu___
        else
          if cmp > Prims.int_zero
          then
            (let uu___1 =
               let uu___2 = btree_remove rbt k in (k', v, lbt, uu___2) in
             StrBranch uu___1)
          else
            (match lbt with
             | StrEmpty -> bt
             | uu___2 ->
                 let uu___3 = btree_extract_min rbt in
                 (match uu___3 with
                  | FStar_Pervasives_Native.None -> lbt
                  | FStar_Pervasives_Native.Some (rbt_min_k, rbt_min_v, rbt')
                      -> StrBranch (rbt_min_k, rbt_min_v, lbt, rbt')))
type prefix_match =
  {
  prefix: Prims.string FStar_Pervasives_Native.option ;
  completion: Prims.string }
let __proj__Mkprefix_match__item__prefix (projectee : prefix_match) :
  Prims.string FStar_Pervasives_Native.option=
  match projectee with | { prefix; completion;_} -> prefix
let __proj__Mkprefix_match__item__completion (projectee : prefix_match) :
  Prims.string= match projectee with | { prefix; completion;_} -> completion
type path_elem = {
  imports: Prims.string Prims.list ;
  segment: prefix_match }
let __proj__Mkpath_elem__item__imports (projectee : path_elem) :
  Prims.string Prims.list=
  match projectee with | { imports; segment;_} -> imports
let __proj__Mkpath_elem__item__segment (projectee : path_elem) :
  prefix_match= match projectee with | { imports; segment;_} -> segment
type path = path_elem Prims.list
let matched_prefix_of_path_elem (elem : path_elem) :
  Prims.string FStar_Pervasives_Native.option= (elem.segment).prefix
type query = Prims.string Prims.list
type ns_info = {
  ns_name: Prims.string ;
  ns_loaded: Prims.bool }
let __proj__Mkns_info__item__ns_name (projectee : ns_info) : Prims.string=
  match projectee with | { ns_name; ns_loaded;_} -> ns_name
let __proj__Mkns_info__item__ns_loaded (projectee : ns_info) : Prims.bool=
  match projectee with | { ns_name; ns_loaded;_} -> ns_loaded
type mod_info =
  {
  mod_name: Prims.string ;
  mod_path: Prims.string ;
  mod_loaded: Prims.bool }
let __proj__Mkmod_info__item__mod_name (projectee : mod_info) : Prims.string=
  match projectee with | { mod_name; mod_path; mod_loaded;_} -> mod_name
let __proj__Mkmod_info__item__mod_path (projectee : mod_info) : Prims.string=
  match projectee with | { mod_name; mod_path; mod_loaded;_} -> mod_path
let __proj__Mkmod_info__item__mod_loaded (projectee : mod_info) : Prims.bool=
  match projectee with | { mod_name; mod_path; mod_loaded;_} -> mod_loaded
let mk_path_el (imports : Prims.string Prims.list) (segment : prefix_match) :
  path_elem= { imports; segment }
let btree_find_prefix (bt : 'a btree) (prefix : Prims.string) :
  (prefix_match * 'a) Prims.list=
  let rec aux bt1 prefix1 acc =
    match bt1 with
    | StrEmpty -> acc
    | StrBranch (k, v, lbt, rbt) ->
        let cmp = string_compare k prefix1 in
        let include_middle = FStarC_Util.starts_with k prefix1 in
        let explore_right = (cmp <= Prims.int_zero) || include_middle in
        let explore_left = cmp > Prims.int_zero in
        let matches = if explore_right then aux rbt prefix1 acc else acc in
        let matches1 =
          if include_middle
          then
            ({
               prefix = (FStar_Pervasives_Native.Some prefix1);
               completion = k
             }, v)
            :: matches
          else matches in
        let matches2 =
          if explore_left then aux lbt prefix1 matches1 else matches1 in
        matches2 in
  aux bt prefix []
let rec btree_fold :
  'a 'b . 'a btree -> (Prims.string -> 'a -> 'b -> 'b) -> 'b -> 'b =
  fun bt f acc ->
    match bt with
    | StrEmpty -> acc
    | StrBranch (k, v, lbt, rbt) ->
        let uu___ = let uu___1 = btree_fold rbt f acc in f k v uu___1 in
        btree_fold lbt f uu___
let query_to_string (q : Prims.string Prims.list) : Prims.string=
  FStarC_String.concat "." q
type 'a name_collection =
  | Names of 'a btree 
  | ImportedNames of (Prims.string * 'a name_collection Prims.list) 
let uu___is_Names (projectee : 'a name_collection) : Prims.bool=
  match projectee with | Names _0 -> true | uu___ -> false
let __proj__Names__item___0 (projectee : 'a name_collection) : 'a btree=
  match projectee with | Names _0 -> _0
let uu___is_ImportedNames (projectee : 'a name_collection) : Prims.bool=
  match projectee with | ImportedNames _0 -> true | uu___ -> false
let __proj__ImportedNames__item___0 (projectee : 'a name_collection) :
  (Prims.string * 'a name_collection Prims.list)=
  match projectee with | ImportedNames _0 -> _0
type 'a names = 'a name_collection Prims.list
type 'a trie = {
  bindings: 'a names ;
  namespaces: 'a trie names }
let __proj__Mktrie__item__bindings (projectee : 'a trie) : 'a names=
  match projectee with | { bindings; namespaces;_} -> bindings
let __proj__Mktrie__item__namespaces (projectee : 'a trie) : 'a trie names=
  match projectee with | { bindings; namespaces;_} -> namespaces
let trie_empty (uu___ : unit) : 'uuuuu trie=
  { bindings = []; namespaces = [] }
let rec names_find_exact :
  'a . 'a names -> Prims.string -> 'a FStar_Pervasives_Native.option =
  fun names1 ns ->
    let uu___ =
      match names1 with
      | [] -> (FStar_Pervasives_Native.None, FStar_Pervasives_Native.None)
      | (Names bt)::names2 ->
          let uu___1 = btree_find_exact bt ns in
          (uu___1, (FStar_Pervasives_Native.Some names2))
      | (ImportedNames (uu___1, names2))::more_names ->
          let uu___2 = names_find_exact names2 ns in
          (uu___2, (FStar_Pervasives_Native.Some more_names)) in
    match uu___ with
    | (result, names2) ->
        (match (result, names2) with
         | (FStar_Pervasives_Native.None, FStar_Pervasives_Native.Some
            scopes) -> names_find_exact scopes ns
         | uu___1 -> result)
let rec trie_descend_exact :
  'a . 'a trie -> query -> 'a trie FStar_Pervasives_Native.option =
  fun tr query1 ->
    match query1 with
    | [] -> FStar_Pervasives_Native.Some tr
    | ns::query2 ->
        let uu___ = names_find_exact tr.namespaces ns in
        FStarC_Option.bind uu___
          (fun scope -> trie_descend_exact scope query2)
let rec trie_find_exact :
  'a . 'a trie -> query -> 'a FStar_Pervasives_Native.option =
  fun tr query1 ->
    match query1 with
    | [] -> failwith "Empty query in trie_find_exact"
    | name::[] -> names_find_exact tr.bindings name
    | ns::query2 ->
        let uu___ = names_find_exact tr.namespaces ns in
        FStarC_Option.bind uu___ (fun scope -> trie_find_exact scope query2)
let names_insert (name_collections : 'a names) (id : Prims.string) (v : 'a) :
  'a names=
  let uu___ =
    match name_collections with
    | (Names bt)::tl -> (bt, tl)
    | uu___1 -> (StrEmpty, name_collections) in
  match uu___ with
  | (bt, name_collections1) ->
      let uu___1 = let uu___2 = btree_insert_replace bt id v in Names uu___2 in
      uu___1 :: name_collections1
let rec namespaces_mutate :
  'a .
    'a trie names ->
      Prims.string ->
        query ->
          query ->
            ('a trie ->
               Prims.string -> query -> query -> 'a trie names -> 'a trie)
              -> ('a trie -> query -> 'a trie) -> 'a trie names
  =
  fun namespaces ns q rev_acc mut_node mut_leaf ->
    let trie1 =
      let uu___ = names_find_exact namespaces ns in
      FStarC_Option.dflt (trie_empty ()) uu___ in
    let uu___ = trie_mutate trie1 q rev_acc mut_node mut_leaf in
    names_insert namespaces ns uu___
and trie_mutate :
  'a .
    'a trie ->
      query ->
        query ->
          ('a trie ->
             Prims.string -> query -> query -> 'a trie names -> 'a trie)
            -> ('a trie -> query -> 'a trie) -> 'a trie
  =
  fun tr q rev_acc mut_node mut_leaf ->
    match q with
    | [] -> mut_leaf tr rev_acc
    | id::q1 ->
        let ns' =
          namespaces_mutate tr.namespaces id q1 (id :: rev_acc) mut_node
            mut_leaf in
        mut_node tr id q1 rev_acc ns'
let trie_mutate_leaf (tr : 'a trie) (query1 : query) :
  ('a trie -> query -> 'a trie) -> 'a trie=
  trie_mutate tr query1 []
    (fun tr1 uu___ uu___1 uu___2 namespaces ->
       { bindings = (tr1.bindings); namespaces })
let trie_insert (tr : 'a trie) (ns_query : query) (id : Prims.string)
  (v : 'a) : 'a trie=
  trie_mutate_leaf tr ns_query
    (fun tr1 uu___ ->
       let uu___1 = names_insert tr1.bindings id v in
       { bindings = uu___1; namespaces = (tr1.namespaces) })
let trie_import (tr : 'a trie) (host_query : query) (included_query : query)
  (mutator : 'a trie -> 'a trie -> Prims.string -> 'a trie) : 'a trie=
  let label = query_to_string included_query in
  let included_trie =
    let uu___ = trie_descend_exact tr included_query in
    FStarC_Option.dflt (trie_empty ()) uu___ in
  trie_mutate_leaf tr host_query
    (fun tr1 uu___ -> mutator tr1 included_trie label)
let trie_include (tr : 'a trie) (host_query : query) (included_query : query)
  : 'a trie=
  trie_import tr host_query included_query
    (fun tr1 inc label ->
       {
         bindings = ((ImportedNames (label, (inc.bindings))) ::
           (tr1.bindings));
         namespaces = (tr1.namespaces)
       })
let trie_open_namespace (tr : 'a trie) (host_query : query)
  (included_query : query) : 'a trie=
  trie_import tr host_query included_query
    (fun tr1 inc label ->
       {
         bindings = (tr1.bindings);
         namespaces = ((ImportedNames (label, (inc.namespaces))) ::
           (tr1.namespaces))
       })
let trie_add_alias (tr : 'a trie) (key : Prims.string) (host_query : query)
  (included_query : query) : 'a trie=
  trie_import tr host_query included_query
    (fun tr1 inc label ->
       trie_mutate_leaf tr1 [key]
         (fun _ignored_overwritten_trie uu___ ->
            {
              bindings = [ImportedNames (label, (inc.bindings))];
              namespaces = []
            }))
let names_revmap (fn : 'a btree -> 'b) (name_collections : 'a names) :
  (Prims.string Prims.list * 'b) Prims.list=
  let rec aux acc imports name_collections1 =
    FStarC_List.fold_left
      (fun acc1 uu___ ->
         match uu___ with
         | Names bt ->
             let uu___1 = let uu___2 = fn bt in (imports, uu___2) in uu___1
               :: acc1
         | ImportedNames (nm, name_collections2) ->
             aux acc1 (nm :: imports) name_collections2) acc
      name_collections1 in
  aux [] [] name_collections
let btree_find_all (prefix : Prims.string FStar_Pervasives_Native.option)
  (bt : 'a btree) : (prefix_match * 'a) Prims.list=
  btree_fold bt (fun k tr acc -> ({ prefix; completion = k }, tr) :: acc) []
type name_search_term =
  | NSTAll 
  | NSTNone 
  | NSTPrefix of Prims.string 
let uu___is_NSTAll (projectee : name_search_term) : Prims.bool=
  match projectee with | NSTAll -> true | uu___ -> false
let uu___is_NSTNone (projectee : name_search_term) : Prims.bool=
  match projectee with | NSTNone -> true | uu___ -> false
let uu___is_NSTPrefix (projectee : name_search_term) : Prims.bool=
  match projectee with | NSTPrefix _0 -> true | uu___ -> false
let __proj__NSTPrefix__item___0 (projectee : name_search_term) :
  Prims.string= match projectee with | NSTPrefix _0 -> _0
let names_find_rev (names1 : 'a names) (id : name_search_term) :
  (path_elem * 'a) Prims.list=
  let matching_values_per_collection_with_imports =
    match id with
    | NSTNone -> []
    | NSTAll ->
        names_revmap (btree_find_all FStar_Pervasives_Native.None) names1
    | NSTPrefix "" ->
        names_revmap (btree_find_all (FStar_Pervasives_Native.Some ""))
          names1
    | NSTPrefix id1 ->
        names_revmap (fun bt -> btree_find_prefix bt id1) names1 in
  let matching_values_per_collection =
    FStarC_List.map
      (fun uu___ ->
         match uu___ with
         | (imports, matches) ->
             FStarC_List.map
               (fun uu___1 ->
                  match uu___1 with
                  | (segment, v) -> ((mk_path_el imports segment), v))
               matches) matching_values_per_collection_with_imports in
  merge_increasing_lists_rev
    (fun uu___ ->
       match uu___ with | (path_el, uu___1) -> (path_el.segment).completion)
    matching_values_per_collection
let rec trie_find_prefix' :
  'a .
    'a trie ->
      path -> query -> (path * 'a) Prims.list -> (path * 'a) Prims.list
  =
  fun tr path_acc query1 acc ->
    let uu___ =
      match query1 with
      | [] -> (NSTAll, NSTAll, [])
      | id::[] -> ((NSTPrefix id), (NSTPrefix id), [])
      | ns::query2 -> ((NSTPrefix ns), NSTNone, query2) in
    match uu___ with
    | (ns_search_term, bindings_search_term, query2) ->
        let matching_namespaces_rev =
          names_find_rev tr.namespaces ns_search_term in
        let acc_with_recursive_bindings =
          FStarC_List.fold_left
            (fun acc1 uu___1 ->
               match uu___1 with
               | (path_el, trie1) ->
                   trie_find_prefix' trie1 (path_el :: path_acc) query2 acc1)
            acc matching_namespaces_rev in
        let matching_bindings_rev =
          names_find_rev tr.bindings bindings_search_term in
        FStarC_List.rev_map_onto
          (fun uu___1 ->
             match uu___1 with
             | (path_el, v) -> ((FStarC_List.rev (path_el :: path_acc)), v))
          matching_bindings_rev acc_with_recursive_bindings
let trie_find_prefix (tr : 'a trie) (query1 : query) :
  (path * 'a) Prims.list= trie_find_prefix' tr [] query1 []
let mod_name (md : mod_info) : Prims.string= md.mod_name
type mod_symbol =
  | Module of mod_info 
  | Namespace of ns_info 
let uu___is_Module (projectee : mod_symbol) : Prims.bool=
  match projectee with | Module _0 -> true | uu___ -> false
let __proj__Module__item___0 (projectee : mod_symbol) : mod_info=
  match projectee with | Module _0 -> _0
let uu___is_Namespace (projectee : mod_symbol) : Prims.bool=
  match projectee with | Namespace _0 -> true | uu___ -> false
let __proj__Namespace__item___0 (projectee : mod_symbol) : ns_info=
  match projectee with | Namespace _0 -> _0
type lid_symbol = FStarC_Ident.lid
type symbol =
  | ModOrNs of mod_symbol 
  | Lid of lid_symbol 
let uu___is_ModOrNs (projectee : symbol) : Prims.bool=
  match projectee with | ModOrNs _0 -> true | uu___ -> false
let __proj__ModOrNs__item___0 (projectee : symbol) : mod_symbol=
  match projectee with | ModOrNs _0 -> _0
let uu___is_Lid (projectee : symbol) : Prims.bool=
  match projectee with | Lid _0 -> true | uu___ -> false
let __proj__Lid__item___0 (projectee : symbol) : lid_symbol=
  match projectee with | Lid _0 -> _0
type table = {
  tbl_lids: lid_symbol trie ;
  tbl_mods: mod_symbol trie }
let __proj__Mktable__item__tbl_lids (projectee : table) : lid_symbol trie=
  match projectee with | { tbl_lids; tbl_mods;_} -> tbl_lids
let __proj__Mktable__item__tbl_mods (projectee : table) : mod_symbol trie=
  match projectee with | { tbl_lids; tbl_mods;_} -> tbl_mods
let empty : table= { tbl_lids = (trie_empty ()); tbl_mods = (trie_empty ()) }
let insert (tbl : table) (host_query : query) (id : Prims.string)
  (c : lid_symbol) : table=
  let uu___ = trie_insert tbl.tbl_lids host_query id c in
  { tbl_lids = uu___; tbl_mods = (tbl.tbl_mods) }
let register_alias (tbl : table) (key : Prims.string) (host_query : query)
  (included_query : query) : table=
  let uu___ = trie_add_alias tbl.tbl_lids key host_query included_query in
  { tbl_lids = uu___; tbl_mods = (tbl.tbl_mods) }
let register_include (tbl : table) (host_query : query)
  (included_query : query) : table=
  let uu___ = trie_include tbl.tbl_lids host_query included_query in
  { tbl_lids = uu___; tbl_mods = (tbl.tbl_mods) }
let register_open (tbl : table) (is_module : Prims.bool) (host_query : query)
  (included_query : query) : table=
  if is_module
  then register_include tbl host_query included_query
  else
    (let uu___1 = trie_open_namespace tbl.tbl_lids host_query included_query in
     { tbl_lids = uu___1; tbl_mods = (tbl.tbl_mods) })
let register_module_path (tbl : table) (loaded : Prims.bool)
  (path1 : Prims.string) (mod_query : query) : table=
  let ins_ns id bindings full_name loaded1 =
    let uu___ =
      let uu___1 = names_find_exact bindings id in (uu___1, loaded1) in
    match uu___ with
    | (FStar_Pervasives_Native.None, uu___1) ->
        names_insert bindings id
          (Namespace { ns_name = full_name; ns_loaded = loaded1 })
    | (FStar_Pervasives_Native.Some (Namespace
       { ns_name = uu___1; ns_loaded = false;_}), true) ->
        names_insert bindings id
          (Namespace { ns_name = full_name; ns_loaded = loaded1 })
    | (FStar_Pervasives_Native.Some uu___1, uu___2) -> bindings in
  let ins_mod id bindings full_name loaded1 =
    names_insert bindings id
      (Module
         { mod_name = full_name; mod_path = path1; mod_loaded = loaded1 }) in
  let name_of_revq query1 = FStarC_String.concat "." (FStarC_List.rev query1) in
  let ins id q revq bindings loaded1 =
    let name = name_of_revq (id :: revq) in
    match q with
    | [] -> ins_mod id bindings name loaded1
    | uu___ -> ins_ns id bindings name loaded1 in
  let uu___ =
    trie_mutate tbl.tbl_mods mod_query []
      (fun tr id q revq namespaces ->
         let uu___1 = ins id q revq tr.bindings loaded in
         { bindings = uu___1; namespaces }) (fun tr uu___1 -> tr) in
  { tbl_lids = (tbl.tbl_lids); tbl_mods = uu___ }
let string_of_path (path1 : path) : Prims.string=
  let uu___ = FStarC_List.map (fun el -> (el.segment).completion) path1 in
  FStarC_String.concat "." uu___
let match_length_of_path (path1 : path) : Prims.int=
  let uu___ =
    FStarC_List.fold_left
      (fun acc elem ->
         let uu___1 = acc in
         match uu___1 with
         | (acc_len, uu___2) ->
             (match (elem.segment).prefix with
              | FStar_Pervasives_Native.Some prefix ->
                  let completion_len =
                    FStarC_String.length (elem.segment).completion in
                  (((acc_len + Prims.int_one) + completion_len),
                    (prefix, completion_len))
              | FStar_Pervasives_Native.None -> acc))
      (Prims.int_zero, ("", Prims.int_zero)) path1 in
  match uu___ with
  | (length, (last_prefix, last_completion_length)) ->
      ((length - Prims.int_one) - last_completion_length) +
        (FStarC_String.length last_prefix)
let first_import_of_path (path1 : path) :
  Prims.string FStar_Pervasives_Native.option=
  match path1 with
  | [] -> FStar_Pervasives_Native.None
  | { imports; segment = uu___;_}::uu___1 -> FStarC_List.last_opt imports
let alist_of_ns_info (ns_info1 : ns_info) :
  (Prims.string * FStarC_Json.json) Prims.list=
  [("name", (FStarC_Json.JsonStr (ns_info1.ns_name)));
  ("loaded", (FStarC_Json.JsonBool (ns_info1.ns_loaded)))]
let alist_of_mod_info (mod_info1 : mod_info) :
  (Prims.string * FStarC_Json.json) Prims.list=
  [("name", (FStarC_Json.JsonStr (mod_info1.mod_name)));
  ("path", (FStarC_Json.JsonStr (mod_info1.mod_path)));
  ("loaded", (FStarC_Json.JsonBool (mod_info1.mod_loaded)))]
type completion_result =
  {
  completion_match_length: Prims.int ;
  completion_candidate: Prims.string ;
  completion_annotation: Prims.string }
let __proj__Mkcompletion_result__item__completion_match_length
  (projectee : completion_result) : Prims.int=
  match projectee with
  | { completion_match_length; completion_candidate; completion_annotation;_}
      -> completion_match_length
let __proj__Mkcompletion_result__item__completion_candidate
  (projectee : completion_result) : Prims.string=
  match projectee with
  | { completion_match_length; completion_candidate; completion_annotation;_}
      -> completion_candidate
let __proj__Mkcompletion_result__item__completion_annotation
  (projectee : completion_result) : Prims.string=
  match projectee with
  | { completion_match_length; completion_candidate; completion_annotation;_}
      -> completion_annotation
let json_of_completion_result (result : completion_result) :
  FStarC_Json.json=
  FStarC_Json.JsonList
    [FStarC_Json.JsonInt (result.completion_match_length);
    FStarC_Json.JsonStr (result.completion_annotation);
    FStarC_Json.JsonStr (result.completion_candidate)]
let completion_result_of_lid (uu___ : (path * 'uuuuu)) : completion_result=
  match uu___ with
  | (path1, _lid) ->
      let uu___1 = match_length_of_path path1 in
      let uu___2 = string_of_path path1 in
      let uu___3 =
        let uu___4 = first_import_of_path path1 in
        FStarC_Option.dflt "" uu___4 in
      {
        completion_match_length = uu___1;
        completion_candidate = uu___2;
        completion_annotation = uu___3
      }
let completion_result_of_mod (annot : Prims.string) (loaded : Prims.bool)
  (path1 : path) : completion_result=
  let uu___ = match_length_of_path path1 in
  let uu___1 = string_of_path path1 in
  let uu___2 = FStarC_Format.fmt1 (if loaded then " %s " else "(%s)") annot in
  {
    completion_match_length = uu___;
    completion_candidate = uu___1;
    completion_annotation = uu___2
  }
let completion_result_of_ns_or_mod (uu___ : (path * mod_symbol)) :
  completion_result=
  match uu___ with
  | (path1, symb) ->
      (match symb with
       | Module
           { mod_name = uu___1; mod_path = uu___2; mod_loaded = loaded;_} ->
           completion_result_of_mod "mod" loaded path1
       | Namespace { ns_name = uu___1; ns_loaded = loaded;_} ->
           completion_result_of_mod "ns" loaded path1)
let find_module_or_ns (tbl : table) (query1 : query) :
  mod_symbol FStar_Pervasives_Native.option=
  trie_find_exact tbl.tbl_mods query1
let autocomplete_lid (tbl : table) (query1 : query) :
  completion_result Prims.list=
  let uu___ = trie_find_prefix tbl.tbl_lids query1 in
  FStarC_List.map completion_result_of_lid uu___
let autocomplete_mod_or_ns (tbl : table) (query1 : query)
  (filter :
    (path * mod_symbol) -> (path * mod_symbol) FStar_Pervasives_Native.option)
  : completion_result Prims.list=
  let uu___ =
    let uu___1 = trie_find_prefix tbl.tbl_mods query1 in
    FStarC_List.filter_map filter uu___1 in
  FStarC_List.map completion_result_of_ns_or_mod uu___
