|    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   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
|    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 | 
|    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 |