libisabelle-protocol/lib/classy/classy.ML
author Walther Neuper <wneuper@ist.tugraz.at>
Wed, 06 Apr 2016 16:56:47 +0200
changeset 59216 f4693c6f4bb2
permissions -rw-r--r--
update libisabelle-0.2.2 to libisabelle 0.3.3

Note: probably the dependency between
Protocol.thy and Isac_Protocol.thy need to be reverted
wneuper@59216
     1
signature CLASSY = sig
wneuper@59216
     2
  val register_class: binding -> ML_Types.ml_type -> local_theory -> local_theory
wneuper@59216
     3
  val register_class_cmd: binding -> string -> local_theory -> local_theory
wneuper@59216
     4
wneuper@59216
     5
  val register_instance_cmd: xstring * Position.T -> binding -> Input.source -> local_theory -> local_theory
wneuper@59216
     6
wneuper@59216
     7
  val check_class: Context.generic -> string * Position.T -> string
wneuper@59216
     8
  val print_classes: Context.generic -> unit
wneuper@59216
     9
wneuper@59216
    10
  val resolve: string -> ML_Types.ml_type -> Context.generic -> string
wneuper@59216
    11
wneuper@59216
    12
  val setup: theory -> theory
wneuper@59216
    13
end
wneuper@59216
    14
wneuper@59216
    15
structure Classy: CLASSY = struct
wneuper@59216
    16
wneuper@59216
    17
type class_table = (ml_type * (ml_type * string) Name_Space.table) Name_Space.table
wneuper@59216
    18
wneuper@59216
    19
exception DUP
wneuper@59216
    20
wneuper@59216
    21
structure Classes = Generic_Data
wneuper@59216
    22
(
wneuper@59216
    23
  type T = class_table
wneuper@59216
    24
  val empty = Name_Space.empty_table "ML class"
wneuper@59216
    25
  val merge = Name_Space.join_tables (fn _ => raise DUP) (* FIXME consistency check *)
wneuper@59216
    26
  val extend = I
wneuper@59216
    27
)
wneuper@59216
    28
wneuper@59216
    29
fun list_comb (term: string) (args: string list) =
wneuper@59216
    30
  space_implode " " (enclose "(" ")" term :: map (enclose "(" ")") args)
wneuper@59216
    31
wneuper@59216
    32
fun product [] = [[]]
wneuper@59216
    33
  | product (xs :: xss) =
wneuper@59216
    34
      maps (fn xs' => map (fn x => x :: xs') xs) (product xss)
wneuper@59216
    35
wneuper@59216
    36
wneuper@59216
    37
fun solve entries problem =
wneuper@59216
    38
  let
wneuper@59216
    39
    fun find (typ, term) =
wneuper@59216
    40
      let
wneuper@59216
    41
        val (args, candidate) = ML_Types.strip_fun typ
wneuper@59216
    42
      in
wneuper@59216
    43
        case ML_Types.match candidate problem [] of
wneuper@59216
    44
          SOME env =>
wneuper@59216
    45
            map (ML_Types.subst env) args
wneuper@59216
    46
            |> map (solve entries)
wneuper@59216
    47
            |> product
wneuper@59216
    48
            |> map (list_comb term)
wneuper@59216
    49
        | NONE => []
wneuper@59216
    50
      end
wneuper@59216
    51
  in
wneuper@59216
    52
    maps find entries
wneuper@59216
    53
  end
wneuper@59216
    54
wneuper@59216
    55
fun resolve class typ context =
wneuper@59216
    56
  let
wneuper@59216
    57
    val classes = Classes.get context
wneuper@59216
    58
    val (constructor, table) = Name_Space.get classes class
wneuper@59216
    59
    val ML_Types.Con (name, [ML_Types.Var _]) = constructor
wneuper@59216
    60
    val entries = map snd (Name_Space.extern_table true (Context.proof_of context) table)
wneuper@59216
    61
    val problem = ML_Types.Con (name, [typ])
wneuper@59216
    62
    val solutions = solve entries problem
wneuper@59216
    63
  in
wneuper@59216
    64
    case solutions of
wneuper@59216
    65
      [] => error "no solutions"
wneuper@59216
    66
    | [solution] => enclose "(" ")" solution
wneuper@59216
    67
    | _ => error "too many solutions"
wneuper@59216
    68
  end
wneuper@59216
    69
wneuper@59216
    70
fun check_class context raw_binding =
wneuper@59216
    71
  fst (Name_Space.check context (Classes.get context) raw_binding)
wneuper@59216
    72
wneuper@59216
    73
val antiquote_setup =
wneuper@59216
    74
  ML_Antiquotation.inline (Binding.qualify true "ML" @{binding class})
wneuper@59216
    75
    (Scan.state -- Scan.lift (Parse.position Args.name) >>
wneuper@59216
    76
      (fn (context, binding) => quote (check_class context binding))) #>
wneuper@59216
    77
  ML_Antiquotation.inline (Binding.qualify true "ML" @{binding resolve})
wneuper@59216
    78
    (Scan.state -- Scan.lift (Parse.ML_source --| @{keyword "::"} -- Parse.position Args.name) >>
wneuper@59216
    79
      (fn (context, (source, binding)) =>
wneuper@59216
    80
         resolve (check_class context binding) (ML_Types.read_ml_type (Input.source_content source)) context))
wneuper@59216
    81
wneuper@59216
    82
fun pretty_classes context =
wneuper@59216
    83
  let
wneuper@59216
    84
    val table = Classes.get context
wneuper@59216
    85
    val ctxt = Context.proof_of context
wneuper@59216
    86
    val space = Name_Space.space_of_table table
wneuper@59216
    87
    val entries = Name_Space.extern_table true ctxt table
wneuper@59216
    88
wneuper@59216
    89
    fun pretty_class ((class, _), (typ, sub_table)) =
wneuper@59216
    90
      let
wneuper@59216
    91
        val header = Pretty.block [Name_Space.pretty ctxt space class, Pretty.str ":", Pretty.brk 1, ML_Types.pretty typ]
wneuper@59216
    92
wneuper@59216
    93
        val sub_space = Name_Space.space_of_table sub_table
wneuper@59216
    94
        val sub_entries = Name_Space.extern_table true ctxt sub_table
wneuper@59216
    95
wneuper@59216
    96
        fun pretty_instance ((instance, _), (typ, _)) =
wneuper@59216
    97
          Pretty.item [Name_Space.pretty ctxt sub_space instance, Pretty.str ":", Pretty.brk 1, ML_Types.pretty typ]
wneuper@59216
    98
wneuper@59216
    99
        val instances = map pretty_instance sub_entries
wneuper@59216
   100
      in
wneuper@59216
   101
        Pretty.item (Pretty.fbreaks (header :: instances))
wneuper@59216
   102
      end
wneuper@59216
   103
  in
wneuper@59216
   104
    Pretty.big_list "Classes" (map pretty_class entries)
wneuper@59216
   105
  end
wneuper@59216
   106
wneuper@59216
   107
val print_classes =
wneuper@59216
   108
  Pretty.writeln o pretty_classes
wneuper@59216
   109
wneuper@59216
   110
fun register_class binding typ =
wneuper@59216
   111
  let
wneuper@59216
   112
    val name =
wneuper@59216
   113
      (case typ of
wneuper@59216
   114
        ML_Types.Con (name, [ML_Types.Var _]) => name
wneuper@59216
   115
      | _ => error "Malformed type")
wneuper@59216
   116
    fun decl _ context =
wneuper@59216
   117
      let
wneuper@59216
   118
        val classes = Classes.get context
wneuper@59216
   119
        val table = Name_Space.empty_table ("ML instances for " ^ name)
wneuper@59216
   120
        val (_, classes') = Name_Space.define context true (binding, (typ, table)) classes
wneuper@59216
   121
      in
wneuper@59216
   122
        Classes.put classes' context
wneuper@59216
   123
      end
wneuper@59216
   124
  in
wneuper@59216
   125
    Local_Theory.declaration {syntax = false, pervasive = false} decl
wneuper@59216
   126
  end
wneuper@59216
   127
wneuper@59216
   128
fun register_class_cmd binding typ =
wneuper@59216
   129
  register_class binding (ML_Types.read_ml_type typ)
wneuper@59216
   130
wneuper@59216
   131
fun register_instance_cmd raw_binding binding source lthy =
wneuper@59216
   132
  let
wneuper@59216
   133
    val typ = ML_Types.ml_type_of lthy (Input.source_content source)
wneuper@59216
   134
    (* doesn't have any effect except for markup *)
wneuper@59216
   135
    val _ = ML_Context.eval_source_in (SOME lthy) ML_Compiler.flags source
wneuper@59216
   136
wneuper@59216
   137
    (* FIXME check correct type *)
wneuper@59216
   138
wneuper@59216
   139
    fun decl _ context =
wneuper@59216
   140
      let
wneuper@59216
   141
        val classes = Classes.get context
wneuper@59216
   142
        val (key, _) = Name_Space.check context classes raw_binding
wneuper@59216
   143
        val upd = Name_Space.define context true (binding, (typ, Input.source_content source)) #> snd
wneuper@59216
   144
        val classes' = Name_Space.map_table_entry key (apsnd upd) classes
wneuper@59216
   145
      in Classes.put classes' context end
wneuper@59216
   146
  in
wneuper@59216
   147
    Local_Theory.declaration {syntax = false, pervasive = false} decl lthy
wneuper@59216
   148
  end
wneuper@59216
   149
wneuper@59216
   150
val _ =
wneuper@59216
   151
  Outer_Syntax.local_theory @{command_keyword "ML.class"} "register new type class"
wneuper@59216
   152
    (Parse.binding --| @{keyword "="} -- Parse.cartouche
wneuper@59216
   153
      >> (fn (binding, typ) => register_class_cmd binding typ))
wneuper@59216
   154
wneuper@59216
   155
val _ =
wneuper@59216
   156
  let
wneuper@59216
   157
    val opt_binding =
wneuper@59216
   158
      Parse.binding --| @{keyword "="} ||
wneuper@59216
   159
        Parse.position (Scan.succeed ()) >>
wneuper@59216
   160
          (fn ((), pos) => Binding.make ("instance" ^ Markup.print_int (serial ()), pos))
wneuper@59216
   161
  in
wneuper@59216
   162
    Outer_Syntax.local_theory @{command_keyword "ML.instance"} "register new type class instance"
wneuper@59216
   163
      (opt_binding -- (Parse.ML_source --| @{keyword "::"} -- Parse.position Args.name)
wneuper@59216
   164
        >> (fn (binding, (source, name)) => register_instance_cmd name binding source))
wneuper@59216
   165
  end
wneuper@59216
   166
wneuper@59216
   167
val _ =
wneuper@59216
   168
  Outer_Syntax.command @{command_keyword "ML.print_classes"} "print all registered classes"
wneuper@59216
   169
    (Scan.succeed (Toplevel.keep (print_classes o Toplevel.generic_theory_of)))
wneuper@59216
   170
wneuper@59216
   171
val setup = antiquote_setup
wneuper@59216
   172
wneuper@59216
   173
end