4 Stand-alone options with external string representation. |
4 Stand-alone options with external string representation. |
5 *) |
5 *) |
6 |
6 |
7 signature OPTIONS = |
7 signature OPTIONS = |
8 sig |
8 sig |
|
9 val boolT: string |
|
10 val intT: string |
|
11 val realT: string |
|
12 val stringT: string |
|
13 val unknownT: string |
9 type T |
14 type T |
10 val empty: T |
15 val empty: T |
11 val typ: T -> string -> string |
16 val typ: T -> string -> string |
12 val bool: T -> string -> bool |
17 val bool: T -> string -> bool |
13 val int: T -> string -> int |
18 val int: T -> string -> int |
14 val real: T -> string -> real |
19 val real: T -> string -> real |
15 val string: T -> string -> string |
20 val string: T -> string -> string |
|
21 val put_bool: string -> bool -> T -> T |
|
22 val put_int: string -> int -> T -> T |
|
23 val put_real: string -> real -> T -> T |
|
24 val put_string: string -> string -> T -> T |
16 val declare: {name: string, typ: string, value: string} -> T -> T |
25 val declare: {name: string, typ: string, value: string} -> T -> T |
|
26 val update: string -> string -> T -> T |
17 val decode: XML.body -> T |
27 val decode: XML.body -> T |
18 val default: unit -> T |
28 val default: unit -> T |
19 val default_bool: string -> bool |
29 val default_bool: string -> bool |
20 val default_int: string -> int |
30 val default_int: string -> int |
21 val default_real: string -> real |
31 val default_real: string -> real |
22 val default_string: string -> string |
32 val default_string: string -> string |
|
33 val default_put_bool: string -> bool -> unit |
|
34 val default_put_int: string -> int -> unit |
|
35 val default_put_real: string -> real -> unit |
|
36 val default_put_string: string -> string -> unit |
|
37 val get_default: string -> string |
|
38 val put_default: string -> string -> unit |
23 val set_default: T -> unit |
39 val set_default: T -> unit |
24 val reset_default: unit -> unit |
40 val reset_default: unit -> unit |
25 val load_default: unit -> unit |
41 val load_default: unit -> unit |
26 end; |
42 end; |
27 |
43 |
32 |
48 |
33 val boolT = "bool"; |
49 val boolT = "bool"; |
34 val intT = "int"; |
50 val intT = "int"; |
35 val realT = "real"; |
51 val realT = "real"; |
36 val stringT = "string"; |
52 val stringT = "string"; |
|
53 val unknownT = "unknown"; |
37 |
54 |
38 datatype T = Options of {typ: string, value: string} Symtab.table; |
55 datatype T = Options of {typ: string, value: string} Symtab.table; |
39 |
56 |
40 val empty = Options Symtab.empty; |
57 val empty = Options Symtab.empty; |
41 |
58 |
42 |
59 |
|
60 (* check *) |
|
61 |
|
62 fun check_name (Options tab) name = |
|
63 let val opt = Symtab.lookup tab name in |
|
64 if is_some opt andalso #typ (the opt) <> unknownT then the opt |
|
65 else error ("Unknown option " ^ quote name) |
|
66 end; |
|
67 |
|
68 fun check_type options name typ = |
|
69 let val opt = check_name options name in |
|
70 if #typ opt = typ then opt |
|
71 else error ("Ill-typed option " ^ quote name ^ " : " ^ #typ opt ^ " vs. " ^ typ) |
|
72 end; |
|
73 |
|
74 |
43 (* typ *) |
75 (* typ *) |
44 |
76 |
45 fun typ (Options tab) name = |
77 fun typ options name = #typ (check_name options name); |
46 (case Symtab.lookup tab name of |
|
47 SOME opt => #typ opt |
|
48 | NONE => error ("Unknown option " ^ quote name)); |
|
49 |
78 |
50 |
79 |
51 (* get *) |
80 (* basic operations *) |
52 |
81 |
53 fun get T parse (Options tab) name = |
82 fun put T print name x (options as Options tab) = |
54 (case Symtab.lookup tab name of |
83 let val opt = check_type options name T |
55 SOME {typ, value} => |
84 in Options (Symtab.update (name, {typ = #typ opt, value = print x}) tab) end; |
56 if typ = T then |
85 |
57 (case parse value of |
86 fun get T parse options name = |
58 SOME x => x |
87 let val opt = check_type options name T in |
59 | NONE => |
88 (case parse (#value opt) of |
60 error ("Malformed value for option " ^ quote name ^ " : " ^ T ^ " =\n" ^ quote value)) |
89 SOME x => x |
61 else error ("Ill-typed option " ^ quote name ^ " : " ^ typ ^ " vs. " ^ T) |
90 | NONE => |
62 | NONE => error ("Unknown option " ^ quote name)); |
91 error ("Malformed value for option " ^ quote name ^ |
|
92 " : " ^ T ^ " =\n" ^ quote (#value opt))) |
|
93 end; |
|
94 |
|
95 |
|
96 (* internal lookup and update *) |
63 |
97 |
64 val bool = get boolT Bool.fromString; |
98 val bool = get boolT Bool.fromString; |
65 val int = get intT Int.fromString; |
99 val int = get intT Int.fromString; |
66 val real = get realT Real.fromString; |
100 val real = get realT Real.fromString; |
67 val string = get stringT SOME; |
101 val string = get stringT SOME; |
68 |
102 |
|
103 val put_bool = put boolT Bool.toString; |
|
104 val put_int = put intT signed_string_of_int; |
|
105 val put_real = put realT signed_string_of_real; |
|
106 val put_string = put stringT I; |
69 |
107 |
70 (* declare *) |
108 |
|
109 (* external updates *) |
|
110 |
|
111 fun check_value options name = |
|
112 let val opt = check_name options name in |
|
113 if #typ opt = boolT then ignore (bool options name) |
|
114 else if #typ opt = intT then ignore (int options name) |
|
115 else if #typ opt = realT then ignore (real options name) |
|
116 else if #typ opt = stringT then ignore (string options name) |
|
117 else () |
|
118 end; |
71 |
119 |
72 fun declare {name, typ, value} (Options tab) = |
120 fun declare {name, typ, value} (Options tab) = |
73 let |
121 let |
74 val check_value = |
|
75 if typ = boolT then ignore oo bool |
|
76 else if typ = intT then ignore oo int |
|
77 else if typ = realT then ignore oo real |
|
78 else if typ = stringT then ignore oo string |
|
79 else error ("Unknown type for option " ^ quote name ^ " : " ^ quote typ); |
|
80 val options' = Options (Symtab.update_new (name, {typ = typ, value = value}) tab) |
122 val options' = Options (Symtab.update_new (name, {typ = typ, value = value}) tab) |
81 handle Symtab.DUP _ => error ("Duplicate declaration of option " ^ quote name); |
123 handle Symtab.DUP _ => error ("Duplicate declaration of option " ^ quote name); |
|
124 val _ = |
|
125 typ = boolT orelse typ = intT orelse typ = realT orelse typ = stringT orelse |
|
126 error ("Unknown type for option " ^ quote name ^ " : " ^ quote typ); |
|
127 val _ = check_value options' name; |
|
128 in options' end; |
|
129 |
|
130 fun update name value (options as Options tab) = |
|
131 let |
|
132 val opt = check_name options name; |
|
133 val options' = Options (Symtab.update (name, {typ = #typ opt, value = value}) tab); |
82 val _ = check_value options' name; |
134 val _ = check_value options' name; |
83 in options' end; |
135 in options' end; |
84 |
136 |
85 |
137 |
86 (* decode *) |
138 (* decode *) |
93 |
145 |
94 (** global default **) |
146 (** global default **) |
95 |
147 |
96 val global_default = Synchronized.var "Options.default" (NONE: T option); |
148 val global_default = Synchronized.var "Options.default" (NONE: T option); |
97 |
149 |
|
150 fun err_no_default () = error "No global default options"; |
|
151 |
|
152 fun change_default f x y = |
|
153 Synchronized.change global_default |
|
154 (fn SOME options => SOME (f x y options) |
|
155 | NONE => err_no_default ()); |
|
156 |
98 fun default () = |
157 fun default () = |
99 (case Synchronized.value global_default of |
158 (case Synchronized.value global_default of |
100 SOME options => options |
159 SOME options => options |
101 | NONE => error "No global default options"); |
160 | NONE => err_no_default ()); |
102 |
161 |
103 fun default_bool name = bool (default ()) name; |
162 fun default_bool name = bool (default ()) name; |
104 fun default_int name = int (default ()) name; |
163 fun default_int name = int (default ()) name; |
105 fun default_real name = real (default ()) name; |
164 fun default_real name = real (default ()) name; |
106 fun default_string name = string (default ()) name; |
165 fun default_string name = string (default ()) name; |
|
166 |
|
167 val default_put_bool = change_default put_bool; |
|
168 val default_put_int = change_default put_int; |
|
169 val default_put_real = change_default put_real; |
|
170 val default_put_string = change_default put_string; |
|
171 |
|
172 fun get_default name = |
|
173 let val options = default () in get (typ options name) SOME options name end; |
|
174 val put_default = change_default update; |
107 |
175 |
108 fun set_default options = Synchronized.change global_default (K (SOME options)); |
176 fun set_default options = Synchronized.change global_default (K (SOME options)); |
109 fun reset_default () = Synchronized.change global_default (K NONE); |
177 fun reset_default () = Synchronized.change global_default (K NONE); |
110 |
178 |
111 fun load_default () = |
179 fun load_default () = |