1 (* Title: Pure/Isar/outer_syntax.ML |
1 (* Title: Pure/Isar/outer_syntax.ML |
2 ID: $Id$ |
|
3 Author: Markus Wenzel, TU Muenchen |
2 Author: Markus Wenzel, TU Muenchen |
4 |
3 |
5 The global Isabelle/Isar outer syntax. |
4 The global Isabelle/Isar outer syntax. |
6 |
5 |
7 Note: the syntax for files is statically determined at the very |
6 Note: the syntax for files is statically determined at the very |
8 beginning; for interactive processing it may change dynamically. |
7 beginning; for interactive processing it may change dynamically. |
9 *) |
8 *) |
10 |
9 |
11 signature OUTER_SYNTAX = |
10 signature OUTER_SYNTAX = |
12 sig |
11 sig |
13 type parser_fn = OuterLex.token list -> |
12 type 'a parser = 'a OuterParse.parser |
14 (Toplevel.transition -> Toplevel.transition) * OuterLex.token list |
13 val command: string -> string -> OuterKeyword.T -> |
15 val command: string -> string -> OuterKeyword.T -> parser_fn -> unit |
14 (Toplevel.transition -> Toplevel.transition) parser -> unit |
16 val markup_command: ThyOutput.markup -> string -> string -> OuterKeyword.T -> parser_fn -> unit |
15 val markup_command: ThyOutput.markup -> string -> string -> OuterKeyword.T -> |
17 val improper_command: string -> string -> OuterKeyword.T -> parser_fn -> unit |
16 (Toplevel.transition -> Toplevel.transition) parser -> unit |
|
17 val improper_command: string -> string -> OuterKeyword.T -> |
|
18 (Toplevel.transition -> Toplevel.transition) parser -> unit |
|
19 val internal_command: string -> (Toplevel.transition -> Toplevel.transition) parser -> unit |
18 val local_theory: string -> string -> OuterKeyword.T -> |
20 val local_theory: string -> string -> OuterKeyword.T -> |
19 (OuterParse.token list -> (local_theory -> local_theory) * OuterLex.token list) -> unit |
21 (local_theory -> local_theory) parser -> unit |
20 val local_theory_to_proof': string -> string -> OuterKeyword.T -> |
22 val local_theory_to_proof': string -> string -> OuterKeyword.T -> |
21 (OuterParse.token list -> (bool -> local_theory -> Proof.state) * OuterLex.token list) -> unit |
23 (bool -> local_theory -> Proof.state) parser -> unit |
22 val local_theory_to_proof: string -> string -> OuterKeyword.T -> |
24 val local_theory_to_proof: string -> string -> OuterKeyword.T -> |
23 (OuterParse.token list -> (local_theory -> Proof.state) * OuterLex.token list) -> unit |
25 (local_theory -> Proof.state) parser -> unit |
24 val print_outer_syntax: unit -> unit |
26 val print_outer_syntax: unit -> unit |
25 val scan: Position.T -> string -> OuterLex.token list |
27 val scan: Position.T -> string -> OuterLex.token list |
26 val parse: Position.T -> string -> Toplevel.transition list |
28 val parse: Position.T -> string -> Toplevel.transition list |
27 val process_file: Path.T -> theory -> theory |
29 val process_file: Path.T -> theory -> theory |
28 type isar |
30 type isar |
83 |
85 |
84 (** global outer syntax **) |
86 (** global outer syntax **) |
85 |
87 |
86 local |
88 local |
87 |
89 |
88 val global_parsers = ref (Symtab.empty: parser Symtab.table); |
90 val global_commands = ref (Symtab.empty: command Symtab.table); |
89 val global_markups = ref ([]: (string * ThyOutput.markup) list); |
91 val global_markups = ref ([]: (string * ThyOutput.markup) list); |
90 |
92 |
91 fun change_parsers f = CRITICAL (fn () => |
93 fun change_commands f = CRITICAL (fn () => |
92 (change global_parsers f; |
94 (change global_commands f; |
93 global_markups := |
95 global_markups := |
94 Symtab.fold (fn (name, Parser {markup = SOME m, ...}) => cons (name, m) | _ => I) |
96 Symtab.fold (fn (name, Command {markup = SOME m, ...}) => cons (name, m) | _ => I) |
95 (! global_parsers) [])); |
97 (! global_commands) [])); |
96 |
98 |
97 in |
99 in |
98 |
100 |
99 (* access current syntax *) |
101 (* access current syntax *) |
100 |
102 |
101 fun get_parsers () = CRITICAL (fn () => ! global_parsers); |
103 fun get_commands () = CRITICAL (fn () => ! global_commands); |
102 fun get_markups () = CRITICAL (fn () => ! global_markups); |
104 fun get_markups () = CRITICAL (fn () => ! global_markups); |
103 |
105 |
104 fun get_parser () = Symtab.lookup (get_parsers ()); |
106 fun get_command () = Symtab.lookup (get_commands ()); |
105 fun get_syntax () = CRITICAL (fn () => (OuterKeyword.get_lexicons (), get_parser ())); |
107 fun get_syntax () = CRITICAL (fn () => (OuterKeyword.get_lexicons (), get_command ())); |
106 |
108 |
107 fun is_markup kind name = AList.lookup (op =) (get_markups ()) name = SOME kind; |
109 fun is_markup kind name = AList.lookup (op =) (get_markups ()) name = SOME kind; |
108 |
110 |
109 |
111 |
110 (* augment syntax *) |
112 (* augment syntax *) |
111 |
113 |
112 fun add_parser name kind parser = CRITICAL (fn () => |
114 fun add_command name kind cmd = CRITICAL (fn () => |
113 (OuterKeyword.command name kind; |
115 (OuterKeyword.command name kind; |
114 if not (Symtab.defined (get_parsers ()) name) then () |
116 if not (Symtab.defined (get_commands ()) name) then () |
115 else warning ("Redefining outer syntax command " ^ quote name); |
117 else warning ("Redefining outer syntax command " ^ quote name); |
116 change_parsers (Symtab.update (name, parser)))); |
118 change_commands (Symtab.update (name, cmd)))); |
117 |
119 |
118 fun command name comment kind parse = |
120 fun command name comment kind parse = |
119 add_parser name kind (make_parser comment NONE false parse); |
121 add_command name kind (make_command comment NONE false parse); |
120 |
122 |
121 fun markup_command markup name comment kind parse = |
123 fun markup_command markup name comment kind parse = |
122 add_parser name kind (make_parser comment (SOME markup) false parse); |
124 add_command name kind (make_command comment (SOME markup) false parse); |
123 |
125 |
124 fun improper_command name comment kind parse = |
126 fun improper_command name comment kind parse = |
125 add_parser name kind (make_parser comment NONE true parse); |
127 add_command name kind (make_command comment NONE true parse); |
126 |
128 |
127 end; |
129 end; |
|
130 |
|
131 fun internal_command name parse = |
|
132 command name "(internal)" OuterKeyword.control (parse >> (fn tr => Toplevel.no_timing o tr)); |
128 |
133 |
129 |
134 |
130 (* local_theory commands *) |
135 (* local_theory commands *) |
131 |
136 |
132 fun local_theory_command do_print trans name comment kind parse = |
137 fun local_theory_command do_print trans name comment kind parse = |
133 command name comment kind (P.opt_target -- parse |
138 command name comment kind (P.opt_target -- parse |
134 >> (fn (loc, f) => (if do_print then Toplevel.print else I) o trans loc f)); |
139 >> (fn (loc, f) => (if do_print then Toplevel.print else I) o trans loc f)); |
135 |
140 |
136 val local_theory = local_theory_command false Toplevel.local_theory; |
141 val local_theory = local_theory_command false Toplevel.local_theory; |
137 val local_theory_to_proof' = local_theory_command true Toplevel.local_theory_to_proof'; |
142 val local_theory_to_proof' = local_theory_command true Toplevel.local_theory_to_proof'; |
138 val local_theory_to_proof = local_theory_command true Toplevel.local_theory_to_proof; |
143 val local_theory_to_proof = local_theory_command true Toplevel.local_theory_to_proof; |
139 |
144 |
140 |
145 |
141 (* inspect syntax *) |
146 (* inspect syntax *) |
142 |
147 |
143 fun dest_parsers () = |
148 fun dest_commands () = |
144 get_parsers () |> Symtab.dest |> sort_wrt #1 |
149 get_commands () |> Symtab.dest |> sort_wrt #1 |
145 |> map (fn (name, Parser {comment, int_only, ...}) => (name, comment, int_only)); |
150 |> map (fn (name, Command {comment, int_only, ...}) => (name, comment, int_only)); |
146 |
151 |
147 fun print_outer_syntax () = |
152 fun print_outer_syntax () = |
148 let |
153 let |
149 fun pretty_cmd (name, comment, _) = |
154 fun pretty_cmd (name, comment, _) = |
150 Pretty.block [Pretty.str (name ^ ":"), Pretty.brk 2, Pretty.str comment]; |
155 Pretty.block [Pretty.str (name ^ ":"), Pretty.brk 2, Pretty.str comment]; |
151 val (int_cmds, cmds) = List.partition #3 (dest_parsers ()); |
156 val (int_cmds, cmds) = List.partition #3 (dest_commands ()); |
152 in |
157 in |
153 [Pretty.strs ("syntax keywords:" :: map quote (OuterKeyword.dest_keywords ())), |
158 [Pretty.strs ("syntax keywords:" :: map quote (OuterKeyword.dest_keywords ())), |
154 Pretty.big_list "commands:" (map pretty_cmd cmds), |
159 Pretty.big_list "commands:" (map pretty_cmd cmds), |
155 Pretty.big_list "interactive-only commands:" (map pretty_cmd int_cmds)] |
160 Pretty.big_list "interactive-only commands:" (map pretty_cmd int_cmds)] |
156 |> Pretty.chunks |> Pretty.writeln |
161 |> Pretty.chunks |> Pretty.writeln |
223 |
228 |
224 fun isar term : isar = |
229 fun isar term : isar = |
225 Source.tty |
230 Source.tty |
226 |> Symbol.source {do_recover = true} |
231 |> Symbol.source {do_recover = true} |
227 |> T.source {do_recover = SOME true} OuterKeyword.get_lexicons Position.none |
232 |> T.source {do_recover = SOME true} OuterKeyword.get_lexicons Position.none |
228 |> toplevel_source term (SOME true) get_parser; |
233 |> toplevel_source term (SOME true) get_command; |
229 |
234 |
230 |
235 |
231 (* prepare toplevel commands -- fail-safe *) |
236 (* prepare toplevel commands -- fail-safe *) |
232 |
237 |
233 val not_singleton = "Exactly one command expected"; |
238 val not_singleton = "Exactly one command expected"; |
234 |
239 |
235 fun prepare_span parser span = |
240 fun prepare_span commands span = |
236 let |
241 let |
237 val range_pos = Position.encode_range (ThyEdit.span_range span); |
242 val range_pos = Position.encode_range (ThyEdit.span_range span); |
238 val toks = ThyEdit.span_content span; |
243 val toks = ThyEdit.span_content span; |
239 val _ = List.app ThyEdit.report_token toks; |
244 val _ = List.app ThyEdit.report_token toks; |
240 in |
245 in |
241 (case Source.exhaust (toplevel_source false NONE (K parser) (Source.of_list toks)) of |
246 (case Source.exhaust (toplevel_source false NONE (K commands) (Source.of_list toks)) of |
242 [tr] => (tr, true) |
247 [tr] => (tr, true) |
243 | [] => (Toplevel.ignored range_pos, false) |
248 | [] => (Toplevel.ignored range_pos, false) |
244 | _ => (Toplevel.malformed range_pos not_singleton, true)) |
249 | _ => (Toplevel.malformed range_pos not_singleton, true)) |
245 handle ERROR msg => (Toplevel.malformed range_pos msg, true) |
250 handle ERROR msg => (Toplevel.malformed range_pos msg, true) |
246 end; |
251 end; |
247 |
252 |
248 fun prepare_unit parser (cmd, proof, proper_proof) = |
253 fun prepare_unit commands (cmd, proof, proper_proof) = |
249 let |
254 let |
250 val (tr, proper_cmd) = prepare_span parser cmd; |
255 val (tr, proper_cmd) = prepare_span commands cmd; |
251 val proof_trs = map (prepare_span parser) proof |> filter #2 |> map #1; |
256 val proof_trs = map (prepare_span commands) proof |> filter #2 |> map #1; |
252 in |
257 in |
253 if proper_cmd andalso proper_proof then [(tr, proof_trs)] |
258 if proper_cmd andalso proper_proof then [(tr, proof_trs)] |
254 else map (rpair []) (if proper_cmd then tr :: proof_trs else proof_trs) |
259 else map (rpair []) (if proper_cmd then tr :: proof_trs else proof_trs) |
255 end; |
260 end; |
256 |
261 |
257 fun prepare_command pos str = |
262 fun prepare_command pos str = |
258 let val (lexs, parser) = get_syntax () in |
263 let val (lexs, commands) = get_syntax () in |
259 (case ThyEdit.parse_spans lexs pos str of |
264 (case ThyEdit.parse_spans lexs pos str of |
260 [span] => #1 (prepare_span parser span) |
265 [span] => #1 (prepare_span commands span) |
261 | _ => Toplevel.malformed pos not_singleton) |
266 | _ => Toplevel.malformed pos not_singleton) |
262 end; |
267 end; |
263 |
268 |
264 |
269 |
265 (* load_thy *) |
270 (* load_thy *) |
266 |
271 |
267 fun load_thy name pos text time = |
272 fun load_thy name pos text time = |
268 let |
273 let |
269 val (lexs, parser) = get_syntax (); |
274 val (lexs, commands) = get_syntax (); |
270 |
275 |
271 val _ = Present.init_theory name; |
276 val _ = Present.init_theory name; |
272 |
277 |
273 val toks = Source.exhausted (ThyEdit.token_source lexs pos (Source.of_list text)); |
278 val toks = Source.exhausted (ThyEdit.token_source lexs pos (Source.of_list text)); |
274 val spans = Source.exhaust (ThyEdit.span_source toks); |
279 val spans = Source.exhaust (ThyEdit.span_source toks); |
275 val _ = List.app ThyEdit.report_span spans; |
280 val _ = List.app ThyEdit.report_span spans; |
276 val units = Source.exhaust (ThyEdit.unit_source (Source.of_list spans)) |
281 val units = Source.exhaust (ThyEdit.unit_source (Source.of_list spans)) |
277 |> maps (prepare_unit parser); |
282 |> maps (prepare_unit commands); |
278 |
283 |
279 val _ = Present.theory_source name |
284 val _ = Present.theory_source name |
280 (fn () => HTML.html_mode (implode o map ThyEdit.present_span) spans); |
285 (fn () => HTML.html_mode (implode o map ThyEdit.present_span) spans); |
281 |
286 |
282 val _ = if time then writeln ("\n**** Starting theory " ^ quote name ^ " ****") else (); |
287 val _ = if time then writeln ("\n**** Starting theory " ^ quote name ^ " ****") else (); |