defer evaluation of Scan.message, for improved performance in the frequent situation where failure is handled later (e.g. via ||);
1 (* Title: HOL/SPARK/Tools/fdl_parser.ML
2 Author: Stefan Berghofer
3 Copyright: secunet Security Networks AG
13 | Quantifier of string * string list * string * expr
14 | Funct of string * expr list
15 | Element of expr * expr list
16 | Update of expr * expr list * expr
17 | Record of string * (string * expr) list
18 | Array of string * expr option *
19 ((expr * expr option) list list * expr) list;
23 | Enum_Type of string list
24 | Array_Type of string list * string
25 | Record_Type of (string list * string) list
29 Inference_Rule of expr list * expr
30 | Substitution_Rule of expr list * expr * expr;
33 ((string * int) * fdl_rule) list *
34 (string * (expr * (string * string) list) list) list;
36 type vcs = (string * (string *
37 ((string * expr) list * (string * expr) list)) list) list;
39 type 'a tab = 'a Symtab.table * (string * 'a) list;
41 val lookup: 'a tab -> string -> 'a option;
42 val update: string * 'a -> 'a tab -> 'a tab;
43 val items: 'a tab -> (string * 'a) list;
49 funs: (string list * string) tab};
51 val parse_vcs: (Fdl_Lexer.chars -> 'a * Fdl_Lexer.chars) -> Position.T ->
52 string -> 'a * ((string * string) * vcs);
54 val parse_declarations: Position.T -> string -> (string * string) * decls;
56 val parse_rules: Position.T -> string -> rules;
59 structure Fdl_Parser: FDL_PARSER =
62 (** error handling **)
65 let val dots = if length cs > n then " ..." else "";
67 space_implode " " (take n cs) ^ dots
72 fun get_pos [] = " (past end-of-file!)"
73 | get_pos (tok :: _) = Fdl_Lexer.pos_of tok;
75 fun err (syms, msg) = fn () =>
76 "Syntax error" ^ get_pos syms ^ " at " ^
77 beginning 10 (map Fdl_Lexer.unparse syms) ^
78 (case msg of NONE => "" | SOME m => "\n" ^ m () ^ " expected");
79 in Scan.!! err scan end;
82 Scan.repeat (Scan.unless (Scan.one Fdl_Lexer.is_eof) (!!! p));
87 fun group s p = p || Scan.fail_with (K (fn () => s));
90 (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Keyword andalso
91 Fdl_Lexer.content_of t = s) >> K s);
93 val identifier = group "identifier"
94 (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Ident) >>
95 Fdl_Lexer.content_of);
97 val long_identifier = group "long identifier"
98 (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Long_Ident) >>
99 Fdl_Lexer.content_of);
101 fun the_identifier s = group s
102 (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Ident andalso
103 Fdl_Lexer.content_of t = s) >> K s);
105 fun prfx_identifier g s = group g
106 (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Ident andalso
107 can (unprefix s) (Fdl_Lexer.content_of t)) >>
108 (unprefix s o Fdl_Lexer.content_of));
110 val mk_identifier = prfx_identifier "identifier \"mk__...\"" "mk__";
111 val hyp_identifier = prfx_identifier "hypothesis identifer" "H";
112 val concl_identifier = prfx_identifier "conclusion identifier" "C";
114 val number = group "number"
115 (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Number) >>
116 (the o Int.fromString o Fdl_Lexer.content_of));
118 val traceability = group "traceability information"
119 (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Traceability) >>
120 Fdl_Lexer.content_of);
122 fun enum1 sep scan = scan ::: Scan.repeat ($$$ sep |-- !!! scan);
123 fun enum sep scan = enum1 sep scan || Scan.succeed [];
125 fun list1 scan = enum1 "," scan;
126 fun list scan = enum "," scan;
129 (* expressions, see section 4.4 of SPARK Proof Manual *)
134 | Quantifier of string * string list * string * expr
135 | Funct of string * expr list
136 | Element of expr * expr list
137 | Update of expr * expr list * expr
138 | Record of string * (string * expr) list
139 | Array of string * expr option *
140 ((expr * expr option) list list * expr) list;
142 fun unop (f, x) = Funct (f, [x]);
144 fun binop p q = p :|-- (fn x => Scan.optional
145 (q -- !!! p >> (fn (f, y) => Funct (f, [x, y]))) x);
147 (* left-associative *)
148 fun binops opp argp =
149 argp -- Scan.repeat (opp -- !!! argp) >> (fn (x, fys) =>
150 fold (fn (f, y) => fn x => Funct (f, [x, y])) fys x);
152 (* right-associative *)
153 fun binops' f p = enum1 f p >> foldr1 (fn (x, y) => Funct (f, [x, y]));
155 val multiplying_operator = $$$ "*" || $$$ "/" || $$$ "div" || $$$ "mod";
157 val adding_operator = $$$ "+" || $$$ "-";
159 val relational_operator =
161 || $$$ "<" || $$$ ">"
162 || $$$ "<="|| $$$ ">=";
164 val quantification_kind = $$$ "for_all" || $$$ "for_some";
166 val quantification_generator =
167 list1 identifier --| $$$ ":" -- identifier;
169 fun expression xs = group "expression"
170 (binop disjunction ($$$ "->" || $$$ "<->")) xs
172 and disjunction xs = binops' "or" conjunction xs
174 and conjunction xs = binops' "and" negation xs
177 ( $$$ "not" -- !!! relation >> unop
180 and relation xs = binop sum relational_operator xs
182 and sum xs = binops adding_operator term xs
184 and term xs = binops multiplying_operator factor xs
187 ( $$$ "+" |-- !!! primary
188 || $$$ "-" -- !!! primary >> unop
189 || binop primary ($$$ "**")) xs
191 and primary xs = group "primary"
193 || $$$ "(" |-- !!! (expression --| $$$ ")")
194 || quantified_expression
195 || function_designator
196 || identifier >> Ident) xs
198 and quantified_expression xs = (quantification_kind --
199 !!! ($$$ "(" |-- quantification_generator --| $$$ "," --
200 expression --| $$$ ")") >> (fn (q, ((xs, T), e)) =>
201 Quantifier (q, xs, T, e))) xs
203 and function_designator xs =
204 ( mk_identifier --| $$$ "(" :|--
205 (fn s => record_args s || array_args s) --| $$$ ")"
206 || $$$ "element" |-- !!! ($$$ "(" |-- expression --| $$$ "," --| $$$ "[" --
207 list1 expression --| $$$ "]" --| $$$ ")") >> Element
208 || $$$ "update" |-- !!! ($$$ "(" |-- expression --| $$$ "," --| $$$ "[" --
209 list1 expression --| $$$ "]" --| $$$ "," -- expression --| $$$ ")") >>
210 (fn ((A, xs), x) => Update (A, xs, x))
211 || identifier --| $$$ "(" -- !!! (list1 expression --| $$$ ")") >> Funct) xs
213 and record_args s xs =
214 (list1 (identifier --| $$$ ":=" -- !!! expression) >> (pair s #> Record)) xs
216 and array_args s xs =
217 ( expression -- Scan.optional ($$$ "," |-- !!! array_associations) [] >>
218 (fn (default, assocs) => Array (s, SOME default, assocs))
219 || array_associations >> (fn assocs => Array (s, NONE, assocs))) xs
221 and array_associations xs =
222 (list1 (enum1 "&" ($$$ "[" |--
223 !!! (list1 (expression -- Scan.option ($$$ ".." |-- !!! expression)) --|
224 $$$ "]")) --| $$$ ":=" -- expression)) xs;
227 (* verification conditions *)
229 type vcs = (string * (string *
230 ((string * expr) list * (string * expr) list)) list) list;
233 identifier --| $$$ "." -- !!!
234 ( $$$ "***" |-- !!! (the_identifier "true" --| $$$ ".") >>
235 (Ident #> pair "1" #> single #> pair [])
236 || $$$ "!!!" |-- !!! (the_identifier "false" --| $$$ ".") >>
237 (Ident #> pair "1" #> single #> pair [])
238 || Scan.repeat1 (hyp_identifier --
239 !!! ($$$ ":" |-- expression --| $$$ ".")) --| $$$ "->" --
240 Scan.repeat1 (concl_identifier --
241 !!! ($$$ ":" |-- expression --| $$$ ".")));
243 val subprogram_kind = $$$ "function" || $$$ "procedure";
246 subprogram_kind -- (long_identifier || identifier) --
247 parse_all (traceability -- !!! (Scan.repeat1 vc));
249 fun parse_vcs header pos s =
251 Fdl_Lexer.tokenize header Fdl_Lexer.c_comment pos ||>
252 filter Fdl_Lexer.is_proper ||>
253 Scan.finite Fdl_Lexer.stopper (Scan.error (!!! vcs)) ||>
257 (* fdl declarations, see section 4.3 of SPARK Proof Manual *)
261 | Enum_Type of string list
262 | Array_Type of string list * string
263 | Record_Type of (string list * string) list
266 (* also store items in a list to preserve order *)
267 type 'a tab = 'a Symtab.table * (string * 'a) list;
269 fun lookup ((tab, _) : 'a tab) = Symtab.lookup tab;
270 fun update decl (tab, items) = (Symtab.update_new decl tab, decl :: items);
271 fun items ((_, items) : 'a tab) = rev items;
274 {types: fdl_type tab,
277 funs: (string list * string) tab};
279 val empty_decls : decls =
280 {types = (Symtab.empty, []), vars = (Symtab.empty, []),
281 consts = (Symtab.empty, []), funs = (Symtab.empty, [])};
283 fun add_type_decl decl {types, vars, consts, funs} =
284 {types = update decl types,
285 vars = vars, consts = consts, funs = funs}
286 handle Symtab.DUP s => error ("Duplicate type " ^ s);
288 fun add_var_decl (vs, ty) {types, vars, consts, funs} =
290 vars = fold (update o rpair ty) vs vars,
291 consts = consts, funs = funs}
292 handle Symtab.DUP s => error ("Duplicate variable " ^ s);
294 fun add_const_decl decl {types, vars, consts, funs} =
295 {types = types, vars = vars,
296 consts = update decl consts,
298 handle Symtab.DUP s => error ("Duplicate constant " ^ s);
300 fun add_fun_decl decl {types, vars, consts, funs} =
301 {types = types, vars = vars, consts = consts,
302 funs = update decl funs}
303 handle Symtab.DUP s => error ("Duplicate function " ^ s);
305 fun type_decl x = ($$$ "type" |-- !!! (identifier --| $$$ "=" --
306 ( identifier >> Basic_Type
307 || $$$ "(" |-- !!! (list1 identifier --| $$$ ")") >> Enum_Type
308 || $$$ "array" |-- !!! ($$$ "[" |-- list1 identifier --| $$$ "]" --|
309 $$$ "of" -- identifier) >> Array_Type
310 || $$$ "record" |-- !!! (enum1 ";"
311 (list1 identifier -- !!! ($$$ ":" |-- identifier)) --|
312 $$$ "end") >> Record_Type
313 || $$$ "pending" >> K Pending_Type)) >> add_type_decl) x;
315 fun const_decl x = ($$$ "const" |-- !!! (identifier --| $$$ ":" -- identifier --|
316 $$$ "=" --| $$$ "pending") >> add_const_decl) x;
318 fun var_decl x = ($$$ "var" |-- !!! (list1 identifier --| $$$ ":" -- identifier) >>
321 fun fun_decl x = ($$$ "function" |-- !!! (identifier --
322 (Scan.optional ($$$ "(" |-- !!! (list1 identifier --| $$$ ")")) [] --|
323 $$$ ":" -- identifier)) >> add_fun_decl) x;
326 ($$$ "title" |-- subprogram_kind -- identifier --| $$$ ";" --
327 (Scan.repeat ((type_decl || const_decl || var_decl || fun_decl) --|
328 !!! ($$$ ";")) >> (fn ds => apply ds empty_decls)) --|
329 $$$ "end" --| $$$ ";") x;
331 fun parse_declarations pos s =
333 Fdl_Lexer.tokenize (Scan.succeed ()) Fdl_Lexer.curly_comment pos |>
334 snd |> filter Fdl_Lexer.is_proper |>
335 Scan.finite Fdl_Lexer.stopper (Scan.error (!!! declarations)) |>
339 (* rules, see section 5 of SPADE Proof Checker Rules Manual *)
342 Inference_Rule of expr list * expr
343 | Substitution_Rule of expr list * expr * expr;
346 ((string * int) * fdl_rule) list *
347 (string * (expr * (string * string) list) list) list;
349 val condition_list = $$$ "[" |-- list expression --| $$$ "]";
350 val if_condition_list = $$$ "if" |-- !!! condition_list;
353 identifier -- !!! ($$$ "(" |-- number --| $$$ ")" --| $$$ ":" --
354 (expression :|-- (fn e =>
355 $$$ "may_be_deduced" >> K (Inference_Rule ([], e))
356 || $$$ "may_be_deduced_from" |--
357 !!! condition_list >> (Inference_Rule o rpair e)
358 || $$$ "may_be_replaced_by" |-- !!! (expression --
359 Scan.optional if_condition_list []) >> (fn (e', cs) =>
360 Substitution_Rule (cs, e, e'))
361 || $$$ "&" |-- !!! (expression --| $$$ "are_interchangeable" --
362 Scan.optional if_condition_list []) >> (fn (e', cs) =>
363 Substitution_Rule (cs, e, e')))) --| $$$ ".") >>
364 (fn (id, (n, rl)) => ((id, n), rl));
367 $$$ "rule_family" |-- identifier --| $$$ ":" --
368 enum1 "&" (expression -- !!! ($$$ "requires" |-- $$$ "[" |--
369 list (identifier -- !!! ($$$ ":" |-- identifier)) --| $$$ "]")) --|
373 parse_all (rule >> (apfst o cons) || rule_family >> (apsnd o cons)) >>
374 (fn rls => apply (rev rls) ([], []));
376 fun parse_rules pos s =
378 Fdl_Lexer.tokenize (Scan.succeed ())
379 (Fdl_Lexer.c_comment || Fdl_Lexer.percent_comment) pos |>
380 snd |> filter Fdl_Lexer.is_proper |>
381 Scan.finite Fdl_Lexer.stopper (Scan.error (!!! rules)) |>