| author | wenzelm | 
| Fri, 08 Dec 2023 20:08:52 +0100 | |
| changeset 79216 | 58f9b0d53d97 | 
| parent 78795 | f7e972d567f3 | 
| permissions | -rw-r--r-- | 
| 58657 | 1 | (* Title: Pure/Tools/plugin.ML | 
| 2 | Author: Makarius | |
| 3 | Author: Jasmin Blanchette | |
| 4 | ||
| 5 | Named plugins for definitional packages. | |
| 6 | *) | |
| 7 | ||
| 8 | (** plugin name **) | |
| 9 | ||
| 10 | signature PLUGIN_NAME = | |
| 11 | sig | |
| 12 | val check: Proof.context -> xstring * Position.T -> string | |
| 58658 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 13 | val define: binding -> string list -> theory -> string * theory | 
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 14 | val define_setup: binding -> string list -> string | 
| 58657 | 15 | val declare: binding -> theory -> string * theory | 
| 58658 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 16 | val declare_setup: binding -> string | 
| 58657 | 17 | type filter = string -> bool | 
| 58660 | 18 | val default_filter: filter | 
| 19 | val make_filter: Proof.context -> (Proof.context -> filter) -> filter | |
| 58657 | 20 | val parse_filter: (Proof.context -> filter) parser | 
| 21 | end; | |
| 22 | ||
| 23 | structure Plugin_Name: PLUGIN_NAME = | |
| 24 | struct | |
| 25 | ||
| 26 | (* theory data *) | |
| 27 | ||
| 28 | structure Data = Theory_Data | |
| 29 | ( | |
| 58658 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 30 | type T = string list Name_Space.table; | 
| 58657 | 31 | val empty: T = Name_Space.empty_table "plugin"; | 
| 32 | val merge = Name_Space.merge_tables; | |
| 33 | ); | |
| 34 | ||
| 35 | ||
| 36 | (* check *) | |
| 37 | ||
| 38 | fun check ctxt = | |
| 39 | #1 o Name_Space.check (Context.Proof ctxt) (Data.get (Proof_Context.theory_of ctxt)); | |
| 40 | ||
| 41 | val _ = Theory.setup | |
| 69592 
a80d8ec6c998
support for isabelle update -u control_cartouches;
 wenzelm parents: 
69349diff
changeset | 42 | (ML_Antiquotation.inline_embedded \<^binding>\<open>plugin\<close> | 
| 74563 | 43 | (Args.context -- Scan.lift Parse.embedded_position >> (ML_Syntax.print_string o uncurry check))); | 
| 58657 | 44 | |
| 45 | ||
| 58658 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 46 | (* indirections *) | 
| 58657 | 47 | |
| 58658 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 48 | fun resolve thy = maps (fn name => | 
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 49 | (case Name_Space.get (Data.get thy) name of | 
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 50 | [] => [name] | 
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 51 | | names => resolve thy names)); | 
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 52 | |
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 53 | fun define binding rhs thy = | 
| 58657 | 54 | let | 
| 58668 | 55 | val context = Context.Theory thy |> Name_Space.map_naming (K Name_Space.global_naming); | 
| 58658 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 56 | val (name, data') = Name_Space.define context true (binding, resolve thy rhs) (Data.get thy); | 
| 58657 | 57 | val thy' = Data.put data' thy; | 
| 58 | in (name, thy') end; | |
| 59 | ||
| 78795 
f7e972d567f3
clarified signature: more concise variations on implicit theory setup;
 wenzelm parents: 
74563diff
changeset | 60 | fun define_setup binding rhs = Theory.setup_result (define binding rhs); | 
| 58658 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 61 | |
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 62 | |
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 63 | (* immediate entries *) | 
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 64 | |
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 65 | fun declare binding thy = define binding [] thy; | 
| 78795 
f7e972d567f3
clarified signature: more concise variations on implicit theory setup;
 wenzelm parents: 
74563diff
changeset | 66 | fun declare_setup binding = Theory.setup_result (declare binding); | 
| 58657 | 67 | |
| 68 | ||
| 69 | (* filter *) | |
| 70 | ||
| 71 | type filter = string -> bool; | |
| 72 | ||
| 58660 | 73 | val default_filter: filter = K true; | 
| 74 | ||
| 58657 | 75 | fun make_filter (ctxt: Proof.context) f : filter = f ctxt; | 
| 76 | ||
| 77 | val parse_filter = | |
| 78 | Parse.position (Parse.reserved "plugins") -- | |
| 79 | Parse.position (Parse.reserved "only" >> K I || Parse.reserved "del" >> K not) -- | |
| 69349 
7cef9e386ffe
more accurate positions for "name" (quoted string) and "embedded" (cartouche): refer to content without delimiters, which is e.g. relevant for systematic selection/renaming of scope groups;
 wenzelm parents: 
67147diff
changeset | 80 | (Parse.$$$ ":" |-- Scan.repeat Parse.name_position) >> | 
| 58657 | 81 | (fn (((_, pos1), (modif, pos2)), args) => fn ctxt => | 
| 82 | let | |
| 58658 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 83 | val thy = Proof_Context.theory_of ctxt; | 
| 58657 | 84 | val _ = Context_Position.reports ctxt (map (rpair Markup.quasi_keyword) [pos1, pos2]); | 
| 58658 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 85 | val basic_names = resolve thy (map (check ctxt) args); | 
| 
9002fe021e2f
support for indirections (defined entries), e.g. relevant for quickcheck and its sub-plugins;
 wenzelm parents: 
58657diff
changeset | 86 | in modif o member (op =) basic_names end); | 
| 58657 | 87 | |
| 88 | end; | |
| 89 | ||
| 90 | ||
| 91 | ||
| 92 | (** plugin content **) | |
| 93 | ||
| 94 | signature PLUGIN = | |
| 95 | sig | |
| 96 | type T | |
| 97 | val data: Plugin_Name.filter -> T -> local_theory -> local_theory | |
| 58666 | 98 | val data_default: T -> local_theory -> local_theory | 
| 58657 | 99 | val interpretation: string -> (T -> local_theory -> local_theory) -> theory -> theory | 
| 100 | end; | |
| 101 | ||
| 102 | functor Plugin(type T): PLUGIN = | |
| 103 | struct | |
| 104 | ||
| 105 | type T = T; | |
| 106 | ||
| 107 | ||
| 108 | (* data with interpretation *) | |
| 109 | ||
| 110 | type data = {filter: Plugin_Name.filter, naming: Name_Space.naming, value: T, id: serial};
 | |
| 111 | type interp = {name: string, apply: T -> local_theory -> local_theory, id: serial};
 | |
| 112 | ||
| 59058 
a78612c67ec0
renamed "pairself" to "apply2", in accordance to @{apply 2};
 wenzelm parents: 
58668diff
changeset | 113 | val eq_data: data * data -> bool = op = o apply2 #id; | 
| 
a78612c67ec0
renamed "pairself" to "apply2", in accordance to @{apply 2};
 wenzelm parents: 
58668diff
changeset | 114 | val eq_interp: interp * interp -> bool = op = o apply2 #id; | 
| 58657 | 115 | |
| 116 | fun mk_data filter naming x : data = {filter = filter, naming = naming, value = x, id = serial ()};
 | |
| 117 | fun mk_interp name f : interp = {name = name, apply = f, id = serial ()};
 | |
| 118 | ||
| 119 | ||
| 120 | (* theory data *) | |
| 121 | ||
| 122 | structure Plugin_Data = Theory_Data | |
| 123 | ( | |
| 124 | type T = data list * (interp * data list) list; | |
| 125 | val empty : T = ([], []); | |
| 126 | val merge_data = merge eq_data; | |
| 127 | fun merge ((data1, interps1), (data2, interps2)) : T = | |
| 128 | (merge_data (data1, data2), AList.join eq_interp (K merge_data) (interps1, interps2)); | |
| 129 | ); | |
| 130 | ||
| 131 | ||
| 132 | (* consolidate data wrt. interpretations *) | |
| 133 | ||
| 134 | local | |
| 135 | ||
| 136 | fun apply change_naming (interp: interp) (data: data) lthy = | |
| 137 | lthy | |
| 59880 
30687c3f2b10
clarified role of naming for background theory: transform_binding (e.g. for "concealed" flag) uses naming of hypothetical context;
 wenzelm parents: 
59145diff
changeset | 138 | |> change_naming ? Local_Theory.map_background_naming (K (#naming data)) | 
| 58657 | 139 | |> #apply interp (#value data) | 
| 59880 
30687c3f2b10
clarified role of naming for background theory: transform_binding (e.g. for "concealed" flag) uses naming of hypothetical context;
 wenzelm parents: 
59145diff
changeset | 140 | |> Local_Theory.restore_background_naming lthy; | 
| 58657 | 141 | |
| 142 | fun unfinished data (interp: interp, data') = | |
| 143 | (interp, | |
| 144 | if eq_list eq_data (data, data') then [] | |
| 145 | else data |> filter (fn d => #filter d (#name interp) andalso not (member eq_data data' d))); | |
| 146 | ||
| 147 | fun unfinished_data thy = | |
| 148 | let | |
| 149 | val (data, interps) = Plugin_Data.get thy; | |
| 150 | val finished = map (apsnd (K data)) interps; | |
| 151 | val thy' = Plugin_Data.put (data, finished) thy; | |
| 152 | in (map (unfinished data) interps, thy') end; | |
| 153 | ||
| 154 | in | |
| 155 | ||
| 156 | val consolidate = | |
| 157 | Local_Theory.raw_theory_result unfinished_data | |
| 158 | #-> fold_rev (fn (interp, data) => fold_rev (apply false interp) data); | |
| 159 | ||
| 160 | val consolidate' = | |
| 161 | unfinished_data #> (fn (unfinished, thy) => | |
| 162 | if forall (null o #2) unfinished then NONE | |
| 163 | else | |
| 58665 | 164 | SOME (Named_Target.theory_map | 
| 165 | (fold_rev (fn (interp, data) => fold_rev (apply true interp) data) unfinished) thy)); | |
| 58657 | 166 | |
| 167 | end; | |
| 168 | ||
| 169 | val _ = Theory.setup (Theory.at_begin consolidate'); | |
| 170 | ||
| 171 | ||
| 172 | (* add content *) | |
| 173 | ||
| 174 | fun data filter x = | |
| 175 | Local_Theory.background_theory (fn thy => | |
| 176 | Plugin_Data.map (apfst (cons (mk_data filter (Sign.naming_of thy) x))) thy) | |
| 177 | #> consolidate; | |
| 178 | ||
| 58666 | 179 | val data_default = data Plugin_Name.default_filter; | 
| 180 | ||
| 58657 | 181 | fun interpretation name f = | 
| 182 | Plugin_Data.map (apsnd (cons (mk_interp name f, []))) | |
| 183 | #> perhaps consolidate'; | |
| 184 | ||
| 185 | end; |