added module system
authorhaftmann
Mon, 14 Nov 2005 16:26:40 +0100
changeset 18170 73ce773f12de
parent 18169 45def66f86cb
child 18171 c4f873d65603
added module system
src/Pure/Tools/codegen_thingol.ML
--- a/src/Pure/Tools/codegen_thingol.ML	Mon Nov 14 15:23:33 2005 +0100
+++ b/src/Pure/Tools/codegen_thingol.ML	Mon Nov 14 16:26:40 2005 +0100
@@ -40,6 +40,41 @@
   val instant_itype: vname * itype -> itype -> itype;
   val invent_tvar_names: itype list -> int -> vname list -> vname -> vname list;
   val invent_evar_names: iexpr list -> int -> vname list -> vname -> vname list;
+
+  datatype def =
+      Nop
+    | Fun of (ipat list * iexpr) list * (ClassPackage.sortcontext * itype)
+    | Typsyn of (vname * string list) list * itype
+    | Datatyp of (vname * string list) list * string list * string list
+    | Datatypcons of string * itype list
+    | Class of string list * string list * string list
+    | Classmember of string * vname * itype
+    | Classinst of string * (string * string list list) * (string * string) list;
+  type module;
+  type transact;
+  type 'dst transact_fin;
+  type ('src, 'dst) gen_codegen = 'src -> transact -> 'dst transact_fin;
+  type gen_defgen = string -> transact -> (def * string list) transact_fin;
+  val eq_def: def * def -> bool;
+  val pretty_def: def -> Pretty.T;
+  val pretty_module: module -> Pretty.T;  
+  val empty_module: module;
+  val get_def: module -> string -> def;
+  val map_defs: (def -> def) -> module -> module;
+  val add_deps: (string * def -> (string * string) list) -> module -> module;
+  val fold_defs: (string * def -> 'a -> 'a) -> module -> 'a -> 'a;
+  val fold_map_defs: (string * def -> 'a -> def * 'a) -> module -> 'a -> module * 'a;
+  val merge_module: module * module -> module;
+  val partof: string list -> module -> module;
+  val succeed: 'a -> transact -> 'a transact_fin;
+  val fail: string -> transact -> 'a transact_fin;
+  val gen_invoke: (string * ('src, 'dst) gen_codegen) list -> string
+    -> 'src -> transact -> 'dst * transact;
+  val gen_ensure_def: (string * gen_defgen) list -> string
+    -> string -> transact -> transact;
+
+  val debug_level : int ref;
+  val debug : int -> ('a -> string) -> 'a -> 'a;
 end;
 
 signature CODEGEN_THINGOL_OP =
@@ -56,8 +91,10 @@
 structure CodegenThingolOp: CODEGEN_THINGOL_OP =
 struct
 
+(** auxiliary **)
 
-(* auxiliary *)
+val debug_level = ref 0;
+fun debug d f x = (if d <= !debug_level then Output.debug (f x) else (); x);
 
 fun foldl' f (l, []) = the l
   | foldl' f (_, (r::rs)) =
@@ -85,6 +122,16 @@
     | SOME (x1, x2) =>
         let val (xs', x') = unfoldr dest x2 in (x1::xs', x') end;
 
+fun get_prefix eq ([], ys) = ([], [], ys)
+  | get_prefix eq (xs, []) = ([], xs, [])
+  | get_prefix eq (xs as x::xs', ys as y::ys') =
+      if eq (x, y) then
+        let val (ps', xs'', ys'') = get_prefix eq (xs', ys')
+        in (x::ps', xs'', ys'') end
+      else ([], xs, ys);
+
+
+(** language core - types, pattern, expressions **)
 
 (* language representation *)
 
@@ -244,18 +291,341 @@
           fold (fn (p, e) => append (vars_of_ipats [p]) #> invent e) cs
   in Term.invent_names (fold invent es used) a n end;
 
+
+(** language module system - definitions, modules, transactions **)
+
+
+
+(* type definitions *)
+
+datatype def =
+    Nop
+  | Fun of (ipat list * iexpr) list * (ClassPackage.sortcontext * itype)
+  | Typsyn of (vname * string list) list * itype
+  | Datatyp of (vname * string list) list * string list * string list
+  | Datatypcons of string * itype list
+  | Class of string list * string list * string list
+  | Classmember of string * string * itype
+  | Classinst of string * (string * string list list) * (string * string) list;
+
+datatype node = Def of def | Module of node Graph.T;
+type module = node Graph.T;
+type transact = Graph.key list * module;
+datatype 'dst transact_res = Succeed of 'dst | Fail of string;
+type 'dst transact_fin = 'dst transact_res * transact;
+type ('src, 'dst) gen_codegen = 'src -> transact -> 'dst transact_fin;
+type gen_defgen = string -> transact -> (def * string list) transact_fin;
+exception FAIL of string;
+
+val eq_def = (op =);
+
+(* simple diagnosis *)
+
+fun pretty_def Nop =
+      Pretty.str "<NOP>"
+  | pretty_def (Fun (eqs, (_, ty))) =
+      Pretty.gen_list " |" "" "" (
+        map (fn (ps, body) =>
+          Pretty.block [
+            Pretty.gen_list "," "[" "]" (map pretty_ipat ps),
+            Pretty.str " |->",
+            Pretty.brk 1,
+            pretty_iexpr body,
+            Pretty.str "::",
+            pretty_itype ty
+          ]) eqs
+        )
+  | pretty_def (Typsyn (vs, ty)) =
+      Pretty.block [
+        Pretty.list "(" ")" (map (pretty_itype o IVarT) vs),
+        Pretty.str " |=> ",
+        pretty_itype ty
+      ]
+  | pretty_def (Datatyp (vs, cs, clss)) =
+      Pretty.block [
+        Pretty.list "(" ")" (map (pretty_itype o IVarT) vs),
+        Pretty.str " |=> ",
+        Pretty.gen_list " |" "" "" (map Pretty.str cs),
+        Pretty.str ", instance of ",
+        Pretty.gen_list "," "[" "]" (map Pretty.str clss)
+      ]
+  | pretty_def (Datatypcons (dtname, tys)) =
+      Pretty.block [
+        Pretty.str "cons ",
+        Pretty.gen_list " ->" "" "" (map pretty_itype tys @ [Pretty.str dtname])
+      ]
+  | pretty_def (Class (supcls, mems, insts)) =
+      Pretty.str "Class ..."
+  | pretty_def (Classmember (cls, v, ty)) =
+      Pretty.str "Classmember ..."
+  | pretty_def (Classinst (cls, insts, mems)) =
+      Pretty.str "Classinst ..."
+
+fun pretty_module modl =
+  let
+    fun pretty (name, Module modl) =
+          Pretty.block (
+            Pretty.str ("module " ^ name ^ " {")
+            :: Pretty.brk 1
+            :: Pretty.chunks (map pretty (AList.make (Graph.get_node modl)
+                 (Graph.strong_conn modl |> List.concat |> rev)))
+            :: Pretty.str "}" :: nil
+          )
+      | pretty (name, Def def) =
+          Pretty.block [Pretty.str name, Pretty.str " :=", Pretty.brk 1, pretty_def def]
+  in pretty ("//", Module modl) end;
+
+
+(* name handling *)
+
+fun dest_name name =
+  let
+    val name' = NameSpace.unpack name
+    val (name'', name_base) = split_last name'
+    val (modl, shallow) = split_last name''
+  in (modl, NameSpace.pack [shallow, name_base]) end
+  handle Empty => error ("not a qualified name: " ^ quote name);
+
+fun dest_modl (Module m) = m;
+fun dest_def (Def d) = d;
+
+
+(* modules *)
+
+val empty_module = Graph.empty; (*read: "depends on"*)
+
+fun get_def modl name =
+  case dest_name name
+   of (modlname, base) =>
+        let
+          fun get (Module node) [] =
+                (dest_def o Graph.get_node node) base
+            | get (Module node) (m::ms) =
+                get (Graph.get_node node m) ms
+        in get (Module modl) modlname end;
+
+fun add_def (name, def) =
+  let
+    val (modl, base) = dest_name name;
+    fun add [] =
+          Graph.new_node (base, Def def)
+      | add (m::ms) =
+          Graph.default_node (m, Module empty_module)
+          #> Graph.map_node m (Module o add ms o dest_modl)
+  in add modl end;
+
+fun map_def name f =
+  let
+    val (modl, base) = dest_name name;
+    fun mapp [] =
+          Graph.map_node base (Def o f o dest_def)
+      | mapp (m::ms) =
+          Graph.map_node m (Module o mapp ms o dest_modl)
+  in mapp modl end;
+
+fun add_dep (name1, name2) modl =
+  if name1 = name2 then modl
+  else
+    let
+      val m1 = dest_name name1 |> apsnd single |> (op @);
+      val m2 = dest_name name2 |> apsnd single |> (op @);
+      val (ms, r1, r2) = get_prefix (op =) (m1, m2);
+      val (ms, s1::r1, s2::r2) = get_prefix (op =) (m1, m2);
+      val add_edge =
+        if null r1 andalso null r2
+        then Graph.add_edge
+        else Graph.add_edge_acyclic
+      fun add [] node =
+            node
+            |> add_edge (s1, s2)
+        | add (m::ms) node =
+            node
+            |> Graph.map_node m (Module o add ms o dest_modl);
+    in add ms modl end;
+
+fun map_defs f =
+  let
+    fun mapp (Def def) =
+          (Def o f) def
+      | mapp (Module modl) =
+          (Module o Graph.map_nodes mapp) modl
+  in dest_modl o mapp o Module end;
+
+fun fold_defs f =
+  let
+    fun fol prfix (name, Def def) =
+          f (NameSpace.pack (prfix @ [name]), def)
+      | fol prfix (name, Module modl) =
+          Graph.fold_nodes (fol (prfix @ [name])) modl
+  in Graph.fold_nodes (fol []) end;
+
+fun add_deps f modl =
+  modl
+  |> fold add_dep ([] |> fold_defs (append o f) modl);
+
+fun fold_map_defs f =
+  let
+    fun foldmap prfix (name, Def def) =
+          apfst Def o f (NameSpace.pack (prfix @ [name]), def)
+      | foldmap prfix (name, Module modl) =
+          apfst Module o Graph.fold_map_nodes (foldmap (prfix @ [name])) modl
+  in Graph.fold_map_nodes (foldmap []) end;
+
+fun merge_module modl12 =
+  let
+    fun join_module (Module m1, Module m2) =
+          (SOME o Module) (merge_module (m1, m2))
+      | join_module (Def d1, Def d2) =
+          if eq_def (d1, d2) then (SOME o Def) d1 else NONE
+      | join_module _ =
+          NONE
+  in Graph.join (K join_module) modl12 end;
+
+fun partof names modl =
+      let
+        datatype pathnode = PN of (string list * (string * pathnode) list);
+        fun mk_path ([], base) (PN (defs, modls)) =
+              PN (base :: defs, modls)
+          | mk_path (n::ns, base) (PN (defs, modls)) =
+              modls
+              |> AList.default (op =) (n, PN ([], []))
+              |> AList.map_entry (op =) n (mk_path (ns, base))
+              |> (pair defs #> PN);
+        fun select (PN (defs, modls)) (Module module) =
+          module
+          |> Graph.subgraph (Graph.all_succs module (defs @ map fst modls))
+          |> fold (fn (name, modls) => Graph.map_node name (select modls)) modls
+          |> Module;
+      in
+        Module modl
+        |> select (fold (mk_path o dest_name) (filter NameSpace.is_qualified names) (PN ([], [])))
+        |> dest_modl
+      end;
+
+fun add_check_transform (name, (Datatypcons (dtname, _))) =
+      ([([dtname],
+          fn [Datatyp (_, _, [])] => NONE | _ => "attempted to add constructor to already instantiating datatype" |> SOME)],
+       [(dtname,
+          fn Datatyp (vs, cs, clss) => Datatyp (vs, name::cs, clss)
+           | def => "attempted to add datatype constructor to non-datatype: "
+              ^ (Pretty.output o pretty_def) def |> error)])
+  | add_check_transform (name, Classmember (clsname, v, ty)) =
+      let
+        fun check_var (IType (tyco, tys)) s =
+              fold check_var tys s
+          | check_var (IFun (ty1, ty2)) s =
+              s
+              |> check_var ty1
+              |> check_var ty2
+          | check_var (IVarT (w, sort)) s =
+              if v = w
+              andalso member (op =) sort clsname
+              then "additional class appears at type variable" |> SOME
+              else NONE
+      in
+        ([([], fn [] => check_var ty NONE),
+          ([clsname],
+             fn [Class (_, _, [])] => NONE
+              | _ => "attempted to add class member to witnessed class" |> SOME)],
+         [(clsname,
+             fn Class (supcs, mems, insts) => Class (supcs, name::mems, insts)
+              | def => "attempted to add class member to non-class"
+                 ^ (Pretty.output o pretty_def) def |> error)])
+      end
+  | add_check_transform (name, Classinst (clsname, (tyco, arity), memdefs)) =
+      let
+        fun check [Classmember (_, v, mtyp_c), Fun (_, (_, mtyp_i))] =
+          let
+            val mtyp_i' = instant_itype (v, tyco `%%
+              map2 IVarT ((invent_tvar_names [mtyp_c] (length arity) [] "a"), arity)) mtyp_c;
+          in if eq_itype (mtyp_i', mtyp_i) (*! PERHAPS TOO STRICT !*)
+          then NONE
+          else "wrong type signature for class member: "
+            ^ (Pretty.output o pretty_itype) mtyp_i' ^ " expected,"
+            ^ (Pretty.output o pretty_itype) mtyp_i ^ " given" |> SOME end
+      in
+        (map (fn (memname, memprim) => ((writeln memname; writeln memprim; [memname, memprim]), check)) memdefs,
+          [(clsname,
+              fn Class (supcs, mems, insts) => Class (supcs, mems, name::insts)
+               | def => "attempted to add class instance to non-class"
+                  ^ (Pretty.output o pretty_def) def |> error),
+           (tyco,
+              fn Datatyp (vs, cs, clss) => Datatyp (vs, cs, clsname::clss)
+               | Nop => Nop
+               | def => "attempted to instantiate non-type to class instance"
+                  ^ (Pretty.output o pretty_def) def |> error)])
+      end
+  | add_check_transform _ = ([], []);
+
+fun succeed some = (pair o Succeed) some;
+fun fail msg = (pair o Fail) msg;
+
+fun check_fail msg' (Succeed dst, trns) = (dst, trns)
+  | check_fail msg' (Fail errmsg, _) = (tracing ("ROLLBACK CHECK: " ^ errmsg ^ "\n" ^ msg'); raise FAIL errmsg);
+
+fun handle_fail msg f modl =
+  f modl handle FAIL msg' => ([], modl) |> fail (msg ^ "\n" ^ msg');
+
+fun select_generator print_msg src [] trns =
+      fail ("no code generator available") trns
+  | select_generator print_msg src [(gname, cgen)] trns =
+      (print_msg gname; cgen src trns)
+  | select_generator print_msg src ((gname, cgen)::cgens) trns =
+      case cgen src trns
+       of result as (Succeed _, _) =>
+            (print_msg gname; result)
+        | _ => select_generator print_msg src cgens trns
+
+fun gen_invoke codegens msg src (deps, modl) =
+  ([], modl)
+  |> select_generator (fn gname => "choosing code generator " ^ gname ^ " for source " ^ quote msg)
+       src codegens
+  |> check_fail msg
+  ||> (fn (deps', modl') => (append deps' deps, modl'));
+
+fun gen_ensure_def defgens msg name (deps, modl) =
+  let
+    fun add (name, def) (deps, modl) =
+      let
+        val (checks, trans) = add_check_transform (name, def);
+        fun check (check_defs, checker) modl =
+          case checker (check_defs |> filter NameSpace.is_qualified |> map (get_def modl))
+           of NONE => modl
+            | SOME e => raise FAIL e;
+        fun transform (name, f) modl =
+          modl
+          |> K (NameSpace.is_qualified name) ? map_def name f;
+      in
+        modl
+        |> fold check checks
+        |> fold (curry add_dep name) deps
+        |> map_def name (fn _ => def)
+        |> fold transform trans
+      end;
+    fun ensure_node name modl =
+      if can (get_def modl) name
+      then ([name], modl)
+      else
+        ([], modl |> add_def (name, Nop))
+        |> select_generator (fn gname => "choosing code generator " ^ gname ^ " for definition of " ^ quote name)
+             name defgens
+        |> check_fail msg
+        |-> (fn (def, names') =>
+           add (name, def)
+           #> fold_map ensure_node names')
+        |-> (fn names' => pair (name :: Library.flat names'))
+  in
+    modl
+    |> ensure_node name
+    |-> (fn names => pair (names@deps))
+  end;
+
 end; (* struct *)
 
 
 structure CodegenThingol : CODEGEN_THINGOL =
 struct
 
-infix 8 `%%;
-infixr 6 `->;
-infixr 6 `-->;
-infix 4 `$;
-infix 4 `$$;
-
 open CodegenThingolOp;
 
 end; (* struct *)