src/Pure/Syntax/syntax_ext.ML
changeset 62783 75ee05386b90
parent 62772 77bbe5af41c3
child 62786 2461a58b3587
--- a/src/Pure/Syntax/syntax_ext.ML	Thu Mar 31 16:23:25 2016 +0200
+++ b/src/Pure/Syntax/syntax_ext.ML	Thu Mar 31 23:36:33 2016 +0200
@@ -8,11 +8,15 @@
 sig
   datatype mfix = Mfix of Symbol_Pos.T list * typ * string * int list * int * Position.T
   val typ_to_nonterm: typ -> string
+  type block_info = {markup: Markup.T, consistent: bool, indent: int}
+  val block_indent: int -> block_info
   datatype xsymb =
     Delim of string |
     Argument of string * int |
     Space of string |
-    Bg of int | Brk of int | En
+    Bg of block_info |
+    Brk of int |
+    En
   datatype xprod = XProd of string * xsymb list * string * int
   val chain_pri: int
   val delims_of: xprod list -> string list list
@@ -62,11 +66,16 @@
   Space s: some white space for printing
   Bg, Brk, En: blocks and breaks for pretty printing*)
 
+type block_info = {markup: Markup.T, consistent: bool, indent: int};
+fun block_indent indent = {markup = Markup.empty, consistent = false, indent = indent};
+
 datatype xsymb =
   Delim of string |
   Argument of string * int |
   Space of string |
-  Bg of int | Brk of int | En;
+  Bg of block_info |
+  Brk of int |
+  En;
 
 fun is_delim (Delim _) = true
   | is_delim _ = false;
@@ -144,19 +153,57 @@
 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;
+
+  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 = 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 read_block_indent =
+  map Symbol_Pos.symbol #> (fn ss =>
+    Bg (block_indent (if ss = ["0", "0"] then ~1 else #1 (Library.read_int ss))));
+
 val is_meta = member (op =) ["(", ")", "/", "_", "\<index>"];
 
 val scan_delim_char =
   $$ "'" |-- scan_one ((not o Symbol.is_blank) andf Symbol.not_eof) ||
   scan_one ((not o is_meta) andf (not o Symbol.is_blank) andf Symbol.not_eof);
 
-fun read_int ["0", "0"] = ~1
-  | read_int cs = #1 (Library.read_int cs);
-
 val scan_sym =
   $$ "_" >> K (Argument ("", 0)) ||
   $$ "\<index>" >> K index ||
-  $$ "(" |-- scan_many Symbol.is_digit >> (Bg o read_int o map Symbol_Pos.symbol) ||
+  $$ "(" |--
+   (Symbol_Pos.scan_cartouche_content "Error in mixfix annotation: " >> read_block_properties ||
+    scan_many Symbol.is_digit >> read_block_indent) ||
   $$ ")" >> K En ||
   $$ "/" -- $$ "/" >> K (Brk ~1) ||
   $$ "/" |-- scan_many Symbol.is_blank >> (Brk o length) ||