CookBook/Parsing.thy
changeset 101 123401a5c8e9
parent 86 fdb9ea86c2a3
child 102 5e309df58557
equal deleted inserted replaced
100:dd8eebae11ec 101:123401a5c8e9
   513 
   513 
   514   @{ML OuterParse.position}
   514   @{ML OuterParse.position}
   515 
   515 
   516 *}
   516 *}
   517 
   517 
   518 ML{*
       
   519   OuterParse.position
       
   520 *}
       
   521 
       
   522 
       
   523 section {* Parsing Inner Syntax *}
   518 section {* Parsing Inner Syntax *}
   524 
   519 
   525 ML{*
   520 ML{*let 
   526 let 
       
   527   val input = OuterSyntax.scan Position.none "0"
   521   val input = OuterSyntax.scan Position.none "0"
   528 in 
   522 in 
   529   OuterParse.prop input
   523   OuterParse.prop input
   530 end 
   524 end*}
   531 
       
   532 *}
       
   533 
       
   534 ML{*
       
   535   OuterParse.opt_target
       
   536 *}
       
   537 
   525 
   538 text {* (FIXME funny output for a proposition) *}
   526 text {* (FIXME funny output for a proposition) *}
   539 
   527 
   540 ML{*
   528 section {* Parsing Specifications *}
   541   OuterParse.opt_target --
   529 
   542   OuterParse.fixes -- 
   530 text {*
   543   OuterParse.for_fixes --
   531   There are a number of special purpose parsers that help for parsing specifications.
   544   Scan.optional (OuterParse.$$$ "where" |--
   532   For example the function @{ML OuterParse.target} reads a target in order to indicate
   545     OuterParse.!!! (OuterParse.enum1 "|" (SpecParse.opt_thm_name ":" -- OuterParse.prop))) []
   533   a locale.
   546 
   534 
   547 *}
   535 @{ML_response [display,gray]
   548 
   536 "let 
   549 ML{* OuterSyntax.command *}
   537   val input = filtered_input \"(in test)\"
       
   538 in 
       
   539   parse OuterParse.target input 
       
   540 end" "(\"test\",[])"}
       
   541   
       
   542   The function @{ML OuterParse.opt_target} makes this parser ``optional''.
       
   543 
       
   544   The function @{ML OuterParse.fixes} reads a list of constants
       
   545   which can include a type annotation and a syntax translation.
       
   546   The list needs to be separated by \isacommand{and}.
       
   547 
       
   548 *}
       
   549 
       
   550 text {*
       
   551 
       
   552 @{ML_response [display,gray]
       
   553 "let
       
   554   val input = filtered_input 
       
   555         \"foo::\\\"int \<Rightarrow> bool\\\" (\\\"FOO\\\" [100] 100) and bar::nat and blonk\"
       
   556 in
       
   557    parse OuterParse.fixes input
       
   558 end"
       
   559 "([(foo, SOME \<dots>, Mixfix (\"FOO\",[100],100)), 
       
   560   (bar, SOME \<dots>, NoSyn), 
       
   561   (blonk, NONE, NoSyn)],[])"}  
       
   562 
       
   563   The types of the constants is stored in the @{ML SOME}s. 
       
   564   We need to write @{text "\\\"int \<Rightarrow> bool\\\""} to properly
       
   565   escape the type.
       
   566 
       
   567   @{ML OuterParse.for_fixes} is an ``optional'' that prefixes 
       
   568   @{ML OuterParse.fixes} with the comman \isacommand{for}.
       
   569 *}
       
   570 
       
   571 ML{*let 
       
   572   val input = filtered_input "test_lemma[intro,foo,elim,dest!,bar]:"
       
   573 in 
       
   574   parse (SpecParse.thm_name ":") input 
       
   575      |> fst |> snd |> (Attrib.pretty_attribs @{context}) |> (map Pretty.string_of)
       
   576 end*}
       
   577 
       
   578 text {*
       
   579   (FIXME: why is intro, elim and dest treated differently from bar?) 
       
   580 *}
       
   581 
       
   582 text {*
       
   583 @{ML_response [display,gray]
       
   584 "let
       
   585   val input = filtered_input
       
   586      (\"even and odd \" ^  
       
   587       \"where \" ^
       
   588       \"  even0[intro]: \\\"even 0\\\" \" ^ 
       
   589       \"| evenS[intro]: \\\"odd n \<Longrightarrow> even (Suc n)\\\" \" ^ 
       
   590       \"| oddS[intro]:  \\\"even n \<Longrightarrow> odd (Suc n)\\\"\")
       
   591 
       
   592   val parser = 
       
   593     OuterParse.opt_target --
       
   594     OuterParse.fixes -- 
       
   595     OuterParse.for_fixes --
       
   596     Scan.optional 
       
   597         (OuterParse.$$$ \"where\" |--
       
   598            OuterParse.!!! 
       
   599              (OuterParse.enum1 \"|\" 
       
   600                 (SpecParse.opt_thm_name \":\" -- OuterParse.prop))) []
       
   601 in
       
   602   parse parser input
       
   603 end"
       
   604 "((((NONE, [(even, NONE, NoSyn), (odd, NONE, NoSyn)]), []),
       
   605      [((even0,\<dots>), \"\\^E\\^Ftoken\\^Eeven 0\\^E\\^F\\^E\"),
       
   606       ((evenS,\<dots>), \"\\^E\\^Ftoken\\^Eodd n \<Longrightarrow> even (Suc n)\\^E\\^F\\^E\"),
       
   607       ((oddS,\<dots>), \"\\^E\\^Ftoken\\^Eeven n \<Longrightarrow> odd (Suc n)\\^E\\^F\\^E\")]), [])"}
       
   608 *}
       
   609 
       
   610 text {* 
       
   611   The (outer?) parser for the package: returns optionally a locale; 
       
   612   a list of predicate constants with optional type-annotation and 
       
   613   optional syntax-annotation; a list of for-fixes (fixed parameters); 
       
   614   and a list of rules where each rule has optionally a name and an attribute.
       
   615 *}
   550 
   616 
   551 section {* New Commands and Keyword Files *}
   617 section {* New Commands and Keyword Files *}
   552 
   618 
   553 text {*
   619 text {*
   554   Often new commands, for example for providing new definitional principles,
   620   Often new commands, for example for providing new definitional principles,
   573   The crucial function @{ML OuterSyntax.command} expects a name for the command, a
   639   The crucial function @{ML OuterSyntax.command} expects a name for the command, a
   574   short description, a kind indicator (which we will explain later on more thoroughly) and a
   640   short description, a kind indicator (which we will explain later on more thoroughly) and a
   575   parser producing a top-level transition function (its purpose will also explained
   641   parser producing a top-level transition function (its purpose will also explained
   576   later). 
   642   later). 
   577 
   643 
   578   While this is everything we have to do on the ML-level, we need a keyword
   644   While this is everything you have to do on the ML-level, you need a keyword
   579   file that can be loaded by ProofGeneral. This is to enable ProofGeneral to
   645   file that can be loaded by ProofGeneral. This is to enable ProofGeneral to
   580   recognise \isacommand{foobar} as a command. Such a keyword file can be
   646   recognise \isacommand{foobar} as a command. Such a keyword file can be
   581   generated with the command-line:
   647   generated with the command-line:
   582 
   648 
   583   @{text [display] "$ isabelle keywords -k foobar some_log_files"}
   649   @{text [display] "$ isabelle keywords -k foobar some_log_files"}
   584 
   650 
   585   The option @{text "-k foobar"} indicates which postfix the name of the keyword file 
   651   The option @{text "-k foobar"} indicates which postfix the name of the keyword file 
   586   will be assigned. In the case above the file will be named @{text
   652   will be assigned. In the case above the file will be named @{text
   587   "isar-keywords-foobar.el"}. This command requires log files to be
   653   "isar-keywords-foobar.el"}. This command requires log files to be
   588   present (in order to extract the keywords from them). To generate these log
   654   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
   655   files, you first need to package the code above into a separate theory file named
   590   @{text "Command.thy"}, say---see Figure~\ref{fig:commandtheory} for the
   656   @{text "Command.thy"}, say---see Figure~\ref{fig:commandtheory} for the
   591   complete code.
   657   complete code.
   592 
   658 
   593 
   659 
   594   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   660   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   631   
   697   
   632   The @{text "Pure-ProofGeneral"} theory needs to be compiled with
   698   The @{text "Pure-ProofGeneral"} theory needs to be compiled with
   633 
   699 
   634   @{text [display] "$ ./build -m \"Pure-ProofGeneral\" \"Pure\""}
   700   @{text [display] "$ ./build -m \"Pure-ProofGeneral\" \"Pure\""}
   635 
   701 
   636   For the theory @{text "Command.thy"}, we first create a ``managed'' subdirectory 
   702   For the theory @{text "Command.thy"}, you first need to create a ``managed'' subdirectory 
   637   with
   703   with
   638 
   704 
   639   @{text [display] "$ isabelle mkdir FoobarCommand"}
   705   @{text [display] "$ isabelle mkdir FoobarCommand"}
   640 
   706 
   641   This generates a directory containing the files 
   707   This generates a directory containing the files 
   645 ./FoobarCommand/ROOT.ML
   711 ./FoobarCommand/ROOT.ML
   646 ./FoobarCommand/document
   712 ./FoobarCommand/document
   647 ./FoobarCommand/document/root.tex"}
   713 ./FoobarCommand/document/root.tex"}
   648 
   714 
   649 
   715 
   650   We need to copy the file @{text "Command.thy"} into the directory @{text "FoobarCommand"}
   716   You need to copy the file @{text "Command.thy"} into the directory @{text "FoobarCommand"}
   651   and add the line 
   717   and add the line 
   652 
   718 
   653   @{text [display] "use_thy \"Command\";"} 
   719   @{text [display] "use_thy \"Command\";"} 
   654   
   720   
   655   to the file @{text "./FoobarCommand/ROOT.ML"}. We can now compile the theory by just typing
   721   to the file @{text "./FoobarCommand/ROOT.ML"}. You can now compile the theory by just typing
   656 
   722 
   657   @{text [display] "$ isabelle make"}
   723   @{text [display] "$ isabelle make"}
   658 
   724 
   659   We created finally all the necessary log files. They are stored 
   725   If the compilation succeeds, you have finally created all the necessary log files. 
   660   in the directory 
   726   They are stored in the directory 
   661   
   727   
   662   @{text [display]  "~/.isabelle/heaps/Isabelle2008/polyml-5.2.1_x86-linux/log"}
   728   @{text [display]  "~/.isabelle/heaps/Isabelle2008/polyml-5.2.1_x86-linux/log"}
   663 
   729 
   664   or something similar depending on your Isabelle distribution and architecture.
   730   or something similar depending on your Isabelle distribution and architecture.
   665   One quick way to assign a shell variable to this directory is by typing
   731   One quick way to assign a shell variable to this directory is by typing
   672 "Pure.gz
   738 "Pure.gz
   673 HOL.gz
   739 HOL.gz
   674 Pure-ProofGeneral.gz
   740 Pure-ProofGeneral.gz
   675 HOL-FoobarCommand.gz"} 
   741 HOL-FoobarCommand.gz"} 
   676 
   742 
   677   From them we create the keyword files. Assuming the name 
   743   From them you can create the keyword files. Assuming the name 
   678   of the directory is in  @{text "$ISABELLE_LOGS"},
   744   of the directory is in  @{text "$ISABELLE_LOGS"},
   679   then the Unix command for creating the keyword file is:
   745   then the Unix command for creating the keyword file is:
   680 
   746 
   681 @{text [display]
   747 @{text [display]
   682 "$ isabelle keywords -k foobar 
   748 "$ isabelle keywords -k foobar 
   685   The result is the file @{text "isar-keywords-foobar.el"}. It should contain
   751   The result is the file @{text "isar-keywords-foobar.el"}. It should contain
   686   the string @{text "foobar"} twice.\footnote{To see whether things are fine, check
   752   the string @{text "foobar"} twice.\footnote{To see whether things are fine, check
   687   that @{text "grep foobar"} on this file returns something
   753   that @{text "grep foobar"} on this file returns something
   688   non-empty.}  This keyword file needs to
   754   non-empty.}  This keyword file needs to
   689   be copied into the directory @{text "~/.isabelle/etc"}. To make Isabelle
   755   be copied into the directory @{text "~/.isabelle/etc"}. To make Isabelle
   690   aware of this keyword file, we have to start Isabelle with the option @{text
   756   aware of this keyword file, you have to start Isabelle with the option @{text
   691   "-k foobar"}, i.e.
   757   "-k foobar"}, i.e.
   692 
   758 
   693 
   759 
   694   @{text [display] "$ isabelle -k foobar a_theory_file"}
   760   @{text [display] "$ isabelle -k foobar a_theory_file"}
   695 
   761 
   696   If we now build a theory on top of @{text "Command.thy"}, 
   762   If you now build a theory on top of @{text "Command.thy"}, 
   697   then we can make use of the command \isacommand{foobar}. 
   763   then the command \isacommand{foobar} can be used. 
   698   Similarly with any other new command. 
   764   Similarly with any other new command. 
   699 
   765 
   700 
   766 
   701   At the moment \isacommand{foobar} is not very useful. Let us refine it a bit 
   767   At the moment \isacommand{foobar} is not very useful. Let us refine it a bit 
   702   next by taking a proposition as argument and printing this proposition inside
   768   next by taking a proposition as argument and printing this proposition inside
   708   returns the simple toplevel function @{ML "Toplevel.theory I"}. We can
   774   returns the simple toplevel function @{ML "Toplevel.theory I"}. We can
   709   replace this code by a function that first parses a proposition (using the
   775   replace this code by a function that first parses a proposition (using the
   710   parser @{ML OuterParse.prop}), then prints out the tracing
   776   parser @{ML OuterParse.prop}), then prints out the tracing
   711   information (using a new top-level function @{text trace_top_lvl}) and 
   777   information (using a new top-level function @{text trace_top_lvl}) and 
   712   finally does nothing. For this we can write
   778   finally does nothing. For this we can write
   713 
       
   714 *}
   779 *}
   715 
   780 
   716 ML{*let
   781 ML{*let
   717   fun trace_top_lvl str = 
   782   fun trace_top_lvl str = 
   718      Toplevel.theory (fn thy => (tracing str; thy))
   783      Toplevel.theory (fn thy => (tracing str; thy))
   795   \end{isabelle}
   860   \end{isabelle}
   796 
   861 
   797   Similarly for the other function composition combinators.
   862   Similarly for the other function composition combinators.
   798 
   863 
   799   
   864   
   800   (FIXME What does @{text "Toplevel.theory"} @{text "Toplevel.print"}?)
   865   (FIXME What do @{ML "Toplevel.theory"} 
       
   866   @{ML "Toplevel.print"} 
       
   867   @{ML Toplevel.local_theory}?)
       
   868 
       
   869   
   801 
   870 
   802   (FIXME read a name and show how to store theorems)
   871   (FIXME read a name and show how to store theorems)
   803 
   872 
   804   (FIXME possibly also read a locale)
   873   (FIXME possibly also read a locale)
   805 *}
   874 *}