CookBook/Parsing.thy
changeset 69 19106a9975c1
parent 68 e7519207c2b7
child 72 7b8c4fe235aa
equal deleted inserted replaced
68:e7519207c2b7 69:19106a9975c1
   200   Let us now return to our example of parsing @{ML "(p -- q) || r" for p q r}. If we want
   200   Let us now return to our example of parsing @{ML "(p -- q) || r" for p q r}. If we want
   201   to generate the correct error message for p-followed-by-q, then
   201   to generate the correct error message for p-followed-by-q, then
   202   we have to write:
   202   we have to write:
   203 *}
   203 *}
   204 
   204 
   205 ML {* 
   205 ML{*fun p_followed_by_q p q r =
   206 fun p_followed_by_q p q r =
       
   207   let 
   206   let 
   208      val err_msg = (fn _ => p ^ " is not followed by " ^ q)
   207      val err_msg = (fn _ => p ^ " is not followed by " ^ q)
   209   in
   208   in
   210     ($$ p -- (!! err_msg ($$ q))) || ($$ r -- $$ r)
   209     ($$ p -- (!! err_msg ($$ q))) || ($$ r -- $$ r)
   211   end
   210   end *}
   212 *}
       
   213 
   211 
   214 
   212 
   215 text {*
   213 text {*
   216   Running this parser with the @{text [quotes] "h"} and @{text [quotes] "e"}, and 
   214   Running this parser with the @{text [quotes] "h"} and @{text [quotes] "e"}, and 
   217   the input @{text [quotes] "holle"} 
   215   the input @{text [quotes] "holle"} 
   393 
   391 
   394   For convenience we define the function
   392   For convenience we define the function
   395 
   393 
   396 *}
   394 *}
   397 
   395 
   398 ML {* 
   396 ML{*fun filtered_input str = 
   399 fun filtered_input str = 
   397        filter OuterLex.is_proper (OuterSyntax.scan Position.none str) *}
   400        filter OuterLex.is_proper (OuterSyntax.scan Position.none str) 
       
   401 *}
       
   402 
   398 
   403 text {*
   399 text {*
   404 
   400 
   405   If we parse
   401   If we parse
   406 
   402 
   475 
   471 
   476   The following function will help us later to run examples
   472   The following function will help us later to run examples
   477 
   473 
   478 *}
   474 *}
   479 
   475 
   480 ML {*
   476 ML{*fun parse p input = Scan.finite OuterLex.stopper (Scan.error p) input *}
   481 fun parse p input = Scan.finite OuterLex.stopper (Scan.error p) input
       
   482 *}
       
   483 
   477 
   484 text {*
   478 text {*
   485 
   479 
   486   The function @{ML "OuterParse.!!!"} can be used to force termination of the
   480   The function @{ML "OuterParse.!!!"} can be used to force termination of the
   487   parser in case of a dead end, just like @{ML "Scan.!!"} (see previous section), 
   481   parser in case of a dead end, just like @{ML "Scan.!!"} (see previous section), 
   518 
   512 
   519   @{ML OuterParse.position}
   513   @{ML OuterParse.position}
   520 
   514 
   521 *}
   515 *}
   522 
   516 
   523 ML {*
   517 ML{*
   524   OuterParse.position
   518   OuterParse.position
   525 *}
   519 *}
   526 
   520 
   527 
   521 
   528 section {* Parsing Inner Syntax *}
   522 section {* Parsing Inner Syntax *}
   529 
   523 
   530 ML {*
   524 ML{*
   531 let 
   525 let 
   532   val input = OuterSyntax.scan Position.none "0"
   526   val input = OuterSyntax.scan Position.none "0"
   533 in 
   527 in 
   534   OuterParse.prop input
   528   OuterParse.prop input
   535 end 
   529 end 
   536 
   530 
   537 *}
   531 *}
   538 
   532 
   539 ML {*
   533 ML{*
   540   OuterParse.opt_target
   534   OuterParse.opt_target
   541 *}
   535 *}
   542 
   536 
   543 text {* (FIXME funny output for a proposition) *}
   537 text {* (FIXME funny output for a proposition) *}
   544 
   538 
   545 ML {*
   539 ML{*
   546   OuterParse.opt_target --
   540   OuterParse.opt_target --
   547   OuterParse.fixes -- 
   541   OuterParse.fixes -- 
   548   OuterParse.for_fixes --
   542   OuterParse.for_fixes --
   549   Scan.optional (OuterParse.$$$ "where" |--
   543   Scan.optional (OuterParse.$$$ "where" |--
   550     OuterParse.!!! (OuterParse.enum1 "|" (SpecParse.opt_thm_name ":" -- OuterParse.prop))) []
   544     OuterParse.!!! (OuterParse.enum1 "|" (SpecParse.opt_thm_name ":" -- OuterParse.prop))) []
   551 
   545 
   552 *}
   546 *}
   553 
   547 
   554 ML {* OuterSyntax.command *}
   548 ML{* OuterSyntax.command *}
   555 
   549 
   556 section {* New Commands and Creating Keyword Files *}
   550 section {* New Commands and Creating Keyword Files *}
   557 
   551 
   558 text {*
   552 text {*
   559   Often new commands, for example for providing new definitional principles,
   553   Often new commands, for example for providing new definitional principles,
   564 
   558 
   565   Let us start with a ``silly'' command, which we call \isacommand{foobar} in what follows.
   559   Let us start with a ``silly'' command, which we call \isacommand{foobar} in what follows.
   566   To keep things simple this command does nothing at all. On the ML-level it can be defined as
   560   To keep things simple this command does nothing at all. On the ML-level it can be defined as
   567 *}
   561 *}
   568 
   562 
   569 ML {* 
   563 ML{*let
   570 let
       
   571   val do_nothing = Scan.succeed (Toplevel.theory I)
   564   val do_nothing = Scan.succeed (Toplevel.theory I)
   572   val kind = OuterKeyword.thy_decl
   565   val kind = OuterKeyword.thy_decl
   573 in
   566 in
   574   OuterSyntax.command "foobar" "description of foobar" kind do_nothing
   567   OuterSyntax.command "foobar" "description of foobar" kind do_nothing
   575 end 
   568 end *}
   576 *}
       
   577 
   569 
   578 text {*
   570 text {*
   579   The function @{ML OuterSyntax.command} expects a name for the command, a
   571   The function @{ML OuterSyntax.command} expects a name for the command, a
   580   short description, a kind indicator (which we will explain later on more thoroughly) and a
   572   short description, a kind indicator (which we will explain later on more thoroughly) and a
   581   parser for a top-level transition function (its purpose will also explained
   573   parser for a top-level transition function (its purpose will also explained
   598   complete code.
   590   complete code.
   599 
   591 
   600 
   592 
   601   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   593   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   602   \begin{figure}[t]
   594   \begin{figure}[t]
   603   \begin{boxedminipage}{\textwidth}\small
   595   \begin{graybox}\small
   604   \isacommand{theory}~@{text Command}\\
   596   \isacommand{theory}~@{text Command}\\
   605   \isacommand{imports}~@{text Main}\\
   597   \isacommand{imports}~@{text Main}\\
   606   \isacommand{begin}\\
   598   \isacommand{begin}\\
   607   \isacommand{ML}~\isa{\isacharverbatimopen}\\
   599   \isacommand{ML}~\isa{\isacharverbatimopen}\\
   608   @{ML
   600   @{ML
   612 in
   604 in
   613   OuterSyntax.command \"foobar\" \"description of foobar\" kind do_nothing
   605   OuterSyntax.command \"foobar\" \"description of foobar\" kind do_nothing
   614 end"}\\
   606 end"}\\
   615   \isa{\isacharverbatimclose}\\
   607   \isa{\isacharverbatimclose}\\
   616   \isacommand{end}
   608   \isacommand{end}
   617   \end{boxedminipage}
   609   \end{graybox}
   618   \caption{The file @{text "Command.thy"} is necessary for generating a log 
   610   \caption{The file @{text "Command.thy"} is necessary for generating a log 
   619   file. This log file enables Isabelle to generate a keyword file containing 
   611   file. This log file enables Isabelle to generate a keyword file containing 
   620   the command \isacommand{foobar}.\label{fig:commandtheory}}
   612   the command \isacommand{foobar}.\label{fig:commandtheory}}
   621   \end{figure}
   613   \end{figure}
   622   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   614   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   696   @{text [display] "$ isabelle -k foobar a-theory-file"}
   688   @{text [display] "$ isabelle -k foobar a-theory-file"}
   697 
   689 
   698   If we now run the original code
   690   If we now run the original code
   699 *}
   691 *}
   700 
   692 
   701 ML {*
   693 ML{*let
   702 let
       
   703   val do_nothing = Scan.succeed (Toplevel.theory I)
   694   val do_nothing = Scan.succeed (Toplevel.theory I)
   704   val kind = OuterKeyword.thy_decl
   695   val kind = OuterKeyword.thy_decl
   705 in
   696 in
   706   OuterSyntax.command "foobar" "description of foobar" kind do_nothing
   697   OuterSyntax.command "foobar" "description of foobar" kind do_nothing
   707 end 
   698 end *}
   708 *}
       
   709 
   699 
   710 text {*
   700 text {*
   711   then we can make use of \isacommand{foobar}! Similarly with any other new command. 
   701   then we can make use of \isacommand{foobar}! Similarly with any other new command. 
   712 
   702 
   713   In the example above, we built the theories on top of the HOL-logic. If you
   703   In the example above, we built the theories on top of the HOL-logic. If you
   725   @{ML "Toplevel.theory I"}. We can replace this code by a function that first 
   715   @{ML "Toplevel.theory I"}. We can replace this code by a function that first 
   726   parses a proposition (using the parser @{ML OuterParse.prop}), then prints out 
   716   parses a proposition (using the parser @{ML OuterParse.prop}), then prints out 
   727   the tracing information and finally does nothing. For this we can write
   717   the tracing information and finally does nothing. For this we can write
   728 *}
   718 *}
   729 
   719 
   730 ML {* 
   720 ML{*let
   731 let
       
   732   val trace_prop = 
   721   val trace_prop = 
   733          OuterParse.prop >> (fn str => (tracing str; (Toplevel.theory I)))
   722          OuterParse.prop >> (fn str => (tracing str; (Toplevel.theory I)))
   734   val kind = OuterKeyword.thy_decl
   723   val kind = OuterKeyword.thy_decl
   735 in
   724 in
   736   OuterSyntax.command "foobar" "traces a proposition" kind trace_prop
   725   OuterSyntax.command "foobar" "traces a proposition" kind trace_prop
   737 end 
   726 end *}
   738 *}
       
   739 
   727 
   740 text {*
   728 text {*
   741   Now we can type for example
   729   Now we can type for example
   742 
   730 
   743   @{ML_response_fake_both [display] "foobar \"True \<and> False\"" "True \<and> False"}
   731   @{ML_response_fake_both [display] "foobar \"True \<and> False\"" "True \<and> False"}
   757   Below we change \isacommand{foobar} is such a way that an proposition as
   745   Below we change \isacommand{foobar} is such a way that an proposition as
   758   argument and then start a proof in order to prove it. Therefore in Line 13
   746   argument and then start a proof in order to prove it. Therefore in Line 13
   759   below, we set the kind indicator to @{ML thy_goal in OuterKeyword}.
   747   below, we set the kind indicator to @{ML thy_goal in OuterKeyword}.
   760 *}
   748 *}
   761 
   749 
   762 ML %linenumbers {*let
   750 ML%linenumbers{*let
   763   fun set_up_thm str ctxt =
   751   fun set_up_thm str ctxt =
   764     let
   752     let
   765       val prop = Syntax.read_prop ctxt str
   753       val prop = Syntax.read_prop ctxt str
   766     in
   754     in
   767       Proof.theorem_i NONE (K I) [[(Syntax.read_prop ctxt str,[])]] ctxt
   755       Proof.theorem_i NONE (K I) [[(Syntax.read_prop ctxt str,[])]] ctxt
   772                     Toplevel.local_theory_to_proof NONE (set_up_thm str))
   760                     Toplevel.local_theory_to_proof NONE (set_up_thm str))
   773   
   761   
   774   val kind = OuterKeyword.thy_goal
   762   val kind = OuterKeyword.thy_goal
   775 in
   763 in
   776   OuterSyntax.command "foobar" "proving a proposition" kind prove_prop
   764   OuterSyntax.command "foobar" "proving a proposition" kind prove_prop
   777 end 
   765 end *}
   778 *}
       
   779 
   766 
   780 text {*
   767 text {*
   781   The function @{text set_up_thm} takes a string (the proposition) and a context.
   768   The function @{text set_up_thm} takes a string (the proposition) and a context.
   782   The context is necessary in order to convert the string into a proper proposition
   769   The context is necessary in order to convert the string into a proper proposition
   783   using the function @{ML Syntax.read_prop}. In Line 6 we use the function
   770   using the function @{ML Syntax.read_prop}. In Line 6 we use the function
  1032 *}
  1019 *}
  1033 
  1020 
  1034 
  1021 
  1035 
  1022 
  1036 
  1023 
  1037 ML {*
  1024 ML{*
  1038   val toks = OuterSyntax.scan Position.none
  1025   val toks = OuterSyntax.scan Position.none
  1039    "theory,imports;begin x.y.z apply ?v1 ?'a 'a -- || 44 simp (* xx *) { * fff * }" ;
  1026    "theory,imports;begin x.y.z apply ?v1 ?'a 'a -- || 44 simp (* xx *) { * fff * }" ;
  1040 *}
  1027 *}
  1041 
  1028 
  1042 ML {*
  1029 ML{*
  1043   print_depth 20 ;
  1030   print_depth 20 ;
  1044 *}
  1031 *}
  1045 
  1032 
  1046 ML {*
  1033 ML{*
  1047   map OuterLex.text_of toks ;
  1034   map OuterLex.text_of toks ;
  1048 *}
  1035 *}
  1049 
  1036 
  1050 ML {*
  1037 ML{*
  1051   val proper_toks = filter OuterLex.is_proper toks ;
  1038   val proper_toks = filter OuterLex.is_proper toks ;
  1052 *}  
  1039 *}  
  1053 
  1040 
  1054 ML {*
  1041 ML{*
  1055   map OuterLex.kind_of proper_toks 
  1042   map OuterLex.kind_of proper_toks 
  1056 *}
  1043 *}
  1057 
  1044 
  1058 ML {*
  1045 ML{*
  1059   map OuterLex.unparse proper_toks ;
  1046   map OuterLex.unparse proper_toks ;
  1060 *}
  1047 *}
  1061 
  1048 
  1062 ML {*
  1049 ML{*
  1063   OuterLex.stopper
  1050   OuterLex.stopper
  1064 *}
  1051 *}
  1065 
  1052 
  1066 text {*
  1053 text {*
  1067 
  1054