(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) 
(*  Title:      Pure/IsaPlanner/focus_term_lib.ML
    ID:		$Id: focus_term_lib.ML,v 1.6 2005/08/15 19:38:25 dixon Exp $
    Author:     Lucas Dixon, University of Edinburgh
                lucasd@dai.ed.ac.uk
    Date:       16 April 2003
*)
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) 
(*  DESCRIPTION:

    Generic Foucs terms (like Zippers), which allows modification and
    manipulation of term keeping track of how we got to the position
    in the term. We provide a signature for terms, ie any kind of
    lamda calculus with abs and application, and some notion of types
    and naming of abstracted vars. 

    FIXME: at some point in the future make a library to work simply
    with polymorphic upterms - that way if I want to use them without
    the focus part, then I don't need to include all the focus stuff.

*)   
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)

(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)

(*  to endoce and decode general terms into the type needed by focus
term, this is an easy thing to write, but needs to be done for each
type that is going to be used with focus terms. *)

signature F_ENCODE_TERM_SIG = 
sig

  type term (* type of term to be encoded into TermT for focus term manip *)
  type TypeT (* type annotation for abstractions *)
  type LeafT (* type for other leaf types in term sturcture *)

  (* the type to be encoded into *)
  datatype TermT = op $ of TermT * TermT
    | Abs of string * TypeT * TermT
    | lf of LeafT

  (* the encode and decode functions *)
  val fakebounds : string * TypeT -> term -> term
  val encode : term -> TermT
  val decode : TermT -> term

end;



(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
signature FOCUS_TERM_SIG = 
sig
     structure MinTermS : F_ENCODE_TERM_SIG

     exception focus_term_exp of string;
     exception out_of_term_exception of string;

     type Term = MinTermS.TermT;
     type Type = MinTermS.TypeT;

     type UpTerm = (Term,Type) UpTermLib.T;

(*   datatype
       UpTerm =
           abs of string * Type * UpTerm
         | appl of Term * UpTerm
         | appr of Term * UpTerm
         | root *)

     datatype FcTerm = focus of Term * UpTerm

     (* translating *)
     val fcterm_of_term : MinTermS.term -> FcTerm
     val term_of_fcterm : FcTerm -> MinTermS.term

     (* editing/constrution *)
     val enc_appl : (MinTermS.term * UpTerm) -> UpTerm
     val enc_appr : (MinTermS.term * UpTerm) -> UpTerm

     (* upterm creatioin *)
     val upterm_of : FcTerm -> UpTerm
     val add_upterm : UpTerm -> FcTerm -> FcTerm
     val mk_term_of_upterm : (MinTermS.term * UpTerm) -> MinTermS.term
     val mk_termf_of_upterm : UpTerm -> 
            (((string * Type) list) * 
             (MinTermS.term -> MinTermS.term))
     val pure_mk_termf_of_upterm : (MinTermS.term, Type) UpTermLib.T -> 
                                   (((string * Type) list) * 
                                    (MinTermS.term -> MinTermS.term))

     (* focusing, throws exceptions *)
     val focus_bot_left_leaf : FcTerm -> FcTerm
     val focus_bot_left_nonabs_leaf : FcTerm -> FcTerm
     val focus_left : FcTerm -> FcTerm
     val focus_strict_left : FcTerm -> FcTerm
     val focus_right : FcTerm -> FcTerm
     val focus_abs : FcTerm -> FcTerm
     val focus_fake_abs : FcTerm -> FcTerm
     val focus_to_top : FcTerm -> FcTerm
     val focus_up : FcTerm -> FcTerm
     val focus_up_right : FcTerm -> FcTerm
     val focus_up_right1 : FcTerm -> FcTerm

     (* optional focus changes *)
     val focus_up_abs : FcTerm -> FcTerm option
     val focus_up_appr : FcTerm -> FcTerm option
     val focus_up_appl : FcTerm -> FcTerm option
     val focus_up_abs_or_appr : FcTerm -> FcTerm option

     val tyenv_of_focus : FcTerm -> (string * Type) list
     val tyenv_of_focus' : FcTerm -> Type list

     (* set/get the focus term *)
     val set_focus_of_fcterm : FcTerm -> MinTermS.term -> FcTerm
     val focus_of_fcterm : FcTerm -> MinTermS.term

     (* leaf navigation *) 
     val leaf_seq_of_fcterm : FcTerm -> FcTerm Seq.seq
     val next_leaf_fcterm : FcTerm -> FcTerm
     val next_leaf_of_fcterm_seq : FcTerm -> FcTerm Seq.seq

     (* analysis *)
     val upsize_of_fcterm : FcTerm -> int
end;



(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
(* 

   NOTE!!! I think this can be done in a purely functional way with a
   pair of a term (the focus) and a function, that when applied
   unfocuses one level... maybe think about this as it would be a very
   nice generic consrtuction, without the need for encoding/decoding
   strutcures.

*)
functor FocusTermFUN(structure EncodeTerm : F_ENCODE_TERM_SIG)
  : FOCUS_TERM_SIG = 
struct

structure MinTermS = EncodeTerm;

local open MinTermS open UpTermLib in

  type Term = MinTermS.TermT;
  type Type = MinTermS.TypeT;

  exception focus_term_exp of string;
  exception out_of_term_exception of string;

  infix 9 $

  (* datatype to hold a term tree and the path to where you are in the term *)
(*   datatype UpTerm = root
                  | appl of (Term * UpTerm)
                  | appr of (Term * UpTerm)
                  | abs of (string * Type * UpTerm); *)

  type UpTerm = (Term,Type) UpTermLib.T;

  fun enc_appl (t,u) = appl((MinTermS.encode t),u);
  fun enc_appr (t,u) = appr((MinTermS.encode t),u);

  datatype FcTerm = focus of (Term * UpTerm);

  (* the the term of the upterm *)
  fun mk_term_of_upt_aux (t, root) = MinTermS.decode t
    | mk_term_of_upt_aux (t, appl (l,m)) =  mk_term_of_upt_aux(l$t, m)
    | mk_term_of_upt_aux (t, appr (r,m)) =  mk_term_of_upt_aux(t$r, m)
    | mk_term_of_upt_aux (t, abs (s,ty,m)) = mk_term_of_upt_aux(Abs(s,ty,t),m);

  fun mk_term_of_upterm (t, ut) = mk_term_of_upt_aux (MinTermS.encode t, ut);

  (* a function version of the above, given an upterm it returns:
     a function on that given a term puts it in the context of the upterm,
     and a list of bound variables that are in the upterm, added as 
     we go up - so in reverse order from that typiclaly used by top-down
     parsing of terms. *)
  fun mk_termf_of_upt_aux (f, bs, root) = 
      (bs, fn t => MinTermS.decode (f t))
    | mk_termf_of_upt_aux (f, bs, appl (l,m)) =  
      mk_termf_of_upt_aux (fn t => l $ (f t), bs, m)
    | mk_termf_of_upt_aux (f, bs, appr (r,m)) =  
      mk_termf_of_upt_aux (fn t => (f t) $ r, bs, m)
    | mk_termf_of_upt_aux (f, bs, abs (s,ty,m)) = 
      mk_termf_of_upt_aux (fn t => Abs(s,ty,(f t)), (s,ty)::bs, m);

  fun mk_termf_of_upterm ut = mk_termf_of_upt_aux (MinTermS.encode, [], ut);

 
  fun upterm_of (focus(t, u)) = u;

  (* put a new upterm at the start of our current term *)
  fun add_upterm u2 (focus(t, u)) = focus(t, UpTermLib.apply u2 u);


  (* As above but work on the pure originial upterm type *)
  fun pure_mk_termf_of_upterm ut = 
      mk_termf_of_upt_aux 
        (encode, [], (map_to_upterm_parts (encode, I) ut));

  fun fcterm_of_term t = focus(encode t, root);

  fun term_of_fcterm (focus (t, m)) = mk_term_of_upt_aux (t, m);

(*  fun term_of_fcterm (focus (t, root)) = mk_term_of_upt_aux (t, root)
    | term_of_fcterm _ = raise focus_term_exp "term_of_fcterm: something bad has happened here."; *)

  fun focus_of_fcterm (focus(t, _)) = MinTermS.decode t;

  (* replace the focus term with a new term... *)
  fun set_focus_of_fcterm (focus(_, m)) nt = focus(MinTermS.encode nt, m);

  fun focus_left (focus(a $ b, m)) = focus(a, appr(b, m))
    | focus_left (focus(Abs(s,ty,t), m)) = focus_left (focus(t, abs(s,ty,m)))
    | focus_left (focus(l, m)) = raise out_of_term_exception "focus_left";

  fun focus_strict_left (focus(a $ b, m)) = focus(a, appr(b, m))
    | focus_strict_left (focus(l, m)) = raise out_of_term_exception "focus_left";

(* Note: ":" is standard for faked bound vars... see: EQStepTacTermTools *)
  fun focus_fake_abs (focus(Abs(s,ty,t), m)) = 
      let val t' = MinTermS.encode (fakebounds (s,ty) (MinTermS.decode t))
      in focus(t', abs(s,ty,m)) end
    | focus_fake_abs (focus(l, m)) = raise out_of_term_exception "focus_fake_abs";

  fun focus_abs (focus(Abs(s,ty,t), m)) = focus(t, abs(s,ty,m))
    | focus_abs (focus(l, m)) = raise out_of_term_exception "focus_abs";


  fun focus_right (focus(a $ b, m)) = focus(b, appl(a, m))
    | focus_right (focus(Abs(s,ty,t), m)) = focus_right (focus(t, abs(s,ty,m)))
    | focus_right (focus(l, m)) = raise out_of_term_exception "focus_right";

  fun focus_up (focus(t, appl(l,m))) = focus(l$t, m)
    | focus_up (focus(t, appr(r,m))) = focus(t$r, m)
    | focus_up (focus(t, abs(s,ty,m))) = focus_up (focus(Abs(s,ty,t), m))
    | focus_up (focus(t, root)) = raise out_of_term_exception "focus_up";

  fun focus_to_top t = 
    focus_to_top (focus_up t) handle out_of_term_exception _ => t;

  (* focus up until you can move right, and then do so *)
  fun focus_up_right (focus(t, appl(l,m))) = 
      focus_up_right (focus(l$t, m))
    | focus_up_right (focus(t, appr(r,m))) = 
      focus(r, appl(t,m))
    | focus_up_right (focus(t, abs(s,ty,m))) = 
      focus_up_right (focus(Abs(s,ty,t), m))
    | focus_up_right (focus(t, root)) = 
      raise out_of_term_exception "focus_up_right";

  (* as above, but do not move up over a left application *)
  fun focus_up_right1 (focus(t, appl(l,m))) = 
      raise out_of_term_exception "focus_up_right1"
    | focus_up_right1 (focus(t, appr(r,m))) = 
      focus(r, appl(t,m))
    | focus_up_right1 (focus(t, abs(s,ty,m))) = 
      focus_up_right (focus(Abs(s,ty,t), m))
    | focus_up_right1 (focus(t, root)) = 
      raise out_of_term_exception "focus_up_right1";

  (* move focus to the bottom left through abstractions *)
  fun focus_bot_left_leaf (ft as focus(t, _)) = 
        focus_bot_left_leaf (focus_left ft) 
        handle out_of_term_exception  _=> ft;

  (* move focus to the bottom left, but not into abstractions *)
  fun focus_bot_left_nonabs_leaf (ft as focus(t, _)) = 
        focus_bot_left_nonabs_leaf (focus_strict_left ft) 
        handle out_of_term_exception  _=> ft;

  (* focus tools for working directly with the focus representation *)
  fun focus_up_appr (focus(t, appl(l,m))) = NONE
    | focus_up_appr (focus(t, appr(r,m))) = SOME (focus(t$r, m))
    | focus_up_appr (focus(t, abs(s,ty,m))) = NONE
    | focus_up_appr (focus(t, root)) = NONE;

  fun focus_up_appl (focus(t, appl(l,m))) = SOME (focus(l$t, m))
    | focus_up_appl (focus(t, appr(r,m))) = NONE
    | focus_up_appl (focus(t, abs(s,ty,m))) = NONE
    | focus_up_appl (focus(t, root)) = NONE;

  fun focus_up_abs (focus(t, appl(l,m))) = NONE
    | focus_up_abs (focus(t, appr(r,m))) = NONE
    | focus_up_abs (focus(t, abs(s,ty,m))) = 
      SOME (focus_up (focus(Abs(s,ty,t), m)))
    | focus_up_abs (focus(t, root)) = NONE;

  fun focus_up_abs_or_appr (focus(t, appl(l,m))) = NONE
    | focus_up_abs_or_appr (focus(t, appr(r,m))) = SOME (focus(t$r, m))
    | focus_up_abs_or_appr (focus(t, abs(s,ty,m))) = 
      SOME (focus(Abs(s,ty,t), m))
    | focus_up_abs_or_appr (focus(t, root)) = NONE;


  fun tyenv_of_focus (focus(t, u)) = tyenv_of_upterm u;
  fun tyenv_of_focus' (focus(t, u)) = tyenv_of_upterm' u;

  (* return the Term.type of the focus term, computes bound vars type,
     does a quick check only. *)
(*  fun fastype_of_focus (focus(t, m)) = 
       let 
         fun boundtypes_of_upterm (abs(s,ty,m)) = 
         ty::(boundtypes_of_upterm m)
           | boundtypes_of_upterm (appl(t,m)) = 
         boundtypes_of_upterm m
           | boundtypes_of_upterm (appr(t,m)) = 
         boundtypes_of_upterm m
           | boundtypes_of_upterm (root) = []
       in
         fastype_of1 ((boundtypes_of_upterm m), t)
       end; *)

  (* gets the next left hand side term, or throws an exception *)
  fun next_leaf_fcterm ft = focus_bot_left_leaf (focus_up_right ft);

  fun next_leaf_of_fcterm_seq_aux t () = 
    let val nextt = next_leaf_fcterm t
    in 
        SOME (nextt, Seq.make (next_leaf_of_fcterm_seq_aux nextt))
    end handle out_of_term_exception _ => NONE;

  (* sequence of next upterms from start upterm... 
     ie a sequence of all leafs after this one*)
  fun next_leaf_of_fcterm_seq in_t = 
    Seq.make (next_leaf_of_fcterm_seq_aux in_t);

  (* returns a sequence of all leaf up terms from term, ie DFS on 
   leafs of term, ie uses time O(n), n = sizeof term. *)
  fun leaf_seq_of_fcterm in_t = 
    let 
      val botleft = (focus_bot_left_leaf in_t)
    in
      Seq.cons (botleft, (Seq.make (next_leaf_of_fcterm_seq_aux botleft)) )
    end;

  fun upsize_of_fcterm (focus(t, ut)) = upsize_of_upterm ut;

end; (* local *)

end; (* functor *)





(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
(* focus term encoding sturcture for isabelle terms *)
structure EncodeIsaFTerm : F_ENCODE_TERM_SIG = 
struct
  infix 9 $;

  type term = Term.term;

  type TypeT = Term.typ;

  datatype LeafT = lConst of string * Term.typ
     | lVar of ((string * int) * Term.typ)
     | lFree of (string * Term.typ)
     | lBound of int;

  datatype TermT = op $ of TermT * TermT
    | Abs of string * TypeT * TermT
    | lf of LeafT;

  fun fakebounds (s, ty) t = subst_bound (Free(":" ^ s, ty), t);

  fun encode (Term.$(a,b)) = (encode a) $ (encode b)
    | encode (Term.Abs(s,ty,t)) = Abs(s,ty,(encode t))
    | encode (Term.Const(s,ty)) = lf(lConst(s,ty))
    | encode (Term.Var((s,i),ty)) = lf(lVar((s,i),ty))
    | encode (Term.Free(s,ty)) = lf(lFree(s,ty))
    | encode (Term.Bound i) = lf(lBound i);

  fun decode (a $ b) = Term.$(decode a, decode b)
    | decode (Abs(s,ty,t)) = (Term.Abs(s,ty,decode t))
    | decode (lf(lConst(s,ty))) = Term.Const(s,ty)
    | decode (lf(lVar((s,i),ty))) = Term.Var((s,i),ty)
    | decode (lf(lFree(s,ty))) = (Term.Free(s,ty))
    | decode (lf(lBound i)) = (Term.Bound i);

end;

