Commit | Line | Data |
---|---|---|
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 | ||
8 | functor Property (Plist: PROPERTY_LIST):> PROPERTY where type Plist.t = Plist.t = | |
9 | struct | |
10 | ||
11 | structure Plist = Plist | |
12 | ||
13 | datatype ('sym, 'val) init = | |
14 | Const of 'val | |
15 | | Fun of 'sym * ('sym -> 'val) -> 'val | |
16 | ||
17 | val initRec = Fun | |
18 | ||
19 | fun initConst c = Const c | |
20 | ||
21 | fun initFun f = initRec (fn (s, _) => f s) | |
22 | ||
23 | fun 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 | ||
31 | fun ('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 | ||
57 | fun ('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 | ||
74 | fun setToSetOnce set (s, v) = | |
75 | set (s, fn _ => v, fn _ => Error.bug "Property.setOnce: set used twice") | |
76 | ||
77 | fun destGetSetOnce z = | |
78 | let val {destroy, get, set} = destructable z | |
79 | in {destroy = destroy, get = get, set = setToSetOnce set} | |
80 | end | |
81 | ||
82 | fun destGet z = | |
83 | let val {destroy, get, ...} = destGetSetOnce z | |
84 | in {destroy = destroy, get = get} | |
85 | end | |
86 | ||
87 | fun getSetOnce z = | |
88 | let | |
89 | val {get, rem, set, ...} = nondestructable z | |
90 | in {get = get, rem = rem, set = setToSetOnce set} | |
91 | end | |
92 | ||
93 | fun get z = | |
94 | let val {get, rem, ...} = getSetOnce z | |
95 | in {get = get, rem = rem} | |
96 | end | |
97 | ||
98 | fun 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 | ||
104 | fun 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 | ||
112 | fun 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 | ||
118 | end | |
119 | ||
120 | structure HetContainer = ExnHetContainer () | |
121 | structure PropertyList = PropertyList (ExnHetContainer ()) | |
122 | structure Property = Property (PropertyList) |