678 @{ML_response [display,gray] |
678 @{ML_response [display,gray] |
679 "let |
679 "let |
680 val input = filtered_input |
680 val input = filtered_input |
681 \"foo::\\\"int \<Rightarrow> bool\\\" and bar::nat (\\\"BAR\\\" 100) and blonk\" |
681 \"foo::\\\"int \<Rightarrow> bool\\\" and bar::nat (\\\"BAR\\\" 100) and blonk\" |
682 in |
682 in |
683 parse OuterParse.fixes input |
683 parse OuterParse.fixes input |
684 end" |
684 end" |
685 "([(foo, SOME \"\\^E\\^Ftoken\\^Eint \<Rightarrow> bool\\^E\\^F\\^E\", NoSyn), |
685 "([(foo, SOME \"\\^E\\^Ftoken\\^Eint \<Rightarrow> bool\\^E\\^F\\^E\", NoSyn), |
686 (bar, SOME \"\\^E\\^Ftoken\\^Enat\\^E\\^F\\^E\", Mixfix (\"BAR\", [], 100)), |
686 (bar, SOME \"\\^E\\^Ftoken\\^Enat\\^E\\^F\\^E\", Mixfix (\"BAR\", [], 100)), |
687 (blonk, NONE, NoSyn)],[])"} |
687 (blonk, NONE, NoSyn)],[])"} |
688 *} |
688 *} |
698 \begin{readmore} |
698 \begin{readmore} |
699 The data structure for syntax annotations is defined in @{ML_file "Pure/Syntax/mixfix.ML"}. |
699 The data structure for syntax annotations is defined in @{ML_file "Pure/Syntax/mixfix.ML"}. |
700 \end{readmore} |
700 \end{readmore} |
701 |
701 |
702 Lines 3 to 7 in the function @{ML spec_parser} implement the parser for a |
702 Lines 3 to 7 in the function @{ML spec_parser} implement the parser for a |
703 list of introduction rules, that is propositions with theorem |
703 list of introduction rules, that is propositions with theorem annotations |
704 annotations. The introduction rules are propositions parsed by @{ML |
704 such as rule names and attributes. The introduction rules are propositions |
705 OuterParse.prop}. However, they can include an optional theorem name plus |
705 parsed by @{ML OuterParse.prop}. However, they can include an optional |
706 some attributes. For example |
706 theorem name plus some attributes. For example |
707 |
707 |
708 @{ML_response [display,gray] "let |
708 @{ML_response [display,gray] "let |
709 val input = filtered_input \"foo_lemma[intro,dest!]:\" |
709 val input = filtered_input \"foo_lemma[intro,dest!]:\" |
710 val ((name, attrib), _) = parse (SpecParse.thm_name \":\") input |
710 val ((name, attrib), _) = parse (SpecParse.thm_name \":\") input |
711 in |
711 in |
765 at all. We shall name this command \isacommand{foobar}. On the ML-level it can be |
763 at all. We shall name this command \isacommand{foobar}. On the ML-level it can be |
766 defined as: |
764 defined as: |
767 *} |
765 *} |
768 |
766 |
769 ML{*let |
767 ML{*let |
770 val do_nothing = Scan.succeed (Toplevel.theory I) |
768 val do_nothing = Scan.succeed (LocalTheory.theory I) |
771 val kind = OuterKeyword.thy_decl |
769 val kind = OuterKeyword.thy_decl |
772 in |
770 in |
773 OuterSyntax.command "foobar" "description of foobar" kind do_nothing |
771 OuterSyntax.local_theory "foobar" "description of foobar" kind do_nothing |
774 end *} |
772 end *} |
775 |
773 |
776 text {* |
774 text {* |
777 The crucial function @{ML OuterSyntax.command} expects a name for the command, a |
775 The crucial function @{ML OuterSyntax.local_theory} expects a name for the command, a |
778 short description, a kind indicator (which we will explain later on more thoroughly) and a |
776 short description, a kind indicator (which we will explain later more thoroughly) and a |
779 parser producing a top-level transition function (its purpose will also explained |
777 parser producing a local theory transition (its purpose will also explained |
780 later). |
778 later). |
781 |
779 |
782 While this is everything you have to do on the ML-level, you need a keyword |
780 While this is everything you have to do on the ML-level, you need a keyword |
783 file that can be loaded by ProofGeneral. This is to enable ProofGeneral to |
781 file that can be loaded by ProofGeneral. This is to enable ProofGeneral to |
784 recognise \isacommand{foobar} as a command. Such a keyword file can be |
782 recognise \isacommand{foobar} as a command. Such a keyword file can be |
802 \isacommand{imports}~@{text Main}\\ |
800 \isacommand{imports}~@{text Main}\\ |
803 \isacommand{begin}\\ |
801 \isacommand{begin}\\ |
804 \isacommand{ML}~@{text "\<verbopen>"}\\ |
802 \isacommand{ML}~@{text "\<verbopen>"}\\ |
805 @{ML |
803 @{ML |
806 "let |
804 "let |
807 val do_nothing = Scan.succeed (Toplevel.theory I) |
805 val do_nothing = Scan.succeed (LocalTheory.theory I) |
808 val kind = OuterKeyword.thy_decl |
806 val kind = OuterKeyword.thy_decl |
809 in |
807 in |
810 OuterSyntax.command \"foobar\" \"description of foobar\" kind do_nothing |
808 OuterSyntax.local_theory \"foobar\" \"description of foobar\" kind do_nothing |
811 end"}\\ |
809 end"}\\ |
812 @{text "\<verbclose>"}\\ |
810 @{text "\<verbclose>"}\\ |
813 \isacommand{end} |
811 \isacommand{end} |
814 \end{graybox} |
812 \end{graybox} |
815 \caption{\small The file @{text "Command.thy"} is necessary for generating a log |
813 \caption{The file @{text "Command.thy"} is necessary for generating a log |
816 file. This log file enables Isabelle to generate a keyword file containing |
814 file. This log file enables Isabelle to generate a keyword file containing |
817 the command \isacommand{foobar}.\label{fig:commandtheory}} |
815 the command \isacommand{foobar}.\label{fig:commandtheory}} |
818 \end{figure} |
816 \end{figure} |
819 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
820 |
818 |
908 inside the tracing buffer. |
906 inside the tracing buffer. |
909 |
907 |
910 The crucial part of a command is the function that determines the behaviour |
908 The crucial part of a command is the function that determines the behaviour |
911 of the command. In the code above we used a ``do-nothing''-function, which |
909 of the command. In the code above we used a ``do-nothing''-function, which |
912 because of @{ML Scan.succeed} does not parse any argument, but immediately |
910 because of @{ML Scan.succeed} does not parse any argument, but immediately |
913 returns the simple toplevel function @{ML "Toplevel.theory I"}. We can |
911 returns the simple function @{ML "LocalTheory.theory I"}. We can |
914 replace this code by a function that first parses a proposition (using the |
912 replace this code by a function that first parses a proposition (using the |
915 parser @{ML OuterParse.prop}), then prints out the tracing |
913 parser @{ML OuterParse.prop}), then prints out the tracing |
916 information (using a new top-level function @{text trace_top_lvl}) and |
914 information (using a new function @{text trace_prop}) and |
917 finally does nothing. For this you can write: |
915 finally does nothing. For this you can write: |
918 *} |
916 *} |
919 |
917 |
920 ML{*let |
918 ML{*let |
921 fun trace_top_lvl str = |
919 fun trace_prop str = |
922 Toplevel.theory (fn thy => (tracing str; thy)) |
920 LocalTheory.theory (fn lthy => (tracing str; lthy)) |
923 |
921 |
924 val trace_prop = OuterParse.prop >> trace_top_lvl |
922 val trace_prop_parser = OuterParse.prop >> trace_prop |
925 |
|
926 val kind = OuterKeyword.thy_decl |
923 val kind = OuterKeyword.thy_decl |
927 in |
924 in |
928 OuterSyntax.command "foobar" "traces a proposition" kind trace_prop |
925 OuterSyntax.local_theory "foobar" "traces a proposition" |
|
926 kind trace_prop_parser |
929 end *} |
927 end *} |
930 |
928 |
931 text {* |
929 text {* |
932 Now you can type |
930 Now you can type |
933 |
931 |
936 @{text "> \"True \<and> False\""} |
934 @{text "> \"True \<and> False\""} |
937 \end{isabelle} |
935 \end{isabelle} |
938 |
936 |
939 and see the proposition in the tracing buffer. |
937 and see the proposition in the tracing buffer. |
940 |
938 |
941 Note that so far we used @{ML thy_decl in OuterKeyword} as the kind indicator |
939 Note that so far we used @{ML thy_decl in OuterKeyword} as the kind |
942 for the command. This means that the command finishes as soon as the |
940 indicator for the command. This means that the command finishes as soon as |
943 arguments are processed. Examples of this kind of commands are |
941 the arguments are processed. Examples of this kind of commands are |
944 \isacommand{definition} and \isacommand{declare}. In other cases, |
942 \isacommand{definition} and \isacommand{declare}. In other cases, commands |
945 commands are expected to parse some arguments, for example a proposition, |
943 are expected to parse some arguments, for example a proposition, and then |
946 and then ``open up'' a proof in order to prove the proposition (for example |
944 ``open up'' a proof in order to prove the proposition (for example |
947 \isacommand{lemma}) or prove some other properties (for example |
945 \isacommand{lemma}) or prove some other properties (for example |
948 \isacommand{function}). To achieve this kind of behaviour, you have to use the kind |
946 \isacommand{function}). To achieve this kind of behaviour, you have to use |
949 indicator @{ML thy_goal in OuterKeyword}. Note, however, once you change the |
947 the kind indicator @{ML thy_goal in OuterKeyword} and the function @{ML |
950 ``kind'' of a command from @{ML thy_decl in OuterKeyword} to @{ML thy_goal in OuterKeyword} |
948 "local_theory_to_proof" in OuterSyntax} to set up the command. Note, |
951 then the keyword file needs to be re-created! |
949 however, once you change the ``kind'' of a command from @{ML thy_decl in |
|
950 OuterKeyword} to @{ML thy_goal in OuterKeyword} then the keyword file needs |
|
951 to be re-created! |
952 |
952 |
953 Below we change \isacommand{foobar} so that it takes a proposition as |
953 Below we change \isacommand{foobar} so that it takes a proposition as |
954 argument and then starts a proof in order to prove it. Therefore in Line 13, |
954 argument and then starts a proof in order to prove it. Therefore in Line 13, |
955 we set the kind indicator to @{ML thy_goal in OuterKeyword}. |
955 we set the kind indicator to @{ML thy_goal in OuterKeyword}. |
956 *} |
956 *} |
957 |
957 |
958 ML%linenosgray{*let |
958 ML%linenosgray{*let |
959 fun set_up_thm str ctxt = |
959 fun prove_prop str ctxt = |
960 let |
960 let |
961 val prop = Syntax.read_prop ctxt str |
961 val prop = Syntax.read_prop ctxt str |
962 in |
962 in |
963 Proof.theorem_i NONE (K I) [[(prop,[])]] ctxt |
963 Proof.theorem_i NONE (K I) [[(prop,[])]] ctxt |
964 end; |
964 end; |
965 |
965 |
966 val prove_prop = OuterParse.prop >> |
966 val prove_prop_parser = OuterParse.prop >> prove_prop |
967 (fn str => Toplevel.print o |
|
968 Toplevel.local_theory_to_proof NONE (set_up_thm str)) |
|
969 |
|
970 val kind = OuterKeyword.thy_goal |
967 val kind = OuterKeyword.thy_goal |
971 in |
968 in |
972 OuterSyntax.command "foobar" "proving a proposition" kind prove_prop |
969 OuterSyntax.local_theory_to_proof "foobar" "proving a proposition" |
|
970 kind prove_prop_parser |
973 end *} |
971 end *} |
974 |
972 |
975 text {* |
973 text {* |
976 The function @{text set_up_thm} in Lines 2 to 7 takes a string (the proposition to be |
974 The function @{text prove_prop} in Lines 2 to 7 takes a string (the proposition to be |
977 proved) and a context as argument. The context is necessary in order to be able to use |
975 proved) and a context as argument. The context is necessary in order to be able to use |
978 @{ML Syntax.read_prop}, which converts a string into a proper proposition. |
976 @{ML Syntax.read_prop}, which converts a string into a proper proposition. |
979 In Line 6 the function @{ML Proof.theorem_i} starts the proof for the |
977 In Line 6 the function @{ML Proof.theorem_i} starts the proof for the |
980 proposition. Its argument @{ML NONE} stands for a locale (which we chose to |
978 proposition. Its argument @{ML NONE} stands for a locale (which we chose to |
981 omit); the argument @{ML "(K I)"} stands for a function that determines what |
979 omit); the argument @{ML "(K I)"} stands for a function that determines what |
982 should be done with the theorem once it is proved (we chose to just forget |
980 should be done with the theorem once it is proved (we chose to just forget |
983 about it). Lines 9 to 11 contain the parser for the proposition. |
981 about it). Line 9 contains the parser for the proposition. |
984 |
982 |
985 If you now type \isacommand{foobar}~@{text [quotes] "True \<and> True"}, you obtain the following |
983 If you now type \isacommand{foobar}~@{text [quotes] "True \<and> True"}, you obtain the following |
986 proof state: |
984 proof state |
987 |
985 |
988 \begin{isabelle} |
986 \begin{isabelle} |
989 \isacommand{foobar}~@{text [quotes] "True \<and> True"}\\ |
987 \isacommand{foobar}~@{text [quotes] "True \<and> True"}\\ |
990 @{text "goal (1 subgoal):"}\\ |
988 @{text "goal (1 subgoal):"}\\ |
991 @{text "1. True \<and> True"} |
989 @{text "1. True \<and> True"} |
992 \end{isabelle} |
990 \end{isabelle} |
993 |
991 |
994 and you can build the proof |
992 and you can build the following proof |
995 |
993 |
996 \begin{isabelle} |
994 \begin{isabelle} |
997 \isacommand{foobar}~@{text [quotes] "True \<and> True"}\\ |
995 \isacommand{foobar}~@{text [quotes] "True \<and> True"}\\ |
998 \isacommand{apply}@{text "(rule conjI)"}\\ |
996 \isacommand{apply}@{text "(rule conjI)"}\\ |
999 \isacommand{apply}@{text "(rule TrueI)+"}\\ |
997 \isacommand{apply}@{text "(rule TrueI)+"}\\ |
1000 \isacommand{done} |
998 \isacommand{done} |
1001 \end{isabelle} |
999 \end{isabelle} |
1002 |
|
1003 |
|
1004 |
|
1005 (FIXME What do @{ML "Toplevel.theory"} |
|
1006 @{ML "Toplevel.print"} |
|
1007 @{ML Toplevel.local_theory} do?) |
|
1008 |
1000 |
1009 (FIXME read a name and show how to store theorems) |
1001 (FIXME read a name and show how to store theorems) |
1010 *} |
1002 *} |
1011 |
1003 |
1012 section {* Methods (TBD) *} |
1004 section {* Methods (TBD) *} |