attribute "code" declares concrete and abstract code equations uniformly; added explicit "code equation" instead
authorhaftmann
Sat, 13 Jul 2013 17:53:58 +0200
changeset 52637 1501ebe39711
parent 52636 238cec044ebf
child 52653 0589394aaaa5
attribute "code" declares concrete and abstract code equations uniformly; added explicit "code equation" instead
NEWS
src/Doc/Codegen/Refinement.thy
src/Doc/IsarRef/HOL_Specific.thy
src/Pure/Isar/code.ML
--- a/NEWS	Sat Jul 13 17:53:57 2013 +0200
+++ b/NEWS	Sat Jul 13 17:53:58 2013 +0200
@@ -84,6 +84,9 @@
 
 *** HOL ***
 
+* Attibute 'code': 'code' now declares concrete and abstract code equations uniformly.
+Use explicit 'code equation' and 'code abstract' to distinguish both when desired.
+
 * Code generator:
   * 'code_printing' unifies 'code_const' / 'code_type' / 'code_class' / 'code_instance'.
   * 'code_identifier' declares name hints for arbitrary identifiers in generated code,
--- a/src/Doc/Codegen/Refinement.thy	Sat Jul 13 17:53:57 2013 +0200
+++ b/src/Doc/Codegen/Refinement.thy	Sat Jul 13 17:53:58 2013 +0200
@@ -236,7 +236,7 @@
   \noindent This we have to prove indirectly as follows:
 *}
 
-lemma %quote [code abstract]:
+lemma %quote [code]:
   "list_of_dlist Dlist.empty = []"
   by (fact list_of_dlist_empty)
 
@@ -247,11 +247,11 @@
   similar:
 *}
 
-lemma %quote [code abstract]:
+lemma %quote [code]:
   "list_of_dlist (Dlist.insert x dxs) = List.insert x (list_of_dlist dxs)"
   by (fact list_of_dlist_insert)
 
-lemma %quote [code abstract]:
+lemma %quote [code]:
   "list_of_dlist (Dlist.remove x dxs) = remove1 x (list_of_dlist dxs)"
   by (fact list_of_dlist_remove)
 
@@ -261,7 +261,7 @@
 
 text %quotetypewriter {*
   @{code_stmts Dlist.empty Dlist.insert Dlist.remove list_of_dlist (Haskell)}
-*} (*(types) dlist (consts) dempty dinsert dremove list_of List.member insert remove *)
+*}
 
 text {*
   Typical data structures implemented by representations involving
--- a/src/Doc/IsarRef/HOL_Specific.thy	Sat Jul 13 17:53:57 2013 +0200
+++ b/src/Doc/IsarRef/HOL_Specific.thy	Sat Jul 13 17:53:58 2013 +0200
@@ -2242,7 +2242,7 @@
     target: 'SML' | 'OCaml' | 'Haskell' | 'Scala' | 'Eval'
     ;
 
-    @@{attribute (HOL) code} ( 'del' | 'abstype' | 'abstract' )?
+    @@{attribute (HOL) code} ( 'del' | 'equation' | 'abstype' | 'abstract' )?
     ;
 
     @@{command (HOL) code_abort} ( const + )
@@ -2397,12 +2397,18 @@
   ``@{verbatim "deriving (Read, Show)"}'' clause to each appropriate
   datatype declaration.
 
-  \item @{attribute (HOL) code} explicitly selects (or with option
-  ``@{text "del"}'' deselects) a code equation for code generation.
-  Usually packages introducing code equations provide a reasonable
-  default setup for selection.  Variants @{text "code abstype"} and
+  \item @{attribute (HOL) code} declare code equations for code
+  generation.  Variant @{text "code equation"} declares a conventional
+  equation as code equation.  Variants @{text "code abstype"} and
   @{text "code abstract"} declare abstract datatype certificates or
   code equations on abstract datatype representations respectively.
+  Vanilla @{text "code"} falls back to @{text "code equation"}
+  or @{text "code abstype"} depending on the syntactic shape
+  of the underlying equation.  Variant @{text "code del"}
+  deselects a code equation for code generation.
+
+  Usually packages introducing code equations provide a reasonable
+  default setup for selection.  
 
   \item @{command (HOL) "code_abort"} declares constants which are not
   required to have a definition by means of code equations; if needed
--- a/src/Pure/Isar/code.ML	Sat Jul 13 17:53:57 2013 +0200
+++ b/src/Pure/Isar/code.ML	Sat Jul 13 17:53:58 2013 +0200
@@ -22,7 +22,6 @@
 
   (*code equations and certificates*)
   val mk_eqn: theory -> thm * bool -> thm * bool
-  val mk_eqn_warning: theory -> thm -> (thm * bool) option
   val mk_eqn_liberal: theory -> thm -> (thm * bool) option
   val assert_eqn: theory -> thm * bool -> thm * bool
   val const_typ_eqn: theory -> thm -> string * typ
@@ -535,7 +534,9 @@
     val _ = case some_tyco of SOME tyco' => if tyco = tyco' then ()
           else bad_thm ("Abstract type mismatch:" ^ quote tyco ^ " vs. " ^ quote tyco')
       | NONE => ();
-    val (vs', (_, (rep', _))) = get_abstype_spec thy tyco;
+    val (vs', (_, (rep', _))) = case try (get_abstype_spec thy) tyco
+     of SOME data => data
+      | NONE => bad_thm ("Not an abstract type: " ^ tyco);
     val _ = if rep_const = rep' then ()
       else bad_thm ("Projection mismatch: " ^ quote rep_const ^ " vs. " ^ quote rep');
     val _ = check_eqn thy { allow_nonlinear = false,
@@ -551,12 +552,19 @@
 fun mk_eqn thy = error_thm (gen_assert_eqn thy false) thy o
   apfst (meta_rewrite thy);
 
-fun mk_eqn_warning thy = Option.map (fn (thm, _) => (thm, is_linear thm))
-  o warning_thm (gen_assert_eqn thy false) thy o rpair false o meta_rewrite thy;
-
 fun mk_eqn_liberal thy = Option.map (fn (thm, _) => (thm, is_linear thm))
   o try_thm (gen_assert_eqn thy false) o rpair false o meta_rewrite thy;
 
+fun mk_eqn_maybe_abs thy raw_thm =
+  let
+    val thm = meta_rewrite thy raw_thm;
+    val some_abs_thm = try_thm (assert_abs_eqn thy NONE) thm;
+  in case some_abs_thm
+   of SOME (thm, tyco) => SOME ((thm, true), SOME tyco)
+    | NONE => (Option.map (fn (thm, _) => ((thm, is_linear thm), NONE))
+        o warning_thm (gen_assert_eqn thy false) thy) (thm, false)
+  end;
+
 fun mk_abs_eqn thy = error_abs_thm (assert_abs_eqn thy NONE) thy o meta_rewrite thy;
 
 val head_eqn = dest_Const o fst o strip_comb o fst o Logic.dest_equals o Thm.plain_prop_of;
@@ -1060,14 +1068,15 @@
       | add_eqn' false _ = Eqns [(thm, proper)];
   in change_fun_spec false c (add_eqn' default) thy end;
 
+fun gen_add_abs_eqn raw_thm thy =
+  let
+    val (abs_thm, tyco) = apfst Thm.close_derivation raw_thm;
+    val c = const_abs_eqn thy abs_thm;
+  in change_fun_spec false c (K (Abstr (abs_thm, tyco))) thy end;
+
 fun add_eqn thm thy =
   gen_add_eqn false (mk_eqn thy (thm, true)) thy;
 
-fun add_warning_eqn thm thy =
-  case mk_eqn_warning thy thm
-   of SOME eqn => gen_add_eqn false eqn thy
-    | NONE => thy;
-
 fun add_nbe_eqn thm thy =
   gen_add_eqn false (mk_eqn thy (thm, false)) thy;
 
@@ -1087,11 +1096,13 @@
   (fn thm => Context.mapping (add_nbe_default_eqn thm) I);
 val add_nbe_default_eqn_attrib = Attrib.internal (K add_nbe_default_eqn_attribute);
 
-fun add_abs_eqn raw_thm thy =
-  let
-    val (abs_thm, tyco) = (apfst Thm.close_derivation o mk_abs_eqn thy) raw_thm;
-    val c = const_abs_eqn thy abs_thm;
-  in change_fun_spec false c (K (Abstr (abs_thm, tyco))) thy end;
+fun add_abs_eqn raw_thm thy = gen_add_abs_eqn (mk_abs_eqn thy raw_thm) thy;
+
+fun add_eqn_maybe_abs thm thy =
+  case mk_eqn_maybe_abs thy thm
+   of SOME (eqn, NONE) => gen_add_eqn false eqn thy
+    | SOME ((thm, _), SOME tyco) => gen_add_abs_eqn (thm, tyco) thy
+    | NONE => thy;
 
 fun del_eqn thm thy = case mk_eqn_liberal thy thm
  of SOME (thm, _) => let
@@ -1226,10 +1237,11 @@
     fun mk_attribute f = Thm.declaration_attribute (fn thm => Context.mapping (f thm) I);
     val code_attribute_parser =
       Args.del |-- Scan.succeed (mk_attribute del_eqn)
+      || Args.$$$ "equation" |-- Scan.succeed (mk_attribute add_eqn)
       || Args.$$$ "nbe" |-- Scan.succeed (mk_attribute add_nbe_eqn)
       || Args.$$$ "abstype" |-- Scan.succeed (mk_attribute add_abstype)
       || Args.$$$ "abstract" |-- Scan.succeed (mk_attribute add_abs_eqn)
-      || Scan.succeed (mk_attribute add_warning_eqn);
+      || Scan.succeed (mk_attribute add_eqn_maybe_abs);
   in
     Datatype_Interpretation.init
     #> Attrib.setup (Binding.name "code") (Scan.lift code_attribute_parser)