src/Pure/ProofGeneral/proof_general_pgip.ML
changeset 21867 8750fbc28d5c
parent 21858 05f57309170c
child 21885 5a11263bd8cf
equal deleted inserted replaced
21866:d589f6f5da65 21867:8750fbc28d5c
   292 
   292 
   293 (* get informed about files *)
   293 (* get informed about files *)
   294 
   294 
   295 val inform_file_retracted = ThyInfo.if_known_thy ThyInfo.remove_thy o thy_name;
   295 val inform_file_retracted = ThyInfo.if_known_thy ThyInfo.remove_thy o thy_name;
   296 val inform_file_processed = ThyInfo.if_known_thy ThyInfo.touch_child_thys o thy_name;
   296 val inform_file_processed = ThyInfo.if_known_thy ThyInfo.touch_child_thys o thy_name;
   297 val openfile_retract = Output.no_warnings (ThyInfo.if_known_thy ThyInfo.remove_thy) o thy_name;
       
   298 
   297 
   299 fun proper_inform_file_processed file state =
   298 fun proper_inform_file_processed file state =
   300   let val name = thy_name file in
   299   let val name = thy_name file in
   301     if Toplevel.is_toplevel state andalso ThyInfo.known_thy name then
   300     if Toplevel.is_toplevel state andalso ThyInfo.known_thy name then
   302      (ThyInfo.touch_child_thys name;
   301      (ThyInfo.touch_child_thys name;
   412         else Output.panic ("PGIP configuration file \"" ^ config_file() ^ "\" not found")
   411         else Output.panic ("PGIP configuration file \"" ^ config_file() ^ "\" not found")
   413     end;
   412     end;
   414 end
   413 end
   415 
   414 
   416 
   415 
   417 (* PGIP identifier tables (prover objects). [incomplete] *)
       
   418 
       
   419 local
       
   420     (* TODO: objtypes should be in pgip_types.ML *)
       
   421     val objtype_thy  = "theory"
       
   422     val objtype_thm  = "theorem"
       
   423     val objtype_term = "term"
       
   424     val objtype_type = "type"
       
   425 
       
   426     fun xml_idtable ty ctx ids =
       
   427         PgipOutput.output (Idtable {objtype=ty,context=ctx,ids=ids})
       
   428 in
       
   429 
       
   430 fun setids t = issue_pgip (Setids {idtables = [t]})
       
   431 fun addids t = issue_pgip (Addids {idtables = [t]})
       
   432 fun delids t = issue_pgip (Delids {idtables = [t]})
       
   433 
       
   434 fun delallids ty = setids (xml_idtable ty NONE [])
       
   435 
       
   436 fun send_thy_idtable ctx thys = setids (xml_idtable objtype_thy ctx thys)
       
   437 fun clear_thy_idtable () = delallids objtype_thy
       
   438 
       
   439 fun send_thm_idtable ctx thy =
       
   440     addids (xml_idtable objtype_thm ctx (map fst (PureThy.thms_of thy)));
       
   441 
       
   442 fun clear_thm_idtable () = delallids objtype_thm
       
   443 
       
   444 (* fun send_type_idtable thy = TODO, it's a bit low-level messy
       
   445    & maybe not so useful anyway *)
       
   446 
       
   447 end
       
   448 
   416 
   449 
   417 
   450 (* Sending commands to Isar *)
   418 (* Sending commands to Isar *)
   451 
   419 
   452 fun isarcmd s =
   420 fun isarcmd s =
   467           | "ML" => isarcmd ("use " ^ quote file)
   435           | "ML" => isarcmd ("use " ^ quote file)
   468           | other => error ("Don't know how to read a file with extension " ^ other)
   436           | other => error ("Don't know how to read a file with extension " ^ other)
   469     end
   437     end
   470 
   438 
   471 
   439 
   472 (**** PGIP actions ****)
   440 (******* PGIP actions *******)
   473 
   441 
   474 
   442 
   475 (* Responses to each of the PGIP input commands. 
   443 (* Responses to each of the PGIP input commands. 
   476    These are programmed uniformly for extensibility. *)
   444    These are programmed uniformly for extensibility. *)
   477 
   445 
   556 fun redostep vs = isarcmd "redo"
   524 fun redostep vs = isarcmd "redo"
   557     
   525     
   558 fun abortgoal vs = isarcmd "ProofGeneral.kill_proof" 
   526 fun abortgoal vs = isarcmd "ProofGeneral.kill_proof" 
   559 
   527 
   560 
   528 
       
   529 (*** PGIP identifier tables ***)
       
   530 
       
   531 fun setids t = issue_pgip (Setids {idtables = [t]})
       
   532 fun addids t = issue_pgip (Addids {idtables = [t]})
       
   533 fun delids t = issue_pgip (Delids {idtables = [t]})
       
   534 
       
   535 (*
       
   536  fun delallids ty = 
       
   537      issue_pgip (Setids {idtables = 
       
   538 	 		[{context=NONE,objtype=ty,ids=[]}]}) *)
       
   539 
   561 fun askids vs = 
   540 fun askids vs = 
   562     let
   541     let
   563 	val thyname = #thyname vs
   542 	val url = #url vs	     (* ask for identifiers within a file *)
   564 	val objtype = #objtype vs
   543 	val thyname = #thyname vs    (* ask for identifiers within a theory *)
       
   544 	val objtype = #objtype vs    (* ask for identifiers of a particular type *)
       
   545 
       
   546 	fun idtable ty ctx ids = {objtype=ty,context=ctx,ids=ids}
       
   547 
       
   548 	val thms_of_thy = (map fst) o PureThy.thms_of o ThyInfo.get_theory
   565     in 
   549     in 
       
   550 (*	case (url_attr,thyname,objtype) of
       
   551 	    (NONE,NONE,NONE) => 
       
   552 *)	    (* top-level: return *)
       
   553 
   566 	(* TODO: add askids for "file" here, which returns single theory with same name *)
   554 	(* TODO: add askids for "file" here, which returns single theory with same name *)
       
   555         (* FIXME: objtypes on both sides *)
   567 	case (thyname,objtype) of 
   556 	case (thyname,objtype) of 
   568            (* only theories known in top context *)
   557            (* only files known in top context *)
   569 	   (NONE, NONE) =>  send_thy_idtable NONE (ThyInfo.names())
   558 	   (NONE, NONE)		      => setids (idtable ObjFile NONE (ThyInfo.names())) (*FIXME: uris?*)
   570 	 | (NONE, SOME "theory")  => send_thy_idtable NONE (ThyInfo.names())
   559 	 | (NONE, SOME ObjFile)        => setids (idtable ObjFile NONE (ThyInfo.names())) (* ditto *)
   571 	 | (SOME thy, SOME "theory") => send_thy_idtable (SOME thy) (ThyInfo.get_preds thy)
   560 	 | (SOME fi, SOME ObjFile)     => setids (idtable ObjTheory (SOME fi) [fi]) (* FIXME: lookup file *)
   572 	 | (SOME thy, SOME "theorem") => send_thm_idtable (SOME thy) (ThyInfo.get_theory thy)
   561 	 | (NONE, SOME ObjTheory)      => setids (idtable ObjTheory NONE (ThyInfo.names()))
   573 	 | (SOME thy, NONE) => (send_thy_idtable (SOME thy) (ThyInfo.get_preds thy);
   562 	 | (SOME thy, SOME ObjTheory)  => setids (idtable ObjTheory (SOME thy) (ThyInfo.get_preds thy))
   574                                send_thm_idtable (SOME thy) (ThyInfo.get_theory thy))
   563 	 | (SOME thy, SOME ObjTheorem) => setids (idtable ObjTheorem (SOME thy) (thms_of_thy thy))
   575 	 | (_, SOME ot) => error ("No objects of type "^(quote ot)^" are available here.")
   564          (* next case is both of above.  FIXME: cleanup this *)					 
       
   565 	 | (SOME thy, NONE) => (setids (idtable ObjTheory (SOME thy) (ThyInfo.get_preds thy));
       
   566 				setids (idtable ObjTheorem (SOME thy) (thms_of_thy thy)))
       
   567 	 | (_, SOME ot) => error ("No objects of type "^(PgipTypes.name_of_objtype ot)^" are available here.")
   576     end
   568     end
   577 
   569 
   578 local
   570 local
   579   (* accumulate printed output in a single PGIP response (inside <pgmltext>) *)
   571   (* accumulate printed output in a single PGIP response (inside <pgmltext>) *)
   580   fun with_displaywrap pgipfn dispfn =
   572   fun with_displaywrap pgipfn dispfn =
   588 in
   580 in
   589 fun showid vs = 
   581 fun showid vs = 
   590     let
   582     let
   591 	val thyname = #thyname vs
   583 	val thyname = #thyname vs
   592 	val objtype = #objtype vs
   584 	val objtype = #objtype vs
   593 	val name = #objtype vs
   585 	val name = #name vs
   594 	val topthy = Toplevel.theory_of o Toplevel.get_state
   586 	val topthy = Toplevel.theory_of o Toplevel.get_state
   595 
   587 
   596 	fun idvalue objtype name strings =
   588 	fun idvalue objtype name strings =
   597 	    Idvalue { name=name, objtype=objtype,
   589 	    Idvalue { name=name, objtype=objtype,
   598 		      text=[XML.Elem("pgmltext",[],map XML.Text strings)] }
   590 		      text=[XML.Elem("pgmltext",[],map XML.Text strings)] }
   599 
   591 
   600 	fun pthm thy name = print_thm (get_thm thy (Name name))
   592 	fun pthm thy name = print_thm (get_thm thy (Name name))
   601     in 
   593     in 
   602 	case (thyname, objtype) of 
   594 	case (thyname, objtype) of 
   603 	    (_,"theory") =>
   595 	    (_,ObjTheory) =>
   604 	    with_displaywrap (idvalue "theory" name) 
   596 	    with_displaywrap (idvalue ObjTheory name) 
   605 			     (fn ()=>(print_theory (ThyInfo.get_theory name)))
   597 			     (fn ()=>(print_theory (ThyInfo.get_theory name)))
   606 	  | (SOME thy, "theorem") =>
   598 	  | (SOME thy, ObjTheorem) =>
   607 	    with_displaywrap (idvalue "theorem" name) 
   599 	    with_displaywrap (idvalue ObjTheorem name) 
   608 			     (fn ()=>(pthm (ThyInfo.get_theory thy) name))
   600 			     (fn ()=>(pthm (ThyInfo.get_theory thy) name))
   609 	  | (NONE, "theorem") =>
   601 	  | (NONE, ObjTheorem) =>
   610 	    with_displaywrap (idvalue "theorem" name) 
   602 	    with_displaywrap (idvalue ObjTheorem name) 
   611 			     (fn ()=>pthm (topthy()) name)
   603 			     (fn ()=>pthm (topthy()) name)
   612 	  | (_, ot) => error ("Cannot show objects of type "^ot)
   604 	  | (_, ot) => error ("Cannot show objects of type "^(PgipTypes.name_of_objtype ot))
   613     end
   605     end
       
   606 
       
   607 (*** Inspecting state ***)
   614 
   608 
   615 (* The file which is currently being processed interactively.  
   609 (* The file which is currently being processed interactively.  
   616    In the pre-PGIP code, this was informed to Isabelle and the theory loader
   610    In the pre-PGIP code, this was informed to Isabelle and the theory loader
   617    on completion, but that allows for circularity in case we read
   611    on completion, but that allows for circularity in case we read
   618    ourselves.  So PGIP opens the filename at the start of a script.
   612    ourselves.  So PGIP opens the filename at the start of a script.
   647     let
   641     let
   648 	val text = #text vs
   642 	val text = #text vs
   649 	val systemdata = #systemdata vs      
   643 	val systemdata = #systemdata vs      
   650 	val location = #location vs   (* TODO: extract position *)
   644 	val location = #location vs   (* TODO: extract position *)
   651 
   645 
   652         val _ = start_delay_msgs ()  (* gather parsing messages *)
   646         val _ = start_delay_msgs ()   (* gather parsing errs/warns *)
   653         val xmls = PgipParser.xmls_of_str text
   647         val doc = PgipParser.pgip_parser text
   654         val errs = end_delayed_msgs ()
   648         val errs = end_delayed_msgs ()
   655 
   649 
   656 	val sysattrs = PgipTypes.opt_attr "systemdata" systemdata
   650 	val sysattrs = PgipTypes.opt_attr "systemdata" systemdata
   657 	val locattrs = PgipTypes.attrs_of_location location
   651 	val locattrs = PgipTypes.attrs_of_location location
   658      in
   652      in
   659         issue_pgip (Parseresult { attrs= sysattrs@locattrs,
   653         issue_pgip (Parseresult { attrs= sysattrs@locattrs,
   660 				  content = (map PgipOutput.output errs)@xmls })
   654 				  doc = doc,
       
   655 				  errs = (map PgipOutput.output errs) })
   661     end
   656     end
   662 
   657 
   663 fun showproofstate vs = isarcmd "pr"
   658 fun showproofstate vs = isarcmd "pr"
   664 
   659 
   665 fun showctxt vs = isarcmd "print_theory"   (* more useful than print_context *)
   660 fun showctxt vs = isarcmd "print_theory"   (* more useful than print_context *)
   683 	val arg = #arg vs
   678 	val arg = #arg vs
   684     in 
   679     in 
   685 	isarcmd ("print_" ^ arg)   (* FIXME: isatool doc?.  Return URLs, maybe? *)
   680 	isarcmd ("print_" ^ arg)   (* FIXME: isatool doc?.  Return URLs, maybe? *)
   686     end
   681     end
   687 
   682 
       
   683 (*** Theory ***)
       
   684 
   688 fun doitem vs =
   685 fun doitem vs =
   689     let
   686     let
   690 	val text = #text vs
   687 	val text = #text vs
   691     in
   688     in
   692 	isarcmd text
   689 	isarcmd text
   706 	val thyname = #thyname vs
   703 	val thyname = #thyname vs
   707     in
   704     in
   708 	isarcmd ("kill_thy " ^ quote thyname)
   705 	isarcmd ("kill_thy " ^ quote thyname)
   709     end
   706     end
   710 
   707 
   711 fun loadfile vs = 
   708 
       
   709 (*** Files ***)
       
   710 
       
   711 (* Path management: we allow theory files to have dependencies in
       
   712    their own directory, but when we change directory for a new file we
       
   713    remove the path.  Leaving it there can cause confusion with
       
   714    difference in batch mode.
       
   715    NB: PGIP does not assume that the prover has a load path. 
       
   716 *)
       
   717 
       
   718 local
       
   719     val current_working_dir = ref (NONE : string option)
       
   720 in
       
   721 fun changecwd_dir newdirpath = 
       
   722    let 
       
   723        val newdir = File.platform_path newdirpath
       
   724    in 
       
   725        (case (!current_working_dir) of
       
   726             NONE => ()
       
   727           | SOME dir => ThyLoad.del_path dir;
       
   728         ThyLoad.add_path newdir;
       
   729         current_working_dir := SOME newdir)
       
   730    end
       
   731 end
       
   732 
       
   733 fun changecwd vs = 
   712     let 
   734     let 
   713 	val url = #url vs
   735 	val url = #url vs
   714     in 
   736 	val newdir = PgipTypes.path_of_pgipurl url
   715 	case !currently_open_file of
   737     in
   716             SOME f => raise PGIP ("<loadfile> when a file is open!")
   738 	changecwd_dir url
   717           | NONE => use_thy_or_ml_file (File.platform_path url)
       
   718     end
   739     end
   719 
   740 
   720 fun openfile vs =
   741 fun openfile vs =
   721   let 
   742   let 
   722       val url = #url vs
   743       val url = #url vs
       
   744       val filepath = PgipTypes.path_of_pgipurl url
       
   745       val filedir = Path.dir filepath
       
   746       val thy_name = Path.implode o #1 o Path.split_ext o Path.base
       
   747       val openfile_retract = Output.no_warnings (ThyInfo.if_known_thy ThyInfo.remove_thy) o thy_name;
   723   in
   748   in
   724       case !currently_open_file of
   749       case !currently_open_file of
   725           SOME f => raise PGIP ("<openfile> when a file is already open! ")
   750           SOME f => raise PGIP ("<openfile> when a file is already open! ")
   726         | NONE => (openfile_retract (File.platform_path url);
   751         | NONE => (openfile_retract filepath;
   727 		   currently_open_file := SOME url) (*(File.platform_path url))*)
   752 		   changecwd_dir filedir;
       
   753 		   currently_open_file := SOME url)
   728   end
   754   end
   729 
   755 
   730 fun closefile vs =
   756 fun closefile vs =
   731     case !currently_open_file of
   757     case !currently_open_file of
   732         SOME f => (proper_inform_file_processed (File.platform_path f) 
   758         SOME f => (proper_inform_file_processed (File.platform_path f) 
   733 						(Isar.state());
   759 						(Isar.state());
   734                    currently_open_file := NONE)
   760                    currently_open_file := NONE)
   735       | NONE => raise PGIP ("<closefile> when no file is open!")
   761       | NONE => raise PGIP ("<closefile> when no file is open!")
   736 
   762 
       
   763 fun loadfile vs = 
       
   764     let 
       
   765 	val url = #url vs
       
   766     in 
       
   767 	case !currently_open_file of
       
   768             SOME f => raise PGIP ("<loadfile> when a file is open!")
       
   769           | NONE => use_thy_or_ml_file (File.platform_path url)
       
   770     end
       
   771 
   737 fun abortfile vs =
   772 fun abortfile vs =
   738     case !currently_open_file of
   773     case !currently_open_file of
   739         SOME f => (isarcmd "init_toplevel";
   774         SOME f => (isarcmd "init_toplevel";
   740 		   currently_open_file := NONE)
   775 		   currently_open_file := NONE)
   741       | NONE => raise PGIP ("<abortfile> when no file is open!")
   776       | NONE => raise PGIP ("<abortfile> when no file is open!")
   747 	case !currently_open_file of
   782 	case !currently_open_file of
   748             SOME f => raise PGIP ("<retractfile> when a file is open!")
   783             SOME f => raise PGIP ("<retractfile> when a file is open!")
   749           | NONE => inform_file_retracted (File.platform_path url)
   784           | NONE => inform_file_retracted (File.platform_path url)
   750     end
   785     end
   751 
   786 
   752 (* Path management: we allow theory files to have dependencies in
   787 
   753    their own directory, but when we change directory for a new file we
   788 (*** System ***)
   754    remove the path.  Leaving it there can cause confusion with
       
   755    difference in batch mode.
       
   756    NB: PGIP does not assume that the prover has a load path. 
       
   757 *)
       
   758 
       
   759 local
       
   760     val current_working_dir = ref (NONE : string option)
       
   761 in
       
   762 fun changecwd vs = 
       
   763     let 
       
   764 	val url = #url vs
       
   765 	val newdir = File.platform_path url
       
   766     in
       
   767         (case (!current_working_dir) of
       
   768              NONE => ()
       
   769            | SOME dir => ThyLoad.del_path dir;
       
   770          ThyLoad.add_path newdir;
       
   771          current_working_dir := SOME newdir)
       
   772     end
       
   773 end
       
   774 
       
   775 
   789 
   776 fun systemcmd vs =
   790 fun systemcmd vs =
   777   let 
   791   let 
   778       val arg = #arg vs
   792       val arg = #arg vs
   779   in
   793   in