1 (* Title: Pure/ProofGeneral/pgip_types.ML
5 PGIP abstraction: types and conversions.
8 (* TODO: PGML, proverflag *)
11 (* Object types: the types of values which can be manipulated externally.
12 Ideally a list of other types would be configured as a parameter. *)
13 datatype objtype = ObjFile | ObjTheory | ObjTheorem | ObjComment
14 | ObjTerm | ObjType | ObjOther of string
16 (* Names for values of objtypes (i.e. prover identifiers). Could be a parameter.
17 Names for ObjFiles are URIs. *)
20 type idtable = { context: objname option, (* container's objname *)
24 (* Types and values (used for preferences and dialogs) *)
26 datatype pgiptype = Pgipnull | Pgipbool | Pgipint of int option * int option | Pgipnat
27 | Pgipstring | Pgipconst of string | Pgipchoice of pgipdtype list
29 and pgipdtype = Pgipdtype of string option * pgiptype (* type with opt. description *)
31 type pgipval (* typed value *)
33 (* URLs we can cope with *)
36 (* Representation error in reading/writing PGIP *)
37 exception PGIP of string
39 (* Interface areas for message output *)
40 datatype displayarea = Status | Message | Display | Tracing | Internal | Other of string
43 datatype fatality = Info | Warning | Nonfatal | Fatal | Panic | Log | Debug
46 type location = { descr: string option,
53 (* Prover preference *)
54 type preference = { name: string,
56 default: string option,
60 signature PGIPTYPES_OPNS =
65 val name_of_objtype : objtype -> string
66 val attrs_of_objtype : objtype -> XML.attributes
67 val objtype_of_attrs : XML.attributes -> objtype (* raises PGIP *)
68 val idtable_to_xml : idtable -> XML.tree
70 (* Values as XML strings *)
71 val read_pgipint : (int option * int option) -> string -> int (* raises PGIP *)
72 val read_pgipnat : string -> int (* raises PGIP *)
73 val read_pgipbool : string -> bool (* raises PGIP *)
74 val read_pgipstring : string -> string (* raises PGIP *)
75 val int_to_pgstring : int -> string
76 val bool_to_pgstring : bool -> string
77 val string_to_pgstring : string -> string
80 val pgiptype_to_xml : pgiptype -> XML.tree
81 val read_pgval : pgiptype -> string -> pgipval (* raises PGIP *)
82 val pgval_to_string : pgipval -> string
84 val attrs_of_displayarea : displayarea -> XML.attributes
85 val attrs_of_fatality : fatality -> XML.attributes
86 val attrs_of_location : location -> XML.attributes
87 val location_of_attrs : XML.attributes -> location (* raises PGIP *)
89 val haspref : preference -> XML.tree
91 val pgipurl_of_url : Url.T -> pgipurl (* raises PGIP *)
92 val pgipurl_of_string : string -> pgipurl (* raises PGIP *)
93 val pgipurl_of_path : Path.T -> pgipurl
94 val path_of_pgipurl : pgipurl -> Path.T
95 val string_of_pgipurl : pgipurl -> string
96 val attrs_of_pgipurl : pgipurl -> XML.attributes
97 val pgipurl_of_attrs : XML.attributes -> pgipurl (* raises PGIP *)
99 (* XML utils, only for PGIP code *)
100 val has_attr : string -> XML.attributes -> bool
101 val attr : string -> string -> XML.attributes
102 val opt_attr : string -> string option -> XML.attributes
103 val opt_attr_map : ('a -> string) -> string -> 'a option -> XML.attributes
104 val get_attr : string -> XML.attributes -> string (* raises PGIP *)
105 val get_attr_opt : string -> XML.attributes -> string option
106 val get_attr_dflt : string -> string -> XML.attributes -> string
109 structure PgipTypes : PGIPTYPES_OPNS =
111 exception PGIP of string
115 fun has_attr attr attrs = Properties.defined attrs attr
117 fun get_attr_opt attr attrs = Properties.get attrs attr
119 fun get_attr attr attrs =
120 (case get_attr_opt attr attrs of
122 | NONE => raise PGIP ("Missing attribute: " ^ quote attr))
124 fun get_attr_dflt attr dflt attrs = the_default dflt (get_attr_opt attr attrs)
126 fun attr x y = [(x,y)] : XML.attributes
128 fun opt_attr_map f attr_name opt_val =
129 case opt_val of NONE => [] | SOME v => [(attr_name,f v)]
130 (* or, if you've got function-itis:
131 the_default [] (Option.map (single o (pair attr_name) o f) opt_val)
134 fun opt_attr attr_name = opt_attr_map I attr_name
139 datatype objtype = ObjFile | ObjTheory | ObjTheorem | ObjComment
140 | ObjTerm | ObjType | ObjOther of string
142 fun name_of_objtype obj =
145 | ObjTheory => "theory"
146 | ObjTheorem => "theorem"
147 | ObjComment => "comment"
152 val attrs_of_objtype = attr "objtype" o name_of_objtype
154 fun objtype_of_attrs attrs = case get_attr "objtype" attrs of
156 | "theory" => ObjTheory
157 | "theorem" => ObjTheorem
158 | "comment" => ObjComment
161 | s => ObjOther s (* where s mem other_objtypes_parameter *)
163 type objname = string
164 type idtable = { context: objname option, (* container's objname *)
168 fun idtable_to_xml {context, objtype, ids} =
170 val objtype_attrs = attrs_of_objtype objtype
171 val context_attrs = opt_attr "context" context
172 val ids_content = map (fn x => XML.Elem("identifier",[],[XML.Text x])) ids
175 objtype_attrs @ context_attrs,
180 (** Types and values **)
182 (* readers and writers for values represented in XML strings *)
184 fun read_pgipbool s =
188 | _ => raise PGIP ("Invalid boolean value: " ^ quote s))
191 fun int_in_range (NONE,NONE) (_: int) = true
192 | int_in_range (SOME min,NONE) i = min<= i
193 | int_in_range (NONE,SOME max) i = i<=max
194 | int_in_range (SOME min,SOME max) i = min<= i andalso i<=max
196 fun read_pgipint range s =
197 (case Int.fromString s of
198 SOME i => if int_in_range range i then i
199 else raise PGIP ("Out of range integer value: " ^ quote s)
200 | NONE => raise PGIP ("Invalid integer value: " ^ quote s))
204 (case Int.fromString s of
205 SOME i => if i >= 0 then i
206 else raise PGIP ("Invalid natural number: " ^ quote s)
207 | NONE => raise PGIP ("Invalid natural number: " ^ quote s))
209 (* NB: we can maybe do without xml decode/encode here. *)
210 fun read_pgipstring s = (* non-empty strings, XML escapes decoded *)
211 (case XML.parse_string s of
213 | NONE => raise PGIP ("Expected a non-empty string: " ^ quote s))
214 handle _ => raise PGIP ("Invalid XML string syntax: " ^ quote s)
216 val int_to_pgstring = signed_string_of_int
218 fun string_to_pgstring s = XML.text s
220 fun bool_to_pgstring b = if b then "true" else "false"
225 This is a reflection of the type structure of PGIP configuration,
226 which is meant for setting up user dialogs and preference settings.
227 These are configured declaratively in XML, using a syntax for types
228 and values which is like a (vastly cut down) form of XML Schema
231 The prover needs to interpret the strings representing the typed
232 values, at least for the types it expects from the dialogs it
233 configures. Here we go further and construct a type-safe
234 encapsulation of these values, which would be useful for more
235 advanced cases (e.g. generating and processing forms).
240 Pgipnull (* unit type: unique element is empty string *)
241 | Pgipbool (* booleans: "true" or "false" *)
242 | Pgipint of int option * int option (* ranged integers, should be XSD canonical *)
243 | Pgipnat (* naturals: non-negative integers (convenience) *)
244 | Pgipstring (* non-empty strings *)
245 | Pgipconst of string (* singleton type *)
246 | Pgipchoice of pgipdtype list (* union type *)
248 (* Compared with the PGIP schema, we push descriptions of types inside choices. *)
250 and pgipdtype = Pgipdtype of string option * pgiptype
252 datatype pgipuval = Pgvalnull | Pgvalbool of bool | Pgvalint of int | Pgvalnat of int
253 | Pgvalstring of string | Pgvalconst of string
255 type pgipval = pgiptype * pgipuval (* type-safe values *)
257 fun pgipdtype_to_xml (desco,ty) =
259 val desc_attr = opt_attr "descr" desco
262 Pgipnull => "pgipnull"
263 | Pgipbool => "pgipbool"
264 | Pgipint _ => "pgipint"
265 | Pgipnat => "pgipint"
266 | Pgipstring => "pgipstring"
267 | Pgipconst _ => "pgipconst"
268 | Pgipchoice _ => "pgipchoice"
270 fun range_attr r v = attr r (int_to_pgstring v)
272 val attrs = case ty of
273 Pgipint (SOME min,SOME max) => (range_attr "min" min)@(range_attr "max" max)
274 | Pgipint (SOME min,NONE) => (range_attr "min" min)
275 | Pgipint (NONE,SOME max) => (range_attr "max" max)
276 | Pgipnat => (range_attr "min" 0)
277 | Pgipconst nm => attr "name" nm
280 fun destpgipdtype (Pgipdtype x) = x
282 val typargs = case ty of
283 Pgipchoice ds => map destpgipdtype ds
286 XML.Elem (elt, (desc_attr @ attrs), (map pgipdtype_to_xml typargs))
289 val pgiptype_to_xml = pgipdtype_to_xml o pair NONE
291 fun read_pguval Pgipnull s =
292 if s="" then Pgvalnull
293 else raise PGIP ("Expecting empty string for null type, not: " ^ quote s)
294 | read_pguval Pgipbool s = Pgvalbool (read_pgipbool s)
295 | read_pguval (Pgipint range) s = Pgvalint (read_pgipint range s)
296 | read_pguval Pgipnat s = Pgvalnat (read_pgipnat s)
297 | read_pguval (Pgipconst c) s =
298 if c=s then Pgvalconst c
299 else raise PGIP ("Given string: "^quote s^" doesn't match expected string: "^quote c)
300 | read_pguval Pgipstring s =
301 if s<>"" then Pgvalstring s
302 else raise PGIP ("Expecting non-empty string, empty string illegal.")
303 | read_pguval (Pgipchoice tydescs) s =
305 (* Union type: match first in list *)
306 fun getty (Pgipdtype(_, ty)) = ty
308 (fn ty => SOME (read_pguval ty s) handle PGIP _ => NONE)
311 case uval of SOME pgv => pgv | NONE => raise PGIP ("Can't match string: "^quote s^
312 " against any allowed types.")
315 fun read_pgval ty s = (ty, read_pguval ty s)
317 fun pgval_to_string (_, Pgvalnull) = ""
318 | pgval_to_string (_, Pgvalbool b) = bool_to_pgstring b
319 | pgval_to_string (_, Pgvalnat n) = int_to_pgstring n
320 | pgval_to_string (_, Pgvalint i) = int_to_pgstring i
321 | pgval_to_string (_, Pgvalconst c) = string_to_pgstring c
322 | pgval_to_string (_, Pgvalstring s) = string_to_pgstring s
325 type pgipurl = Path.T (* URLs: only local files *)
327 datatype displayarea = Status | Message | Display | Tracing | Internal | Other of string
329 datatype fatality = Info | Warning | Nonfatal | Fatal | Panic | Log | Debug
331 type location = { descr: string option,
340 (** Url operations **)
343 fun pgipurl_of_string url = (* only handle file:/// or file://localhost/ *)
344 case Url.explode url of
345 (Url.File path) => path
346 | _ => raise PGIP ("Cannot access non-local URL " ^ quote url)
348 fun pgipurl_of_path p = p
350 fun path_of_pgipurl p = p (* potentially raises PGIP, but not with this implementation *)
352 fun string_of_pgipurl p = Path.implode p
354 fun attrval_of_pgipurl purl = "file:" ^ (XML.text (File.platform_path (File.full_path purl)))
355 fun attrs_of_pgipurl purl = [("url", attrval_of_pgipurl purl)]
357 val pgipurl_of_attrs = pgipurl_of_string o get_attr "url"
359 fun pgipurl_of_url (Url.File p) = p
360 | pgipurl_of_url url =
361 raise PGIP ("Cannot access non-local/non-file URL " ^ quote (Url.implode url))
364 (** Messages and errors **)
367 fun string_of_area Status = "status"
368 | string_of_area Message = "message"
369 | string_of_area Display = "display"
370 | string_of_area Tracing = "tracing"
371 | string_of_area Internal = "internal"
372 | string_of_area (Other s) = s
374 fun string_of_fatality Info = "info"
375 | string_of_fatality Warning = "warning"
376 | string_of_fatality Nonfatal = "nonfatal"
377 | string_of_fatality Fatal = "fatal"
378 | string_of_fatality Panic = "panic"
379 | string_of_fatality Log = "log"
380 | string_of_fatality Debug = "debug"
382 fun attrs_of_displayarea area = [("area", string_of_area area)]
384 fun attrs_of_fatality fatality = [("fatality", string_of_fatality fatality)]
386 fun attrs_of_location ({ descr, url, line, column, char, length }:location) =
388 val descr = opt_attr "location_descr" descr
389 val url = opt_attr_map attrval_of_pgipurl "location_url" url
390 val line = opt_attr_map int_to_pgstring "locationline" line
391 val column = opt_attr_map int_to_pgstring "locationcolumn" column
392 val char = opt_attr_map int_to_pgstring "locationcharacter" char
393 val length = opt_attr_map int_to_pgstring "locationlength" length
395 descr @ url @ line @ column @ char @ length
398 fun pgipint_of_string err s =
399 case Int.fromString s of
401 | NONE => raise PGIP ("Type error in " ^ quote err ^ ": expected integer.")
403 fun location_of_attrs attrs =
405 val descr = get_attr_opt "location_descr" attrs
406 val url = Option.map pgipurl_of_string (get_attr_opt "location_url" attrs)
407 val line = Option.map (pgipint_of_string "location element line attribute")
408 (get_attr_opt "locationline" attrs)
409 val column = Option.map (pgipint_of_string "location element column attribute")
410 (get_attr_opt "locationcolumn" attrs)
411 val char = Option.map (pgipint_of_string "location element char attribute")
412 (get_attr_opt "locationcharacter" attrs)
413 val length = Option.map (pgipint_of_string "location element length attribute")
414 (get_attr_opt "locationlength" attrs)
416 {descr=descr, url=url, line=line, column=column, char=char, length=length}
422 type preference = { name: string,
423 descr: string option,
424 default: string option,
427 fun haspref ({ name, descr, default, pgiptype}:preference) =
430 opt_attr "descr" descr @
431 opt_attr "default" default,
432 [pgiptype_to_xml pgiptype])