Import Upstream version 20180207
[hcoop/debian/mlton.git] / lib / mlton / basic / property.fun
CommitLineData
7f918cf1
CE
1(* Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
3 *
4 * MLton is released under a BSD-style license.
5 * See the file MLton-LICENSE for details.
6 *)
7
8functor Property (Plist: PROPERTY_LIST):> PROPERTY where type Plist.t = Plist.t =
9struct
10
11structure Plist = Plist
12
13datatype ('sym, 'val) init =
14 Const of 'val
15 | Fun of 'sym * ('sym -> 'val) -> 'val
16
17val initRec = Fun
18
19fun initConst c = Const c
20
21fun initFun f = initRec (fn (s, _) => f s)
22
23fun initRaise (name, layout) =
24 initFun
25 (fn s =>
26 Error.bug
27 (let open Layout
28 in toString (seq [layout s, str " has no ", str name, str " property"])
29 end))
30
31fun ('sym, 'val) nondestructable (plist: 'sym -> Plist.t,
32 init: ('sym, 'val) init) =
33 let
34 val {add, peek, remove, ...} = Plist.newProperty ()
35 fun get (s: 'sym) =
36 let
37 val p = plist s
38 in
39 case peek p of
40 NONE => (case init of
41 Const c => c
42 | Fun f =>
43 let val v = f (s, get)
44 in add (p, v); v
45 end)
46 | SOME v => v
47 end
48 fun set (s: 'sym, none: unit -> 'val, some: 'val -> unit): unit =
49 let val p = plist s
50 in case peek p of
51 NONE => add (p, none ())
52 | SOME v => some v
53 end
54 in {get = get, rem = remove o plist, remove = remove, set = set}
55 end
56
57fun ('sym, 'val) destructable (plist, init) =
58 let
59 val plists = ref []
60 fun add s = List.push (plists, plist s)
61 val {get, remove, set, ...} =
62 nondestructable (plist,
63 case init of
64 Const _ => init
65 | Fun f => Fun (fn z as (s, _) => (add s; f z)))
66 val set: 'sym * (unit -> 'val) * ('val -> unit) -> unit =
67 fn (s, none, some) => set (s, fn () => (add s; none ()), some)
68 fun destroy () =
69 (List.foreach (!plists, remove)
70 ; plists := [])
71 in {destroy = destroy, get = get, set = set}
72 end
73
74fun setToSetOnce set (s, v) =
75 set (s, fn _ => v, fn _ => Error.bug "Property.setOnce: set used twice")
76
77fun destGetSetOnce z =
78 let val {destroy, get, set} = destructable z
79 in {destroy = destroy, get = get, set = setToSetOnce set}
80 end
81
82fun destGet z =
83 let val {destroy, get, ...} = destGetSetOnce z
84 in {destroy = destroy, get = get}
85 end
86
87fun getSetOnce z =
88 let
89 val {get, rem, set, ...} = nondestructable z
90 in {get = get, rem = rem, set = setToSetOnce set}
91 end
92
93fun get z =
94 let val {get, rem, ...} = getSetOnce z
95 in {get = get, rem = rem}
96 end
97
98fun setInit (plist, init) =
99 (plist,
100 case init of
101 Const c => Fun (fn _ => ref c)
102 | Fun f => Fun (fn (s, get) => ref (f (s, ! o get))))
103
104fun destGetSet z =
105 let
106 val {destroy, get, set} = destructable (setInit z)
107 val set = fn (s, v) => set (s, fn () => ref v, fn r => r := v)
108 in
109 {destroy = destroy, get = ! o get, set = set}
110 end
111
112fun getSet z =
113 let val {get, rem, set, ...} = nondestructable (setInit z)
114 val set = fn (s, v) => set (s, fn () => ref v, fn r => r := v)
115 in {get = ! o get, rem = rem, set = set}
116 end
117
118end
119
120structure HetContainer = ExnHetContainer ()
121structure PropertyList = PropertyList (ExnHetContainer ())
122structure Property = Property (PropertyList)