4 Isabelle/Isar outer syntax. |
4 Isabelle/Isar outer syntax. |
5 *) |
5 *) |
6 |
6 |
7 signature OUTER_SYNTAX = |
7 signature OUTER_SYNTAX = |
8 sig |
8 sig |
9 datatype markup = Markup | Markup_Env | Verbatim |
|
10 val is_markup: theory -> markup -> string -> bool |
|
11 val help: theory -> string list -> unit |
9 val help: theory -> string list -> unit |
12 val print_commands: theory -> unit |
10 val print_commands: theory -> unit |
13 type command_spec = string * Position.T |
11 type command_spec = string * Position.T |
14 val command: command_spec -> string -> |
12 val command: command_spec -> string -> |
15 (Toplevel.transition -> Toplevel.transition) parser -> unit |
|
16 val markup_command: markup -> command_spec -> string -> |
|
17 (Toplevel.transition -> Toplevel.transition) parser -> unit |
13 (Toplevel.transition -> Toplevel.transition) parser -> unit |
18 val local_theory': command_spec -> string -> |
14 val local_theory': command_spec -> string -> |
19 (bool -> local_theory -> local_theory) parser -> unit |
15 (bool -> local_theory -> local_theory) parser -> unit |
20 val local_theory: command_spec -> string -> |
16 val local_theory: command_spec -> string -> |
21 (local_theory -> local_theory) parser -> unit |
17 (local_theory -> local_theory) parser -> unit |
45 err_command "Duplicate outer syntax command " name ps; |
41 err_command "Duplicate outer syntax command " name ps; |
46 |
42 |
47 |
43 |
48 (* command parsers *) |
44 (* command parsers *) |
49 |
45 |
50 datatype markup = Markup | Markup_Env | Verbatim; |
|
51 |
|
52 datatype command = Command of |
46 datatype command = Command of |
53 {comment: string, |
47 {comment: string, |
54 markup: markup option, |
|
55 parse: (Toplevel.transition -> Toplevel.transition) parser, |
48 parse: (Toplevel.transition -> Toplevel.transition) parser, |
56 pos: Position.T, |
49 pos: Position.T, |
57 id: serial}; |
50 id: serial}; |
58 |
51 |
59 fun eq_command (Command {id = id1, ...}, Command {id = id2, ...}) = id1 = id2; |
52 fun eq_command (Command {id = id1, ...}, Command {id = id2, ...}) = id1 = id2; |
60 |
53 |
61 fun new_command comment markup parse pos = |
54 fun new_command comment parse pos = |
62 Command {comment = comment, markup = markup, parse = parse, pos = pos, id = serial ()}; |
55 Command {comment = comment, parse = parse, pos = pos, id = serial ()}; |
63 |
56 |
64 fun command_pos (Command {pos, ...}) = pos; |
57 fun command_pos (Command {pos, ...}) = pos; |
65 |
58 |
66 fun command_markup def (name, Command {pos, id, ...}) = |
59 fun command_markup def (name, Command {pos, id, ...}) = |
67 Markup.properties (Position.entity_properties_of def id pos) |
60 Markup.properties (Position.entity_properties_of def id pos) |
72 (Pretty.marks_str |
65 (Pretty.marks_str |
73 ([Active.make_markup Markup.sendbackN {implicit = true, properties = [Markup.padding_line]}, |
66 ([Active.make_markup Markup.sendbackN {implicit = true, properties = [Markup.padding_line]}, |
74 command_markup false cmd], name) :: Pretty.str ":" :: Pretty.brk 2 :: Pretty.text comment); |
67 command_markup false cmd], name) :: Pretty.str ":" :: Pretty.brk 2 :: Pretty.text comment); |
75 |
68 |
76 |
69 |
77 (* type syntax *) |
70 (* theory data *) |
78 |
|
79 datatype syntax = Syntax of |
|
80 {commands: command Symtab.table, |
|
81 markups: (string * markup) list}; |
|
82 |
|
83 fun make_syntax (commands, markups) = |
|
84 Syntax {commands = commands, markups = markups}; |
|
85 |
71 |
86 structure Data = Theory_Data |
72 structure Data = Theory_Data |
87 ( |
73 ( |
88 type T = syntax; |
74 type T = command Symtab.table; |
89 val empty = make_syntax (Symtab.empty, []); |
75 val empty = Symtab.empty; |
90 val extend = I; |
76 val extend = I; |
91 fun merge (Syntax {commands = commands1, markups = markups1}, |
77 fun merge data : T = |
92 Syntax {commands = commands2, markups = markups2}) = |
78 data |> Symtab.join (fn name => fn (cmd1, cmd2) => |
93 let |
79 if eq_command (cmd1, cmd2) then raise Symtab.SAME |
94 val commands' = (commands1, commands2) |
80 else err_dup_command name [command_pos cmd1, command_pos cmd2]); |
95 |> Symtab.join (fn name => fn (cmd1, cmd2) => |
|
96 if eq_command (cmd1, cmd2) then raise Symtab.SAME |
|
97 else err_dup_command name [command_pos cmd1, command_pos cmd2]); |
|
98 val markups' = AList.merge (op =) (K true) (markups1, markups2); |
|
99 in make_syntax (commands', markups') end; |
|
100 ); |
81 ); |
101 |
82 |
102 |
83 val get_commands = Data.get; |
103 (* inspect syntax *) |
84 val dest_commands = get_commands #> Symtab.dest #> sort_wrt #1; |
104 |
85 val lookup_commands = Symtab.lookup o get_commands; |
105 val get_syntax = Data.get; |
|
106 |
|
107 val dest_commands = |
|
108 get_syntax #> (fn Syntax {commands, ...} => commands |> Symtab.dest |> sort_wrt #1); |
|
109 |
|
110 val lookup_commands = |
|
111 get_syntax #> (fn Syntax {commands, ...} => Symtab.lookup commands); |
|
112 |
|
113 val is_markup = |
|
114 get_syntax #> (fn Syntax {markups, ...} => fn kind => fn name => |
|
115 AList.lookup (op =) markups name = SOME kind); |
|
116 |
86 |
117 fun help thy pats = |
87 fun help thy pats = |
118 dest_commands thy |
88 dest_commands thy |
119 |> filter (fn (name, _) => forall (fn pat => match_string pat name) pats) |
89 |> filter (fn (name, _) => forall (fn pat => match_string pat name) pats) |
120 |> map pretty_command |
90 |> map pretty_command |
130 Pretty.big_list "commands:" (map pretty_command commands)] |
100 Pretty.big_list "commands:" (map pretty_command commands)] |
131 |> Pretty.writeln_chunks |
101 |> Pretty.writeln_chunks |
132 end; |
102 end; |
133 |
103 |
134 |
104 |
135 (* build syntax *) |
105 (* maintain commands *) |
136 |
106 |
137 fun add_command name cmd thy = thy |> Data.map (fn Syntax {commands, ...} => |
107 fun add_command name cmd thy = |
138 let |
108 let |
139 val keywords = Thy_Header.get_keywords thy; |
109 val _ = |
140 val _ = |
110 Keyword.is_command (Thy_Header.get_keywords thy) name orelse |
141 Keyword.is_command keywords name orelse |
|
142 err_command "Undeclared outer syntax command " name [command_pos cmd]; |
111 err_command "Undeclared outer syntax command " name [command_pos cmd]; |
143 |
112 val _ = |
144 val _ = |
113 (case lookup_commands thy name of |
145 (case Symtab.lookup commands name of |
|
146 NONE => () |
114 NONE => () |
147 | SOME cmd' => err_dup_command name [command_pos cmd, command_pos cmd']); |
115 | SOME cmd' => err_dup_command name [command_pos cmd, command_pos cmd']); |
148 |
|
149 val _ = |
116 val _ = |
150 Context_Position.report_generic (ML_Context.the_generic_context ()) |
117 Context_Position.report_generic (ML_Context.the_generic_context ()) |
151 (command_pos cmd) (command_markup true (name, cmd)); |
118 (command_pos cmd) (command_markup true (name, cmd)); |
152 |
119 in Data.map (Symtab.update (name, cmd)) thy end; |
153 val commands' = Symtab.update (name, cmd) commands; |
|
154 val markups' = |
|
155 Symtab.fold (fn (name, Command {markup = SOME m, ...}) => cons (name, m) | _ => I) |
|
156 commands' []; |
|
157 in make_syntax (commands', markups') end); |
|
158 |
120 |
159 val _ = Theory.setup (Theory.at_end (fn thy => |
121 val _ = Theory.setup (Theory.at_end (fn thy => |
160 let |
122 let |
161 val keywords = Thy_Header.get_keywords thy; |
123 val command_keywords = |
162 val major = Keyword.major_keywords keywords; |
124 Scan.dest_lexicon (Keyword.major_keywords (Thy_Header.get_keywords thy)); |
163 val _ = |
125 val _ = |
164 (case subtract (op =) (map #1 (dest_commands thy)) (Scan.dest_lexicon major) of |
126 (case subtract (op =) (map #1 (dest_commands thy)) command_keywords of |
165 [] => () |
127 [] => () |
166 | missing => error ("Missing outer syntax command(s) " ^ commas_quote missing)) |
128 | missing => error ("Missing outer syntax command(s) " ^ commas_quote missing)) |
167 in NONE end)); |
129 in NONE end)); |
168 |
130 |
169 |
131 |
170 (* implicit theory setup *) |
132 (* implicit theory setup *) |
171 |
133 |
172 type command_spec = string * Position.T; |
134 type command_spec = string * Position.T; |
173 |
135 |
174 fun command (name, pos) comment parse = |
136 fun command (name, pos) comment parse = |
175 Theory.setup (add_command name (new_command comment NONE parse pos)); |
137 Theory.setup (add_command name (new_command comment parse pos)); |
176 |
|
177 fun markup_command markup (name, pos) comment parse = |
|
178 Theory.setup (add_command name (new_command comment (SOME markup) parse pos)); |
|
179 |
138 |
180 fun local_theory_command trans command_spec comment parse = |
139 fun local_theory_command trans command_spec comment parse = |
181 command command_spec comment (Parse.opt_target -- parse >> (fn (loc, f) => trans loc f)); |
140 command command_spec comment (Parse.opt_target -- parse >> (fn (loc, f) => trans loc f)); |
182 |
141 |
183 val local_theory' = local_theory_command Toplevel.local_theory'; |
142 val local_theory' = local_theory_command Toplevel.local_theory'; |