CookBook/Parsing.thy
changeset 74 f6f8f8ba1eb1
parent 72 7b8c4fe235aa
child 75 f2dea0465bb4
equal deleted inserted replaced
73:bcbcf5c839ae 74:f6f8f8ba1eb1
   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   
   633   For the theory @{text "Command.thy"}, we first create a ``managed'' subdirectory 
   637   For the theory @{text "Command.thy"}, we first create a ``managed'' subdirectory 
   634   with
   638   with
   635 
   639 
   636   @{text [display] "$ isabelle mkdir FoobarCommand"}
   640   @{text [display] "$ isabelle mkdir FoobarCommand"}
   637 
   641 
   638   This creates a directory containing the files 
   642   This generates a directory containing the files 
   639 
   643 
   640   @{text [display] 
   644   @{text [display] 
   641 "./IsaMakefile
   645 "./IsaMakefile
   642 ./FoobarCommand/ROOT.ML
   646 ./FoobarCommand/ROOT.ML
   643 ./FoobarCommand/document
   647 ./FoobarCommand/document
   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