34 "ML_Context.eval_in"} in Line 4 below). The complete code of the |
34 "ML_Context.eval_in"} in Line 4 below). The complete code of the |
35 antiquotation is as follows: |
35 antiquotation is as follows: |
36 |
36 |
37 *} |
37 *} |
38 |
38 |
39 ML {* Pretty.str *} |
|
40 |
|
41 ML%linenosgray{*fun ml_val code_txt = "val _ = " ^ code_txt |
39 ML%linenosgray{*fun ml_val code_txt = "val _ = " ^ code_txt |
42 |
40 |
43 fun output_ml {source = src, context = ctxt, ...} code_txt = |
41 fun output_ml {context = ctxt, ...} code_txt = |
44 (ML_Context.eval_in (SOME ctxt) false Position.none (ml_val code_txt); |
42 (ML_Context.eval_in (SOME ctxt) false Position.none (ml_val code_txt); |
45 ThyOutput.output (map Pretty.str (space_explode "\n" code_txt))) |
43 ThyOutput.output (map Pretty.str (space_explode "\n" code_txt))) |
46 |
44 |
47 val _ = ThyOutput.antiquotation "ML_checked" (Scan.lift Args.name) output_ml*} |
45 val _ = ThyOutput.antiquotation "ML_checked" (Scan.lift Args.name) output_ml*} |
48 |
46 |
49 text {* |
47 text {* |
50 |
48 |
51 Note that the parser @{ML "(Scan.lift Args.name)"} in line 9 parses a string, |
49 Note that the parser @{ML "(Scan.lift Args.name)"} in line 9 parses a string, |
52 in this case the code given as argument. As mentioned before, this argument |
50 in this case the code. As mentioned before, the code |
53 is sent to the ML-compiler in the line 4 using the function @{ML ml_val}, |
51 is sent to the ML-compiler in the line 4 using the function @{ML ml_val}, |
54 which constructs the appropriate ML-expression. |
52 which constructs the appropriate ML-expression. |
55 If the code is ``approved'' by the compiler, then the output function @{ML |
53 If the code is ``approved'' by the compiler, then the output function @{ML |
56 "ThyOutput.output"} in the next line pretty prints the |
54 "ThyOutput.output"} in the next line pretty prints the |
57 code. This function expects that the code is a list of strings where each |
55 code. This function expects that the code is a list of strings where each |
58 string correspond to a line in the output. Therefore the use of |
56 string correspond to a line in the output. Therefore the use of |
59 @{ML "(space_explode \"\\n\" txt)" for txt} |
57 @{ML "(space_explode \"\\n\" txt)" for txt} |
60 which produces this list according to linebreaks. There are a number of options |
58 which produces this list according to linebreaks. There are a number of options |
61 for antiquotations that are observed by @{ML ThyOutput.output} when printing the |
59 for antiquotations that are observed by @{ML ThyOutput.output} when printing the |
62 code (including @{text "[display]"} and @{text "[quotes]"}). |
60 code (including @{text "[display]"} and @{text "[quotes]"}). Line 7 sets |
|
61 up the new antiquotation. |
63 |
62 |
64 \begin{readmore} |
63 \begin{readmore} |
65 For more information about options of antiquotations see \rsccite{sec:antiq}). |
64 For more information about options of antiquotations see \rsccite{sec:antiq}). |
66 \end{readmore} |
65 \end{readmore} |
67 |
66 |
68 Since we used the argument @{ML "Position.none"}, the compiler cannot give specific |
67 Since we used the argument @{ML "Position.none"}, the compiler cannot give specific |
69 information about the line number, in case an error is detected. We |
68 information about the line number, in case an error is detected. We |
70 can improve the code above slightly by writing |
69 can improve the code above slightly by writing |
71 *} |
70 *} |
72 |
71 |
73 ML%linenosgray{*fun output_ml {source = src, context = ctxt, ...} (code_txt,pos) = |
72 ML%linenosgray{*fun output_ml {context = ctxt, ...} (code_txt,pos) = |
74 (ML_Context.eval_in (SOME ctxt) false pos (ml_val code_txt); |
73 (ML_Context.eval_in (SOME ctxt) false pos (ml_val code_txt); |
75 ThyOutput.output (map Pretty.str (space_explode "\n" code_txt))) |
74 ThyOutput.output (map Pretty.str (space_explode "\n" code_txt))) |
76 |
75 |
77 val _ = ThyOutput.antiquotation "ML_checked" |
76 val _ = ThyOutput.antiquotation "ML_checked" |
78 (Scan.lift (OuterParse.position Args.name)) output_ml *} |
77 (Scan.lift (OuterParse.position Args.name)) output_ml *} |
79 |
78 |
80 text {* |
79 text {* |
81 where in Lines 1 and 2 the positional information is properly treated. |
80 where in Lines 1 and 2 the positional information is properly treated. |
82 |
|
83 (FIXME: say something about OuterParse.position) |
|
84 |
81 |
85 We can now write in a document @{text "@{ML_checked \"2 + 3\"}"} in order to |
82 We can now write in a document @{text "@{ML_checked \"2 + 3\"}"} in order to |
86 obtain @{ML_checked "2 + 3"} and be sure that this code compiles until |
83 obtain @{ML_checked "2 + 3"} and be sure that this code compiles until |
87 somebody changes the definition of \mbox{@{ML "(op +)"}}. |
84 somebody changes the definition of \mbox{@{ML "(op +)"}}. |
88 |
85 |
89 |
86 |
90 The second antiquotation we describe extends the first by allowing also to give |
87 The second antiquotation we describe extends the first by a pattern that |
91 a pattern that specifies what the result of the ML-code should be and to check |
88 specifies what the result of the ML-code should be and check |
92 the consistency of the actual result with the given pattern. For this we are going |
89 the consistency of the actual result with the given pattern. For this we are going |
93 to implement the antiquotation |
90 to implement the antiquotation |
94 |
91 |
95 @{text [display] "@{ML_resp \"a_piece_of_code\" \"pattern\"}"} |
92 @{text [display] "@{ML_resp \"a_piece_of_code\" \"a_pattern\"}"} |
96 |
93 |
97 To add some convenience and also to deal with large outputs, |
94 To add some convenience and also to deal with large outputs, the user can |
98 the user can give a partial specification by giving the abbreviation |
95 give a partial specification inside the pattern by giving abbreviations of |
99 @{text [quotes] "\<dots>"}. For example @{text "(\<dots>,\<dots>)"} for a pair. |
96 the form @{text [quotes] "\<dots>"}. For example @{text "(\<dots>, \<dots>)"} to specify a |
|
97 pair. |
100 |
98 |
101 Whereas in the antiquotation @{text "@{ML_checked \"piece_of_code\"}"} above, |
99 Whereas in the antiquotation @{text "@{ML_checked \"piece_of_code\"}"} |
102 we have sent the expression |
100 above, we have sent the expression @{text [quotes] "val _ = piece_of_code"} |
103 @{text [quotes] "val _ = piece_of_code"} to the compiler, in the second the |
101 to the compiler, in the second the wildcard @{text "_"} we will be replaced |
104 wildcard @{text "_"} we will be replaced by a proper pattern. To do this we |
102 by the given pattern. To do this we need to replace the @{text [quotes] "\<dots>"} |
105 need to replace the @{text [quotes] "\<dots>"} by |
103 by @{text [quotes] "_"} before sending the code to the compiler. The |
106 @{text [quotes] "_"} before sending the code to the compiler. The following |
104 following function will do this: |
107 function will do this: |
|
108 |
|
109 *} |
105 *} |
110 |
106 |
111 ML{*fun ml_pat (code_txt, pat) = |
107 ML{*fun ml_pat (code_txt, pat) = |
112 let val pat' = |
108 let val pat' = |
113 implode (map (fn "\<dots>" => "_" | s => s) (Symbol.explode pat)) |
109 implode (map (fn "\<dots>" => "_" | s => s) (Symbol.explode pat)) |
114 in |
110 in |
115 "val " ^ pat' ^ " = " ^ code_txt |
111 "val " ^ pat' ^ " = " ^ code_txt |
116 end*} |
112 end*} |
117 |
113 |
118 text {* |
114 text {* |
119 Next we like to add a response indicator to the result using: |
115 Next we like to add a response indicator to the result using: |
120 *} |
116 *} |
121 |
117 |