|     67  |     67  | 
|     68   The function @{ML \<open>$$\<close>} will either succeed (as in the two examples above) |     68   The function @{ML \<open>$$\<close>} will either succeed (as in the two examples above) | 
|     69   or raise the exception \<open>FAIL\<close> if no string can be consumed. For |     69   or raise the exception \<open>FAIL\<close> if no string can be consumed. For | 
|     70   example trying to parse |     70   example trying to parse | 
|     71  |     71  | 
|     72   @{ML_matchresult_fake [display,gray]  |     72   @{ML_response [display,gray]  | 
|     73   \<open>($$ "x") (Symbol.explode "world")\<close>  |     73   \<open>($$ "x") (Symbol.explode "world")\<close>  | 
|     74   \<open>Exception FAIL raised\<close>} |     74   \<open>exception FAIL NONE raised\<close>} | 
|     75    |     75    | 
|     76   will raise the exception \<open>FAIL\<close>. The function @{ML_ind "$$" in Scan} will also |     76   will raise the exception \<open>FAIL\<close>. The function @{ML_ind "$$" in Scan} will also | 
|     77   fail if you try to consume more than a single character. |     77   fail if you try to consume more than a single character. | 
|     78  |     78  | 
|     79   There are three exceptions that are raised by the parsing combinators: |     79   There are three exceptions that are raised by the parsing combinators: | 
|     95   @{ML_ind explode in String}, for obtaining an input list for the parser. The reason is |     95   @{ML_ind explode in String}, for obtaining an input list for the parser. The reason is | 
|     96   that @{ML explode in Symbol} is aware of character |     96   that @{ML explode in Symbol} is aware of character | 
|     97   sequences, for example \<open>\<foo>\<close>, that have a special meaning in |     97   sequences, for example \<open>\<foo>\<close>, that have a special meaning in | 
|     98   Isabelle. To see the difference consider |     98   Isabelle. To see the difference consider | 
|     99  |     99  | 
|    100 @{ML_matchresult_fake [display,gray] |    100 @{ML_matchresult [display,gray] | 
|    101 \<open>let  |    101 \<open>String.explode "\<foo> bar"\<close> | 
|    102   val input = "\<foo> bar" |    102 \<open>[#"\\", #"<", #"f", #"o", #"o", #">", #" ", #"b", #"a", #"r"]\<close>} | 
|    103 in |    103  | 
|    104   (String.explode input, Symbol.explode input) |    104 @{ML_matchresult [display,gray] | 
|    105 end\<close> |    105 \<open>Symbol.explode "\<foo> bar"\<close> | 
|    106 \<open>(["\\", "<", "f", "o", "o", ">", " ", "b", "a", "r"], |    106 \<open>["\<foo>", " ", "b", "a", "r"]\<close>} | 
|    107  ["\<foo>", " ", "b", "a", "r"])\<close>} |         | 
|    108  |    107  | 
|    109   Slightly more general than the parser @{ML \<open>$$\<close>} is the function  |    108   Slightly more general than the parser @{ML \<open>$$\<close>} is the function  | 
|    110   @{ML_ind one in Scan}, in that it takes a predicate as argument and  |    109   @{ML_ind one in Scan}, in that it takes a predicate as argument and  | 
|    111   then parses exactly |    110   then parses exactly | 
|    112   one item from the input list satisfying this predicate. For example the |    111   one item from the input list satisfying this predicate. For example the | 
|    234   \<open>(!! (fn _ => fn _ => "foo") ($$ "h")) (Symbol.explode "hello")\<close>  |    233   \<open>(!! (fn _ => fn _ => "foo") ($$ "h")) (Symbol.explode "hello")\<close>  | 
|    235   \<open>("h", ["e", "l", "l", "o"])\<close>} |    234   \<open>("h", ["e", "l", "l", "o"])\<close>} | 
|    236  |    235  | 
|    237   but if you invoke it on @{text [quotes] "world"} |    236   but if you invoke it on @{text [quotes] "world"} | 
|    238  |    237  | 
|    239   @{ML_matchresult_fake [display,gray] \<open>(!! (fn _ => fn _ => "foo") ($$ "h")) (Symbol.explode "world")\<close> |    238   @{ML_response [display,gray] \<open>(!! (fn _ => fn _ => "foo") ($$ "h")) (Symbol.explode "world")\<close> | 
|    240                                \<open>Exception ABORT raised\<close>} |    239                                \<open>exception ABORT fn raised\<close>} | 
|    241  |    240  | 
|    242   then the parsing aborts and the error message \<open>foo\<close> is printed. In order to |    241   then the parsing aborts and the error message \<open>foo\<close> is printed. In order to | 
|    243   see the error message properly, you need to prefix the parser with the function  |    242   see the error message properly, you need to prefix the parser with the function  | 
|    244   @{ML_ind error in Scan}. For example: |    243   @{ML_ind error in Scan}. For example: | 
|    245  |    244  | 
|    246   @{ML_matchresult_fake [display,gray]  |    245   @{ML_response [display,gray]  | 
|    247   \<open>Scan.error (!! (fn _ => fn _ => "foo") ($$ "h")) (Symbol.explode "world")\<close> |    246   \<open>Scan.error (!! (fn _ => fn _ => "foo") ($$ "h")) (Symbol.explode "world")\<close> | 
|    248   \<open>Exception Error "foo" raised\<close>} |    247   \<open>foo\<close>} | 
|    249  |    248  | 
|    250   This kind of ``prefixing'' to see the correct error message is usually done by wrappers  |    249   This kind of ``prefixing'' to see the correct error message is usually done by wrappers  | 
|    251   such as @{ML_ind local_theory in Outer_Syntax}  |    250   such as @{ML_ind local_theory in Outer_Syntax}  | 
|    252   (see Section~\ref{sec:newcommand} which explains this function in more detail).  |    251   (see Section~\ref{sec:newcommand} which explains this function in more detail).  | 
|    253    |    252    | 
|    267 text \<open> |    266 text \<open> | 
|    268   Running this parser with the arguments |    267   Running this parser with the arguments | 
|    269   @{text [quotes] "h"}, @{text [quotes] "e"} and @{text [quotes] "w"}, and  |    268   @{text [quotes] "h"}, @{text [quotes] "e"} and @{text [quotes] "w"}, and  | 
|    270   the input @{text [quotes] "holle"}  |    269   the input @{text [quotes] "holle"}  | 
|    271  |    270  | 
|    272   @{ML_matchresult_fake [display,gray] \<open>Scan.error (p_followed_by_q "h" "e" "w") (Symbol.explode "holle")\<close> |    271   @{ML_response [display,gray] \<open>Scan.error (p_followed_by_q "h" "e" "w") (Symbol.explode "holle")\<close> | 
|    273                                \<open>Exception ERROR "h is not followed by e" raised\<close>}  |    272                                \<open>h is not followed by e\<close>}  | 
|    274  |    273  | 
|    275   produces the correct error message. Running it with |    274   produces the correct error message. Running it with | 
|    276   |    275   | 
|    277   @{ML_matchresult [display,gray] \<open>Scan.error (p_followed_by_q "h" "e" "w") (Symbol.explode "wworld")\<close> |    276   @{ML_matchresult [display,gray] \<open>Scan.error (p_followed_by_q "h" "e" "w") (Symbol.explode "wworld")\<close> | 
|    278                           \<open>(("w", "w"), ["o", "r", "l", "d"])\<close>} |    277                           \<open>(("w", "w"), ["o", "r", "l", "d"])\<close>} | 
|    316   where the function @{ML_ind not_eof in Symbol} ensures that we do not read beyond the  |    315   where the function @{ML_ind not_eof in Symbol} ensures that we do not read beyond the  | 
|    317   end of the input string (i.e.~stopper symbol). |    316   end of the input string (i.e.~stopper symbol). | 
|    318  |    317  | 
|    319   The function @{ML_ind unless in Scan} takes two parsers: if the first one can  |    318   The function @{ML_ind unless in Scan} takes two parsers: if the first one can  | 
|    320   parse the input, then the whole parser fails; if not, then the second is tried. Therefore |    319   parse the input, then the whole parser fails; if not, then the second is tried. Therefore | 
|    321    |    320  | 
|    322   @{ML_matchresult_fake_both [display,gray] \<open>Scan.unless ($$ "h") ($$ "w") (Symbol.explode "hello")\<close> |    321   @{ML_response [display,gray] \<open>Scan.unless ($$ "h") ($$ "w") (Symbol.explode "hello")\<close> | 
|    323                                \<open>Exception FAIL raised\<close>} |    322                                "exception FAIL NONE raised"} | 
|    324  |    323  | 
|    325   fails, while |    324   fails, while | 
|    326  |    325  | 
|    327   @{ML_matchresult [display,gray] \<open>Scan.unless ($$ "h") ($$ "w") (Symbol.explode "world")\<close> |    326   @{ML_matchresult [display,gray] \<open>Scan.unless ($$ "h") ($$ "w") (Symbol.explode "world")\<close> | 
|    328                           \<open>("w",["o", "r", "l", "d"])\<close>} |    327                           \<open>("w",["o", "r", "l", "d"])\<close>} | 
|    499   @{ML \<open>Position.none\<close>} since, |    498   @{ML \<open>Position.none\<close>} since, | 
|    500   at the moment, we are not interested in generating precise error |    499   at the moment, we are not interested in generating precise error | 
|    501   messages. The following code |    500   messages. The following code | 
|    502  |    501  | 
|    503  |    502  | 
|    504 @{ML_matchresult_fake [display,gray] \<open>Token.explode  |    503 @{ML_response [display,gray] \<open>Token.explode  | 
|    505   (Thy_Header.get_keywords' @{context}) Position.none "hello world"\<close> |    504   (Thy_Header.get_keywords' @{context}) Position.none "hello world"\<close> | 
|    506 \<open>[Token (_,(Ident, "hello"),_),  |    505 \<open>[Token (\<dots>(Ident, "hello"),\<dots>),  | 
|    507  Token (_,(Space, " "),_),  |    506  Token (\<dots>(Space, " "),\<dots>),  | 
|    508  Token (_,(Ident, "world"),_)]\<close>} |    507  Token (\<dots>(Ident, "world"),\<dots>)]\<close>} | 
|    509  |    508  | 
|    510   produces three tokens where the first and the last are identifiers, since |    509   produces three tokens where the first and the last are identifiers, since | 
|    511   @{text [quotes] "hello"} and @{text [quotes] "world"} do not match any |    510   @{text [quotes] "hello"} and @{text [quotes] "world"} do not match any | 
|    512   other syntactic category. The second indicates a space. |    511   other syntactic category. The second indicates a space. | 
|    513  |    512  | 
|    521  |    520  | 
|    522  |    521  | 
|    523 text \<open> |    522 text \<open> | 
|    524   then lexing @{text [quotes] "hello world"} will produce |    523   then lexing @{text [quotes] "hello world"} will produce | 
|    525  |    524  | 
|    526   @{ML_matchresult_fake [display,gray] \<open>Token.explode  |    525   @{ML_response [display,gray] \<open>Token.explode | 
|    527   (Thy_Header.get_keywords' @{context}) Position.none "hello world"\<close>  |    526   (Thy_Header.get_keywords' @{context}) Position.none "hello world"\<close>  | 
|    528 \<open>[Token (_,(Keyword, "hello"),_),  |    527 \<open>[Token (\<dots>(Keyword, "hello"),\<dots>),  | 
|    529  Token (_,(Space, " "),_),  |    528  Token (\<dots>(Space, " "),\<dots>),  | 
|    530  Token (_,(Ident, "world"),_)]\<close>} |    529  Token (\<dots>(Ident, "world"),\<dots>)]\<close>} | 
|    531  |    530  | 
|    532   Many parsing functions later on will require white space, comments and the like |    531   Many parsing functions later on will require white space, comments and the like | 
|    533   to have already been filtered out.  So from now on we are going to use the  |    532   to have already been filtered out.  So from now on we are going to use the  | 
|    534   functions @{ML filter} and @{ML_ind is_proper in Token} to do this.  |    533   functions @{ML filter} and @{ML_ind is_proper in Token} to do this.  | 
|    535   For example: |    534   For example: | 
|    536  |    535  | 
|    537 @{ML_matchresult_fake [display,gray] |    536 @{ML_response [display,gray] | 
|    538 \<open>let |    537 \<open>let | 
|    539    val input = Token.explode (Thy_Header.get_keywords' @{context}) Position.none "hello world" |    538    val input = Token.explode (Thy_Header.get_keywords' @{context}) Position.none "hello world" | 
|    540 in |    539 in | 
|    541    filter Token.is_proper input |    540    filter Token.is_proper input | 
|    542 end\<close>  |    541 end\<close>  | 
|    543 \<open>[Token (_,(Ident, "hello"), _), Token (_,(Ident, "world"), _)]\<close>} |    542 \<open>[Token (\<dots>(Keyword, "hello"), \<dots>), Token (\<dots>(Ident, "world"), \<dots>)]\<close>} | 
|    544  |    543  | 
|    545   For convenience we define the function: |    544   For convenience we define the function: | 
|    546 \<close> |    545 \<close> | 
|    547  |    546  | 
|    548 ML %grayML\<open>fun filtered_input str =  |    547 ML %grayML\<open>fun filtered_input str =  | 
|    550  |    549  | 
|    551 ML \<open>filtered_input "inductive | for"\<close> |    550 ML \<open>filtered_input "inductive | for"\<close> | 
|    552 text \<open> |    551 text \<open> | 
|    553   If you now parse |    552   If you now parse | 
|    554  |    553  | 
|    555 @{ML_matchresult_fake [display,gray]  |    554 @{ML_response [display,gray]  | 
|    556 \<open>filtered_input "inductive | for"\<close>  |    555 \<open>filtered_input "inductive | for"\<close>  | 
|    557 \<open>[Token (_,(Command, "inductive"),_),  |    556 \<open>[Token (\<dots>(Command, "inductive"),\<dots>),  | 
|    558  Token (_,(Keyword, "|"),_),  |    557  Token (\<dots>(Keyword, "|"),\<dots>),  | 
|    559  Token (_,(Keyword, "for"),_)]\<close>} |    558  Token (\<dots>(Keyword, "for"),\<dots>)]\<close>} | 
|    560  |    559  | 
|    561   you obtain a list consisting of only one command and two keyword tokens. |    560   you obtain a list consisting of only one command and two keyword tokens. | 
|    562   If you want to see which keywords and commands are currently known to Isabelle,  |    561   If you want to see which keywords and commands are currently known to Isabelle,  | 
|    563   use the function @{ML_ind get_keywords' in Thy_Header}: |    562   use the function @{ML_ind get_keywords' in Thy_Header}: | 
|    564  |    563  | 
|    635   The function @{ML_ind "!!!" in Parse} can be used to force termination |    634   The function @{ML_ind "!!!" in Parse} can be used to force termination | 
|    636   of the parser in case of a dead end, just like @{ML \<open>Scan.!!\<close>} (see previous |    635   of the parser in case of a dead end, just like @{ML \<open>Scan.!!\<close>} (see previous | 
|    637   section). A difference, however, is that the error message of @{ML \<open>Parse.!!!\<close>} is fixed to be @{text [quotes] "Outer syntax error"} |    636   section). A difference, however, is that the error message of @{ML \<open>Parse.!!!\<close>} is fixed to be @{text [quotes] "Outer syntax error"} | 
|    638   together with a relatively precise description of the failure. For example: |    637   together with a relatively precise description of the failure. For example: | 
|    639  |    638  | 
|    640 @{ML_matchresult_fake [display,gray] |    639 @{ML_response [display,gray] | 
|    641 \<open>let  |    640 \<open>let  | 
|    642   val input = filtered_input "in |" |    641   val input = filtered_input "in |" | 
|    643   val parse_bar_then_in = Parse.$$$ "|" -- Parse.$$$ "in" |    642   val parse_bar_then_in = Parse.$$$ "|" -- Parse.$$$ "in" | 
|    644 in  |    643 in  | 
|    645   parse (Parse.!!! parse_bar_then_in) input  |    644   parse (Parse.!!! parse_bar_then_in) input  | 
|    646 end\<close> |    645 end\<close> | 
|    647 \<open>Exception ERROR "Outer syntax error: keyword "|" expected,  |    646 \<open>Outer syntax error: keyword "|" expected,  | 
|    648 but keyword in was found" raised\<close> |    647 but keyword in was found\<close> | 
|    649 } |    648 } | 
|    650  |    649  | 
|    651   \begin{exercise} (FIXME) |    650   \begin{exercise} (FIXME) | 
|    652   A type-identifier, for example @{typ "'a"}, is a token of  |    651   A type-identifier, for example @{typ "'a"}, is a token of  | 
|    653   kind @{ML_ind Keyword in Token}. It can be parsed using  |    652   kind @{ML_ind Keyword in Token}. It can be parsed using  | 
|    667        filter Token.is_proper (Token.explode (Thy_Header.get_keywords' @{context}) (Position.line 7) str)\<close> |    666        filter Token.is_proper (Token.explode (Thy_Header.get_keywords' @{context}) (Position.line 7) str)\<close> | 
|    668  |    667  | 
|    669 text \<open> |    668 text \<open> | 
|    670   where we pretend the parsed string starts on line 7. An example is |    669   where we pretend the parsed string starts on line 7. An example is | 
|    671  |    670  | 
|    672 @{ML_matchresult_fake [display,gray] |    671 @{ML_response [display,gray] | 
|    673 \<open>filtered_input' "foo \\n bar"\<close> |    672 \<open>filtered_input' "foo \n bar"\<close> | 
|    674 \<open>[Token (("foo", ({line=7, end_line=7}, {line=7})), (Ident, "foo"), _), |    673 \<open>[Token (("foo", ({line=7, offset=1, end_offset=4}, {line=7, offset=4})), (Ident, "foo"),\<dots>), | 
|    675  Token (("bar", ({line=8, end_line=8}, {line=8})), (Ident, "bar"), _)]\<close>} |    674  Token (("bar", ({line=8, offset=7, end_offset=10}, {line=8, offset=10})), (Ident, "bar"),\<dots>)]\<close>} | 
|    676  |    675  | 
|    677   in which the @{text [quotes] "\\n"} causes the second token to be in  |    676   in which the @{text [quotes] "\\n"} causes the second token to be in  | 
|    678   line 8. |    677   line 8. | 
|    679  |    678  | 
|    680   By using the parser @{ML position in Parse} you can access the token  |    679   By using the parser @{ML position in Parse} you can access the token  | 
|    681   position and return it as part of the parser result. For example |    680   position and return it as part of the parser result. For example | 
|    682  |    681  | 
|    683 @{ML_matchresult_fake [display,gray] |    682 @{ML_response [display,gray] | 
|    684 \<open>let |    683 \<open>let | 
|    685   val input = filtered_input' "where" |    684   val input = filtered_input' "where" | 
|    686 in  |    685 in  | 
|    687   parse (Parse.position (Parse.$$$ "where")) input |    686   parse (Parse.position (Parse.$$$ "where")) input | 
|    688 end\<close> |    687 end\<close> | 
|    689 \<open>(("where", {line=7, end_line=7}), [])\<close>} |    688 \<open>(("where", {line=7, offset=1, end_offset=6}), [])\<close>} | 
|    690  |    689  | 
|    691   \begin{readmore} |    690   \begin{readmore} | 
|    692   The functions related to positions are implemented in the file |    691   The functions related to positions are implemented in the file | 
|    693   @{ML_file "Pure/General/position.ML"}. |    692   @{ML_file "Pure/General/position.ML"}. | 
|    694   \end{readmore} |    693   \end{readmore} | 
|    749 text \<open> |    748 text \<open> | 
|    750   There is usually no need to write your own parser for parsing inner syntax, that is  |    749   There is usually no need to write your own parser for parsing inner syntax, that is  | 
|    751   for terms and  types: you can just call the predefined parsers. Terms can  |    750   for terms and  types: you can just call the predefined parsers. Terms can  | 
|    752   be parsed using the function @{ML_ind term in Parse}. For example: |    751   be parsed using the function @{ML_ind term in Parse}. For example: | 
|    753  |    752  | 
|    754 @{ML_matchresult_fake [display,gray] |    753 @{ML_response [display,gray] | 
|    755 \<open>let  |    754 \<open>let  | 
|    756   val input = Token.explode (Thy_Header.get_keywords' @{context}) Position.none "foo" |    755   val input = Token.explode (Thy_Header.get_keywords' @{context}) Position.none "foo" | 
|    757 in  |    756 in  | 
|    758   Parse.term input |    757   Parse.term input | 
|    759 end\<close> |    758 end\<close> | 
|    765   the parsed string, but also some markup information. You can decode the |    764   the parsed string, but also some markup information. You can decode the | 
|    766   information with the function @{ML_ind parse in YXML} in @{ML_structure YXML}.  |    765   information with the function @{ML_ind parse in YXML} in @{ML_structure YXML}.  | 
|    767   The result of the decoding is an XML-tree. You can see better what is going on if |    766   The result of the decoding is an XML-tree. You can see better what is going on if | 
|    768   you replace @{ML Position.none} by @{ML \<open>Position.line 42\<close>}, say: |    767   you replace @{ML Position.none} by @{ML \<open>Position.line 42\<close>}, say: | 
|    769  |    768  | 
|    770 @{ML_matchresult_fake [display,gray] |    769 @{ML_response [display,gray] | 
|    771 \<open>let  |    770 \<open>let  | 
|    772   val input = Token.explode (Thy_Header.get_keywords' @{context}) (Position.line 42) "foo" |    771   val input = Token.explode (Thy_Header.get_keywords' @{context}) (Position.line 42) "foo" | 
|    773 in  |    772 in  | 
|    774   YXML.parse (fst (Parse.term input)) |    773   YXML.parse (fst (Parse.term input)) | 
|    775 end\<close> |    774 end\<close> | 
|    776 \<open>Elem ("token", [("line", "42"), ("end_line", "42")], [XML.Text "foo"])\<close>} |    775 \<open><input delimited="false" line="42" offset="1" end_offset="4">foo</input>\<close>} | 
|    777  |    776  | 
|    778   The positional information is stored as part of an XML-tree so that code  |    777   The positional information is stored as part of an XML-tree so that code  | 
|    779   called later on will be able to give more precise error messages.  |    778   called later on will be able to give more precise error messages.  | 
|    780  |    779  | 
|    781   \begin{readmore} |    780   \begin{readmore} | 
|    845    [((even0,_),_), |    844    [((even0,_),_), | 
|    846     ((evenS,_),_), |    845     ((evenS,_),_), | 
|    847     ((oddS,_),_)]), [])\<close>} |    846     ((oddS,_),_)]), [])\<close>} | 
|    848 \<close> |    847 \<close> | 
|    849  |    848  | 
|    850 ML \<open>let |         | 
|    851   val input = filtered_input  |         | 
|    852         "foo::\"int \<Rightarrow> bool\" and bar::nat (\"BAR\" 100) and blonk" |         | 
|    853 in |         | 
|    854   parse Parse.vars input |         | 
|    855 end\<close> |         | 
|    856  |         | 
|    857 text \<open> |    849 text \<open> | 
|    858   As you see, the result is a pair consisting of a list of |    850   As you see, the result is a pair consisting of a list of | 
|    859   variables with optional type-annotation and syntax-annotation, and a list of |    851   variables with optional type-annotation and syntax-annotation, and a list of | 
|    860   rules where every rule has optionally a name and an attribute. |    852   rules where every rule has optionally a name and an attribute. | 
|    861  |    853  | 
|    864   list of variables that can include optional type annotations and syntax translations.  |    856   list of variables that can include optional type annotations and syntax translations.  | 
|    865   For example:\footnote{Note that in the code we need to write  |    857   For example:\footnote{Note that in the code we need to write  | 
|    866   \<open>"int \<Rightarrow> bool"\<close> in order to properly escape the double quotes |    858   \<open>"int \<Rightarrow> bool"\<close> in order to properly escape the double quotes | 
|    867   in the compound type.} |    859   in the compound type.} | 
|    868  |    860  | 
|    869 @{ML_matchresult_fake [display,gray] |    861 @{ML_response [display,gray] | 
|    870 \<open>let |    862 \<open>let | 
|    871   val input = filtered_input  |    863   val input = filtered_input  | 
|    872         "foo::\"int \<Rightarrow> bool\" and bar::nat (\"BAR\" 100) and blonk" |    864         "foo::\"int \<Rightarrow> bool\" and bar::nat (\"BAR\" 100) and blonk" | 
|    873 in |    865 in | 
|    874   parse Parse.vars input |    866   parse Parse.vars input | 
|    875 end\<close> |    867 end\<close> | 
|    876 \<open>([(foo, SOME _, NoSyn),  |    868 \<open>([("foo", SOME \<dots>, NoSyn),  | 
|    877   (bar, SOME _, Mixfix (Source {text="BAR",...}, [], 100, _)),  |    869   ("bar", SOME \<dots>, Mixfix (Source {\<dots>text = "BAR"}, [], 100, \<dots>)),  | 
|    878   (blonk, NONE, NoSyn)],[])\<close>}   |    870   ("blonk", NONE, NoSyn)], [])\<close>}   | 
|    879 \<close> |    871 \<close> | 
|    880  |    872  | 
|    881 text \<open> |    873 text \<open> | 
|    882   Whenever types are given, they are stored in the @{ML SOME}s. The types are |    874   Whenever types are given, they are stored in the @{ML SOME}s. The types are | 
|    883   not yet used to type the variables: this must be done by type-inference later |    875   not yet used to type the variables: this must be done by type-inference later | 
|    951  |    943  | 
|    952 section \<open>New Commands\label{sec:newcommand}\<close> |    944 section \<open>New Commands\label{sec:newcommand}\<close> | 
|    953  |    945  | 
|    954 text \<open> |    946 text \<open> | 
|    955   Often new commands, for example for providing new definitional principles, |    947   Often new commands, for example for providing new definitional principles, | 
|    956   need to be implemented. While this is not difficult on the ML-level and for |    948   need to be implemented.  | 
|    957   jEdit, in order to be backwards compatible, new commands need also to be recognised  |         | 
|    958   by Proof-General. This results in some subtle configuration issues, which we will  |         | 
|    959   explain in the next section. Here we just describe how to define new commands |         | 
|    960   to work with jEdit. |         | 
|    961  |    949  | 
|    962   Let us start with a ``silly'' command that does nothing at all. We |    950   Let us start with a ``silly'' command that does nothing at all. We | 
|    963   shall name this command \isacommand{foobar}.  Before you can |    951   shall name this command \isacommand{foobar}.  Before you can | 
|    964   implement any new command, you have to ``announce'' it in the |    952   implement any new command, you have to ``announce'' it in the | 
|    965   \isacommand{keywords}-section of your theory header. For \isacommand{foobar} |    953   \isacommand{keywords}-section of your theory header. For \isacommand{foobar} | 
|    998  |    986  | 
|    999 foobar |    987 foobar | 
|   1000  |    988  | 
|   1001 text \<open> |    989 text \<open> | 
|   1002   but of course you will not see anything since \isacommand{foobar} is |    990   but of course you will not see anything since \isacommand{foobar} is | 
|   1003   not intended to do anything.  Remember, however, that this only |    991   not intended to do anything. | 
|   1004   works in jEdit. In order to enable also Proof-General recognise this |         | 
|   1005   command, a keyword file needs to be generated (see next section). |         | 
|   1006  |    992  | 
|   1007   As it stands, the command \isacommand{foobar} is not very useful. Let |    993   As it stands, the command \isacommand{foobar} is not very useful. Let | 
|   1008   us refine it a bit next by letting it take a proposition as argument |    994   us refine it a bit next by letting it take a proposition as argument | 
|   1009   and printing this proposition inside the tracing buffer. We announce |    995   and printing this proposition inside the tracing buffer. We announce | 
|   1010   the command \isacommand{foobar\_trace} in the theory header as |    996   the command \isacommand{foobar\_trace} in the theory header as |