Library MetaCoq.Translations.translation_utils


Axiom todo : {A}, A.

Definition tsl_table := list (global_reference × term).

Fixpoint lookup_tsl_table (E : tsl_table) (gr : global_reference)
  : option term :=
  match E with
  | nilNone
  | hd :: tl
    if gref_eq_dec gr (fst hd) then Some (snd hd)
    else lookup_tsl_table tl gr
  end.

Definition tsl_context := (global_env_ext × tsl_table)%type.

Definition emptyTC : tsl_context := (empty_ext [], []).

Inductive tsl_error :=
| NotEnoughFuel
| TranslationNotFound (id : ident)
| TranslationNotHandeled
| TypingError (t : type_error).

Inductive tsl_result A :=
| Success : A tsl_result A
| Error : tsl_error tsl_result A.


Instance tsl_monad : Monad tsl_result :=
  {| ret A a := Success a ;
     bind A B m f :=
       match m with
       | Success a f a
       | Error e Error e
       end
  |}.

Instance monad_exc : MonadExc tsl_error tsl_result :=
  { raise A e := Error e;
    catch A m f :=
      match m with
      | Success am
      | Error tf t
      end
  }.

Definition lookup_tsl_table' E gr :=
  match lookup_tsl_table E gr with
  | Some tret t
  | Noneraise (TranslationNotFound (string_of_gref gr))
  end.

Class Translation :=
  { tsl_id : ident ident ;
    tsl_tm : tsl_context term tsl_result term ;
    tsl_ty : option (tsl_context term tsl_result term) ;

    
    tsl_ind : tsl_context string kername mutual_inductive_body
               tsl_result (tsl_table × list mutual_inductive_body) }.

Definition tsl_ident (id : ident) : ident := (id ++ "ᵗ")%string.

Definition tsl_name tsl_ident n :=
  match n with
  | nAnonnAnon
  | nNamed nnNamed (tsl_ident n)
  end.

Definition tmDebug {A} : A TemplateMonad unit
  := tmPrint.

Definition add_global_decl d (Σ : global_env_ext) : global_env_ext
  := (d :: Σ.1, Σ.2).

Definition Translate {tsl : Translation} (ΣE : tsl_context) (id : ident)
  : TemplateMonad tsl_context :=
  tmDebug ("Translate" ++ id);;
  gr <- tmAbout id ;;
  tmDebug gr;;
  match gr with
  | Nonefail_nf (id ++ " not found")
  | Some (ConstructRef (mkInd kn n) _)
  | Some (IndRef (mkInd kn n)) ⇒
    mp <- tmCurrentModPath tt ;;
    d <- tmQuoteInductive id ;;
    d' <- tmEval lazy (tsl_ind ΣE mp kn d) ;;
    match d' with
    | Error e
      print_nf e ;;
      fail_nf ("Translation error during the translation of the inductive " ++ id)
    | Success (E, decls)
      monad_iter tmMkInductive' decls ;;
      let Σ' := add_global_decl (InductiveDecl kn d) (fst ΣE) in
      let E' := (E ++ (snd ΣE))%list in
      Σ' <- tmEval lazy Σ' ;;
      E' <- tmEval lazy E' ;;
      tmMsg (kn ++ " has been translated.") ;;
      ret (Σ', E')
    end
    
  | Some (ConstRef kn) ⇒
    e <- tmQuoteConstant kn true ;;
    match e with
    | ParameterEntry _
      fail_nf (id ++ " is an axiom, not a definition. Use Implement Existing.")
    | DefinitionEntry {| definition_entry_type := A;
                         definition_entry_universes := univs;
                         definition_entry_body := t |}
      tmDebug t ;;
      t' <- tmEval lazy (tsl_tm ΣE t) ;;
      tmDebug t' ;;
      match t' with
      | Error e
        print_nf e ;;
        fail_nf ("Translation error during the translation of the body of " ++ id)
      | Success t'
        id' <- tmEval all (tsl_id id) ;;
            tmDebug "here" ;;
            tmDebug id' ;;
            tmDebug t' ;;
        tmMkDefinition id' t' ;;
            tmDebug "doneu" ;;
        let decl := {| cst_universes := univs;
                       cst_type := A; cst_body := Some t |} in
        let Σ' := add_global_decl (ConstantDecl kn decl) (fst ΣE) in
        let E' := (ConstRef kn, tConst id' []) :: (snd ΣE) in
        Σ' <- tmEval lazy Σ' ;;
        E' <- tmEval lazy E' ;;
        print_nf (id ++ " has been translated as " ++ id') ;;
        ret (Σ', E')
      end
    end
  end.

Definition Implement {tsl : Translation} (ΣE : tsl_context)
           (id : ident) (A : Type)
  : TemplateMonad (tsl_context) :=
  tA <- tmQuote A ;;
  match tsl_ty with
  | NonetmFail "No implementation of tsl_ty provided for this translation."
  | Some tsl_ty
  tA' <- tmEval lazy (tsl_ty ΣE tA) ;;
  print_nf tA' ;;
  match tA' with
  | Error e
    print_nf e ;;
    tmFail "Translation error during the translation of the type."
  | Success tA'
      id' <- tmEval all (tsl_id id) ;;
      tmBind (tmUnquoteTyped Type tA') (fun A'
      tmLemma id' A' ;;
      tmAxiom id A ;;
      gr <- tmAbout id ;;
      match gr with
      | Some (ConstRef kn) ⇒
        let decl := {| cst_universes := Monomorphic_ctx ContextSet.empty;
                       cst_type := tA; cst_body := None |} in
        let Σ' := add_global_decl (ConstantDecl kn decl) (fst ΣE) in
        let E' := (ConstRef kn, tConst id' []) :: (snd ΣE) in
        print_nf (id ++ " has been translated as " ++ id') ;;
        ret (Σ', E')
      | _fail_nf (id ++ " was not found or is not a constant. This is a bug.")
      end)
  end
  end.

Definition body_constant_entry (e : constant_entry) : option term :=
  match e with
  | ParameterEntry _None
  | DefinitionEntry {| definition_entry_body := t |}Some t
  end.

Definition ImplementExisting {tsl : Translation} (ΣE : tsl_context) (id : ident)
  : TemplateMonad tsl_context :=
  gr <- tmAbout id ;;
  id' <- tmEval all (tsl_id id) ;;
  mp <- tmCurrentModPath tt ;;
  match tsl_ty with
  | NonetmFail "No implementation of tsl_ty provided for this translation."
  | Some tsl_ty
  match gr with
  | Nonefail_nf (id ++ " not found")
  | Some (ConstRef kn) ⇒
    e <- tmQuoteConstant kn true ;;
    match e with
    | ParameterEntry {| parameter_entry_type := A |}
    | DefinitionEntry {| definition_entry_type := A |}
      tmDebug "plop1" ;;
      ΣE <- tmEval lazy ΣE ;;
      tmDebug ΣE ;;
      tA' <- tmEval lazy (tsl_ty ΣE A) ;;
      tmDebug "plop" ;;
      match tA' with
      | Error e
        print_nf e ;;
        fail_nf ("Translation error during the translation of the type of " ++ id)
      | Success tA'
        tmDebug "plop2" ;;
        tmBind (tmUnquoteTyped Type tA') (fun A'
        tmDebug "plop3" ;;
        tmLemma id' A' ;;
        let decl := {| cst_universes := Monomorphic_ctx ContextSet.empty;
                       cst_type := A; cst_body := body_constant_entry e |} in
        let Σ' := add_global_decl (ConstantDecl kn decl) (fst ΣE) in
        let E' := (ConstRef kn, tConst id' []) :: (snd ΣE) in
        print_nf (id ++ " has been translated as " ++ id') ;;
        ret (Σ', E'))
      end
    end
  | Some (IndRef (mkInd kn n)) ⇒
    d <- tmQuoteInductive kn ;;
    match List.nth_error (ind_bodies d) n with
      | Nonefail_nf ("The declaration of "
                          ++ id ++ " has not enough bodies. This is a bug.")
      | Some {| ind_type := A |}
      tA' <- tmEval lazy (tsl_ty ΣE A) ;;
      match tA' with
      | Error e
        print_nf e ;;
        fail_nf ("Translation error during the translation of the type of " ++ id)
      | Success tA'
        id' <- tmEval all (tsl_id id) ;;
        tmBind (tmUnquoteTyped Type tA') (fun A'
        tmLemma id' A' ;;
        let Σ' := add_global_decl (InductiveDecl kn d) (fst ΣE) in
        let E' := (IndRef (mkInd kn n), tConst id' []) :: (snd ΣE) in
        print_nf (id ++ " has been translated as " ++ id') ;;
        ret (Σ', E'))
      end
    end

  | Some (ConstructRef (mkInd kn n) k) ⇒
    d <- tmQuoteInductive kn ;;
    tmDebug "plop1" ;;
    match List.nth_error (ind_bodies d) n with
    | Nonefail_nf ("The declaration of "
                        ++ id ++ " has not enough bodies. This is a bug.")
    | Some {| ind_ctors := ctors |}
      tmDebug "plop2" ;;
      match List.nth_error ctors k with
      | Nonefail_nf ("The body of "
                          ++ id ++ " has not enough constructors. This is a bug.")
      | Some (_, ty, _)
        tmDebug "plop3" ;;
        let A := subst0 (inds kn [] (ind_bodies d)) ty in
        tmDebug "plop4" ;;
        tA' <- tmEval lazy (tsl_ty ΣE A) ;;
        tmDebug "plop5" ;;
        match tA' with
        | Error e
          print_nf e ;;
          fail_nf ("Translation error during the translation of the type of " ++ id)
        | Success tA'
          tmDebug "plop6" ;;
          id' <- tmEval all (tsl_id id) ;;
          tmBind (tmUnquoteTyped Type tA') (fun A'
          tmDebug "plop7" ;;
          tmLemma id' A' ;;
          let E' := (ConstructRef (mkInd kn n) k, tConst id' []) :: (snd ΣE) in
          print_nf (id ++ " has been translated as " ++ id') ;;
          ret (fst ΣE, E'))
        end
      end
    end
  end
  end.


Fixpoint string_of_ascii_list l :=
  match l with
  | nilEmptyString
  | a :: sString a (string_of_ascii_list s)
  end.

Definition string_of_ascii_list_rev l := string_of_ascii_list (rev l).


Fixpoint split_string_aux (sep : ascii) (s : string) (acc : list ascii)
  : list string :=
  match s with
  | EmptyString[string_of_ascii_list_rev acc]
  | String a sif Ascii.ascii_dec a sep then (string_of_ascii_list_rev acc)
                                                 :: (split_string_aux sep s [])
                 else split_string_aux sep s (a :: acc)
  end.

Definition split_string (sep : Ascii.ascii) (s : string) : list string :=
  split_string_aux sep s [].


Definition ident_of_kn (kn : kername) : ident
  := last (split_string "."%char kn) kn.

Definition tsl_kn (tsl_ident : ident ident) (kn : kername) mp
  := mp ++ "." ++ (tsl_ident (ident_of_kn kn)).

Definition TranslateRec {tsl : Translation} (ΣE : tsl_context) {A} (t : A) :=
  p <- tmQuoteRec t ;;
  tmPrint "~~~~~~~~~~~~~~~~~~" ;;
  monad_fold_left (fun ΣE decl
    print_nf ("Translating " ++ global_decl_ident decl) ;;
    match decl with
    | ConstantDecl kn decl
      match lookup_tsl_table (snd ΣE) (ConstRef kn) with
      | Some _print_nf (kn ++ " was already translated") ;; ret ΣE
      | None
        match decl with
        | {| cst_body := None |}
          fail_nf (kn ++ " is an axiom. Use Implement Existing.")
                    
        | {| cst_type := A; cst_body := Some t; cst_universes := univs |}
          tmDebug "go";;
          t' <- tmEval lazy (tsl_tm ΣE t) ;;
          tmDebug "done";;
          match t' with
          | Error e
            print_nf e ;;
            fail_nf ("Translation error during the translation of the body of "
                       ++ kn)
          | Success t'
            let id := ident_of_kn kn in
            let id' := tsl_ident id in
            tmDebug "here";;
            tmDebug id' ;;
            tmDebug t' ;;
            tmMkDefinition id' t' ;;
            tmDebug "there";;
            let Σ' := add_global_decl (ConstantDecl kn decl) (fst ΣE) in
            let E' := (ConstRef kn, tConst id' []) :: (snd ΣE) in
            Σ' <- tmEval lazy Σ' ;;
            E' <- tmEval lazy E' ;;
            print_nf (id ++ " has been translated as " ++ id') ;;
            ret (Σ', E')
          end
        end
      end

    | InductiveDecl kn d
      match lookup_tsl_table (snd ΣE) (IndRef (mkInd kn 0)) with
      | Some _print_nf (kn ++ " was already translated") ;; ret ΣE
      | None
        tmDebug "go'";;
        mp <- tmCurrentModPath tt ;;
        d' <- tmEval lazy (tsl_ind ΣE mp kn d) ;;
        tmDebug "done'";;
         match d' with
         | Error e
           print_nf e ;;
           fail_nf ("Translation error during the translation of the inductive "
                      ++ kn)
         | Success (E, decls)
           monad_iter tmMkInductive' decls ;;
           let Σ' := add_global_decl (InductiveDecl kn d) (fst ΣE) in
           let E' := (E ++ (snd ΣE))%list in
           Σ' <- tmEval lazy Σ' ;;
           E' <- tmEval lazy E' ;;
           print_nf (kn ++ " has been translated.") ;;
           ret (Σ', E')
         end
      end
    end)
  (fst p) ΣE.