src/Pure/System/options.ML
changeset 51943 3278729bfa38
parent 51942 527e39becafc
child 51945 5b1ac9843f02
equal deleted inserted replaced
51942:527e39becafc 51943:3278729bfa38
     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 () =