190 |
190 |
191 then the parsing aborts and the error message @{text "foo"} is printed out. In order to |
191 then the parsing aborts and the error message @{text "foo"} is printed out. In order to |
192 see the error message properly, we need to prefix the parser with the function |
192 see the error message properly, we need to prefix the parser with the function |
193 @{ML "Scan.error"}. For example |
193 @{ML "Scan.error"}. For example |
194 |
194 |
195 @{ML_response_fake [display,gray] "Scan.error ((!! (fn _ => \"foo\") ($$ \"h\")))" |
195 @{ML_response_fake [display,gray] "Scan.error (!! (fn _ => \"foo\") ($$ \"h\"))" |
196 "Exception Error \"foo\" raised"} |
196 "Exception Error \"foo\" raised"} |
197 |
197 |
198 This ``prefixing'' is usually done by wrappers such as @{ML "OuterSyntax.command"} |
198 This ``prefixing'' is usually done by wrappers such as @{ML "OuterSyntax.command"} |
199 (FIXME: give reference to later place). |
199 (FIXME: give reference to later place). |
200 |
200 |
555 need to be implemented. While this is not difficult on the ML-level, |
555 need to be implemented. While this is not difficult on the ML-level, |
556 new commands, in order to be useful, need to be recognised by |
556 new commands, in order to be useful, need to be recognised by |
557 ProofGeneral. This results in some subtle configuration issues, which we |
557 ProofGeneral. This results in some subtle configuration issues, which we |
558 will explain in this section. |
558 will explain in this section. |
559 |
559 |
560 Let us start with a ``silly'' command, which we call \isacommand{foobar} in what follows. |
560 To keep things simple, let us start with a ``silly'' command that does nothing |
561 To keep things simple this command does nothing at all. On the ML-level it can be defined as |
561 at all. We shall name this command \isacommand{foobar}. On the ML-level it can be |
|
562 defined as |
562 *} |
563 *} |
563 |
564 |
564 ML{*let |
565 ML{*let |
565 val do_nothing = Scan.succeed (Toplevel.theory I) |
566 val do_nothing = Scan.succeed (Toplevel.theory I) |
566 val kind = OuterKeyword.thy_decl |
567 val kind = OuterKeyword.thy_decl |
567 in |
568 in |
568 OuterSyntax.command "foobar" "description of foobar" kind do_nothing |
569 OuterSyntax.command "foobar" "description of foobar" kind do_nothing |
569 end *} |
570 end *} |
570 |
571 |
571 text {* |
572 text {* |
572 The function @{ML OuterSyntax.command} expects a name for the command, a |
573 The crucial function @{ML OuterSyntax.command} expects a name for the command, a |
573 short description, a kind indicator (which we will explain later on more thoroughly) and a |
574 short description, a kind indicator (which we will explain later on more thoroughly) and a |
574 parser for a top-level transition function (its purpose will also explained |
575 parser producing a top-level transition function (its purpose will also explained |
575 later). |
576 later). |
576 |
577 |
577 While this is everything we have to do on the ML-level, we need a keyword |
578 While this is everything we have to do on the ML-level, we need a keyword |
578 file that can be loaded by ProofGeneral. This is to enable ProofGeneral to |
579 file that can be loaded by ProofGeneral. This is to enable ProofGeneral to |
579 recognise \isacommand{foobar} as a command. Such a keyword file can be |
580 recognise \isacommand{foobar} as a command. Such a keyword file can be |
580 generated with the command-line |
581 generated with the command-line: |
581 |
582 |
582 |
583 |
583 @{text [display] "$ isabelle keywords -k foobar some-log-files"} |
584 @{text [display] "$ isabelle keywords -k foobar some_log_files"} |
584 |
585 |
585 The option @{text "-k foobar"} indicates which postfix the keyword file will |
586 The option @{text "-k foobar"} indicates which postfix the name of the keyword file |
586 obtain. In the case above the generated file will be named @{text |
587 will be assigned. In the case above the generated file will be named @{text |
587 "isar-keywords-foobar.el"}. However, this command requires log files to be |
588 "isar-keywords-foobar.el"}. As indicated, this command requires log files to be |
588 present (in order to extract the keywords from them). To generate these log |
589 present (in order to extract the keywords from them). To generate these log |
589 files, we first package the code above into a separate theory file named |
590 files, we first package the code above into a separate theory file named |
590 @{text "Command.thy"}, say---see Figure~\ref{fig:commandtheory} for the |
591 @{text "Command.thy"}, say---see Figure~\ref{fig:commandtheory} for the |
591 complete code. |
592 complete code. |
592 |
593 |
615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
616 |
617 |
617 For our purposes it is sufficient to use the log files for the theories |
618 For our purposes it is sufficient to use the log files for the theories |
618 @{text "Pure"}, @{text "HOL"} and @{text "Pure-ProofGeneral"}, as well as |
619 @{text "Pure"}, @{text "HOL"} and @{text "Pure-ProofGeneral"}, as well as |
619 the theory @{text "Command.thy"} containing the new |
620 the theory @{text "Command.thy"} containing the new |
620 \isacommand{foobar}-command. @{text Pure} and @{text HOL} are usually |
621 \isacommand{foobar}-command. If you target another logics besides HOL, such |
621 compiled during the installation of Isabelle. So log files for them should be |
622 as Nominal or ZF, then you need to adapt the log files appropriately. |
622 already available. If not, then they can be conveniently compiled using |
623 @{text Pure} and @{text HOL} are usually compiled during the installation of |
623 build-script from the Isabelle distribution |
624 Isabelle. So log files for them should be already available. If not, then |
|
625 they can be conveniently compiled using build-script from the Isabelle |
|
626 distribution |
|
627 |
624 |
628 |
625 @{text [display] |
629 @{text [display] |
626 "$ ./build -m \"Pure\" |
630 "$ ./build -m \"Pure\" |
627 $ ./build -m \"HOL\""} |
631 $ ./build -m \"HOL\""} |
628 |
632 |
651 |
655 |
652 to the file @{text "./FoobarCommand/ROOT.ML"}. We can now compile the theory by just typing |
656 to the file @{text "./FoobarCommand/ROOT.ML"}. We can now compile the theory by just typing |
653 |
657 |
654 @{text [display] "$ isabelle make"} |
658 @{text [display] "$ isabelle make"} |
655 |
659 |
656 We created finally all the necessary log files. They are typically stored |
660 We created finally all the necessary log files. They are stored |
657 in the directory |
661 in the directory |
658 |
662 |
659 @{text [display] "~/.isabelle/heaps/Isabelle2008/polyml-5.2.1_x86-linux/log"} |
663 @{text [display] "~/.isabelle/heaps/Isabelle2008/polyml-5.2.1_x86-linux/log"} |
660 |
664 |
661 or something similar depending on your Isabelle distribution and architecture. |
665 or something similar depending on your Isabelle distribution and architecture. |
662 Let us assume the name of this directory is stored in the shell variable |
666 One quick way to assign a shell variable to this directory is by typing |
663 @{text "ISABELLE_LOGS"}. One way to assign this shell variable is by typing |
|
664 |
667 |
665 @{text [display] "$ ISABELLE_LOGS=\"$(isabelle getenv -b ISABELLE_OUTPUT)\"/log"} |
668 @{text [display] "$ ISABELLE_LOGS=\"$(isabelle getenv -b ISABELLE_OUTPUT)\"/log"} |
666 |
669 |
667 on the Unix prompt. This directory should include the files |
670 on the Unix prompt. The directory should include the files |
668 |
671 |
669 @{text [display] |
672 @{text [display] |
670 "Pure.gz |
673 "Pure.gz |
671 HOL.gz |
674 HOL.gz |
672 Pure-ProofGeneral.gz |
675 Pure-ProofGeneral.gz |
673 HOL-FoobarCommand.gz"} |
676 HOL-FoobarCommand.gz"} |
674 |
677 |
675 They are the ones we use for creating the keyword files. The corresponding Unix command |
678 They are the ones we need for creating the keyword files. Assuming the name |
676 is |
679 of the directory is in @{text "ISABELLE_LOGS"}, |
|
680 then the Unix command for creating the keyword file is: |
677 |
681 |
678 @{text [display] |
682 @{text [display] |
679 "$ isabelle keywords -k foobar |
683 "$ isabelle keywords -k foobar |
680 $ISABELLE_LOGS/{Pure.gz,HOL.gz,Pure-ProofGeneral.gz,HOL-FoobarCommand.gz}"} |
684 $ISABELLE_LOGS/{Pure.gz,HOL.gz,Pure-ProofGeneral.gz,HOL-FoobarCommand.gz}"} |
681 |
685 |
682 The result is the file @{text "isar-keywords-foobar.el"}. It should contain the |
686 The result is the file @{text "isar-keywords-foobar.el"}. It should contain the |
683 string @{text "foobar"} twice (check for example that @{text [quotes] "grep foobar |
687 string @{text "foobar"} twice (check for example that @{text "grep foobar |
684 isar-keywords-foobar.el"} returns something non-empty). This keyword file |
688 isar-keywords-foobar.el"} returns something non-empty). This keyword file |
685 needs to be copied into the directory @{text "~/.isabelle/etc"}. To make |
689 needs to be copied into the directory @{text "~/.isabelle/etc"}. To make |
686 Isabelle use this keyword file, we have to start it with the option @{text |
690 Isabelle aware of this keyword file, we have to start it with the option @{text |
687 "-k foobar"}, i.e. |
691 "-k foobar"}, i.e. |
688 |
692 |
689 @{text [display] "$ isabelle -k foobar a-theory-file"} |
693 @{text [display] "$ isabelle -k foobar a_theory_file"} |
690 |
694 |
691 If we now run the original code |
695 If we now run the original code |
692 *} |
696 *} |
693 |
697 |
694 ML{*let |
698 ML{*let |
697 in |
701 in |
698 OuterSyntax.command "foobar" "description of foobar" kind do_nothing |
702 OuterSyntax.command "foobar" "description of foobar" kind do_nothing |
699 end *} |
703 end *} |
700 |
704 |
701 text {* |
705 text {* |
702 then we can make use of \isacommand{foobar}! Similarly with any other new command. |
706 then we can make use of \isacommand{foobar} in a theory that builds on @{text "Command.thy"}! |
703 |
707 Similarly with any other new command. |
704 In the example above, we built the theories on top of the HOL-logic. If you |
708 |
705 target other logics, such as Nominal or ZF, then you need to adapt the |
709 |
706 log files appropriately. |
710 At the moment \isacommand{foobar} is not very useful. Let us next refine it a bit |
707 |
|
708 At the moment, \isacommand{foobar} is not very useful. Let us refine it a bit |
|
709 by taking a proposition as argument and printing this proposition inside |
711 by taking a proposition as argument and printing this proposition inside |
710 the tracing buffer. |
712 the tracing buffer. |
711 |
713 |
712 The crucial part of a command is the function that determines |
714 The crucial part of a command is the function that determines |
713 the behaviour of the command. In the code above we used the the |
715 the behaviour of the command. In the code above we used a |
714 @{text do_nothing}-function, which because of @{ML Scan.succeed} does not parse |
716 ``do-nothing''-function, which because of @{ML Scan.succeed} does not parse |
715 any argument, but immediately returns the simple toplevel function |
717 any argument, but immediately returns the simple toplevel function |
716 @{ML "Toplevel.theory I"}. We can replace this code by a function that first |
718 @{ML "Toplevel.theory I"}. We can replace this code by a function that first |
717 parses a proposition (using the parser @{ML OuterParse.prop}), then prints out |
719 parses a proposition (using the parser @{ML OuterParse.prop}), then prints out |
718 the tracing information and finally does nothing. For this we can write |
720 the tracing information and finally does nothing. For this we can write |
719 *} |
721 *} |
727 end *} |
729 end *} |
728 |
730 |
729 text {* |
731 text {* |
730 Now we can type for example |
732 Now we can type for example |
731 |
733 |
732 @{ML_response_fake_both [display,gray] "foobar \"True \<and> False\"" "True \<and> False"} |
734 \begin{isabelle} |
|
735 \isacommand{foobar}~@{text [quotes] "True \<and> False"}\\ |
|
736 @{text "> True \<and> False"} |
|
737 \end{isabelle} |
733 |
738 |
734 and see the proposition in the tracing buffer. |
739 and see the proposition in the tracing buffer. |
735 |
740 |
736 Note that so far we used @{ML thy_decl in OuterKeyword} as kind indicator |
741 Note that so far we used @{ML thy_decl in OuterKeyword} as the kind indicator |
737 for the command. This means that the command finishes as soon as the |
742 for the command. This means that the command finishes as soon as the |
738 arguments are processed. Examples of this kind of commands are |
743 arguments are processed. Examples of this kind of commands are |
739 \isacommand{definition} and \isacommand{declare}. In other cases, however, |
744 \isacommand{definition} and \isacommand{declare}. In other cases |
740 commands are expected to parse some arguments, for example a proposition, |
745 commands are expected to parse some arguments, for example a proposition, |
741 and then ``open up'' a proof in order to prove the proposition (think of |
746 and then ``open up'' a proof in order to prove the proposition (think of |
742 \isacommand{lemma}) or prove some other properties (for example in |
747 \isacommand{lemma}) or prove some other properties (for example in |
743 \isacommand{function}). To achieve this behaviour we have to use the kind |
748 \isacommand{function}). To achieve this behaviour, we have to use the kind |
744 indicator @{ML thy_goal in OuterKeyword}. |
749 indicator @{ML thy_goal in OuterKeyword}. |
745 |
750 |
746 Below we change \isacommand{foobar} is such a way that an proposition as |
751 Below we change \isacommand{foobar} so that it expects a proposition as |
747 argument and then start a proof in order to prove it. Therefore in Line 13 |
752 argument and then starts a proof in order to prove it. Therefore in Line 13 |
748 below, we set the kind indicator to @{ML thy_goal in OuterKeyword}. |
753 below, we set the kind indicator to @{ML thy_goal in OuterKeyword}. |
749 *} |
754 *} |
750 |
755 |
751 ML%linenumbers{*let |
756 ML%linenumbers{*let |
752 fun set_up_thm str ctxt = |
757 fun set_up_thm str ctxt = |
764 in |
769 in |
765 OuterSyntax.command "foobar" "proving a proposition" kind prove_prop |
770 OuterSyntax.command "foobar" "proving a proposition" kind prove_prop |
766 end *} |
771 end *} |
767 |
772 |
768 text {* |
773 text {* |
769 The function @{text set_up_thm} takes a string (the proposition) and a context. |
774 The function @{text set_up_thm} takes a string (the proposition to be |
770 The context is necessary in order to convert the string into a proper proposition |
775 proved) and a context. The context is necessary in order to be able to use |
771 using the function @{ML Syntax.read_prop}. In Line 6 we use the function |
776 @{ML Syntax.read_prop}, which converts a string into a proper proposition. |
772 @{ML Proof.theorem_i} to start the proof for the proposition. In Lines 9 to |
777 In Line 6 the function @{ML Proof.theorem_i} starts the proof for the |
773 11 contain the parser for the proposition. |
778 proposition. In Lines 9 to 11 contain the parser for the proposition. |
774 |
779 |
775 If we now type @{text "foobar \"True \<and> True\""}, we obtain the following |
780 If we now type \isacommand{foobar}~@{text [quotes] "True \<and> True"}, we obtain the following |
776 proof state: |
781 proof state: |
777 |
782 |
778 @{ML_response_fake_both [display,gray] "foobar \"True \<and> True\"" |
783 \begin{isabelle} |
779 "goal (1 subgoal): |
784 \isacommand{foobar}~@{text [quotes] "True \<and> False"}\\ |
780 1. True \<and> True"} |
785 @{text "goal (1 subgoal)"}\\ |
|
786 @{text "1. True \<and> True"} |
|
787 \end{isabelle} |
781 |
788 |
782 and we can build the proof |
789 and we can build the proof |
783 |
790 |
784 @{text [display,gray] "foobar \"True \<and> True\" |
791 \begin{isabelle} |
785 apply(rule conjI) |
792 \isacommand{foobar}~@{text [quotes] "True \<and> False"}\\ |
786 apply(rule TrueI)+ |
793 \isacommand{apply}@{text "(rule conjI)"}\\ |
787 done"} |
794 \isacommand{apply}@{text "(rule TrueI)+"}\\ |
|
795 \isacommand{done} |
|
796 \end{isabelle} |
|
797 |
788 |
798 |
789 (FIXME What does @{text "Toplevel.theory"}?) |
799 (FIXME What does @{text "Toplevel.theory"}?) |
790 |
800 |
791 (FIXME Explain @{text "OuterKeyword.thy_decl"} and parser) |
801 (FIXME Explain @{text "OuterKeyword.thy_decl"} and parser) |
792 |
802 |