ocaml/camlp4/Camlp4/Struct/Grammar/Parser.ml

360 lines
13 KiB
OCaml

(****************************************************************************)
(* *)
(* Objective Caml *)
(* *)
(* INRIA Rocquencourt *)
(* *)
(* Copyright 2006 Institut National de Recherche en Informatique et *)
(* en Automatique. All rights reserved. This file is distributed under *)
(* the terms of the GNU Library General Public License, with the special *)
(* exception on linking described in LICENSE at the top of the Objective *)
(* Caml source tree. *)
(* *)
(****************************************************************************)
(* Authors:
* - Daniel de Rauglaudre: initial version
* - Nicolas Pouillard: refactoring
*)
module Make (Structure : Structure.S) = struct
module Tools = Tools.Make Structure;
module Failed = Failed.Make Structure;
module Print = Print.Make Structure;
open Structure;
open Sig.Grammar.Structure;
module Stream = struct
include Stream;
value junk strm = Context.junk strm;
value count strm = Context.bp strm;
end;
value add_loc c bp parse_fun strm =
let x = parse_fun strm in
let ep = Context.loc_ep c in
let loc = Loc.merge bp ep in
(x, loc);
value level_number entry lab =
let rec lookup levn =
fun
[ [] -> failwith ("unknown level " ^ lab)
| [lev :: levs] ->
if Tools.is_level_labelled lab lev then levn else lookup (succ levn) levs ]
in
match entry.edesc with
[ Dlevels elev -> lookup 0 elev
| Dparser _ -> raise Not_found ]
;
value strict_parsing = ref False;
value strict_parsing_warning = ref False;
value rec top_symb entry =
fun
[ Sself | Snext -> Snterm entry
| Snterml e _ -> Snterm e
| Slist1sep s sep -> Slist1sep (top_symb entry s) sep
| _ -> raise Stream.Failure ]
;
value top_tree entry =
fun
[ Node {node = s; brother = bro; son = son} ->
Node {node = top_symb entry s; brother = bro; son = son}
| LocAct _ _ | DeadEnd -> raise Stream.Failure ]
;
value entry_of_symb entry =
fun
[ Sself | Snext -> entry
| Snterm e -> e
| Snterml e _ -> e
| _ -> raise Stream.Failure ]
;
value continue entry loc a s c son p1 =
parser
[: a = (entry_of_symb entry s).econtinue 0 loc a c;
act = p1 ?? Failed.tree_failed entry a s son :] ->
Action.mk (fun _ -> Action.getf act a)
;
value skip_if_empty c bp p strm =
(* if Stream.count strm == bp then Action.mk (fun _ -> p strm) *)
if Context.loc_ep c == bp then Action.mk (fun _ -> p strm)
else raise Stream.Failure
;
value do_recover parser_of_tree entry nlevn alevn loc a s c son =
parser
[ [: a = parser_of_tree entry nlevn alevn c (top_tree entry son) :] -> a
| [: a = skip_if_empty c loc (parser []) :] -> a
| [: a =
continue entry loc a s c son
(parser_of_tree entry nlevn alevn c son) :] ->
a ]
;
value recover parser_of_tree entry nlevn alevn loc a s c son strm =
if strict_parsing.val then raise (Stream.Error (Failed.tree_failed entry a s son))
else
let _ =
if strict_parsing_warning.val then
do {
let msg = Failed.tree_failed entry a s son;
Format.eprintf "Warning: trying to recover from syntax error";
if entry.ename <> "" then Format.eprintf " in [%s]" entry.ename else ();
Format.eprintf "\n%s%a@." msg Loc.print loc;
} else () in
do_recover parser_of_tree entry nlevn alevn loc a s c son strm
;
value rec parser_of_tree entry nlevn alevn c =
fun
[ DeadEnd -> parser []
| LocAct act _ -> parser [: :] -> act
| Node {node = Sself; son = LocAct act _; brother = DeadEnd} ->
parser [: a = entry.estart alevn c :] -> Action.getf act a
| Node {node = Sself; son = LocAct act _; brother = bro} ->
let p2 = parser_of_tree entry nlevn alevn c bro in
parser
[ [: a = entry.estart alevn c :] -> Action.getf act a
| [: a = p2 :] -> a ]
| Node {node = s; son = son; brother = DeadEnd} ->
let tokl =
match s with
[ Stoken _ | Skeyword _ -> Tools.get_token_list entry [] s son
| _ -> None ]
in
match tokl with
[ None ->
let ps = parser_of_symbol entry nlevn c s in
let p1 = parser_of_tree entry nlevn alevn c son in
let p1 = parser_cont p1 entry nlevn alevn s c son in
parser bp [: a = ps; act = p1 bp a :] -> Action.getf act a
| Some (tokl, last_tok, son) ->
let p1 = parser_of_tree entry nlevn alevn c son in
let p1 = parser_cont p1 entry nlevn alevn last_tok c son in
parser_of_token_list p1 tokl c ]
| Node {node = s; son = son; brother = bro} ->
let tokl =
match s with
[ Stoken _ | Skeyword _ -> Tools.get_token_list entry [] s son
| _ -> None ]
in
match tokl with
[ None ->
let ps = parser_of_symbol entry nlevn c s in
let p1 = parser_of_tree entry nlevn alevn c son in
let p1 = parser_cont p1 entry nlevn alevn s c son in
let p2 = parser_of_tree entry nlevn alevn c bro in
parser bp
[ [: a = ps; act = p1 bp a :] -> Action.getf act a
| [: a = p2 :] -> a ]
| Some (tokl, last_tok, son) ->
let p1 = parser_of_tree entry nlevn alevn c son in
let p1 = parser_cont p1 entry nlevn alevn last_tok c son in
let p1 = parser_of_token_list p1 tokl c in
let p2 = parser_of_tree entry nlevn alevn c bro in
parser
[ [: a = p1 :] -> a
| [: a = p2 :] -> a ] ] ]
and parser_cont p1 entry nlevn alevn s c son loc a =
parser
[ [: a = p1 :] -> a
| [: a = recover parser_of_tree entry nlevn alevn loc a s c son :] -> a
| [: :] -> raise (Stream.Error (Failed.tree_failed entry a s son)) ]
and parser_of_token_list p1 tokl c =
loop 1 tokl where rec loop n =
fun
[ [Stoken (tematch, _) :: tokl] ->
match tokl with
[ [] ->
let ps _ =
match Context.peek_nth c n with
[ Some (tok, _) when tematch tok -> do { Context.njunk c n; Action.mk tok }
| _ -> raise Stream.Failure ]
in parser bp [: a = ps; act = p1 bp a :] -> Action.getf act a
| _ ->
let ps _ =
match Context.peek_nth c n with
[ Some (tok, _) when tematch tok -> tok
| _ -> raise Stream.Failure ]
in
let p1 = loop (n + 1) tokl in
parser [: tok = ps; s :] -> let act = p1 s in Action.getf act tok ]
| [Skeyword kwd :: tokl] ->
match tokl with
[ [] ->
let ps _ =
match Context.peek_nth c n with
[ Some (tok, _) when Token.match_keyword kwd tok ->
do { Context.njunk c n; Action.mk tok }
| _ -> raise Stream.Failure ]
in parser bp [: a = ps; act = p1 bp a :] -> Action.getf act a
| _ ->
let ps _ =
match Context.peek_nth c n with
[ Some (tok, _) when Token.match_keyword kwd tok -> tok
| _ -> raise Stream.Failure ]
in
let p1 = loop (n + 1) tokl in
parser
[: tok = ps; s :] ->
let act = p1 s in Action.getf act tok ]
| _ -> invalid_arg "parser_of_token_list" ]
and parser_of_symbol entry nlevn c =
fun
[ Smeta _ symbl act ->
let act = Obj.magic act entry symbl in
Obj.magic
(List.fold_left
(fun act symb -> Obj.magic act (parser_of_symbol entry nlevn c symb))
act symbl)
| Slist0 s ->
let ps = parser_of_symbol entry nlevn c s in
let rec loop al =
parser
[ [: a = ps; s :] -> loop [a :: al] s
| [: :] -> al ]
in
parser [: a = loop [] :] -> Action.mk (List.rev a)
| Slist0sep symb sep ->
let ps = parser_of_symbol entry nlevn c symb in
let pt = parser_of_symbol entry nlevn c sep in
let rec kont al =
parser
[ [: v = pt; a = ps ?? Failed.symb_failed entry v sep symb; s :] ->
kont [a :: al] s
| [: :] -> al ]
in
parser
[ [: a = ps; s :] -> Action.mk (List.rev (kont [a] s))
| [: :] -> Action.mk [] ]
| Slist1 s ->
let ps = parser_of_symbol entry nlevn c s in
let rec loop al =
parser
[ [: a = ps; s :] -> loop [a :: al] s
| [: :] -> al ]
in
parser [: a = ps; s :] -> Action.mk (List.rev (loop [a] s))
| Slist1sep symb sep ->
let ps = parser_of_symbol entry nlevn c symb in
let pt = parser_of_symbol entry nlevn c sep in
let rec kont al =
parser
[ [: v = pt;
a =
parser
[ [: a = ps :] -> a
| [: a = parse_top_symb' entry symb c :] -> a
| [: :] ->
raise (Stream.Error (Failed.symb_failed entry v sep symb)) ];
s :] ->
kont [a :: al] s
| [: :] -> al ]
in
parser [: a = ps; s :] -> Action.mk (List.rev (kont [a] s))
| Sopt s ->
let ps = parser_of_symbol entry nlevn c s in
parser
[ [: a = ps :] -> Action.mk (Some a)
| [: :] -> Action.mk None ]
| Stree t ->
let pt = parser_of_tree entry 1 0 c t in
parser bp [: (act, loc) = add_loc c bp pt :] -> Action.getf act loc
| Snterm e -> parser [: a = e.estart 0 c :] -> a
| Snterml e l -> parser [: a = e.estart (level_number e l) c :] -> a
| Sself -> parser [: a = entry.estart 0 c :] -> a
| Snext -> parser [: a = entry.estart nlevn c :] -> a
| Skeyword kwd ->
parser
[: `(tok, _) when Token.match_keyword kwd tok :] -> Action.mk tok
| Stoken (f, _) -> parser [: `(tok, _) when f tok :] -> Action.mk tok ]
and parse_top_symb' entry symb c =
parser_of_symbol entry 0 c (top_symb entry symb)
and parse_top_symb entry symb =
fun strm ->
let c = Context.mk strm
in parse_top_symb' entry symb c (Context.stream c);
value rec start_parser_of_levels entry clevn c =
fun
[ [] -> fun _ -> parser []
| [lev :: levs] ->
let p1 = start_parser_of_levels entry (succ clevn) c levs in
match lev.lprefix with
[ DeadEnd -> p1
| tree ->
let alevn =
match lev.assoc with
[ LeftA | NonA -> succ clevn
| RightA -> clevn ]
in
let p2 = parser_of_tree entry (succ clevn) alevn c tree in
match levs with
[ [] ->
fun levn ->
parser bp
[: (act, loc) = add_loc c bp p2; strm :] ->
let a = Action.getf act loc in
entry.econtinue levn loc a c strm
| _ ->
fun levn strm ->
if levn > clevn then p1 levn strm
else
match strm with parser bp
[ [: (act, loc) = add_loc c bp p2 :] ->
let a = Action.getf act loc in
entry.econtinue levn loc a c strm
| [: act = p1 levn :] -> act ] ] ] ]
;
value start_parser_of_entry entry =
debug gram "start_parser_of_entry: @[<2>%a@]@." Print.entry entry in
match entry.edesc with
[ Dlevels [] -> Tools.empty_entry entry.ename
| Dlevels elev -> fun levn c ->
start_parser_of_levels entry 0 c elev levn
| Dparser p -> fun _ _ strm -> p strm ]
;
value rec continue_parser_of_levels entry clevn c =
fun
[ [] -> fun _ _ _ -> parser []
| [lev :: levs] ->
let p1 = continue_parser_of_levels entry (succ clevn) c levs in
match lev.lsuffix with
[ DeadEnd -> p1
| tree ->
let alevn =
match lev.assoc with
[ LeftA | NonA -> succ clevn
| RightA -> clevn ]
in
let p2 = parser_of_tree entry (succ clevn) alevn c tree in
fun levn bp a strm ->
if levn > clevn then p1 levn bp a strm
else
match strm with parser bp
[ [: act = p1 levn bp a :] -> act
| [: (act, loc) = add_loc c bp p2 :] ->
let a = Action.getf2 act a loc in
entry.econtinue levn loc a c strm ] ] ]
;
value continue_parser_of_entry entry =
debug gram "continue_parser_of_entry: @[<2>%a@]@." Print.entry entry in
match entry.edesc with
[ Dlevels elev ->
let p = continue_parser_of_levels entry 0 in
fun levn bp a c ->
parser
[ [: a = p c elev levn bp a :] -> a
| [: :] -> a ]
| Dparser _ -> fun _ _ _ _ -> parser [] ]
;
end;