CookBook/Parsing.thy
changeset 66 d563f8ff6aa0
parent 65 c8e9a4f97916
child 67 5fbeeac2901b
equal deleted inserted replaced
65:c8e9a4f97916 66:d563f8ff6aa0
   551 
   551 
   552 *}
   552 *}
   553 
   553 
   554 ML {* OuterSyntax.command *}
   554 ML {* OuterSyntax.command *}
   555 
   555 
   556 section {* New Commands and Keyword Files *}
   556 section {* New Commands and Creating Keyword Files *}
   557 
   557 
   558 text {*
   558 text {*
   559 
       
   560   Often new commands, for example for providing a new definitional principle,
   559   Often new commands, for example for providing a new definitional principle,
   561   need to be programmed. While this is not too difficult to do on the
   560   need to be programmed. While this is not difficult to do on the ML-level,
   562   ML-level, new commands, in order to be useful, need to be recognised by
   561   new commands, in order to be useful, need to be recognised by
   563   ProofGeneral. This results in some subtle configuration issues, which we
   562   ProofGeneral. This results in some subtle configuration issues, which we
   564   will explain in this section.
   563   will explain in this section.
   565 
   564 
   566 
   565   Let us start with a ``silly'' command, below named \isacommand{foo}, which does nothing at all. 
   567   Let us start with a silly command, named \isacommand{foo}, which does nothing at all. 
   566   On the ML-level it can be defined as
   568   It can be defined as
       
   569 
   567 
   570 @{ML [display]
   568 @{ML [display]
   571 "let
   569 "let
   572   val do_nothing = Scan.succeed (Toplevel.theory (fn x => x))
   570   val do_nothing = Scan.succeed (Toplevel.theory (fn x => x))
   573   val flag = OuterKeyword.thy_decl
   571   val flag = OuterKeyword.thy_decl
   574 in
   572 in
   575   OuterSyntax.command \"foo\" \"description of foo\" flag do_nothing
   573   OuterSyntax.command \"foo\" \"description of foo\" flag do_nothing
   576 end"}
   574 end"}
   577 
   575 
   578   The crucial function that makes the command \isacommand{foo} known to
   576   The function @{ML OuterSyntax.command} expects a name for the command, a
   579   Isabelle is @{ML OuterSyntax.command}.  It expects a name of a command, a
   577   short description, a flag (which we will explain it later on more thoroughly) and a
   580   short description, a flag (we will explain it later more thoroughly) and a
       
   581   parser for a top-level transition function (its purpose will also explained
   578   parser for a top-level transition function (its purpose will also explained
   582   later on). Lets also assume we packaged this function into a separate
   579   later). 
   583   theory named @{text "Command"}, say, and a file named @{text "Command.thy"}. 
   580 
   584 
   581   While this is everything we have to do on the ML-level, we need 
   585   We now need a keyword file, that can be loaded by ProofGeneral in
   582   now a keyword file that can be loaded by ProofGeneral. This is to enable ProofGeneral 
   586   order to recognise \isacommand{foo} as command. Such a keyword file
   583   to recognise  \isacommand{foo} as a command. Such a keyword file can be generated with 
   587   can be generated with the command-line
   584   the command-line
   588 
   585 
   589   @{text [display] "$ isabelle keywords -k foo some-log-files"}
   586   @{text [display] "$ isabelle keywords -k foo <some-log-files>"}
   590 
   587 
   591   The option @{text "-k foo"} indicates which postfix the keyword file will obtain. In
   588   The option @{text "-k foo"} indicates which postfix the keyword file will obtain. In
   592   the case above the generated file is named @{text "isar-keywords-foo.el"}. This command
   589   the case above the generated file will be named @{text "isar-keywords-foo.el"}. This command
   593   requires log files to be present (in order to extract the keywords from them). For 
   590   requires log files to be present (in order to extract the keywords from them). 
       
   591   To generate these log files, we first package the code above into a separate theory file 
       
   592   named @{text "Command.thy"}, say---see Figure~\ref{fig:commandtheory} for the complete code. 
       
   593 
       
   594   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
       
   595   \begin{figure}[t]
       
   596   \begin{boxedminipage}{\textwidth}
       
   597   \isacommand{theory}~@{text Command}\\
       
   598   \isacommand{imports}~@{text Main}\\
       
   599   \isacommand{begin}\\
       
   600   \isacommand{ML}~\isa{\isacharverbatimopen}\\
       
   601   @{ML
       
   602 "let
       
   603   val do_nothing = Scan.succeed (Toplevel.theory (fn x => x))
       
   604   val flag = OuterKeyword.thy_decl
       
   605 in
       
   606   OuterSyntax.command \"foo\" \"description of foo\" flag do_nothing
       
   607 end"}\\
       
   608   \isa{\isacharverbatimclose}\\
       
   609   \isacommand{end}
       
   610   \end{boxedminipage}
       
   611   \caption{The file @{text "Command.thy"} is necessary for generating a log 
       
   612   file. This log file enables Isabelle to generate a keyword file containing 
       
   613   the command \isacommand{foo}.\label{fig:commandtheory}}
       
   614   \end{figure}
       
   615   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
       
   616 
       
   617   For 
   594   our purposes it is sufficient to use the log files for the theories @{text "Pure"},
   618   our purposes it is sufficient to use the log files for the theories @{text "Pure"},
   595   @{text "HOL"} and @{text "Pure-ProofGeneral"}, as well as the theory @{text "Command.thy"}
   619   @{text "HOL"} and @{text "Pure-ProofGeneral"}, as well as the theory @{text "Command.thy"}
   596   containing the new command. @{text Pure} and @{text HOL} are usually compiled during the 
   620   containing the new command. @{text Pure} and @{text HOL} are usually compiled during the 
   597   installation of Isabelle, if not this can be done conveniently using build script from 
   621   installation of Isabelle. So log files for them are already available. If not, then they 
   598   the distribution
   622   can be conveniently compiled using build-script from the distribution
   599 
   623 
   600   @{text [display] 
   624   @{text [display] 
   601 "$ ./build -m \"Pure\"
   625 "$ ./build -m \"Pure\"
   602 $ ./build -m \"HOL\""}
   626 $ ./build -m \"HOL\""}
   603   
   627   
   604   The @{text "Pure-ProofGeneral"} theory needs to be compiled with
   628   The @{text "Pure-ProofGeneral"} theory needs to be compiled with
   605 
   629 
   606   @{text [display] "$ ./build -m \"Pure-ProofGeneral\" \"Pure\""}
   630   @{text [display] "$ ./build -m \"Pure-ProofGeneral\" \"Pure\""}
   607 
   631 
   608   For the theory containing the new command \isacommand{foo}, we first
   632   For the theory @{text "Command.thy"}, we first create a ``managed'' subdirectory 
   609   create a ``managed'' subdirectory by
   633   with
   610 
   634 
   611 
   635   @{text [display] "$ isabelle mkdir FooCommand"}
   612   This creates files @{text "IsaMakefile"} and @{text "./FooCommand/ROOT.ML"}. We
   636 
   613   need to copy the file @{text "Command.thy"} into the directory @{text "FooCommand"}
   637   This creates a directory containing the files 
   614   and add @{text "use_thy \"Command\";"} to @{text "./FooCommand/ROOT.ML"}.
   638 
   615   Now we can compile the theory by just typing
   639   @{text [display] 
       
   640 "./IsaMakefile
       
   641 ./FooCommand/ROOT.ML
       
   642 ./FooCommand/document
       
   643 ./FooCommand/document/root.tex"}
       
   644 
       
   645 
       
   646   We need to copy the file @{text "Command.thy"} into the directory @{text "FooCommand"}
       
   647   and add the line 
       
   648 
       
   649   @{text [display] "use_thy \"Command\";"} 
       
   650   
       
   651   to the file @{text "./FooCommand/ROOT.ML"}. Now we can compile the theory by just typing
   616 
   652 
   617   @{text [display] "$ isabelle make"}
   653   @{text [display] "$ isabelle make"}
   618 
   654 
   619   All these compilations created the log files that we are after. They are typically stored 
   655   We created now the necessary log files. They are typically stored 
   620   under the directory 
   656   in the directory 
   621   
   657   
   622   @{text [display]  "~/.isabelle/heaps/\<dots>\<dots>/\<dots>\<dots>/log"}
   658   @{text [display]  "~/.isabelle/heaps/Isabelle2008/polyml-5.2.1_x86-linux/log"}
   623 
   659 
   624   where the dots stand for names of the current Isabelle distribution and 
   660   or something similar depending on your Isabelle distribution and architecture. 
   625   hardware architecture. In it are the files
   661   Let us assume the name of this directory is stored in the shell variable 
       
   662   @{text "ISABELLE_LOGS"}. One way to assign this shell variable is by typing
       
   663 
       
   664   @{text [display] "$ ISABELLE_LOGS=\"$(isabelle getenv -b ISABELLE_OUTPUT)\"/log"}
       
   665  
       
   666   In this directory are the files
   626 
   667 
   627   @{text [display] 
   668   @{text [display] 
   628 "Pure.gz
   669 "Pure.gz
   629 HOL.gz
   670 HOL.gz
   630 Pure-ProofGeneral.gz
   671 Pure-ProofGeneral.gz
   631 HOL-FooCommand.gz"} 
   672 HOL-FooCommand.gz"} 
   632 
   673 
   633   Let us assume the directory with these files is stored in the shell variable 
       
   634   @{text "ISABELLE_LOGS"}, by typing for example
       
   635 
       
   636   @{text [display] "$ ISABELLE_LOGS=\"$(isabelle getenv -b ISABELLE_OUTPUT)\"/log"}
       
   637  
       
   638   We can now create the keyword file with
   674   We can now create the keyword file with
   639 
   675 
   640 @{text [display]
   676 @{text [display]
   641 "$ isabelle keywords -k foo 
   677 "$ isabelle keywords -k foo 
   642        `$ISABELLE_LOGS/{Pure.gz,HOL.gz,Pure-ProofGeneral,HOL-FooCommand.gz}`"}
   678        `$ISABELLE_LOGS/{Pure.gz,HOL.gz,Pure-ProofGeneral,HOL-FooCommand.gz}`"}
   643 
   679 
   644   The result is the file @{text "isar-keywords-foo.el"}, which needs to be 
   680   The result is the file @{text "isar-keywords-foo.el"}, which needs to be 
   645   copied in the directory @{text "~/.isabelle/etc"}. To make Isabelle use
   681   copied to the directory @{text "~/.isabelle/etc"}. To make Isabelle use
   646   this keyword file, we need to start it with the option @{text "-k foo"}:
   682   this keyword file, we need to start it with the option @{text "-k foo"}, i.e.
   647 
   683 
   648   @{text [display] "isabelle -k foo a-theory-file"}
   684   @{text [display] "isabelle -k foo <a-theory-file>"}
   649 
   685 
   650   If we now run the original code creating the command
   686   If we now run the original code
   651 
   687 
   652   @{ML [display]
   688   @{ML [display]
   653 "let
   689 "let
   654   val do_nothing = Scan.succeed (Toplevel.theory (fn x => x))
   690   val do_nothing = Scan.succeed (Toplevel.theory (fn x => x))
   655   val flag = OuterKeyword.thy_decl
   691   val flag = OuterKeyword.thy_decl