ProgTutorial/Parsing.thy
changeset 321 e450fa467e3f
parent 319 6bce4acf7f2a
child 322 2b7c08d90e2e
equal deleted inserted replaced
320:185921021551 321:e450fa467e3f
     1 theory Parsing
     1 theory Parsing
     2 imports Base "Package/Simple_Inductive_Package"
     2 imports Base "Helper/Command/Command" "Package/Simple_Inductive_Package"
     3 uses "Parsing.ML"
     3 uses "Parsing.ML"
     4 begin
     4 begin
     5 
     5 
     6 chapter {* Parsing *}
     6 chapter {* Parsing *}
     7 
     7 
     8 text {*
     8 text {*
     9 
     9   Isabelle distinguishes between \emph{outer} and \emph{inner}
    10   Isabelle distinguishes between \emph{outer} and \emph{inner} syntax. 
    10   syntax. Commands, such as \isacommand{definition}, \isacommand{inductive}
    11   Commands, such as \isacommand{definition}, \isacommand{inductive} and so
    11   and so on, belong to the outer syntax, whereas terms, types and so on belong
    12   on, belong to the outer syntax, whereas terms, types and so on belong to the 
    12   to the inner syntax. For parsing inner syntax, Isabelle uses a rather
    13   inner syntax. For parsing inner syntax, 
    13   general and sophisticated algorithm, which is driven by priority
    14   Isabelle uses a rather general and sophisticated algorithm, which 
    14   grammars. Parsers for outer syntax are built up by functional parsing
    15   is driven by priority grammars. Parsers for outer syntax are built up by functional
    15   combinators. These combinators are a well-established technique for parsing,
    16   parsing combinators. These combinators are a well-established technique for parsing, 
    16   which has, for example, been described in Paulson's classic ML-book
    17   which has, for example, been described in Paulson's classic ML-book \cite{paulson-ml2}.
    17   \cite{paulson-ml2}.  Isabelle developers are usually concerned with writing
    18   Isabelle developers are usually concerned with writing these outer syntax parsers, 
    18   these outer syntax parsers, either for new definitional packages or for
    19   either for new definitional packages or for calling methods with specific arguments. 
    19   calling methods with specific arguments.
    20 
    20 
    21   \begin{readmore}
    21   \begin{readmore}
    22   The library for writing parser combinators is split up, roughly, into two
    22   The library for writing parser combinators is split up, roughly, into two
    23   parts. The first part consists of a collection of generic parser combinators
    23   parts. The first part consists of a collection of generic parser combinators
    24   defined in the structure @{ML_struct Scan} in the file @{ML_file
    24   defined in the structure @{ML_struct Scan} in the file @{ML_file
    25   "Pure/General/scan.ML"}. The second part of the library consists of
    25   "Pure/General/scan.ML"}. The second part of the library consists of
    26   combinators for dealing with specific token types, which are defined in the
    26   combinators for dealing with specific token types, which are defined in the
    27   structure @{ML_struct OuterParse} in the file @{ML_file
    27   structure @{ML_struct OuterParse} in the file @{ML_file
    28   "Pure/Isar/outer_parse.ML"}. Specific parsers for packages are defined
    28   "Pure/Isar/outer_parse.ML"}. Specific parsers for packages are defined in
    29   in @{ML_file "Pure/Isar/spec_parse.ML"}. Parsers for method arguments
    29   @{ML_file "Pure/Isar/spec_parse.ML"}. Parsers for method arguments are
    30   are defined in @{ML_file "Pure/Isar/args.ML"}.
    30   defined in @{ML_file "Pure/Isar/args.ML"}.
    31   \end{readmore}
    31   \end{readmore}
    32 
    32 
    33 *}
    33 *}
    34 
    34 
    35 section {* Building Generic Parsers *}
    35 section {* Building Generic Parsers *}
   134 in
   134 in
   135   (hw input1, hw input2)
   135   (hw input1, hw input2)
   136 end"
   136 end"
   137   "((\"h\", [\"e\", \"l\", \"l\", \"o\"]), (\"w\", [\"o\", \"r\", \"l\", \"d\"]))"}
   137   "((\"h\", [\"e\", \"l\", \"l\", \"o\"]), (\"w\", [\"o\", \"r\", \"l\", \"d\"]))"}
   138 
   138 
   139   The functions @{ML_ind  "|--"} and @{ML_ind  "--|"} work like the sequencing function 
   139   The functions @{ML_ind "|--"} and @{ML_ind "--|"} work like the sequencing
   140   for parsers, except that they discard the item being parsed by the first (respectively second)
   140   function for parsers, except that they discard the item being parsed by the
   141   parser. For example:
   141   first (respectively second) parser. For example:
   142   
   142   
   143 @{ML_response [display,gray]
   143 @{ML_response [display,gray]
   144 "let 
   144 "let 
   145   val just_e = $$ \"h\" |-- $$ \"e\" 
   145   val just_e = $$ \"h\" |-- $$ \"e\" 
   146   val just_h = $$ \"h\" --| $$ \"e\" 
   146   val just_h = $$ \"h\" --| $$ \"e\" 
   942 @{text [display]
   942 @{text [display]
   943 "$ isabelle keywords -k foobar 
   943 "$ isabelle keywords -k foobar 
   944    $ISABELLE_LOGS/{Pure.gz,HOL.gz,Pure-ProofGeneral.gz,HOL-FoobarCommand.gz}"}
   944    $ISABELLE_LOGS/{Pure.gz,HOL.gz,Pure-ProofGeneral.gz,HOL-FoobarCommand.gz}"}
   945 
   945 
   946   The result is the file @{text "isar-keywords-foobar.el"}. It should contain
   946   The result is the file @{text "isar-keywords-foobar.el"}. It should contain
   947   the string @{text "foobar"} twice.\footnote{To see whether things are fine, check
   947   the string @{text "foobar"} twice.\footnote{To see whether things are fine,
   948   that @{text "grep foobar"} on this file returns something
   948   check that @{text "grep foobar"} on this file returns something non-empty.}
   949   non-empty.}  This keyword file needs to
   949   This keyword file needs to be copied into the directory @{text
   950   be copied into the directory @{text "~/.isabelle/etc"}. To make ProofGeneral
   950   "~/.isabelle/etc"}. To make ProofGeneral aware of it, you have to start
   951   aware of this keyword file, you have to start Isabelle with the option @{text
   951   Isabelle with the option @{text "-k foobar"}, that is:
   952   "-k foobar"}, that is:
       
   953 
   952 
   954 
   953 
   955   @{text [display] "$ isabelle emacs -k foobar a_theory_file"}
   954   @{text [display] "$ isabelle emacs -k foobar a_theory_file"}
   956 
   955 
   957   If you now build a theory on top of @{text "Command.thy"}, 
   956   If you now build a theory on top of @{text "Command.thy"}, 
   958   then the command \isacommand{foobar} can be used. 
   957   then the command \isacommand{foobar} can be used. You can just write
   959   Similarly with any other new command, and also any new keyword that is 
   958 *}
   960   introduced with
   959 
       
   960 foobar
       
   961 
       
   962 text {* 
       
   963   but you will not see any action as we chose to implement this command to do
       
   964   nothing.  A similarly procedure has to be done with any other new command, and 
       
   965   also any new keyword that is introduced with @{ML_ind OuterKeyword.keyword}.
       
   966 
   961 *}
   967 *}
   962 
   968 
   963 ML{*val _ = OuterKeyword.keyword "blink" *}
   969 ML{*val _ = OuterKeyword.keyword "blink" *}
   964 
   970 
   965 text {*
   971 text {*
   966   At the moment the command \isacommand{foobar} is not very useful. Let us refine 
   972   At the moment the command \isacommand{foobar} is not very useful. Let us
   967   it a bit 
   973   refine it a bit next by letting it take a proposition as argument and
   968   next by letting it take a proposition as argument and printing this proposition 
   974   printing this proposition inside the tracing buffer.
   969   inside the tracing buffer. 
       
   970 
   975 
   971   The crucial part of a command is the function that determines the behaviour
   976   The crucial part of a command is the function that determines the behaviour
   972   of the command. In the code above we used a ``do-nothing''-function, which
   977   of the command. In the code above we used a ``do-nothing''-function, which
   973   because of @{ML_ind  succeed in Scan} does not parse any argument, but immediately
   978   because of @{ML_ind  succeed in Scan} does not parse any argument, but immediately
   974   returns the simple function @{ML "LocalTheory.theory I"}. We can
   979   returns the simple function @{ML "LocalTheory.theory I"}. We can
   983      LocalTheory.theory (fn lthy => (tracing str; lthy))
   988      LocalTheory.theory (fn lthy => (tracing str; lthy))
   984 
   989 
   985   val trace_prop_parser = OuterParse.prop >> trace_prop
   990   val trace_prop_parser = OuterParse.prop >> trace_prop
   986   val kind = OuterKeyword.thy_decl
   991   val kind = OuterKeyword.thy_decl
   987 in
   992 in
   988   OuterSyntax.local_theory "foobar" "traces a proposition" 
   993   OuterSyntax.local_theory "foobar_trace" "traces a proposition" 
   989     kind trace_prop_parser
   994     kind trace_prop_parser
   990 end *}
   995 end *}
   991 
   996 
   992 
   997 text {*
   993 text {*
   998   The command is now \isacommand{foobar\_trace} and can be used to 
   994   Now you can type
   999   see the proposition in the tracing buffer.  
   995 
  1000 *}
   996   \begin{isabelle}
  1001 
   997   \isacommand{foobar}~@{text [quotes] "True \<and> False"}\\
  1002 foobar_trace "True \<and> False"
   998   @{text "> \"True \<and> False\""}
  1003 
   999   \end{isabelle}
  1004 text {*
  1000   
       
  1001   and see the proposition in the tracing buffer.  
       
  1002 
       
  1003   Note that so far we used @{ML_ind  thy_decl in OuterKeyword} as the kind
  1005   Note that so far we used @{ML_ind  thy_decl in OuterKeyword} as the kind
  1004   indicator for the command.  This means that the command finishes as soon as
  1006   indicator for the command.  This means that the command finishes as soon as
  1005   the arguments are processed. Examples of this kind of commands are
  1007   the arguments are processed. Examples of this kind of commands are
  1006   \isacommand{definition} and \isacommand{declare}.  In other cases, commands
  1008   \isacommand{definition} and \isacommand{declare}.  In other cases, commands
  1007   are expected to parse some arguments, for example a proposition, and then
  1009   are expected to parse some arguments, for example a proposition, and then
  1012   "local_theory_to_proof" in OuterSyntax} to set up the command.  Note,
  1014   "local_theory_to_proof" in OuterSyntax} to set up the command.  Note,
  1013   however, once you change the ``kind'' of a command from @{ML thy_decl in
  1015   however, once you change the ``kind'' of a command from @{ML thy_decl in
  1014   OuterKeyword} to @{ML thy_goal in OuterKeyword} then the keyword file needs
  1016   OuterKeyword} to @{ML thy_goal in OuterKeyword} then the keyword file needs
  1015   to be re-created!
  1017   to be re-created!
  1016 
  1018 
  1017   Below we change \isacommand{foobar} so that it takes a proposition as
  1019   Below we change \isacommand{foobar\_trace} so that it takes a proposition as
  1018   argument and then starts a proof in order to prove it. Therefore in Line 13, 
  1020   argument and then starts a proof in order to prove it. Therefore in Line 13, 
  1019   we set the kind indicator to @{ML thy_goal in OuterKeyword}.
  1021   we set the kind indicator to @{ML thy_goal in OuterKeyword}.
  1020 *}
  1022 *}
  1021 
  1023 
  1022 ML%linenosgray{*let
  1024 ML%linenosgray{*let
  1028     end;
  1030     end;
  1029   
  1031   
  1030   val prove_prop_parser = OuterParse.prop >> prove_prop 
  1032   val prove_prop_parser = OuterParse.prop >> prove_prop 
  1031   val kind = OuterKeyword.thy_goal
  1033   val kind = OuterKeyword.thy_goal
  1032 in
  1034 in
  1033   OuterSyntax.local_theory_to_proof "foobar" "proving a proposition" 
  1035   OuterSyntax.local_theory_to_proof "foobar_goal" "proving a proposition" 
  1034     kind prove_prop_parser
  1036     kind prove_prop_parser
  1035 end *}
  1037 end *}
  1036 
  1038 
  1037 text {*
  1039 text {*
  1038   The function @{text prove_prop} in Lines 2 to 7 takes a string (the proposition to be
  1040   The function @{text prove_prop} in Lines 2 to 7 takes a string (the proposition to be
  1042   proposition. Its argument @{ML NONE} stands for a locale (which we chose to
  1044   proposition. Its argument @{ML NONE} stands for a locale (which we chose to
  1043   omit); the argument @{ML "(K I)"} stands for a function that determines what
  1045   omit); the argument @{ML "(K I)"} stands for a function that determines what
  1044   should be done with the theorem once it is proved (we chose to just forget
  1046   should be done with the theorem once it is proved (we chose to just forget
  1045   about it). Line 9 contains the parser for the proposition.
  1047   about it). Line 9 contains the parser for the proposition.
  1046 
  1048 
  1047   If you now type \isacommand{foobar}~@{text [quotes] "True \<and> True"}, you obtain the following 
  1049   If you now type \isacommand{foobar\_goal}~@{text [quotes] "True \<and> True"},
  1048   proof state
  1050   you obtain the following proof state
  1049 
  1051 *}
  1050   \begin{isabelle}
  1052 
  1051   \isacommand{foobar}~@{text [quotes] "True \<and> True"}\\
  1053 foobar_goal "True \<and> True"
  1052   @{text "goal (1 subgoal):"}\\
  1054 txt {*
  1053   @{text "1. True \<and> True"}
  1055   \begin{minipage}{\textwidth}
  1054   \end{isabelle}
  1056   @{subgoals [display]}
  1055 
  1057   \end{minipage}\medskip
  1056   and you can build the following proof
  1058 
  1057 
  1059   and can prove the proposition as follows.
  1058   \begin{isabelle}
  1060 *}
  1059   \isacommand{foobar}~@{text [quotes] "True \<and> True"}\\
  1061 apply(rule conjI)
  1060   \isacommand{apply}@{text "(rule conjI)"}\\
  1062 apply(rule TrueI)+
  1061   \isacommand{apply}@{text "(rule TrueI)+"}\\
  1063 done
  1062   \isacommand{done}
  1064 
  1063   \end{isabelle}
  1065 text {*
  1064 
  1066 
  1065   (FIXME: read a name and show how to store theorems; see @{ML_ind  note in LocalTheory})
  1067   (FIXME: read a name and show how to store theorems; see @{ML_ind  note in LocalTheory})
  1066   
  1068   
  1067 *}
  1069 *}
       
  1070 
       
  1071 ML_val{*val r = ref (NONE:(unit -> term) option)*}
       
  1072 ML{*let
       
  1073    fun setup_proof (txt, pos) lthy =
       
  1074    let
       
  1075      val trm = ML_Context.evaluate lthy true ("r", r) txt
       
  1076    in
       
  1077        Proof.theorem_i NONE (K I) [[(trm,[])]] lthy
       
  1078    end;
       
  1079 
       
  1080    val setup_proof_parser = OuterParse.ML_source >> setup_proof
       
  1081         
       
  1082    val kind = OuterKeyword.thy_goal
       
  1083 in
       
  1084    OuterSyntax.local_theory_to_proof "foobar_prove" "proving a proposition" 
       
  1085     kind setup_proof_parser
       
  1086 end*}
       
  1087 
       
  1088 foobar_prove {* @{prop "True"} *}
       
  1089 apply(rule TrueI)
       
  1090 done
  1068 
  1091 
  1069 
  1092 
  1070 
  1093 
  1071 
  1094 
  1072 section {* Methods (TBD) *}
  1095 section {* Methods (TBD) *}