improved case syntax: more careful treatment of position constraints, which enables PIDE markup;
authorwenzelm
Thu, 05 Jan 2012 18:18:39 +0100
changeset 46125 00cd193a48dc
parent 46124 3ee75fe01986
child 46126 bab00660539d
improved case syntax: more careful treatment of position constraints, which enables PIDE markup; tuned;
NEWS
src/HOL/HOL.thy
src/HOL/HOLCF/One.thy
src/HOL/HOLCF/Ssum.thy
src/HOL/HOLCF/Tools/Domain/domain_constructors.ML
src/HOL/HOLCF/Up.thy
src/HOL/List.thy
src/HOL/Tools/Datatype/datatype_case.ML
--- a/NEWS	Thu Jan 05 15:31:49 2012 +0100
+++ b/NEWS	Thu Jan 05 18:18:39 2012 +0100
@@ -60,6 +60,12 @@
 
 *** HOL ***
 
+* Concrete syntax for case expressions includes constraints for source
+positions, and thus produces Prover IDE markup for its bindings.
+INCOMPATIBILITY for old-style syntax translations that augment the
+pattern notation; e.g. see src/HOL/HOLCF/One.thy for translations of
+one_case.
+
 * Finite_Set.fold now qualified.  INCOMPATIBILITY.
 
 * Renamed some facts on canonical fold on lists, in order to avoid problems
--- a/src/HOL/HOL.thy	Thu Jan 05 15:31:49 2012 +0100
+++ b/src/HOL/HOL.thy	Thu Jan 05 18:18:39 2012 +0100
@@ -104,34 +104,31 @@
 notation (xsymbols)
   iff  (infixr "\<longleftrightarrow>" 25)
 
-nonterminal letbinds and letbind
-nonterminal case_pat and case_syn and cases_syn
+syntax
+  "_The" :: "[pttrn, bool] => 'a"  ("(3THE _./ _)" [0, 10] 10)
+translations
+  "THE x. P" == "CONST The (%x. P)"
+print_translation {*
+  [(@{const_syntax The}, fn [Abs abs] =>
+      let val (x, t) = Syntax_Trans.atomic_abs_tr' abs
+      in Syntax.const @{syntax_const "_The"} $ x $ t end)]
+*}  -- {* To avoid eta-contraction of body *}
 
+nonterminal letbinds and letbind
 syntax
-  "_The"        :: "[pttrn, bool] => 'a"                 ("(3THE _./ _)" [0, 10] 10)
-
   "_bind"       :: "[pttrn, 'a] => letbind"              ("(2_ =/ _)" 10)
   ""            :: "letbind => letbinds"                 ("_")
   "_binds"      :: "[letbind, letbinds] => letbinds"     ("_;/ _")
   "_Let"        :: "[letbinds, 'a] => 'a"                ("(let (_)/ in (_))" [0, 10] 10)
 
-  "_case_syntax"      :: "['a, cases_syn] => 'b"              ("(case _ of/ _)" 10)
-  "_case1"            :: "[case_pat, 'b] => case_syn"         ("(2_ =>/ _)" 10)
-  ""                  :: "case_syn => cases_syn"              ("_")
-  "_case2"            :: "[case_syn, cases_syn] => cases_syn" ("_/ | _")
-  "_strip_positions"  :: "'a => case_pat"                     ("_")
-
+nonterminal case_syn and cases_syn
+syntax
+  "_case_syntax" :: "['a, cases_syn] => 'b"  ("(case _ of/ _)" 10)
+  "_case1" :: "['a, 'b] => case_syn"  ("(2_ =>/ _)" 10)
+  "" :: "case_syn => cases_syn"  ("_")
+  "_case2" :: "[case_syn, cases_syn] => cases_syn"  ("_/ | _")
 syntax (xsymbols)
-  "_case1" :: "[case_pat, 'b] => case_syn"  ("(2_ \<Rightarrow>/ _)" 10)
-
-translations
-  "THE x. P"              == "CONST The (%x. P)"
-
-print_translation {*
-  [(@{const_syntax The}, fn [Abs abs] =>
-      let val (x, t) = Syntax_Trans.atomic_abs_tr' abs
-      in Syntax.const @{syntax_const "_The"} $ x $ t end)]
-*}  -- {* To avoid eta-contraction of body *}
+  "_case1" :: "['a, 'b] => case_syn"  ("(2_ \<Rightarrow>/ _)" 10)
 
 notation (xsymbols)
   All  (binder "\<forall>" 10) and
--- a/src/HOL/HOLCF/One.thy	Thu Jan 05 15:31:49 2012 +0100
+++ b/src/HOL/HOLCF/One.thy	Thu Jan 05 18:18:39 2012 +0100
@@ -58,6 +58,7 @@
 
 translations
   "case x of XCONST ONE \<Rightarrow> t" == "CONST one_case\<cdot>t\<cdot>x"
+  "case x of XCONST ONE :: 'a \<Rightarrow> t" => "CONST one_case\<cdot>t\<cdot>x"
   "\<Lambda> (XCONST ONE). t" == "CONST one_case\<cdot>t"
 
 lemma one_case1 [simp]: "(case \<bottom> of ONE \<Rightarrow> t) = \<bottom>"
--- a/src/HOL/HOLCF/Ssum.thy	Thu Jan 05 15:31:49 2012 +0100
+++ b/src/HOL/HOLCF/Ssum.thy	Thu Jan 05 18:18:39 2012 +0100
@@ -168,6 +168,7 @@
 
 translations
   "case s of XCONST sinl\<cdot>x \<Rightarrow> t1 | XCONST sinr\<cdot>y \<Rightarrow> t2" == "CONST sscase\<cdot>(\<Lambda> x. t1)\<cdot>(\<Lambda> y. t2)\<cdot>s"
+  "case s of (XCONST sinl :: 'a)\<cdot>x \<Rightarrow> t1 | XCONST sinr\<cdot>y \<Rightarrow> t2" => "CONST sscase\<cdot>(\<Lambda> x. t1)\<cdot>(\<Lambda> y. t2)\<cdot>s"
 
 translations
   "\<Lambda>(XCONST sinl\<cdot>x). t" == "CONST sscase\<cdot>(\<Lambda> x. t)\<cdot>\<bottom>"
--- a/src/HOL/HOLCF/Tools/Domain/domain_constructors.ML	Thu Jan 05 15:31:49 2012 +0100
+++ b/src/HOL/HOLCF/Tools/Domain/domain_constructors.ML	Thu Jan 05 18:18:39 2012 +0100
@@ -452,27 +452,35 @@
       val cabs = app "_cabs"
       val capp = app @{const_syntax Rep_cfun}
       val capps = Library.foldl capp
-      fun con1 authentic n (con,args) =
+      fun con1 authentic n (con, args) =
           Library.foldl capp (c_ast authentic con, argvars n args)
-      fun case1 authentic (n, c) =
-          app "_case1" (Ast.strip_positions (con1 authentic n c), expvar n)
+      fun con1_constraint authentic n (con, args) =
+          Library.foldl capp
+            (Ast.Appl
+              [Ast.Constant @{syntax_const "_constrain"}, c_ast authentic con,
+                Ast.Variable ("'a" ^ string_of_int n)],
+             argvars n args)
+      fun case1 constraint authentic (n, c) =
+        app @{syntax_const "_case1"}
+          ((if constraint then con1_constraint else con1) authentic n c, expvar n)
       fun arg1 (n, (_, args)) = List.foldr cabs (expvar n) (argvars n args)
       fun when1 n (m, c) = if n = m then arg1 (n, c) else Ast.Constant @{const_syntax bottom}
       val case_constant = Ast.Constant (syntax (case_const dummyT))
-      fun case_trans authentic =
-        (if authentic then Syntax.Parse_Print_Rule else Syntax.Parse_Rule)
+      fun case_trans constraint authentic =
           (app "_case_syntax"
             (Ast.Variable "x",
-             foldr1 (app "_case2") (map_index (case1 authentic) spec)),
+             foldr1 (app @{syntax_const "_case2"}) (map_index (case1 constraint authentic) spec)),
            capp (capps (case_constant, map_index arg1 spec), Ast.Variable "x"))
       fun one_abscon_trans authentic (n, c) =
-        (if authentic then Syntax.Parse_Print_Rule else Syntax.Parse_Rule)
-          (cabs (con1 authentic n c, expvar n),
-           capps (case_constant, map_index (when1 n) spec))
+          (if authentic then Syntax.Parse_Print_Rule else Syntax.Parse_Rule)
+            (cabs (con1 authentic n c, expvar n),
+             capps (case_constant, map_index (when1 n) spec))
       fun abscon_trans authentic =
           map_index (one_abscon_trans authentic) spec
       val trans_rules : Ast.ast Syntax.trrule list =
-          case_trans false :: case_trans true ::
+          Syntax.Parse_Print_Rule (case_trans false true) ::
+          Syntax.Parse_Rule (case_trans false false) ::
+          Syntax.Parse_Rule (case_trans true false) ::
           abscon_trans false @ abscon_trans true
     in
       val thy = Sign.add_trrules trans_rules thy
--- a/src/HOL/HOLCF/Up.thy	Thu Jan 05 15:31:49 2012 +0100
+++ b/src/HOL/HOLCF/Up.thy	Thu Jan 05 18:18:39 2012 +0100
@@ -181,6 +181,7 @@
 
 translations
   "case l of XCONST up\<cdot>x \<Rightarrow> t" == "CONST fup\<cdot>(\<Lambda> x. t)\<cdot>l"
+  "case l of (XCONST up :: 'a)\<cdot>x \<Rightarrow> t" => "CONST fup\<cdot>(\<Lambda> x. t)\<cdot>l"
   "\<Lambda>(XCONST up\<cdot>x). t" == "CONST fup\<cdot>(\<Lambda> x. t)"
 
 text {* continuous versions of lemmas for @{typ "('a)u"} *}
--- a/src/HOL/List.thy	Thu Jan 05 15:31:49 2012 +0100
+++ b/src/HOL/List.thy	Thu Jan 05 18:18:39 2012 +0100
@@ -386,7 +386,7 @@
       (* FIXME proper name context!? *)
       val x = Free (singleton (Name.variant_list (fold Term.add_free_names [p, e] [])) "x", dummyT);
       val e = if opti then singl e else e;
-      val case1 = Syntax.const @{syntax_const "_case1"} $ Term_Position.strip_positions p $ e;
+      val case1 = Syntax.const @{syntax_const "_case1"} $ p $ e;
       val case2 =
         Syntax.const @{syntax_const "_case1"} $
           Syntax.const @{const_syntax dummy_pattern} $ NilC;
--- a/src/HOL/Tools/Datatype/datatype_case.ML	Thu Jan 05 15:31:49 2012 +0100
+++ b/src/HOL/Tools/Datatype/datatype_case.ML	Thu Jan 05 18:18:39 2012 +0100
@@ -3,6 +3,9 @@
     Author:     Stefan Berghofer, TU Muenchen
 
 Datatype package: nested case expressions on datatypes.
+
+TODO: generic tool with separate data slot, without hard-wiring the
+datatype package.
 *)
 
 signature DATATYPE_CASE =
@@ -57,25 +60,30 @@
       strip_constraints t ||> cons tT
   | strip_constraints t = (t, []);
 
-fun mk_fun_constrain tT t =
-  Syntax.const @{syntax_const "_constrain"} $ t $
-    (Syntax.const @{type_syntax fun} $ tT $ Syntax.const @{type_syntax dummy});
+fun constrain_Abs tT t = Syntax.const @{syntax_const "_constrainAbs"} $ t $ tT;
 
 
 (*Produce an instance of a constructor, plus fresh variables for its arguments.*)
 fun fresh_constr ty_match ty_inst colty used c =
   let
-    val (_, Ty) = dest_Const c;
-    val Ts = binder_types Ty;
+    val (_, T) = dest_Const c;
+    val Ts = binder_types T;
     val names =
       Name.variant_list used (Datatype_Prop.make_tnames (map Logic.unvarifyT_global Ts));
-    val ty = body_type Ty;
+    val ty = body_type T;
     val ty_theta = ty_match ty colty
       handle Type.TYPE_MATCH => raise CASE_ERROR ("type mismatch", ~1);
     val c' = ty_inst ty_theta c;
     val gvars = map (ty_inst ty_theta o Free) (names ~~ Ts);
   in (c', gvars) end;
 
+fun strip_comb_positions tm =
+  let
+    fun result t ts = (Term_Position.strip_positions t, ts);
+    fun strip (t as (Const (@{syntax_const "_constrain"}, _) $ _ $ _)) ts = result t ts
+      | strip (f $ t) ts = strip f (t :: ts)
+      | strip t ts = result t ts;
+  in strip tm [] end;
 
 (*Go through a list of rows and pick out the ones beginning with a
   pattern with constructor = name.*)
@@ -83,7 +91,7 @@
   let val k = length (binder_types T) in
     fold (fn (row as ((prfx, p :: ps), rhs as (_, i))) =>
       fn ((in_group, not_in_group), (names, cnstrts)) =>
-        (case strip_comb p of
+        (case strip_comb_positions p of
           (Const (name', _), args) =>
             if name = name' then
               if length args = k then
@@ -162,7 +170,8 @@
       | mk path (rows as ((row as ((_, [Free _]), _)) :: _ :: _)) = mk path [row]
       | mk (u :: us) (rows as ((_, _ :: _), _) :: _) =
           let val col0 = map (fn ((_, p :: _), (_, i)) => (p, i)) rows in
-            (case Option.map (apfst head_of) (find_first (not o is_Free o fst) col0) of
+            (case Option.map (apfst (fst o strip_comb_positions))
+                (find_first (not o is_Free o fst) col0) of
               NONE =>
                 let
                   val rows' = map (fn ((v, _), row) => row ||>
@@ -186,7 +195,7 @@
                         map2 (fn {new_formals, names, constraints, ...} =>
                           fold_rev (fn ((x as Free (_, T), s), cnstrts) => fn t =>
                             Abs (if s = "" then name else s, T, abstract_over (x, t))
-                            |> fold mk_fun_constrain cnstrts) (new_formals ~~ names ~~ constraints))
+                            |> fold constrain_Abs cnstrts) (new_formals ~~ names ~~ constraints))
                         subproblems dtrees;
                       val types = map type_of (case_functions @ [u]);
                       val case_const = Const (case_name, types ---> range_ty);
@@ -210,7 +219,7 @@
           case_error (quote s ^ " occurs repeatedly in the pattern " ^
             quote (Syntax.string_of_term ctxt pat))
         else x :: xs)
-    | _ => I) pat [];
+    | _ => I) (Term_Position.strip_positions pat) [];
 
 fun gen_make_case ty_match ty_inst type_of ctxt config used x clauses =
   let
@@ -432,7 +441,8 @@
                 | Const (s, _) => Syntax.const (Lexicon.mark_const s)
                 | t => t) pat $
             map_aterms
-              (fn x as Free (s, T) => if member (op =) xs (s, T) then Syntax_Trans.mark_bound s else x
+              (fn x as Free (s, T) =>
+                  if member (op =) xs (s, T) then Syntax_Trans.mark_bound s else x
                 | t => t) rhs
         end;
     in