src/Pure/Syntax/syntax_ext.ML
changeset 62786 2461a58b3587
parent 62783 75ee05386b90
child 62787 f90a9fe3329f
--- a/src/Pure/Syntax/syntax_ext.ML	Fri Apr 01 14:38:54 2016 +0200
+++ b/src/Pure/Syntax/syntax_ext.ML	Fri Apr 01 14:49:02 2016 +0200
@@ -143,6 +143,59 @@
 val typ_to_nonterm1 = typ_to_nt "logic";
 
 
+(* properties *)
+
+local
+
+open Basic_Symbol_Pos;
+
+val err_prefix = "Error in mixfix block properties: ";
+val !!! = Symbol_Pos.!!! (fn () => err_prefix ^ "expected identifier or numeral or cartouche");
+
+val scan_atom =
+  Symbol_Pos.scan_ident ||
+  ($$$ "-" @@@ (Symbol_Pos.scan_float || Symbol_Pos.scan_nat)) ||
+  Symbol_Pos.scan_float || Symbol_Pos.scan_nat ||
+  Symbol_Pos.scan_cartouche_content err_prefix;
+
+val scan_blanks = Scan.many (Symbol.is_blank o Symbol_Pos.symbol);
+val scan_item =
+  scan_blanks |-- scan_atom --| scan_blanks
+    >> (fn ss => (Symbol_Pos.content ss, #1 (Symbol_Pos.range ss)));
+
+val scan_prop =
+  scan_item -- Scan.optional ($$ "=" |-- !!! scan_item >> #1) "true"
+    >> (fn ((x, pos), y) => (x, (y, pos)));
+
+val scan_end = Scan.ahead (Scan.one Symbol_Pos.is_eof) >> K ("", Position.none) || !!! Scan.fail;
+
+fun get_property default parse name props =
+  (case AList.lookup (op =) props name of
+    NONE => default
+  | SOME (s, pos) =>
+      (parse s handle Fail msg => error (msg ^ " for property " ^ quote name ^ Position.here pos)));
+
+in
+
+fun show_props props =
+  commas_quote (map #1 props) ^ Position.here_list (map (#2 o #2) props);
+
+fun read_properties ss =
+  let
+    val props = the (Scan.read Symbol_Pos.stopper (Scan.repeat1 scan_prop --| scan_end) ss);
+    val _ =
+      (case duplicates (eq_fst op =) props of
+        [] => ()
+      | dups => error ("Duplicate properties: " ^ show_props dups));
+  in props end;
+
+val get_string = get_property "" I;
+val get_bool = get_property false Markup.parse_bool;
+val get_nat = get_property 0 Markup.parse_nat;
+
+end;
+
+
 (* read mixfix annotations *)
 
 local
@@ -153,40 +206,21 @@
 fun scan_many pred = Scan.many (pred o Symbol_Pos.symbol);
 fun scan_many1 pred = Scan.many1 (pred o Symbol_Pos.symbol);
 
-(*block properties*)
-local
-  val err_prefix = "Error in mixfix block properties: ";
-  val !!! = Symbol_Pos.!!! (fn () => err_prefix ^ "expected identifier or numeral or cartouche");
-
-  val scan_atom =
-    Symbol_Pos.scan_ident ||
-    ($$$ "-" @@@ (Symbol_Pos.scan_float || Symbol_Pos.scan_nat)) ||
-    Symbol_Pos.scan_float || Symbol_Pos.scan_nat ||
-    Symbol_Pos.scan_cartouche_content err_prefix;
-
-  val scan_blanks = scan_many Symbol.is_blank;
-  val scan_item = scan_blanks |-- scan_atom --| scan_blanks >> Symbol_Pos.content;
+fun read_block_properties ss =
+  let
+    val props = read_properties ss;
 
-  val scan_prop = scan_item -- Scan.optional ($$ "=" |-- !!! scan_item) "true";
-  val scan_end = Scan.ahead (Scan.one Symbol_Pos.is_eof) >> K "" || !!! Scan.fail;
-in
-  fun read_block_properties ss =
-    let
-      fun err msg = error (msg ^ Position.here (#1 (Symbol_Pos.range ss)));
-      val props = the (Scan.read Symbol_Pos.stopper (Scan.repeat1 scan_prop --| scan_end) ss);
+    val markup_name = get_string Markup.markupN props;
+    val markup_props = fold (AList.delete (op =)) Markup.block_properties props;
+    val markup = (markup_name, map (apsnd #1) markup_props);
+    val _ =
+      if markup_name = "" andalso not (null markup_props) then
+        error ("Markup name required for block properties: " ^ show_props markup_props)
+      else ();
 
-      val markup_name = Markup.get_markup props;
-      val markup_props =
-        fold Properties.remove [Markup.markupN, Markup.consistentN, Markup.indentN] props;
-      val _ =
-        if markup_name = "" andalso not (null markup_props) then
-          err ("Markup name required for block properties: " ^ commas_quote (map #1 markup_props))
-        else ();
-
-      val consistent = Markup.get_consistent props handle Fail msg => err msg;
-      val indent = Markup.get_indent props handle Fail msg => err msg;
-    in Bg {markup = (markup_name, markup_props), consistent = consistent, indent = indent} end;
-end;
+    val consistent = get_bool Markup.consistentN props;
+    val indent = get_nat Markup.indentN props;
+  in Bg {markup = markup, consistent = consistent, indent = indent} end;
 
 val read_block_indent =
   map Symbol_Pos.symbol #> (fn ss =>