1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
|
open Util;;
open System;;
open Pp;;
open Libnames;;
open Library;;
open Ascent;;
open Vtp;;
open Xlate;;
open Line_parser;;
open Pcoq;;
open Vernacexpr;;
open Mltop;;
type parsed_tree =
| P_cl of ct_COMMAND_LIST
| P_c of ct_COMMAND
| P_t of ct_TACTIC_COM
| P_f of ct_FORMULA
| P_id of ct_ID
| P_s of ct_STRING
| P_i of ct_INT;;
let print_parse_results n msg =
print_string "message\nparsed\n";
print_int n;
print_string "\n";
(match msg with
| P_cl x -> fCOMMAND_LIST x
| P_c x -> fCOMMAND x
| P_t x -> fTACTIC_COM x
| P_f x -> fFORMULA x
| P_id x -> fID x
| P_s x -> fSTRING x
| P_i x -> fINT x);
print_string "e\nblabla\n";
flush stdout;;
let ctf_SyntaxErrorMessage reqid pps =
fnl () ++ str "message" ++ fnl () ++ str "syntax_error" ++ fnl () ++
int reqid ++ fnl () ++
pps ++ fnl () ++ str "E-n-d---M-e-s-s-a-g-e" ++ fnl ();;
let ctf_SyntaxWarningMessage reqid pps =
fnl () ++ str "message" ++ fnl () ++ str "syntax_warning" ++ fnl () ++
int reqid ++ fnl () ++ pps ++ fnl () ++ str "E-n-d---M-e-s-s-a-g-e" ++ fnl();;
let ctf_FileErrorMessage reqid pps =
fnl () ++ str "message" ++ fnl () ++ str "file_error" ++ fnl () ++
int reqid ++ fnl () ++ pps ++ fnl () ++ str "E-n-d---M-e-s-s-a-g-e" ++
fnl ();;
(*
(*In the code for CoqV6.2, the require_module call is encapsulated in
a function "without_mes_ambig". Here I have supposed that this
function has no effect on parsing *)
let try_require_module import specif names =
try Library.require_module
(if specif = "UNSPECIFIED" then None
else Some (specif = "SPECIFICATION"))
(List.map
(fun name ->
(dummy_loc,Libnames.make_short_qualid (Names.id_of_string name)))
names)
(import = "IMPORT")
with
| e -> msgnl (str "Reinterning of " ++ prlist str names ++ str " failed");;
*)
(*
let try_require_module_from_file import specif name fname =
try Library.require_module_from_file (if specif = "UNSPECIFIED" then None
else Some (specif = "SPECIFICATION")) (Some (Names.id_of_string name)) fname (import = "IMPORT")
with
| e -> msgnl (str "Reinterning of " ++ str name ++ str " failed");;
*)
(*
let execute_when_necessary ast =
(match ast with
| Node (_, "GRAMMAR", ((Nvar (_, s)) :: ((Node (_, "ASTLIST", al)) :: []))) ->
Metasyntax.add_grammar_obj s (List.map Ctast.ct_to_ast al)
(* Obsolete
| Node (_, "TOKEN", ((Str (_, s)) :: [])) -> Metasyntax.add_token_obj s
*)
| Node (_, "Require",
((Str (_, import)) ::
((Str (_, specif)) :: l))) ->
let mnames = List.map (function
| (Nvar (_, m)) -> m
| _ -> error "parse_string_action : bad require expression") l in
try_require_module import specif mnames
| Node (_, "RequireFrom",
((Str (_, import)) ::
((Str (_, specif)) ::
((Nvar (_, mname)) :: ((Str (_, file_name)) :: []))))) ->
try_require_module_from_file import specif mname file_name
| _ -> ()); ast;;
*)
let execute_when_necessary v =
(match v with
| VernacGrammar _ -> Vernacentries.interp v
| VernacOpenCloseScope sc -> Vernacentries.interp v
| VernacRequire (_,_,l) ->
(try
Vernacentries.interp v
with _ ->
let l=prlist_with_sep spc pr_reference l in
msgnl (str "Reinterning of " ++ l ++ str " failed"))
| VernacRequireFrom (_,_,f) ->
(try
Vernacentries.interp v
with _ ->
msgnl (str "Reinterning of " ++ Util.pr_str f ++ str " failed"))
| _ -> ()); v;;
let parse_to_dot =
let rec dot st = match Stream.next st with
| ("", ".") -> ()
| ("EOI", "") -> raise End_of_file
| _ -> dot st in
Gram.Entry.of_parser "Coqtoplevel.dot" dot;;
let rec discard_to_dot stream =
try Gram.Entry.parse parse_to_dot (Gram.parsable stream) with
| Stdpp.Exc_located(_, Token.Error _) -> discard_to_dot stream;;
let rec decompose_string_aux s n =
try let index = String.index_from s n '\n' in
(String.sub s n (index - n))::
(decompose_string_aux s (index + 1))
with Not_found -> [String.sub s n ((String.length s) - n)];;
let decompose_string s n =
match decompose_string_aux s n with
""::tl -> tl
| a -> a;;
let make_string_list file_chan fst_pos snd_pos =
let len = (snd_pos - fst_pos) in
let s = String.create len in
begin
seek_in file_chan fst_pos;
really_input file_chan s 0 len;
decompose_string s 0;
end;;
let rec get_sub_aux string_list snd_pos =
match string_list with
[] -> []
| s::l ->
let len = String.length s in
if len >= snd_pos then
if snd_pos < 0 then
[]
else
[String.sub s 0 snd_pos]
else
s::(get_sub_aux l (snd_pos - len - 1));;
let rec get_substring_list string_list fst_pos snd_pos =
match string_list with
[] -> []
| s::l ->
let len = String.length s in
if fst_pos > len then
get_substring_list l (fst_pos - len - 1) (snd_pos - len - 1)
else
(* take into account the fact that carriage returns are not in the *)
(* strings. *)
let fst_pos2 = if fst_pos = 0 then 1 else fst_pos in
if snd_pos > len then
String.sub s (fst_pos2 - 1) (len + 1 - fst_pos2)::
(get_sub_aux l (snd_pos - len - 2))
else
let gap = (snd_pos - fst_pos2) in
if gap < 0 then
[]
else
[String.sub s (fst_pos2 - 1) gap];;
(* When parsing a list of commands, we try to recover error messages for
each individual command. *)
type parse_result =
| ParseOK of Vernacexpr.vernac_expr located option
| ParseError of string * string list
let embed_string s =
CT_coerce_STRING_OPT_to_VARG (CT_coerce_STRING_to_STRING_OPT (CT_string s))
let make_parse_error_item s l =
CT_user_vernac (CT_ident s, CT_varg_list (List.map embed_string l))
let parse_command_list reqid stream string_list =
let rec parse_whole_stream () =
let this_pos = Stream.count stream in
let first_ast =
try ParseOK (Gram.Entry.parse Pcoq.main_entry (Gram.parsable stream))
with
| (Stdpp.Exc_located(l, Stream.Error txt)) as e ->
begin
msgnl (ctf_SyntaxWarningMessage reqid (Cerrors.explain_exn e));
try
discard_to_dot stream;
msgnl (str "debug" ++ fnl () ++ int this_pos ++ fnl () ++
int (Stream.count stream));
(*
Some( Node(l, "PARSING_ERROR",
List.map Ctast.str
(get_substring_list string_list this_pos
(Stream.count stream))))
*)
ParseError ("PARSING_ERROR",
get_substring_list string_list this_pos
(Stream.count stream))
with End_of_file -> ParseOK None
end
| e->
begin
discard_to_dot stream;
(*
Some(Node((0,0), "PARSING_ERROR2",
List.map Ctast.str
(get_substring_list string_list this_pos
(Stream.count stream))))
*)
ParseError ("PARSING_ERROR2",
get_substring_list string_list this_pos (Stream.count stream))
end in
match first_ast with
| ParseOK (Some (loc,ast)) ->
let ast0 = (execute_when_necessary ast) in
(try xlate_vernac ast
with e ->
(*
xlate_vernac
(Node((0,0), "PARSING_ERROR2",
List.map Ctast.str
(get_substring_list string_list this_pos
(Stream.count stream)))))::parse_whole_stream()
*)
make_parse_error_item "PARSING_ERROR2"
(get_substring_list string_list this_pos
(Stream.count stream)))::parse_whole_stream()
| ParseOK None -> []
| ParseError (s,l) ->
(make_parse_error_item s l)::parse_whole_stream()
in
match parse_whole_stream () with
| first_one::tail -> (P_cl (CT_command_list(first_one, tail)))
| [] -> raise (UserError ("parse_string", (str "empty text.")));;
(*When parsing a string using a phylum, the string is first transformed
into a Coq Ast using the regular Coq parser, then it is transformed into
the right ascent term using xlate functions, then it is transformed into
a stream, using the right vtp function. There is a special case for commands,
since some of these must be executed!*)
let parse_string_action reqid phylum char_stream string_list =
try let msg =
match phylum with
| "COMMAND_LIST" ->
parse_command_list reqid char_stream string_list
| "COMMAND" ->
P_c
(xlate_vernac
(execute_when_necessary
(Gram.Entry.parse Pcoq.Vernac_.vernac_eoi (Gram.parsable char_stream))))
| "TACTIC_COM" ->
P_t
(xlate_tactic (Gram.Entry.parse Pcoq.Tactic.tactic_eoi
(Gram.parsable char_stream)))
| "FORMULA" ->
P_f
(xlate_formula
(Gram.Entry.parse
(Pcoq.eoi_entry Pcoq.Constr.lconstr) (Gram.parsable char_stream)))
| "ID" -> P_id (CT_ident
(Libnames.string_of_qualid
(snd
(Gram.Entry.parse (Pcoq.eoi_entry Pcoq.Prim.qualid)
(Gram.parsable char_stream)))))
| "STRING" ->
P_s
(CT_string (Gram.Entry.parse Pcoq.Prim.string
(Gram.parsable char_stream)))
| "INT" ->
P_i (CT_int (Gram.Entry.parse Pcoq.Prim.natural
(Gram.parsable char_stream)))
| _ -> error "parse_string_action : bad phylum" in
print_parse_results reqid msg
with
| Stdpp.Exc_located(l,Match_failure(_,_,_)) ->
flush_until_end_of_stream char_stream;
msgnl (ctf_SyntaxErrorMessage reqid
(Cerrors.explain_exn
(Stdpp.Exc_located(l,Stream.Error "match failure"))))
| e ->
flush_until_end_of_stream char_stream;
msgnl (ctf_SyntaxErrorMessage reqid (Cerrors.explain_exn e));;
let quiet_parse_string_action char_stream =
try let _ =
Gram.Entry.parse Pcoq.Vernac_.vernac_eoi (Gram.parsable char_stream) in
()
with
| _ -> flush_until_end_of_stream char_stream; ();;
let parse_file_action reqid file_name =
try let file_chan = open_in file_name in
(* file_chan_err, stream_err are the channel and stream used to
get the text when a syntax error occurs *)
let file_chan_err = open_in file_name in
let stream = Stream.of_channel file_chan in
let stream_err = Stream.of_channel file_chan_err in
let rec discard_to_dot () =
try Gram.Entry.parse parse_to_dot (Gram.parsable stream)
with Stdpp.Exc_located(_,Token.Error _) -> discard_to_dot() in
match let rec parse_whole_file () =
let this_pos = Stream.count stream in
match
try
ParseOK(Gram.Entry.parse Pcoq.main_entry (Gram.parsable stream))
with
| Stdpp.Exc_located(l,Stream.Error txt) ->
msgnl (ctf_SyntaxWarningMessage reqid
(str "Error with file" ++ spc () ++
str file_name ++ fnl () ++
Cerrors.explain_exn
(Stdpp.Exc_located(l,Stream.Error txt))));
(try
begin
discard_to_dot ();
ParseError ("PARSING_ERROR",
(make_string_list file_chan_err this_pos
(Stream.count stream)))
end
with End_of_file -> ParseOK None)
| e ->
begin
Gram.Entry.parse parse_to_dot (Gram.parsable stream);
ParseError ("PARSING_ERROR2",
(make_string_list file_chan this_pos
(Stream.count stream)))
end
with
| ParseOK (Some (_,ast)) ->
let ast0=(execute_when_necessary ast) in
let term =
(try xlate_vernac ast
with e ->
print_string ("translation error between " ^
(string_of_int this_pos) ^
" " ^
(string_of_int (Stream.count stream)) ^
"\n");
make_parse_error_item "PARSING_ERROR2"
(make_string_list file_chan_err this_pos
(Stream.count stream))) in
term::parse_whole_file ()
| ParseOK None -> []
| ParseError (s,l) ->
(make_parse_error_item s l)::parse_whole_file () in
parse_whole_file () with
| first_one :: tail ->
print_parse_results reqid
(P_cl (CT_command_list (first_one, tail)))
| [] -> raise (UserError ("parse_file_action", str "empty file."))
with
| Stdpp.Exc_located(l,Match_failure(_,_,_)) ->
msgnl
(ctf_SyntaxErrorMessage reqid
(str "Error with file" ++ spc () ++ str file_name ++
fnl () ++
Cerrors.explain_exn
(Stdpp.Exc_located(l,Stream.Error "match failure"))))
| e ->
msgnl
(ctf_SyntaxErrorMessage reqid
(str "Error with file" ++ spc () ++ str file_name ++
fnl () ++ Cerrors.explain_exn e));;
let add_rec_path_action reqid string_arg ident_arg =
let directory_name = glob string_arg in
begin
add_rec_path directory_name (Libnames.dirpath_of_string ident_arg)
end;;
let add_path_action reqid string_arg =
let directory_name = glob string_arg in
begin
add_path directory_name Names.empty_dirpath
end;;
let print_version_action () =
msgnl (mt ());
msgnl (str "$Id: parse.ml,v 1.22 2004/04/21 08:36:58 barras Exp $");;
let load_syntax_action reqid module_name =
msg (str "loading " ++ str module_name ++ str "... ");
try
(let qid = Libnames.make_short_qualid (Names.id_of_string module_name) in
read_library (dummy_loc,qid);
msg (str "opening... ");
Declaremods.import_module false (Nametab.locate_module qid);
msgnl (str "done" ++ fnl ());
())
with
| UserError (label, pp_stream) ->
(*This one may be necessary to make sure that the message won't be indented *)
msgnl (mt ());
msgnl
(fnl () ++ str "error while loading syntax module " ++ str module_name ++
str ": " ++ str label ++ fnl () ++ pp_stream)
| e ->
msgnl (mt ());
msgnl
(fnl () ++ str "message" ++ fnl () ++ str "load_error" ++ fnl () ++
int reqid ++ fnl ());
();;
let coqparser_loop inchan =
(parser_loop : (unit -> unit) *
(int -> string -> char Stream.t -> string list -> unit) *
(char Stream.t -> unit) * (int -> string -> unit) *
(int -> string -> unit) * (int -> string -> string -> unit) *
(int -> string -> unit) -> in_channel -> unit)
(print_version_action, parse_string_action, quiet_parse_string_action, parse_file_action,
add_path_action, add_rec_path_action, load_syntax_action) inchan;;
if !Sys.interactive then ()
else
Libobject.relax true;
(let coqdir =
try Sys.getenv "COQDIR"
with Not_found ->
let coqdir = Coq_config.coqlib in
if Sys.file_exists coqdir then
coqdir
else
(msgnl (str "could not find the value of COQDIR"); exit 1) in
begin
add_rec_path (Filename.concat coqdir "theories")
(Names.make_dirpath [Nameops.coq_root]);
add_rec_path (Filename.concat coqdir "contrib")
(Names.make_dirpath [Nameops.coq_root])
end;
(let vernacrc =
try
Sys.getenv "VERNACRC"
with
Not_found ->
List.fold_left
(fun s1 s2 -> (Filename.concat s1 s2))
coqdir [ "contrib"; "interface"; "vernacrc"] in
try
(Gramext.warning_verbose := false;
Esyntax.warning_verbose := false;
coqparser_loop (open_in vernacrc))
with
| End_of_file -> ()
| e ->
(msgnl (Cerrors.explain_exn e);
msgnl (str "could not load the VERNACRC file"));
try
msgnl (str vernacrc)
with
e -> ());
(try let user_vernacrc =
try Some(Sys.getenv "USERVERNACRC")
with
| Not_found as e ->
msgnl (str "no .vernacrc file"); None in
(match user_vernacrc with
Some f -> coqparser_loop (open_in f)
| None -> ())
with
| End_of_file -> ()
| e ->
msgnl (Cerrors.explain_exn e);
msgnl (str "error in your .vernacrc file"));
msgnl (str "Starting Centaur Specialized Parser Loop");
try
coqparser_loop stdin
with
| End_of_file -> ()
| e -> msgnl(Cerrors.explain_exn e))
|