137 val scan_blanks = Scan.many (Symbol.is_blank o Symbol_Pos.symbol); |
140 val scan_blanks = Scan.many (Symbol.is_blank o Symbol_Pos.symbol); |
138 val scan_item = |
141 val scan_item = |
139 scan_blanks |-- scan_atom --| scan_blanks |
142 scan_blanks |-- scan_atom --| scan_blanks |
140 >> (fn ss => (Symbol_Pos.content ss, #1 (Symbol_Pos.range ss))); |
143 >> (fn ss => (Symbol_Pos.content ss, #1 (Symbol_Pos.range ss))); |
141 |
144 |
142 val scan_prop = |
145 val scan_prop = scan_item -- Scan.option ($$ "=" |-- !!! scan_item); |
143 scan_item -- Scan.optional ($$ "=" |-- !!! scan_item >> #1) "true" |
146 |
144 >> (fn ((x, pos), y) => (x, (y, pos))); |
147 fun get_property default0 default1 parse name props = |
145 |
148 (case find_first (fn ((a, _), _) => a = name) props of |
146 fun get_property default parse name props = |
149 NONE => default0 |
147 (case AList.lookup (op =) props name of |
150 | SOME (_, NONE) => default1 |
148 NONE => default |
151 | SOME ((_, pos1), SOME (b, pos2)) => |
149 | SOME (s, pos) => |
152 (parse (b, pos2) handle Fail msg => |
150 (parse s handle Fail msg => |
153 error (msg ^ " for property " ^ quote name ^ Position.here_list [pos1, pos2]))); |
151 error (msg ^ " for property " ^ quote name ^ Position.here pos))); |
|
152 |
154 |
153 in |
155 in |
154 |
156 |
155 fun read_properties ss = |
157 fun read_properties ss = |
156 let |
158 let |
157 val props = |
159 val props = |
158 (case Scan.error (Scan.finite Symbol_Pos.stopper (Scan.repeat scan_prop)) ss of |
160 (case Scan.error (Scan.finite Symbol_Pos.stopper (Scan.repeat scan_prop)) ss of |
159 (props, []) => props |
161 (props, []) => props |
160 | (_, (_, pos) :: _) => error (err_prefix ^ "bad input" ^ Position.here pos)); |
162 | (_, (_, pos) :: _) => error (err_prefix ^ "bad input" ^ Position.here pos)); |
|
163 fun ok (_, bs) = length bs <= 1; |
161 val _ = |
164 val _ = |
162 (case AList.group (op =) props |> filter (fn (_, [_]) => false | _ => true) of |
165 (case AList.group (eq_fst op =) props |> filter_out ok of |
163 [] => () |
166 [] => () |
164 | dups => error ("Duplicate properties: " ^ commas_quote (map #1 dups) ^ |
167 | dups => error ("Duplicate properties: " ^ show_names (map #1 dups))); |
165 Position.here_list (map #2 (maps #2 dups)))); |
|
166 in props end; |
168 in props end; |
167 |
169 |
168 val get_string = get_property "" I; |
170 val get_string = get_property "" "" #1; |
169 val get_bool = get_property false Value.parse_bool; |
171 val get_bool = get_property false true (Value.parse_bool o #1); |
170 val get_nat = get_property 0 Value.parse_nat; |
172 val get_nat = get_property 0 1 (Value.parse_nat o #1); |
171 |
173 |
172 end; |
174 end; |
173 |
175 |
174 |
176 |
175 (* read mixfix annotations *) |
177 (* read mixfix annotations *) |
212 fun read_block_properties ss = |
214 fun read_block_properties ss = |
213 let |
215 let |
214 val props = read_properties ss; |
216 val props = read_properties ss; |
215 |
217 |
216 val markup_name = get_string Markup.markupN props; |
218 val markup_name = get_string Markup.markupN props; |
217 val markup_props = fold (AList.delete (op =)) Markup.block_properties props; |
219 val markup_props = props |> map_filter (fn (a, opt_b) => |
218 val markup = (markup_name, map (apsnd #1) markup_props); |
220 if member (op =) Markup.block_properties (#1 a) then NONE |
|
221 else SOME (a, the_default ("", Position.none) opt_b)); |
|
222 val markup = (markup_name, map (apply2 #1) markup_props); |
219 val _ = |
223 val _ = |
220 if markup_name = "" andalso not (null markup_props) then |
224 if markup_name = "" andalso not (null markup_props) then |
221 error ("Markup name required for block properties: " ^ |
225 error ("Markup name required for block properties: " ^ show_names (map #1 markup_props)) |
222 commas_quote (map #1 markup_props) ^ Position.here_list (map (#2 o #2) markup_props)) |
|
223 else (); |
226 else (); |
224 |
227 |
225 val consistent = get_bool Markup.consistentN props; |
228 val consistent = get_bool Markup.consistentN props; |
226 val unbreakable = get_bool Markup.unbreakableN props; |
229 val unbreakable = get_bool Markup.unbreakableN props; |
227 val indent = get_nat Markup.indentN props; |
230 val indent = get_nat Markup.indentN props; |