ProgTutorial/Recipes/Antiquotes.thy
changeset 562 daf404920ab9
parent 555 2c34c69236ce
child 565 cecd7a941885
equal deleted inserted replaced
561:aec7073d4645 562:daf404920ab9
    37   a_piece_of_code"} to the ML-compiler (i.e.~the function @{ML
    37   a_piece_of_code"} to the ML-compiler (i.e.~the function @{ML
    38   "ML_Context.eval_source_in"} in Line 7 below). The complete code of the
    38   "ML_Context.eval_source_in"} in Line 7 below). The complete code of the
    39   document antiquotation is as follows:
    39   document antiquotation is as follows:
    40 
    40 
    41 *}
    41 *}
    42 
    42 ML \<open>Input.pos_of\<close>
    43 ML%linenosgray{*fun ml_val code_txt = "val _ = " ^ code_txt
    43 ML%linenosgray{*fun ml_enclose bg en source =
    44 
    44   ML_Lex.read bg @ ML_Lex.read_source false source @ ML_Lex.read en;*}
    45 fun output_ml {context = ctxt, ...} code_txt =
    45 
       
    46 ML%linenosgray{*fun ml_val code_txt = (ml_enclose "val _ = " "" code_txt)
       
    47 
       
    48 fun output_ml ctxt code_txt =
    46 let
    49 let
    47   val srcpos = {delimited = false, text = (ml_val code_txt), pos = Position.none}
    50   val _ = ML_Context.eval_in (SOME ctxt) ML_Compiler.flags (Input.pos_of code_txt) (ml_val code_txt)
    48 in
    51 in 
    49   (ML_Context.eval_source_in (SOME ctxt) ML_Compiler.flags srcpos; 
    52    Pretty.str (Input.source_content code_txt)
    50    Thy_Output.output ctxt (map Pretty.str (space_explode "\n" code_txt)))
    53 end
    51 end
    54 
    52 
    55 val ml_checked_setup = Thy_Output.antiquotation_pretty_source @{binding "ML_checked"} (Scan.lift Args.text_input) output_ml*}
    53 val ml_checked_setup = Thy_Output.antiquotation @{binding "ML_checked"} (Scan.lift Args.name) output_ml*}
       
    54 
    56 
    55 setup {* ml_checked_setup *}
    57 setup {* ml_checked_setup *}
       
    58 
    56 
    59 
    57 text {*
    60 text {*
    58   The parser @{ML "(Scan.lift Args.name)"} in Line 7 parses a string, in this
    61   The parser @{ML "(Scan.lift Args.name)"} in Line 7 parses a string, in this
    59   case the code, and then calls the function @{ML output_ml}. As mentioned
    62   case the code, and then calls the function @{ML output_ml}. As mentioned
    60   before, the parsed code is sent to the ML-compiler in Line 4 using the
    63   before, the parsed code is sent to the ML-compiler in Line 4 using the
    61   function @{ML ml_val}, which constructs the appropriate ML-expression, and
    64   function @{ML ml_val}, which constructs the appropriate ML-expression, and
    62   using @{ML "eval_in" in ML_Context}, which calls the compiler.  If the code is
    65   using @{ML "eval_in" in ML_Context}, which calls the compiler.  If the code is
    63   ``approved'' by the compiler, then the output function @{ML "output" in
    66   ``approved'' by the compiler, then the output function @{ML "output" in
    64   Thy_Output} in the next line pretty prints the code. This function expects
    67   Document_Antiquotation} in the next line pretty prints the code. This function expects
    65   that the code is a list of (pretty)strings where each string correspond to a
    68   that the code is a list of (pretty)strings where each string correspond to a
    66   line in the output. Therefore the use of @{ML "(space_explode \"\\n\" txt)"
    69   line in the output. Therefore the use of @{ML "(space_explode \"\\n\" txt)"
    67   for txt} which produces such a list according to linebreaks.  There are a
    70   for txt} which produces such a list according to linebreaks.  There are a
    68   number of options for antiquotations that are observed by the function 
    71   number of options for antiquotations that are observed by the function 
    69   @{ML "output" in Thy_Output} when printing the code (including @{text "[display]"} 
    72   @{ML "output" in Document_Antiquotation} when printing the code (including @{text "[display]"} 
    70   and @{text "[quotes]"}). The function @{ML "antiquotation" in Thy_Output} in 
    73   and @{text "[quotes]"}). The function @{ML "antiquotation_raw" in Thy_Output} in 
    71   Line 7 sets up the new document antiquotation.
    74   Line 7 sets up the new document antiquotation.
    72 
    75 
    73   \begin{readmore}
    76   \begin{readmore}
    74   For more information about options of document antiquotations see \rsccite{sec:antiq}).
    77   For more information about options of document antiquotations see \rsccite{sec:antiq}).
    75   \end{readmore}
    78   \end{readmore}
    76 
    79 
    77   Since we used the argument @{ML "Position.none"}, the compiler cannot give specific 
    80   Since we used the argument @{ML "Position.none"}, the compiler cannot give specific 
    78   information about the line number, in case an error is detected. We 
    81   information about the line number, in case an error is detected. We 
    79   can improve the code above slightly by writing 
    82   can improve the code above slightly by writing 
    80 *}
    83 *}
    81 
    84 (* FIXME: remove
    82 ML%linenosgray{*fun output_ml {context = ctxt, ...} (code_txt, pos) =
    85 ML%linenosgray{*fun output_ml ctxt (code_txt, pos) =
    83 let
    86 let
    84   val srcpos = {delimited = false, pos = pos, text = ml_val code_txt}
    87   val srcpos = {delimited = false, pos = pos, text = ml_val code_txt}
    85 in
    88 in
    86   (ML_Context.eval_source_in (SOME ctxt) ML_Compiler.flags srcpos;
    89   (ML_Context.eval_source_in (SOME ctxt) ML_Compiler.flags srcpos;
    87    Thy_Output.output ctxt (map Pretty.str (space_explode "\n" code_txt)))
    90    code_txt 
       
    91    |> space_explode "\n"
       
    92    |> map Pretty.str
       
    93    |> Pretty.list "" ""
       
    94    |> Document_Antiquotation.output ctxt
       
    95    |> Latex.string)
    88 end
    96 end
    89 
    97 
    90 val ml_checked_setup2 = Thy_Output.antiquotation @{binding "ML_checked2"}
    98 val ml_checked_setup2 = Thy_Output.antiquotation @{binding "ML_checked2"}
    91          (Scan.lift (Parse.position Args.name)) output_ml *}
    99          (Scan.lift (Parse.position Args.name)) output_ml *}
    92 
   100 
    93 setup {* ml_checked_setup2 *}
   101 setup {* ml_checked_setup2 *}
    94 
   102 *)
    95 text {*
   103 text {*
    96   where in Lines 1 and 2 the positional information is properly treated. The
   104   where in Lines 1 and 2 the positional information is properly treated. The
    97   parser @{ML Parse.position} encodes the positional information in the 
   105   parser @{ML Parse.position} encodes the positional information in the 
    98   result.
   106   result.
    99 
   107 
   100   We can now write @{text "@{ML_checked2 \"2 + 3\"}"} in a document in order to
   108   We can now write @{text "@{ML_checked2 \"2 + 3\"}"} in a document in order to
   101   obtain @{ML_checked2 "2 + 3"} and be sure that this code compiles until
   109   obtain @{ML_checked "2 + 3"} and be sure that this code compiles until
   102   somebody changes the definition of addition.
   110   somebody changes the definition of addition.
   103 
   111 
   104 
   112 
   105   The second document antiquotation we describe extends the first by a pattern
   113   The second document antiquotation we describe extends the first by a pattern
   106   that specifies what the result of the ML-code should be and checks the
   114   that specifies what the result of the ML-code should be and checks the
   119   must be be replaced by the given pattern. However, we have to remove all
   127   must be be replaced by the given pattern. However, we have to remove all
   120   ellipses from it and replace them by @{text [quotes] "_"}. The following 
   128   ellipses from it and replace them by @{text [quotes] "_"}. The following 
   121   function will do this:
   129   function will do this:
   122 *}
   130 *}
   123 
   131 
   124 ML %grayML{*fun ml_pat (code_txt, pat) =
   132 ML%linenosgray{*fun ml_pat pat code =
       
   133   ML_Lex.read "val" @ ML_Lex.read_source false pat @ ML_Lex.read " = " @ ML_Lex.read_source false code*}
       
   134 
       
   135 (*
       
   136 ML %grayML{*fun ml_pat code_txt pat =
   125 let val pat' = 
   137 let val pat' = 
   126          implode (map (fn "\<dots>" => "_" | s => s) (Symbol.explode pat))
   138          implode (map (fn "\<dots>" => "_" | s => s) (Symbol.explode pat))
   127 in 
   139 in 
   128   "val " ^ pat' ^ " = " ^ code_txt 
   140   ml_enclose ("val " ^ pat' ^ " = ") "" code_txt 
   129 end*}
   141 end*}
   130 
   142 *)
   131 text {* 
   143 text {* 
   132   Next we add a response indicator to the result using:
   144   Next we add a response indicator to the result using:
   133 *}
   145 *}
   134 
   146 
   135 
   147 
   137 
   149 
   138 text {* 
   150 text {* 
   139   The rest of the code of @{text "ML_resp"} is: 
   151   The rest of the code of @{text "ML_resp"} is: 
   140 *}
   152 *}
   141 
   153 
       
   154 ML %linenosgray\<open>
       
   155 fun output_ml_resp ctxt (code_txt, pat) =
       
   156 let
       
   157   val _ = ML_Context.eval_in (SOME ctxt) ML_Compiler.flags (Input.pos_of code_txt) (ml_pat pat code_txt)
       
   158   val code = space_explode "\n" (Input.source_content code_txt)
       
   159   val resp = add_resp (space_explode "\n" (Input.source_content pat))
       
   160 in 
       
   161    Pretty.str (cat_lines (code @ resp))
       
   162 end
       
   163 
       
   164 val ml_response_setup = Thy_Output.antiquotation_pretty_source @{binding "ML_resp"} (Scan.lift (Args.text_input -- Args.text_input)) output_ml_resp
       
   165 
       
   166 \<close>
       
   167 
       
   168 (*
   142 ML %linenosgray{*fun output_ml_resp {context = ctxt, ...} ((code_txt, pat), pos) = 
   169 ML %linenosgray{*fun output_ml_resp {context = ctxt, ...} ((code_txt, pat), pos) = 
   143   (let
   170   (let
   144      val srcpos = {delimited = false, text = ml_pat (code_txt, pat), pos = pos}
   171      val srcpos = {delimited = false, text = ml_pat (code_txt, pat), pos = pos}
   145    in
   172    in
   146      ML_Context.eval_source_in (SOME ctxt) ML_Compiler.flags srcpos 
   173      ML_Context.eval_source_in (SOME ctxt) ML_Compiler.flags srcpos 
   152      Thy_Output.output ctxt (map Pretty.str (code_output @ resp_output)) 
   179      Thy_Output.output ctxt (map Pretty.str (code_output @ resp_output)) 
   153    end)
   180    end)
   154 
   181 
   155 
   182 
   156 val ml_resp_setup = Thy_Output.antiquotation @{binding "ML_resp"} 
   183 val ml_resp_setup = Thy_Output.antiquotation @{binding "ML_resp"} 
   157           (Scan.lift (Parse.position (Args.name -- Args.name))) 
   184           (Scan.lift (Parse.position (Args.text_input -- Args.text_input))) 
   158              output_ml_resp*}
   185              output_ml_resp*}
   159 
   186 *)
   160 setup {* ml_resp_setup *}
   187 setup {* ml_response_setup *}
   161 
   188 
   162 text {*
   189 (* FIXME *)
   163   In comparison with @{text "ML_checked2"}, we only changed the line about 
   190 text {* 
       
   191   In comparison with @{text "ML_checked"}, we only changed the line about 
   164   the compiler (Line~2), the lines about
   192   the compiler (Line~2), the lines about
   165   the output (Lines 4 to 7) and the parser in the setup (Line 11). Now 
   193   the output (Lines 4 to 7) and the parser in the setup (Line 11). Now 
   166   you can write
   194   you can write
   167  
   195  
   168   @{text [display] "@{ML_resp [display] \"true andalso false\" \"false\"}"}
   196   @{text [display] "@{ML_resp [display] \"true andalso false\" \"false\"}"}
   175 
   203 
   176   @{text [display] "@{ML_resp [display] \"let val i = 3 in (i * i, \"foo\") end\" \"(9, \<dots>)\"}"}
   204   @{text [display] "@{ML_resp [display] \"let val i = 3 in (i * i, \"foo\") end\" \"(9, \<dots>)\"}"}
   177   
   205   
   178   to obtain
   206   to obtain
   179 
   207 
   180   @{ML_resp [display] "let val i = 3 in (i * i, \"foo\") end" "(9, \<dots>)"} 
   208   @{ML_resp [display] "let val i = 3 in (i * i, \"foo\") end" "(9, _)"} 
   181 
   209 
   182   In both cases, the check by the compiler ensures that code and result
   210   In both cases, the check by the compiler ensures that code and result
   183   match. A limitation of this document antiquotation, however, is that the
   211   match. A limitation of this document antiquotation, however, is that the
   184   pattern can only be given for values that can be constructed. This excludes
   212   pattern can only be given for values that can be constructed. This excludes
   185   values that are abstract datatypes, like @{ML_type thm}s and @{ML_type cterm}s.
   213   values that are abstract datatypes, like @{ML_type thm}s and @{ML_type cterm}s.