src/HOL/SPARK/Tools/fdl_parser.ML
author wenzelm
Sat, 23 Jul 2011 16:37:17 +0200
changeset 44818 9b00f09f7721
parent 41868 f88eca2e9ebd
child 47662 7cc567fd2789
permissions -rw-r--r--
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
     4 
     5 Parser for fdl files.
     6 *)
     7 
     8 signature FDL_PARSER =
     9 sig
    10   datatype expr =
    11       Ident of string
    12     | Number of int
    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;
    20 
    21   datatype fdl_type =
    22       Basic_Type of string
    23     | Enum_Type of string list
    24     | Array_Type of string list * string
    25     | Record_Type of (string list * string) list
    26     | Pending_Type;
    27 
    28   datatype fdl_rule =
    29       Inference_Rule of expr list * expr
    30     | Substitution_Rule of expr list * expr * expr;
    31 
    32   type rules =
    33     ((string * int) * fdl_rule) list *
    34     (string * (expr * (string * string) list) list) list;
    35 
    36   type vcs = (string * (string *
    37     ((string * expr) list * (string * expr) list)) list) list;
    38 
    39   type 'a tab = 'a Symtab.table * (string * 'a) list;
    40 
    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;
    44 
    45   type decls =
    46     {types: fdl_type tab,
    47      vars: string tab,
    48      consts: string tab,
    49      funs: (string list * string) tab};
    50 
    51   val parse_vcs: (Fdl_Lexer.chars -> 'a * Fdl_Lexer.chars) -> Position.T ->
    52     string -> 'a * ((string * string) * vcs);
    53 
    54   val parse_declarations:  Position.T -> string -> (string * string) * decls;
    55 
    56   val parse_rules: Position.T -> string -> rules;
    57 end;
    58 
    59 structure Fdl_Parser: FDL_PARSER =
    60 struct
    61 
    62 (** error handling **)
    63 
    64 fun beginning n cs =
    65   let val dots = if length cs > n then " ..." else "";
    66   in
    67     space_implode " " (take n cs) ^ dots
    68   end;
    69 
    70 fun !!! scan =
    71   let
    72     fun get_pos [] = " (past end-of-file!)"
    73       | get_pos (tok :: _) = Fdl_Lexer.pos_of tok;
    74 
    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;
    80 
    81 fun parse_all p =
    82   Scan.repeat (Scan.unless (Scan.one Fdl_Lexer.is_eof) (!!! p));
    83 
    84 
    85 (** parsers **)
    86 
    87 fun group s p = p || Scan.fail_with (K (fn () => s));
    88 
    89 fun $$$ s = group s
    90   (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Keyword andalso
    91      Fdl_Lexer.content_of t = s) >> K s);
    92 
    93 val identifier = group "identifier"
    94   (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Ident) >>
    95      Fdl_Lexer.content_of);
    96 
    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);
   100 
   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);
   104 
   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));
   109 
   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";
   113 
   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));
   117 
   118 val traceability = group "traceability information"
   119   (Scan.one (fn t => Fdl_Lexer.kind_of t = Fdl_Lexer.Traceability) >>
   120      Fdl_Lexer.content_of);
   121 
   122 fun enum1 sep scan = scan ::: Scan.repeat ($$$ sep |-- !!! scan);
   123 fun enum sep scan = enum1 sep scan || Scan.succeed [];
   124 
   125 fun list1 scan = enum1 "," scan;
   126 fun list scan = enum "," scan;
   127 
   128 
   129 (* expressions, see section 4.4 of SPARK Proof Manual *)
   130 
   131 datatype expr =
   132     Ident of string
   133   | Number of int
   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;
   141 
   142 fun unop (f, x) = Funct (f, [x]);
   143 
   144 fun binop p q = p :|-- (fn x => Scan.optional
   145   (q -- !!! p >> (fn (f, y) => Funct (f, [x, y]))) x);
   146 
   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);
   151 
   152 (* right-associative *)
   153 fun binops' f p = enum1 f p >> foldr1 (fn (x, y) => Funct (f, [x, y]));
   154 
   155 val multiplying_operator = $$$ "*" || $$$ "/" || $$$ "div" || $$$ "mod";
   156 
   157 val adding_operator = $$$ "+" || $$$ "-";
   158 
   159 val relational_operator =
   160      $$$ "=" || $$$ "<>"
   161   || $$$ "<" || $$$ ">"
   162   || $$$ "<="|| $$$ ">=";
   163 
   164 val quantification_kind = $$$ "for_all" || $$$ "for_some";
   165 
   166 val quantification_generator =
   167   list1 identifier --| $$$ ":" -- identifier;
   168 
   169 fun expression xs = group "expression"
   170   (binop disjunction ($$$ "->" || $$$ "<->")) xs
   171 
   172 and disjunction xs = binops' "or" conjunction xs
   173 
   174 and conjunction xs = binops' "and" negation xs
   175 
   176 and negation xs =
   177   (   $$$ "not" -- !!! relation >> unop
   178    || relation) xs
   179 
   180 and relation xs = binop sum relational_operator xs
   181 
   182 and sum xs = binops adding_operator term xs
   183 
   184 and term xs = binops multiplying_operator factor xs
   185 
   186 and factor xs =
   187   (   $$$ "+" |-- !!! primary
   188    || $$$ "-" -- !!! primary >> unop
   189    || binop primary ($$$ "**")) xs
   190 
   191 and primary xs = group "primary"
   192   (   number >> Number
   193    || $$$ "(" |-- !!! (expression --| $$$ ")")
   194    || quantified_expression
   195    || function_designator
   196    || identifier >> Ident) xs
   197 
   198 and quantified_expression xs = (quantification_kind --
   199   !!! ($$$ "(" |-- quantification_generator --|  $$$ "," --
   200     expression --| $$$ ")") >> (fn (q, ((xs, T), e)) =>
   201       Quantifier (q, xs, T, e))) xs
   202 
   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
   212 
   213 and record_args s xs =
   214   (list1 (identifier --| $$$ ":=" -- !!! expression) >> (pair s #> Record)) xs
   215 
   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
   220 
   221 and array_associations xs =
   222   (list1 (enum1 "&" ($$$ "[" |--
   223      !!! (list1 (expression -- Scan.option ($$$ ".." |-- !!! expression)) --|
   224        $$$ "]")) --| $$$ ":=" -- expression)) xs;
   225 
   226 
   227 (* verification conditions *)
   228 
   229 type vcs = (string * (string *
   230   ((string * expr) list * (string * expr) list)) list) list;
   231 
   232 val vc =
   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 --| $$$ ".")));
   242 
   243 val subprogram_kind = $$$ "function" || $$$ "procedure";
   244 
   245 val vcs =
   246   subprogram_kind -- (long_identifier || identifier) --
   247   parse_all (traceability -- !!! (Scan.repeat1 vc));
   248 
   249 fun parse_vcs header pos s =
   250   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)) ||>
   254   fst;
   255 
   256 
   257 (* fdl declarations, see section 4.3 of SPARK Proof Manual *)
   258 
   259 datatype fdl_type =
   260     Basic_Type of string
   261   | Enum_Type of string list
   262   | Array_Type of string list * string
   263   | Record_Type of (string list * string) list
   264   | Pending_Type;
   265 
   266 (* also store items in a list to preserve order *)
   267 type 'a tab = 'a Symtab.table * (string * 'a) list;
   268 
   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;
   272 
   273 type decls =
   274   {types: fdl_type tab,
   275    vars: string tab,
   276    consts: string tab,
   277    funs: (string list * string) tab};
   278 
   279 val empty_decls : decls =
   280   {types = (Symtab.empty, []), vars = (Symtab.empty, []),
   281    consts = (Symtab.empty, []), funs = (Symtab.empty, [])};
   282 
   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);
   287 
   288 fun add_var_decl (vs, ty) {types, vars, consts, funs} =
   289   {types = types,
   290    vars = fold (update o rpair ty) vs vars,
   291    consts = consts, funs = funs}
   292   handle Symtab.DUP s => error ("Duplicate variable " ^ s);
   293 
   294 fun add_const_decl decl {types, vars, consts, funs} =
   295   {types = types, vars = vars,
   296    consts = update decl consts,
   297    funs = funs}
   298   handle Symtab.DUP s => error ("Duplicate constant " ^ s);
   299 
   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);
   304 
   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;
   314 
   315 fun const_decl x = ($$$ "const" |-- !!! (identifier --| $$$ ":" -- identifier --|
   316   $$$ "=" --| $$$ "pending") >> add_const_decl) x;
   317 
   318 fun var_decl x = ($$$ "var" |-- !!! (list1 identifier --| $$$ ":" -- identifier) >>
   319   add_var_decl) x;
   320 
   321 fun fun_decl x = ($$$ "function" |-- !!! (identifier --
   322   (Scan.optional ($$$ "(" |-- !!! (list1 identifier --| $$$ ")")) [] --|
   323    $$$ ":" -- identifier)) >> add_fun_decl) x;
   324 
   325 fun declarations 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;
   330 
   331 fun parse_declarations pos s =
   332   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)) |>
   336   fst;
   337 
   338 
   339 (* rules, see section 5 of SPADE Proof Checker Rules Manual *)
   340 
   341 datatype fdl_rule =
   342     Inference_Rule of expr list * expr
   343   | Substitution_Rule of expr list * expr * expr;
   344 
   345 type rules =
   346   ((string * int) * fdl_rule) list *
   347   (string * (expr * (string * string) list) list) list;
   348 
   349 val condition_list = $$$ "[" |-- list expression --| $$$ "]";
   350 val if_condition_list = $$$ "if" |-- !!! condition_list;
   351 
   352 val rule =
   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));
   365 
   366 val rule_family = 
   367   $$$ "rule_family" |-- identifier --| $$$ ":" --
   368   enum1 "&" (expression -- !!! ($$$ "requires" |-- $$$ "[" |--
   369     list (identifier -- !!! ($$$ ":" |-- identifier)) --| $$$ "]")) --|
   370   $$$ ".";
   371 
   372 val rules =
   373   parse_all (rule >> (apfst o cons) || rule_family >> (apsnd o cons)) >>
   374   (fn rls => apply (rev rls) ([], []));
   375 
   376 fun parse_rules pos s =
   377   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)) |>
   382   fst;
   383 
   384 end;