diff options
Diffstat (limited to 'gramlib')
| -rw-r--r-- | gramlib/LICENSE | 29 | ||||
| -rw-r--r-- | gramlib/dune | 4 | ||||
| -rw-r--r-- | gramlib/gramext.ml | 12 | ||||
| -rw-r--r-- | gramlib/gramext.mli | 12 | ||||
| -rw-r--r-- | gramlib/gramlib.mllib | 4 | ||||
| -rw-r--r-- | gramlib/grammar.ml | 1595 | ||||
| -rw-r--r-- | gramlib/grammar.mli | 93 | ||||
| -rw-r--r-- | gramlib/plexing.ml | 18 | ||||
| -rw-r--r-- | gramlib/plexing.mli | 28 | ||||
| -rw-r--r-- | gramlib/ploc.ml | 25 | ||||
| -rw-r--r-- | gramlib/ploc.mli | 37 |
11 files changed, 1857 insertions, 0 deletions
diff --git a/gramlib/LICENSE b/gramlib/LICENSE new file mode 100644 index 0000000000..b696affde7 --- /dev/null +++ b/gramlib/LICENSE @@ -0,0 +1,29 @@ +gramlib was derived from Daniel de Rauglaudre's camlp5 +(https://github.com/camlp5/camlp5) whose licence follows: + +* Copyright (c) 2007-2017, INRIA (Institut National de Recherches en +* Informatique et Automatique). All rights reserved. +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of INRIA, nor the names of its contributors may be +* used to endorse or promote products derived from this software without +* specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY INRIA AND CONTRIBUTORS ``AS IS'' AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INRIA AND +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. diff --git a/gramlib/dune b/gramlib/dune new file mode 100644 index 0000000000..8ca6aff25a --- /dev/null +++ b/gramlib/dune @@ -0,0 +1,4 @@ +(library + (name gramlib) + (public_name coq.gramlib) + (libraries coq.lib)) diff --git a/gramlib/gramext.ml b/gramlib/gramext.ml new file mode 100644 index 0000000000..c396bbab34 --- /dev/null +++ b/gramlib/gramext.ml @@ -0,0 +1,12 @@ +(* camlp5r *) +(* gramext.ml,v *) +(* Copyright (c) INRIA 2007-2017 *) + +type position = + First + | Last + | Before of string + | After of string + | Level of string + +type g_assoc = NonA | RightA | LeftA diff --git a/gramlib/gramext.mli b/gramlib/gramext.mli new file mode 100644 index 0000000000..f9daf5bf10 --- /dev/null +++ b/gramlib/gramext.mli @@ -0,0 +1,12 @@ +(* camlp5r *) +(* gramext.mli,v *) +(* Copyright (c) INRIA 2007-2017 *) + +type position = + First + | Last + | Before of string + | After of string + | Level of string + +type g_assoc = NonA | RightA | LeftA diff --git a/gramlib/gramlib.mllib b/gramlib/gramlib.mllib new file mode 100644 index 0000000000..4c915b2b05 --- /dev/null +++ b/gramlib/gramlib.mllib @@ -0,0 +1,4 @@ +Ploc +Plexing +Gramext +Grammar diff --git a/gramlib/grammar.ml b/gramlib/grammar.ml new file mode 100644 index 0000000000..c452c7b307 --- /dev/null +++ b/gramlib/grammar.ml @@ -0,0 +1,1595 @@ +(* camlp5r *) +(* grammar.ml,v *) +(* Copyright (c) INRIA 2007-2017 *) + +open Gramext +open Format +open Util + +(* Functorial interface *) + +module type GLexerType = Plexing.Lexer + +module type S = + sig + type te + type 'c pattern + type parsable + val parsable : ?loc:Loc.t -> char Stream.t -> parsable + val tokens : string -> (string option * int) list + module Entry : + sig + type 'a e + val create : string -> 'a e + val parse : 'a e -> parsable -> 'a + val name : 'a e -> string + val of_parser : string -> (te Stream.t -> 'a) -> 'a e + val parse_token_stream : 'a e -> te Stream.t -> 'a + val print : Format.formatter -> 'a e -> unit + end + type ty_norec = TyNoRec + type ty_mayrec = TyMayRec + type ('self, 'trec, 'a) ty_symbol + type ('self, 'trec, 'f, 'r) ty_rule + type 'a ty_rules + type 'a ty_production + val s_nterm : 'a Entry.e -> ('self, ty_norec, 'a) ty_symbol + val s_nterml : 'a Entry.e -> string -> ('self, ty_norec, 'a) ty_symbol + val s_list0 : ('self, 'trec, 'a) ty_symbol -> ('self, 'trec, 'a list) ty_symbol + val s_list0sep : + ('self, 'trec, 'a) ty_symbol -> ('self, ty_norec, 'b) ty_symbol -> bool -> + ('self, 'trec, 'a list) ty_symbol + val s_list1 : ('self, 'trec, 'a) ty_symbol -> ('self, 'trec, 'a list) ty_symbol + val s_list1sep : + ('self, 'trec, 'a) ty_symbol -> ('self, ty_norec, 'b) ty_symbol -> bool -> + ('self, 'trec, 'a list) ty_symbol + val s_opt : ('self, 'trec, 'a) ty_symbol -> ('self, 'trec, 'a option) ty_symbol + val s_self : ('self, ty_mayrec, 'self) ty_symbol + val s_next : ('self, ty_mayrec, 'self) ty_symbol + val s_token : 'c pattern -> ('self, ty_norec, 'c) ty_symbol + val s_rules : warning:(string -> unit) option -> 'a ty_rules list -> ('self, ty_norec, 'a) ty_symbol + val r_stop : ('self, ty_norec, 'r, 'r) ty_rule + val r_next : + ('self, _, 'a, 'r) ty_rule -> ('self, _, 'b) ty_symbol -> + ('self, ty_mayrec, 'b -> 'a, 'r) ty_rule + val r_next_norec : + ('self, ty_norec, 'a, 'r) ty_rule -> ('self, ty_norec, 'b) ty_symbol -> + ('self, ty_norec, 'b -> 'a, 'r) ty_rule + val rules : (_, ty_norec, 'f, Loc.t -> 'a) ty_rule * 'f -> 'a ty_rules + val production : ('a, _, 'f, Loc.t -> 'a) ty_rule * 'f -> 'a ty_production + module Unsafe : + sig + val clear_entry : 'a Entry.e -> unit + end + val safe_extend : warning:(string -> unit) option -> + 'a Entry.e -> Gramext.position option -> + (string option * Gramext.g_assoc option * 'a ty_production list) + list -> + unit + val safe_delete_rule : 'a Entry.e -> ('a, _, 'r, 'f) ty_rule -> unit + end + +(* Implementation *) + +module GMake (L : GLexerType) = +struct + +type te = L.te +type 'c pattern = 'c L.pattern + +type 'a parser_t = L.te Stream.t -> 'a + +type grammar = + { gtokens : (string * string option, int ref) Hashtbl.t } + +let egram = + {gtokens = Hashtbl.create 301 } + +let tokens con = + let list = ref [] in + Hashtbl.iter + (fun (p_con, p_prm) c -> if p_con = con then list := (p_prm, !c) :: !list) + egram.gtokens; + !list + +type ty_norec = TyNoRec +type ty_mayrec = TyMayRec + +type ('a, 'b, 'c) ty_and_rec = +| NoRec2 : (ty_norec, ty_norec, ty_norec) ty_and_rec +| MayRec2 : ('a, 'b, ty_mayrec) ty_and_rec + +type ('a, 'b, 'c, 'd) ty_and_rec3 = +| NoRec3 : (ty_norec, ty_norec, ty_norec, ty_norec) ty_and_rec3 +| MayRec3 : ('a, 'b, 'c, ty_mayrec) ty_and_rec3 + +type 'a ty_entry = { + ename : string; + mutable estart : int -> 'a parser_t; + mutable econtinue : int -> int -> 'a -> 'a parser_t; + mutable edesc : 'a ty_desc; +} + +and 'a ty_desc = +| Dlevels of 'a ty_level list +| Dparser of 'a parser_t + +and 'a ty_level = Level : (_, _, 'a) ty_rec_level -> 'a ty_level + +and ('trecs, 'trecp, 'a) ty_rec_level = { + assoc : g_assoc; + lname : string option; + lsuffix : ('a, 'trecs, 'a -> Loc.t -> 'a) ty_tree; + lprefix : ('a, 'trecp, Loc.t -> 'a) ty_tree; +} + +and ('self, 'trec, 'a) ty_symbol = +| Stoken : 'c pattern -> ('self, ty_norec, 'c) ty_symbol +| Slist1 : ('self, 'trec, 'a) ty_symbol -> ('self, 'trec, 'a list) ty_symbol +| Slist1sep : ('self, 'trec, 'a) ty_symbol * ('self, ty_norec, _) ty_symbol * bool -> ('self, 'trec, 'a list) ty_symbol +| Slist0 : ('self, 'trec, 'a) ty_symbol -> ('self, 'trec, 'a list) ty_symbol +| Slist0sep : ('self, 'trec, 'a) ty_symbol * ('self, ty_norec, _) ty_symbol * bool -> ('self, 'trec, 'a list) ty_symbol +| Sopt : ('self, 'trec, 'a) ty_symbol -> ('self, 'trec, 'a option) ty_symbol +| Sself : ('self, ty_mayrec, 'self) ty_symbol +| Snext : ('self, ty_mayrec, 'self) ty_symbol +| Snterm : 'a ty_entry -> ('self, ty_norec, 'a) ty_symbol +| Snterml : 'a ty_entry * string -> ('self, ty_norec, 'a) ty_symbol +| Stree : ('self, 'trec, Loc.t -> 'a) ty_tree -> ('self, 'trec, 'a) ty_symbol + +and ('self, _, _, 'r) ty_rule = +| TStop : ('self, ty_norec, 'r, 'r) ty_rule +| TNext : ('trr, 'trs, 'tr) ty_and_rec * ('self, 'trr, 'a, 'r) ty_rule * ('self, 'trs, 'b) ty_symbol -> ('self, 'tr, 'b -> 'a, 'r) ty_rule + +and ('self, 'trec, 'a) ty_tree = +| Node : ('trn, 'trs, 'trb, 'tr) ty_and_rec3 * ('self, 'trn, 'trs, 'trb, 'b, 'a) ty_node -> ('self, 'tr, 'a) ty_tree +| LocAct : 'k * 'k list -> ('self, ty_norec, 'k) ty_tree +| DeadEnd : ('self, ty_norec, 'k) ty_tree + +and ('self, 'trec, 'trecs, 'trecb, 'a, 'r) ty_node = { + node : ('self, 'trec, 'a) ty_symbol; + son : ('self, 'trecs, 'a -> 'r) ty_tree; + brother : ('self, 'trecb, 'r) ty_tree; +} + +type 'a ty_rules = +| TRules : (_, ty_norec, 'act, Loc.t -> 'a) ty_rule * 'act -> 'a ty_rules + +type 'a ty_production = +| TProd : ('a, _, 'act, Loc.t -> 'a) ty_rule * 'act -> 'a ty_production + +let rec derive_eps : type s r a. (s, r, a) ty_symbol -> bool = + function + Slist0 _ -> true + | Slist0sep (_, _, _) -> true + | Sopt _ -> true + | Stree t -> tree_derive_eps t + | Slist1 _ -> false + | Slist1sep (_, _, _) -> false + | Snterm _ -> false | Snterml (_, _) -> false + | Snext -> false + | Sself -> false + | Stoken _ -> false +and tree_derive_eps : type s tr a. (s, tr, a) ty_tree -> bool = + function + LocAct (_, _) -> true + | Node (_, {node = s; brother = bro; son = son}) -> + derive_eps s && tree_derive_eps son || tree_derive_eps bro + | DeadEnd -> false + +(** FIXME: find a way to do that type-safely *) +let eq_entry : type a1 a2. a1 ty_entry -> a2 ty_entry -> (a1, a2) eq option = fun e1 e2 -> + if (Obj.magic e1) == (Obj.magic e2) then Some (Obj.magic Refl) + else None + +let rec eq_symbol : type s r1 r2 a1 a2. (s, r1, a1) ty_symbol -> (s, r2, a2) ty_symbol -> (a1, a2) eq option = fun s1 s2 -> + match s1, s2 with + Snterm e1, Snterm e2 -> eq_entry e1 e2 + | Snterml (e1, l1), Snterml (e2, l2) -> + if String.equal l1 l2 then eq_entry e1 e2 else None + | Slist0 s1, Slist0 s2 -> + begin match eq_symbol s1 s2 with None -> None | Some Refl -> Some Refl end + | Slist0sep (s1, sep1, b1), Slist0sep (s2, sep2, b2) -> + if b1 = b2 then match eq_symbol s1 s2 with + | None -> None + | Some Refl -> + match eq_symbol sep1 sep2 with + | None -> None + | Some Refl -> Some Refl + else None + | Slist1 s1, Slist1 s2 -> + begin match eq_symbol s1 s2 with None -> None | Some Refl -> Some Refl end + | Slist1sep (s1, sep1, b1), Slist1sep (s2, sep2, b2) -> + if b1 = b2 then match eq_symbol s1 s2 with + | None -> None + | Some Refl -> + match eq_symbol sep1 sep2 with + | None -> None + | Some Refl -> Some Refl + else None + | Sopt s1, Sopt s2 -> + begin match eq_symbol s1 s2 with None -> None | Some Refl -> Some Refl end + | Stree _, Stree _ -> None + | Sself, Sself -> Some Refl + | Snext, Snext -> Some Refl + | Stoken p1, Stoken p2 -> L.tok_pattern_eq p1 p2 + | _ -> None + +let is_before : type s1 s2 r1 r2 a1 a2. (s1, r1, a1) ty_symbol -> (s2, r2, a2) ty_symbol -> bool = fun s1 s2 -> + match s1, s2 with + | Stoken p1, Stoken p2 -> + snd (L.tok_pattern_strings p1) <> None + && snd (L.tok_pattern_strings p2) = None + | Stoken _, _ -> true + | _ -> false + +(** Ancilliary datatypes *) + +type 'a ty_rec = MayRec : ty_mayrec ty_rec | NoRec : ty_norec ty_rec + +type ('a, 'b, 'c) ty_and_ex = +| NR00 : (ty_mayrec, ty_mayrec, ty_mayrec) ty_and_ex +| NR01 : (ty_mayrec, ty_norec, ty_mayrec) ty_and_ex +| NR10 : (ty_norec, ty_mayrec, ty_mayrec) ty_and_ex +| NR11 : (ty_norec, ty_norec, ty_norec) ty_and_ex + +type ('a, 'b) ty_mayrec_and_ex = +| MayRecNR : ('a, 'b, _) ty_and_ex -> ('a, 'b) ty_mayrec_and_ex + +type ('s, 'a) ty_mayrec_symbol = +| MayRecSymbol : ('s, _, 'a) ty_symbol -> ('s, 'a) ty_mayrec_symbol + +type ('s, 'a) ty_mayrec_tree = +| MayRecTree : ('s, 'tr, 'a) ty_tree -> ('s, 'a) ty_mayrec_tree + +type ('s, 'a, 'r) ty_mayrec_rule = +| MayRecRule : ('s, _, 'a, 'r) ty_rule -> ('s, 'a, 'r) ty_mayrec_rule + +type ('self, 'trec, _) ty_symbols = +| TNil : ('self, ty_norec, unit) ty_symbols +| TCns : ('trh, 'trt, 'tr) ty_and_rec * ('self, 'trh, 'a) ty_symbol * ('self, 'trt, 'b) ty_symbols -> ('self, 'tr, 'a * 'b) ty_symbols + +(** ('i, 'p, 'f, 'r) rel_prod0 ~ + ∃ α₁ ... αₙ. + p ≡ αₙ * ... α₁ * 'i ∧ + f ≡ α₁ -> ... -> αₙ -> 'r +*) +type ('i, _, 'f, _) rel_prod0 = +| Rel0 : ('i, 'i, 'f, 'f) rel_prod0 +| RelS : ('i, 'p, 'f, 'a -> 'r) rel_prod0 -> ('i, 'a * 'p, 'f, 'r) rel_prod0 + +type ('p, 'k, 'r) rel_prod = (unit, 'p, 'k, 'r) rel_prod0 + +type ('s, 'tr, 'i, 'k, 'r) any_symbols = +| AnyS : ('s, 'tr, 'p) ty_symbols * ('i, 'p, 'k, 'r) rel_prod0 -> ('s, 'tr, 'i, 'k, 'r) any_symbols + +type ('s, 'tr, 'k, 'r) ty_belast_rule = +| Belast : ('trr, 'trs, 'tr) ty_and_rec * ('s, 'trr, 'k, 'a -> 'r) ty_rule * ('s, 'trs, 'a) ty_symbol -> ('s, 'tr, 'k, 'r) ty_belast_rule + +(* unfortunately, this is quadratic, but ty_rules aren't too long + * (99% of the time of length less or equal 10 and maximum is 22 + * when compiling Coq and its standard library) *) +let rec get_symbols : type s trec k r. (s, trec, k, r) ty_rule -> (s, trec, unit, k, r) any_symbols = + let rec belast_rule : type s trr trs tr a k r. (trr, trs, tr) ty_and_rec -> (s, trr, k, r) ty_rule -> (s, trs, a) ty_symbol -> (s, tr, a -> k, r) ty_belast_rule = + fun ar r s -> match ar, r with + | NoRec2, TStop -> Belast (NoRec2, TStop, s) + | MayRec2, TStop -> Belast (MayRec2, TStop, s) + | NoRec2, TNext (NoRec2, r, s') -> + let Belast (NoRec2, r, s') = belast_rule NoRec2 r s' in + Belast (NoRec2, TNext (NoRec2, r, s), s') + | MayRec2, TNext (_, r, s') -> + let Belast (_, r, s') = belast_rule MayRec2 r s' in + Belast (MayRec2, TNext (MayRec2, r, s), s') in + function + | TStop -> AnyS (TNil, Rel0) + | TNext (MayRec2, r, s) -> + let Belast (MayRec2, r, s) = belast_rule MayRec2 r s in + let AnyS (r, pf) = get_symbols r in + AnyS (TCns (MayRec2, s, r), RelS pf) + | TNext (NoRec2, r, s) -> + let Belast (NoRec2, r, s) = belast_rule NoRec2 r s in + let AnyS (r, pf) = get_symbols r in + AnyS (TCns (NoRec2, s, r), RelS pf) + +let get_rec_symbols (type s tr p) (s : (s, tr, p) ty_symbols) : tr ty_rec = + match s with TCns (MayRec2, _, _) -> MayRec + | TCns (NoRec2, _, _) -> NoRec | TNil -> NoRec + +let get_rec_tree (type s tr f) (s : (s, tr, f) ty_tree) : tr ty_rec = + match s with Node (MayRec3, _) -> MayRec + | Node (NoRec3, _) -> NoRec | LocAct _ -> NoRec | DeadEnd -> NoRec + +let and_symbols_tree (type s trs trt p f) (s : (s, trs, p) ty_symbols) (t : (s, trt, f) ty_tree) : (trs, trt) ty_mayrec_and_ex = + match get_rec_symbols s, get_rec_tree t with + | MayRec, MayRec -> MayRecNR NR00 | MayRec, NoRec -> MayRecNR NR01 + | NoRec, MayRec -> MayRecNR NR10 | NoRec, NoRec -> MayRecNR NR11 + +let and_and_tree (type s tr' trt tr trn trs trb f) (ar : (tr', trt, tr) ty_and_rec) (arn : (trn, trs, trb, trt) ty_and_rec3) (t : (s, trb, f) ty_tree) : (tr', trb, tr) ty_and_rec = + match ar, arn, get_rec_tree t with + | MayRec2, _, MayRec -> MayRec2 | MayRec2, _, NoRec -> MayRec2 + | NoRec2, NoRec3, NoRec -> NoRec2 + +let insert_tree (type s trs trt tr p k a) ~warning entry_name (ar : (trs, trt, tr) ty_and_ex) (gsymbols : (s, trs, p) ty_symbols) (pf : (p, k, a) rel_prod) (action : k) (tree : (s, trt, a) ty_tree) : (s, tr, a) ty_tree = + let rec insert : type trs trt tr p f k. (trs, trt, tr) ty_and_ex -> (s, trs, p) ty_symbols -> (p, k, f) rel_prod -> (s, trt, f) ty_tree -> k -> (s, tr, f) ty_tree = + fun ar symbols pf tree action -> + match symbols, pf with + TCns (ars, s, sl), RelS pf -> insert_in_tree ar ars s sl pf tree action + | TNil, Rel0 -> + let node (type tb) ({node = s; son = son; brother = bro} : (_, _, _, tb, _, _) ty_node) = + let ar : (ty_norec, tb, tb) ty_and_ex = + match get_rec_tree bro with MayRec -> NR10 | NoRec -> NR11 in + {node = s; son = son; brother = insert ar TNil Rel0 bro action} in + match ar, tree with + | NR10, Node (_, n) -> Node (MayRec3, node n) + | NR11, Node (NoRec3, n) -> Node (NoRec3, node n) + | NR11, LocAct (old_action, action_list) -> + begin match warning with + | None -> () + | Some warn_fn -> + let msg = + "<W> Grammar extension: " ^ + (if entry_name = "" then "" else "in ["^entry_name^"%s], ") ^ + "some rule has been masked" in + warn_fn msg + end; + LocAct (action, old_action :: action_list) + | NR11, DeadEnd -> LocAct (action, []) + and insert_in_tree : type trs trs' trs'' trt tr a p f k. (trs'', trt, tr) ty_and_ex -> (trs, trs', trs'') ty_and_rec -> (s, trs, a) ty_symbol -> (s, trs', p) ty_symbols -> (p, k, a -> f) rel_prod -> (s, trt, f) ty_tree -> k -> (s, tr, f) ty_tree = + fun ar ars s sl pf tree action -> + let ar : (trs'', trt, tr) ty_and_rec = match ar with NR11 -> NoRec2 + | NR00 -> MayRec2 | NR01 -> MayRec2 | NR10 -> MayRec2 in + match try_insert ar ars s sl pf tree action with + Some t -> t + | None -> + let node ar = + {node = s; son = insert ar sl pf DeadEnd action; brother = tree} in + match ar, ars, get_rec_symbols sl with + | MayRec2, MayRec2, MayRec -> Node (MayRec3, node NR01) + | MayRec2, _, NoRec -> Node (MayRec3, node NR11) + | NoRec2, NoRec2, NoRec -> Node (NoRec3, node NR11) + and try_insert : type trs trs' trs'' trt tr a p f k. (trs'', trt, tr) ty_and_rec -> (trs, trs', trs'') ty_and_rec -> (s, trs, a) ty_symbol -> (s, trs', p) ty_symbols -> (p, k, a -> f) rel_prod -> (s, trt, f) ty_tree -> k -> (s, tr, f) ty_tree option = + fun ar ars s sl pf tree action -> + match tree with + Node (arn, {node = s1; son = son; brother = bro}) -> + begin match eq_symbol s s1 with + | Some Refl -> + let MayRecNR arss = and_symbols_tree sl son in + let son = insert arss sl pf son action in + let node = {node = s1; son = son; brother = bro} in + begin match ar, ars, arn, arss with + | MayRec2, _, _, _ -> Some (Node (MayRec3, node)) + | NoRec2, NoRec2, NoRec3, NR11 -> Some (Node (NoRec3, node)) end + | None -> + let ar' = and_and_tree ar arn bro in + if is_before s1 s || derive_eps s && not (derive_eps s1) then + let bro = + match try_insert ar' ars s sl pf bro action with + Some bro -> bro + | None -> + let MayRecNR arss = and_symbols_tree sl DeadEnd in + let son = insert arss sl pf DeadEnd action in + let node = {node = s; son = son; brother = bro} in + match ar, ars, arn, arss with + | MayRec2, _, _, _ -> Node (MayRec3, node) + | NoRec2, NoRec2, NoRec3, NR11 -> Node (NoRec3, node) + in + let node = {node = s1; son = son; brother = bro} in + match ar, arn with + | MayRec2, _ -> Some (Node (MayRec3, node)) + | NoRec2, NoRec3 -> Some (Node (NoRec3, node)) + else + match try_insert ar' ars s sl pf bro action with + Some bro -> + let node = {node = s1; son = son; brother = bro} in + begin match ar, arn with + | MayRec2, _ -> Some (Node (MayRec3, node)) + | NoRec2, NoRec3 -> Some (Node (NoRec3, node)) end + | None -> None + end + | LocAct (_, _) -> None | DeadEnd -> None + in + insert ar gsymbols pf tree action + +let insert_tree_norec (type s p k a) ~warning entry_name (gsymbols : (s, ty_norec, p) ty_symbols) (pf : (p, k, a) rel_prod) (action : k) (tree : (s, ty_norec, a) ty_tree) : (s, ty_norec, a) ty_tree = + insert_tree ~warning entry_name NR11 gsymbols pf action tree + +let insert_tree (type s trs trt p k a) ~warning entry_name (gsymbols : (s, trs, p) ty_symbols) (pf : (p, k, a) rel_prod) (action : k) (tree : (s, trt, a) ty_tree) : (s, a) ty_mayrec_tree = + let MayRecNR ar = and_symbols_tree gsymbols tree in + MayRecTree (insert_tree ~warning entry_name ar gsymbols pf action tree) + +let srules (type self a) ~warning (rl : a ty_rules list) : (self, ty_norec, a) ty_symbol = + let rec retype_tree : type s a. (s, ty_norec, a) ty_tree -> (self, ty_norec, a) ty_tree = + function + | Node (NoRec3, {node = s; son = son; brother = bro}) -> + Node (NoRec3, {node = retype_symbol s; son = retype_tree son; brother = retype_tree bro}) + | LocAct (k, kl) -> LocAct (k, kl) + | DeadEnd -> DeadEnd + and retype_symbol : type s a. (s, ty_norec, a) ty_symbol -> (self, ty_norec, a) ty_symbol = + function + | Stoken p -> Stoken p + | Slist1 s -> Slist1 (retype_symbol s) + | Slist1sep (s, sep, b) -> Slist1sep (retype_symbol s, retype_symbol sep, b) + | Slist0 s -> Slist0 (retype_symbol s) + | Slist0sep (s, sep, b) -> Slist0sep (retype_symbol s, retype_symbol sep, b) + | Sopt s -> Sopt (retype_symbol s) + | Snterm e -> Snterm e + | Snterml (e, l) -> Snterml (e, l) + | Stree t -> Stree (retype_tree t) in + let rec retype_rule : type s k r. (s, ty_norec, k, r) ty_rule -> (self, ty_norec, k, r) ty_rule = + function + | TStop -> TStop + | TNext (NoRec2, r, s) -> TNext (NoRec2, retype_rule r, retype_symbol s) in + let t = + List.fold_left + (fun tree (TRules (symbols, action)) -> + let symbols = retype_rule symbols in + let AnyS (symbols, pf) = get_symbols symbols in + insert_tree_norec ~warning "" symbols pf action tree) + DeadEnd rl + in + Stree t + +let is_level_labelled n (Level lev) = + match lev.lname with + Some n1 -> n = n1 + | None -> false + +let insert_level (type s tr p k) ~warning entry_name (symbols : (s, tr, p) ty_symbols) (pf : (p, k, Loc.t -> s) rel_prod) (action : k) (slev : s ty_level) : s ty_level = + match symbols with + | TCns (_, Sself, symbols) -> + let Level slev = slev in + let RelS pf = pf in + let MayRecTree lsuffix = insert_tree ~warning entry_name symbols pf action slev.lsuffix in + Level + {assoc = slev.assoc; lname = slev.lname; + lsuffix = lsuffix; + lprefix = slev.lprefix} + | _ -> + let Level slev = slev in + let MayRecTree lprefix = insert_tree ~warning entry_name symbols pf action slev.lprefix in + Level + {assoc = slev.assoc; lname = slev.lname; lsuffix = slev.lsuffix; + lprefix = lprefix} + +let empty_lev lname assoc = + let assoc = + match assoc with + Some a -> a + | None -> LeftA + in + Level + {assoc = assoc; lname = lname; lsuffix = DeadEnd; lprefix = DeadEnd} + +let change_lev ~warning (Level lev) n lname assoc = + let a = + match assoc with + None -> lev.assoc + | Some a -> + if a <> lev.assoc then + begin + match warning with + | None -> () + | Some warn_fn -> + warn_fn ("<W> Changing associativity of level \""^n^"\"") + end; + a + in + begin match lname with + Some n -> + if lname <> lev.lname then + begin match warning with + | None -> () + | Some warn_fn -> + warn_fn ("<W> Level label \""^n^"\" ignored") + end; + | None -> () + end; + Level + {assoc = a; lname = lev.lname; lsuffix = lev.lsuffix; lprefix = lev.lprefix} + +let get_level ~warning entry position levs = + match position with + Some First -> [], empty_lev, levs + | Some Last -> levs, empty_lev, [] + | Some (Level n) -> + let rec get = + function + [] -> + eprintf "No level labelled \"%s\" in entry \"%s\"\n" n + entry.ename; + flush stderr; + failwith "Grammar.extend" + | lev :: levs -> + if is_level_labelled n lev then [], change_lev ~warning lev n, levs + else + let (levs1, rlev, levs2) = get levs in lev :: levs1, rlev, levs2 + in + get levs + | Some (Before n) -> + let rec get = + function + [] -> + eprintf "No level labelled \"%s\" in entry \"%s\"\n" n + entry.ename; + flush stderr; + failwith "Grammar.extend" + | lev :: levs -> + if is_level_labelled n lev then [], empty_lev, lev :: levs + else + let (levs1, rlev, levs2) = get levs in lev :: levs1, rlev, levs2 + in + get levs + | Some (After n) -> + let rec get = + function + [] -> + eprintf "No level labelled \"%s\" in entry \"%s\"\n" n + entry.ename; + flush stderr; + failwith "Grammar.extend" + | lev :: levs -> + if is_level_labelled n lev then [lev], empty_lev, levs + else + let (levs1, rlev, levs2) = get levs in lev :: levs1, rlev, levs2 + in + get levs + | None -> + match levs with + lev :: levs -> [], change_lev ~warning lev "<top>", levs + | [] -> [], empty_lev, [] + +let change_to_self0 (type s) (type trec) (type a) (entry : s ty_entry) : (s, trec, a) ty_symbol -> (s, a) ty_mayrec_symbol = + function + | Snterm e -> + begin match eq_entry e entry with + | None -> MayRecSymbol (Snterm e) + | Some Refl -> MayRecSymbol (Sself) + end + | x -> MayRecSymbol x + +let rec change_to_self : type s trec a r. s ty_entry -> (s, trec, a, r) ty_rule -> (s, a, r) ty_mayrec_rule = fun e r -> match r with +| TStop -> MayRecRule TStop +| TNext (_, r, t) -> + let MayRecRule r = change_to_self e r in + let MayRecSymbol t = change_to_self0 e t in + MayRecRule (TNext (MayRec2, r, t)) + +let insert_tokens gram symbols = + let rec insert : type s trec a. (s, trec, a) ty_symbol -> unit = + function + | Slist0 s -> insert s + | Slist1 s -> insert s + | Slist0sep (s, t, _) -> insert s; insert t + | Slist1sep (s, t, _) -> insert s; insert t + | Sopt s -> insert s + | Stree t -> tinsert t + | Stoken tok -> + L.tok_using tok; + let r = + let tok = L.tok_pattern_strings tok in + try Hashtbl.find gram.gtokens tok with + Not_found -> let r = ref 0 in Hashtbl.add gram.gtokens tok r; r + in + incr r + | Snterm _ -> () | Snterml (_, _) -> () + | Snext -> () + | Sself -> () + and tinsert : type s tr a. (s, tr, a) ty_tree -> unit = + function + Node (_, {node = s; brother = bro; son = son}) -> + insert s; tinsert bro; tinsert son + | LocAct (_, _) -> () | DeadEnd -> () + and linsert : type s tr p. (s, tr, p) ty_symbols -> unit = function + | TNil -> () + | TCns (_, s, r) -> insert s; linsert r + in + linsert symbols + +let levels_of_rules ~warning entry position rules = + let elev = + match entry.edesc with + Dlevels elev -> elev + | Dparser _ -> + eprintf "Error: entry not extensible: \"%s\"\n" entry.ename; + flush stderr; + failwith "Grammar.extend" + in + match rules with + | [] -> elev + | _ -> + let (levs1, make_lev, levs2) = get_level ~warning entry position elev in + let (levs, _) = + List.fold_left + (fun (levs, make_lev) (lname, assoc, level) -> + let lev = make_lev lname assoc in + let lev = + List.fold_left + (fun lev (TProd (symbols, action)) -> + let MayRecRule symbols = change_to_self entry symbols in + let AnyS (symbols, pf) = get_symbols symbols in + insert_tokens egram symbols; + insert_level ~warning entry.ename symbols pf action lev) + lev level + in + lev :: levs, empty_lev) + ([], make_lev) rules + in + levs1 @ List.rev levs @ levs2 + +let logically_eq_symbols entry = + let rec eq_symbols : type s1 s2 trec1 trec2 a1 a2. (s1, trec1, a1) ty_symbol -> (s2, trec2, a2) ty_symbol -> bool = fun s1 s2 -> + match s1, s2 with + Snterm e1, Snterm e2 -> e1.ename = e2.ename + | Snterm e1, Sself -> e1.ename = entry.ename + | Sself, Snterm e2 -> entry.ename = e2.ename + | Snterml (e1, l1), Snterml (e2, l2) -> e1.ename = e2.ename && l1 = l2 + | Slist0 s1, Slist0 s2 -> eq_symbols s1 s2 + | Slist0sep (s1, sep1, b1), Slist0sep (s2, sep2, b2) -> + eq_symbols s1 s2 && eq_symbols sep1 sep2 && b1 = b2 + | Slist1 s1, Slist1 s2 -> eq_symbols s1 s2 + | Slist1sep (s1, sep1, b1), Slist1sep (s2, sep2, b2) -> + eq_symbols s1 s2 && eq_symbols sep1 sep2 && b1 = b2 + | Sopt s1, Sopt s2 -> eq_symbols s1 s2 + | Stree t1, Stree t2 -> eq_trees t1 t2 + | Stoken p1, Stoken p2 -> L.tok_pattern_eq p1 p2 <> None + | Sself, Sself -> true + | Snext, Snext -> true + | _ -> false + and eq_trees : type s1 s2 tr1 tr2 a1 a2. (s1, tr1, a1) ty_tree -> (s2, tr2, a2) ty_tree -> bool = fun t1 t2 -> + match t1, t2 with + Node (_, n1), Node (_, n2) -> + eq_symbols n1.node n2.node && eq_trees n1.son n2.son && + eq_trees n1.brother n2.brother + | LocAct _, LocAct _ -> true + | LocAct _, DeadEnd -> true + | DeadEnd, LocAct _ -> true + | DeadEnd, DeadEnd -> true + | _ -> false + in + eq_symbols + +(* [delete_rule_in_tree] returns + [Some (dsl, t)] if success + [dsl] = + Some (list of deleted nodes) if branch deleted + None if action replaced by previous version of action + [t] = remaining tree + [None] if failure *) + +type 's ex_symbols = +| ExS : ('s, 'tr, 'p) ty_symbols -> 's ex_symbols + +let delete_rule_in_tree entry = + let rec delete_in_tree : + type s tr tr' p r. (s, tr, p) ty_symbols -> (s, tr', r) ty_tree -> (s ex_symbols option * (s, r) ty_mayrec_tree) option = + fun symbols tree -> + match symbols, tree with + | TCns (_, s, sl), Node (_, n) -> + if logically_eq_symbols entry s n.node then delete_son sl n + else + begin match delete_in_tree symbols n.brother with + Some (dsl, MayRecTree t) -> + Some (dsl, MayRecTree (Node (MayRec3, {node = n.node; son = n.son; brother = t}))) + | None -> None + end + | TCns (_, s, sl), _ -> None + | TNil, Node (_, n) -> + begin match delete_in_tree TNil n.brother with + Some (dsl, MayRecTree t) -> + Some (dsl, MayRecTree (Node (MayRec3, {node = n.node; son = n.son; brother = t}))) + | None -> None + end + | TNil, DeadEnd -> None + | TNil, LocAct (_, []) -> Some (Some (ExS TNil), MayRecTree DeadEnd) + | TNil, LocAct (_, action :: list) -> Some (None, MayRecTree (LocAct (action, list))) + and delete_son : + type s p tr trn trs trb a r. (s, tr, p) ty_symbols -> (s, trn, trs, trb, a, r) ty_node -> (s ex_symbols option * (s, r) ty_mayrec_tree) option = + fun sl n -> + match delete_in_tree sl n.son with + Some (Some (ExS dsl), MayRecTree DeadEnd) -> Some (Some (ExS (TCns (MayRec2, n.node, dsl))), MayRecTree n.brother) + | Some (Some (ExS dsl), MayRecTree t) -> + let t = Node (MayRec3, {node = n.node; son = t; brother = n.brother}) in + Some (Some (ExS (TCns (MayRec2, n.node, dsl))), MayRecTree t) + | Some (None, MayRecTree t) -> + let t = Node (MayRec3, {node = n.node; son = t; brother = n.brother}) in + Some (None, MayRecTree t) + | None -> None + in + delete_in_tree + +let rec decr_keyw_use : type s tr a. _ -> (s, tr, a) ty_symbol -> unit = fun gram -> + function + Stoken tok -> + let tok' = L.tok_pattern_strings tok in + let r = Hashtbl.find gram.gtokens tok' in + decr r; + if !r == 0 then + begin + Hashtbl.remove gram.gtokens tok'; + L.tok_removing tok + end + | Slist0 s -> decr_keyw_use gram s + | Slist1 s -> decr_keyw_use gram s + | Slist0sep (s1, s2, _) -> decr_keyw_use gram s1; decr_keyw_use gram s2 + | Slist1sep (s1, s2, _) -> decr_keyw_use gram s1; decr_keyw_use gram s2 + | Sopt s -> decr_keyw_use gram s + | Stree t -> decr_keyw_use_in_tree gram t + | Sself -> () + | Snext -> () + | Snterm _ -> () | Snterml (_, _) -> () +and decr_keyw_use_in_tree : type s tr a. _ -> (s, tr, a) ty_tree -> unit = fun gram -> + function + DeadEnd -> () | LocAct (_, _) -> () + | Node (_, n) -> + decr_keyw_use gram n.node; + decr_keyw_use_in_tree gram n.son; + decr_keyw_use_in_tree gram n.brother +and decr_keyw_use_in_list : type s tr p. _ -> (s, tr, p) ty_symbols -> unit = fun gram -> + function + | TNil -> () + | TCns (_, s, l) -> decr_keyw_use gram s; decr_keyw_use_in_list gram l + +let rec delete_rule_in_suffix entry symbols = + function + Level lev :: levs -> + begin match delete_rule_in_tree entry symbols lev.lsuffix with + Some (dsl, MayRecTree t) -> + begin match dsl with + Some (ExS dsl) -> decr_keyw_use_in_list egram dsl + | None -> () + end; + begin match t, lev.lprefix with + DeadEnd, DeadEnd -> levs + | _ -> + let lev = + {assoc = lev.assoc; lname = lev.lname; lsuffix = t; + lprefix = lev.lprefix} + in + Level lev :: levs + end + | None -> + let levs = delete_rule_in_suffix entry symbols levs in + Level lev :: levs + end + | [] -> raise Not_found + +let rec delete_rule_in_prefix entry symbols = + function + Level lev :: levs -> + begin match delete_rule_in_tree entry symbols lev.lprefix with + Some (dsl, MayRecTree t) -> + begin match dsl with + Some (ExS dsl) -> decr_keyw_use_in_list egram dsl + | None -> () + end; + begin match t, lev.lsuffix with + DeadEnd, DeadEnd -> levs + | _ -> + let lev = + {assoc = lev.assoc; lname = lev.lname; lsuffix = lev.lsuffix; + lprefix = t} + in + Level lev :: levs + end + | None -> + let levs = delete_rule_in_prefix entry symbols levs in + Level lev :: levs + end + | [] -> raise Not_found + +let delete_rule_in_level_list (type s tr p) (entry : s ty_entry) (symbols : (s, tr, p) ty_symbols) levs = + match symbols with + TCns (_, Sself, symbols) -> delete_rule_in_suffix entry symbols levs + | TCns (_, Snterm e, symbols') -> + begin match eq_entry e entry with + | None -> delete_rule_in_prefix entry symbols levs + | Some Refl -> + delete_rule_in_suffix entry symbols' levs + end + | _ -> delete_rule_in_prefix entry symbols levs + +let rec flatten_tree : type s tr a. (s, tr, a) ty_tree -> s ex_symbols list = + function + DeadEnd -> [] + | LocAct (_, _) -> [ExS TNil] + | Node (_, {node = n; brother = b; son = s}) -> + List.map (fun (ExS l) -> ExS (TCns (MayRec2, n, l))) (flatten_tree s) @ flatten_tree b + +let utf8_print = ref true + +let utf8_string_escaped s = + let b = Buffer.create (String.length s) in + let rec loop i = + if i = String.length s then Buffer.contents b + else + begin + begin match s.[i] with + '"' -> Buffer.add_string b "\\\"" + | '\\' -> Buffer.add_string b "\\\\" + | '\n' -> Buffer.add_string b "\\n" + | '\t' -> Buffer.add_string b "\\t" + | '\r' -> Buffer.add_string b "\\r" + | '\b' -> Buffer.add_string b "\\b" + | c -> Buffer.add_char b c + end; + loop (i + 1) + end + in + loop 0 + +let string_escaped s = + if !utf8_print then utf8_string_escaped s else String.escaped s + +let print_str ppf s = fprintf ppf "\"%s\"" (string_escaped s) + +let rec print_symbol : type s tr r. formatter -> (s, tr, r) ty_symbol -> unit = + fun ppf -> + function + | Slist0 s -> fprintf ppf "LIST0 %a" print_symbol1 s + | Slist0sep (s, t, osep) -> + fprintf ppf "LIST0 %a SEP %a%s" print_symbol1 s print_symbol1 t + (if osep then " OPT_SEP" else "") + | Slist1 s -> fprintf ppf "LIST1 %a" print_symbol1 s + | Slist1sep (s, t, osep) -> + fprintf ppf "LIST1 %a SEP %a%s" print_symbol1 s print_symbol1 t + (if osep then " OPT_SEP" else "") + | Sopt s -> fprintf ppf "OPT %a" print_symbol1 s + | Stoken p when L.tok_pattern_strings p <> ("", None) -> + begin match L.tok_pattern_strings p with + | con, Some prm -> fprintf ppf "%s@ %a" con print_str prm + | con, None -> fprintf ppf "%s" con end + | Snterml (e, l) -> + fprintf ppf "%s%s@ LEVEL@ %a" e.ename "" + print_str l + | s -> print_symbol1 ppf s +and print_symbol1 : type s tr r. formatter -> (s, tr, r) ty_symbol -> unit = + fun ppf -> + function + | Snterm e -> fprintf ppf "%s%s" e.ename "" + | Sself -> pp_print_string ppf "SELF" + | Snext -> pp_print_string ppf "NEXT" + | Stoken p -> + begin match L.tok_pattern_strings p with + | "", Some s -> print_str ppf s + | con, None -> pp_print_string ppf con + | con, Some prm -> fprintf ppf "(%s@ %a)" con print_str prm end + | Stree t -> print_level ppf pp_print_space (flatten_tree t) + | s -> + fprintf ppf "(%a)" print_symbol s +and print_rule : type s tr p. formatter -> (s, tr, p) ty_symbols -> unit = + fun ppf symbols -> + fprintf ppf "@[<hov 0>"; + let rec fold : type s tr p. _ -> (s, tr, p) ty_symbols -> unit = + fun sep symbols -> + match symbols with + | TNil -> () + | TCns (_, symbol, symbols) -> + fprintf ppf "%t%a" sep print_symbol symbol; + fold (fun ppf -> fprintf ppf ";@ ") symbols + in + let () = fold (fun ppf -> ()) symbols in + fprintf ppf "@]" +and print_level : type s. _ -> _ -> s ex_symbols list -> _ = + fun ppf pp_print_space rules -> + fprintf ppf "@[<hov 0>[ "; + let _ = + List.fold_left + (fun sep (ExS rule) -> + fprintf ppf "%t%a" sep print_rule rule; + fun ppf -> fprintf ppf "%a| " pp_print_space ()) + (fun ppf -> ()) rules + in + fprintf ppf " ]@]" + +let print_levels ppf elev = + let _ = + List.fold_left + (fun sep (Level lev) -> + let rules = + List.map (fun (ExS t) -> ExS (TCns (MayRec2, Sself, t))) (flatten_tree lev.lsuffix) @ + flatten_tree lev.lprefix + in + fprintf ppf "%t@[<hov 2>" sep; + begin match lev.lname with + Some n -> fprintf ppf "%a@;<1 2>" print_str n + | None -> () + end; + begin match lev.assoc with + LeftA -> fprintf ppf "LEFTA" + | RightA -> fprintf ppf "RIGHTA" + | NonA -> fprintf ppf "NONA" + end; + fprintf ppf "@]@;<1 2>"; + print_level ppf pp_force_newline rules; + fun ppf -> fprintf ppf "@,| ") + (fun ppf -> ()) elev + in + () + +let print_entry ppf e = + fprintf ppf "@[<v 0>[ "; + begin match e.edesc with + Dlevels elev -> print_levels ppf elev + | Dparser _ -> fprintf ppf "<parser>" + end; + fprintf ppf " ]@]" + +let floc = ref (fun _ -> failwith "internal error when computing location") + +let loc_of_token_interval bp ep = + if bp == ep then + if bp == 0 then Ploc.dummy else Ploc.after (!floc (bp - 1)) 0 1 + else + let loc1 = !floc bp in let loc2 = !floc (pred ep) in Loc.merge loc1 loc2 + +let name_of_symbol : type s tr a. s ty_entry -> (s, tr, a) ty_symbol -> string = + fun entry -> + function + Snterm e -> "[" ^ e.ename ^ "]" + | Snterml (e, l) -> "[" ^ e.ename ^ " level " ^ l ^ "]" + | Sself -> "[" ^ entry.ename ^ "]" + | Snext -> "[" ^ entry.ename ^ "]" + | Stoken tok -> L.tok_text tok + | _ -> "???" + +type ('r, 'f) tok_list = +| TokNil : ('f, 'f) tok_list +| TokCns : 'a pattern * ('r, 'f) tok_list -> ('a -> 'r, 'f) tok_list + +type ('s, 'f) tok_tree = TokTree : 'a pattern * ('s, _, 'a -> 'r) ty_tree * ('r, 'f) tok_list -> ('s, 'f) tok_tree + +let rec tok_list_length : type a b. (a, b) tok_list -> int = + function + | TokNil -> 0 + | TokCns (_, t) -> 1 + tok_list_length t + +let rec get_token_list : type s tr a r f. + s ty_entry -> a pattern -> (r, f) tok_list -> (s, tr, a -> r) ty_tree -> (s, f) tok_tree option = + fun entry last_tok rev_tokl tree -> + match tree with + Node (_, {node = Stoken tok; son = son; brother = DeadEnd}) -> + get_token_list entry tok (TokCns (last_tok, rev_tokl)) son + | _ -> + match rev_tokl with + | TokNil -> None + | _ -> Some (TokTree (last_tok, tree, rev_tokl)) + +let rec name_of_symbol_failed : type s tr a. s ty_entry -> (s, tr, a) ty_symbol -> _ = + fun entry -> + function + | Slist0 s -> name_of_symbol_failed entry s + | Slist0sep (s, _, _) -> name_of_symbol_failed entry s + | Slist1 s -> name_of_symbol_failed entry s + | Slist1sep (s, _, _) -> name_of_symbol_failed entry s + | Sopt s -> name_of_symbol_failed entry s + | Stree t -> name_of_tree_failed entry t + | s -> name_of_symbol entry s +and name_of_tree_failed : type s tr a. s ty_entry -> (s, tr, a) ty_tree -> _ = + fun entry -> + function + Node (_, {node = s; brother = bro; son = son}) -> + let tokl = + match s with + Stoken tok -> get_token_list entry tok TokNil son + | _ -> None + in + begin match tokl with + None -> + let txt = name_of_symbol_failed entry s in + let txt = + match s, son with + Sopt _, Node _ -> txt ^ " or " ^ name_of_tree_failed entry son + | _ -> txt + in + let txt = + match bro with + DeadEnd -> txt | LocAct (_, _) -> txt + | Node _ -> txt ^ " or " ^ name_of_tree_failed entry bro + in + txt + | Some (TokTree (last_tok, _, rev_tokl)) -> + let rec build_str : type a b. string -> (a, b) tok_list -> string = + fun s -> function + | TokNil -> s + | TokCns (tok, t) -> build_str (L.tok_text tok ^ " " ^ s) t in + build_str (L.tok_text last_tok) rev_tokl + end + | DeadEnd -> "???" | LocAct (_, _) -> "???" + +let tree_failed (type s tr a) (entry : s ty_entry) (prev_symb_result : a) (prev_symb : (s, tr, a) ty_symbol) tree = + let txt = name_of_tree_failed entry tree in + let txt = + match prev_symb with + Slist0 s -> + let txt1 = name_of_symbol_failed entry s in + txt1 ^ " or " ^ txt ^ " expected" + | Slist1 s -> + let txt1 = name_of_symbol_failed entry s in + txt1 ^ " or " ^ txt ^ " expected" + | Slist0sep (s, sep, _) -> + begin match prev_symb_result with + [] -> + let txt1 = name_of_symbol_failed entry s in + txt1 ^ " or " ^ txt ^ " expected" + | _ -> + let txt1 = name_of_symbol_failed entry sep in + txt1 ^ " or " ^ txt ^ " expected" + end + | Slist1sep (s, sep, _) -> + begin match prev_symb_result with + [] -> + let txt1 = name_of_symbol_failed entry s in + txt1 ^ " or " ^ txt ^ " expected" + | _ -> + let txt1 = name_of_symbol_failed entry sep in + txt1 ^ " or " ^ txt ^ " expected" + end + | Sopt _ -> txt ^ " expected" + | Stree _ -> txt ^ " expected" + | _ -> txt ^ " expected after " ^ name_of_symbol_failed entry prev_symb + in + txt ^ " (in [" ^ entry.ename ^ "])" + +let symb_failed entry prev_symb_result prev_symb symb = + let tree = Node (MayRec3, {node = symb; brother = DeadEnd; son = DeadEnd}) in + tree_failed entry prev_symb_result prev_symb tree + +let level_number entry lab = + let rec lookup levn = + function + [] -> failwith ("unknown level " ^ lab) + | lev :: levs -> + if 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 + +let rec top_symb : type s tr a. s ty_entry -> (s, tr, a) ty_symbol -> (s, ty_norec, a) ty_symbol = + fun entry -> + function + Sself -> Snterm entry + | Snext -> Snterm entry + | Snterml (e, _) -> Snterm e + | Slist1sep (s, sep, b) -> Slist1sep (top_symb entry s, sep, b) + | _ -> raise Stream.Failure + +let entry_of_symb : type s tr a. s ty_entry -> (s, tr, a) ty_symbol -> a ty_entry = + fun entry -> + function + Sself -> entry + | Snext -> entry + | Snterm e -> e + | Snterml (e, _) -> e + | _ -> raise Stream.Failure + +let top_tree : type s tr a. s ty_entry -> (s, tr, a) ty_tree -> (s, tr, a) ty_tree = + fun entry -> + function + Node (MayRec3, {node = s; brother = bro; son = son}) -> + Node (MayRec3, {node = top_symb entry s; brother = bro; son = son}) + | Node (NoRec3, {node = s; brother = bro; son = son}) -> + Node (NoRec3, {node = top_symb entry s; brother = bro; son = son}) + | LocAct (_, _) -> raise Stream.Failure | DeadEnd -> raise Stream.Failure + +let skip_if_empty bp p strm = + if Stream.count strm == bp then fun a -> p strm + else raise Stream.Failure + +let continue entry bp a s son p1 (strm__ : _ Stream.t) = + let a = (entry_of_symb entry s).econtinue 0 bp a strm__ in + let act = + try p1 strm__ with + Stream.Failure -> raise (Stream.Error (tree_failed entry a s son)) + in + fun _ -> act a + +let do_recover parser_of_tree entry nlevn alevn bp a s son + (strm__ : _ Stream.t) = + try parser_of_tree entry nlevn alevn (top_tree entry son) strm__ with + Stream.Failure -> + try + skip_if_empty bp (fun (strm__ : _ Stream.t) -> raise Stream.Failure) + strm__ + with Stream.Failure -> + continue entry bp a s son (parser_of_tree entry nlevn alevn son) + strm__ + +let recover parser_of_tree entry nlevn alevn bp a s son strm = + do_recover parser_of_tree entry nlevn alevn bp a s son strm + +let token_count = ref 0 + +let peek_nth n strm = + let list = Stream.npeek n strm in + token_count := Stream.count strm + n; + let rec loop list n = + match list, n with + x :: _, 1 -> Some x + | _ :: l, n -> loop l (n - 1) + | [], _ -> None + in + loop list n + +let item_skipped = ref false + +let call_and_push ps al strm = + item_skipped := false; + let a = ps strm in + let al = if !item_skipped then al else a :: al in item_skipped := false; al + +let token_ematch gram tok = + let tematch = L.tok_match tok in + fun tok -> tematch tok + +let rec parser_of_tree : type s tr r. s ty_entry -> int -> int -> (s, tr, r) ty_tree -> r parser_t = + fun entry nlevn alevn -> + function + DeadEnd -> (fun (strm__ : _ Stream.t) -> raise Stream.Failure) + | LocAct (act, _) -> (fun (strm__ : _ Stream.t) -> act) + | Node (_, {node = Sself; son = LocAct (act, _); brother = DeadEnd}) -> + (fun (strm__ : _ Stream.t) -> + let a = entry.estart alevn strm__ in act a) + | Node (_, {node = Sself; son = LocAct (act, _); brother = bro}) -> + let p2 = parser_of_tree entry nlevn alevn bro in + (fun (strm__ : _ Stream.t) -> + match + try Some (entry.estart alevn strm__) with Stream.Failure -> None + with + Some a -> act a + | _ -> p2 strm__) + | Node (_, {node = s; son = son; brother = DeadEnd}) -> + let tokl = + match s with + Stoken tok -> get_token_list entry tok TokNil son + | _ -> None + in + begin match tokl with + None -> + let ps = parser_of_symbol entry nlevn s in + let p1 = parser_of_tree entry nlevn alevn son in + let p1 = parser_cont p1 entry nlevn alevn s son in + (fun (strm__ : _ Stream.t) -> + let bp = Stream.count strm__ in + let a = ps strm__ in + let act = + try p1 bp a strm__ with + Stream.Failure -> + raise (Stream.Error (tree_failed entry a s son)) + in + act a) + | Some (TokTree (last_tok, son, rev_tokl)) -> + let lt = Stoken last_tok in + let p1 = parser_of_tree entry nlevn alevn son in + let p1 = parser_cont p1 entry nlevn alevn lt son in + parser_of_token_list entry son p1 rev_tokl last_tok + end + | Node (_, {node = s; son = son; brother = bro}) -> + let tokl = + match s with + Stoken tok -> get_token_list entry tok TokNil son + | _ -> None + in + match tokl with + None -> + let ps = parser_of_symbol entry nlevn s in + let p1 = parser_of_tree entry nlevn alevn son in + let p1 = parser_cont p1 entry nlevn alevn s son in + let p2 = parser_of_tree entry nlevn alevn bro in + (fun (strm : _ Stream.t) -> + let bp = Stream.count strm in + match try Some (ps strm) with Stream.Failure -> None with + Some a -> + begin match + (try Some (p1 bp a strm) with Stream.Failure -> None) + with + Some act -> act a + | None -> raise (Stream.Error (tree_failed entry a s son)) + end + | None -> p2 strm) + | Some (TokTree (last_tok, son, rev_tokl)) -> + let lt = Stoken last_tok in + let p2 = parser_of_tree entry nlevn alevn bro in + let p1 = parser_of_tree entry nlevn alevn son in + let p1 = parser_cont p1 entry nlevn alevn lt son in + let p1 = + parser_of_token_list entry son p1 rev_tokl last_tok + in + fun (strm__ : _ Stream.t) -> + try p1 strm__ with Stream.Failure -> p2 strm__ +and parser_cont : type s tr tr' a r. + (a -> r) parser_t -> s ty_entry -> int -> int -> (s, tr, a) ty_symbol -> (s, tr', a -> r) ty_tree -> int -> a -> (a -> r) parser_t = + fun p1 entry nlevn alevn s son bp a (strm__ : _ Stream.t) -> + try p1 strm__ with + Stream.Failure -> + recover parser_of_tree entry nlevn alevn bp a s son strm__ +and parser_of_token_list : type s tr lt r f. + s ty_entry -> (s, tr, lt -> r) ty_tree -> + (int -> lt -> (lt -> r) parser_t) -> (r, f) tok_list -> lt pattern -> f parser_t = + fun entry son p1 rev_tokl last_tok -> + let n = tok_list_length rev_tokl + 1 in + let plast : r parser_t = + let tematch = token_ematch egram last_tok in + let ps strm = + match peek_nth n strm with + Some tok -> + let r = tematch tok in + for _i = 1 to n do Stream.junk strm done; r + | None -> raise Stream.Failure + in + fun (strm : _ Stream.t) -> + let bp = Stream.count strm in + let a = ps strm in + match try Some (p1 bp a strm) with Stream.Failure -> None with + Some act -> act a + | None -> raise (Stream.Error (tree_failed entry a (Stoken last_tok) son)) + in + let rec loop : type s f. _ -> (s, f) tok_list -> s parser_t -> f parser_t = + fun n tokl plast -> match tokl with + | TokNil -> plast + | TokCns (tok, tokl) -> + let tematch = token_ematch egram tok in + let ps strm = + match peek_nth n strm with + Some tok -> tematch tok + | None -> raise Stream.Failure + in + let plast = fun (strm : _ Stream.t) -> + let a = ps strm in let act = plast strm in act a in + loop (n - 1) tokl plast in + loop (n - 1) rev_tokl plast +and parser_of_symbol : type s tr a. + s ty_entry -> int -> (s, tr, a) ty_symbol -> a parser_t = + fun entry nlevn -> + function + | Slist0 s -> + let ps = call_and_push (parser_of_symbol entry nlevn s) in + let rec loop al (strm__ : _ Stream.t) = + match try Some (ps al strm__) with Stream.Failure -> None with + Some al -> loop al strm__ + | _ -> al + in + (fun (strm__ : _ Stream.t) -> + let a = loop [] strm__ in List.rev a) + | Slist0sep (symb, sep, false) -> + let ps = call_and_push (parser_of_symbol entry nlevn symb) in + let pt = parser_of_symbol entry nlevn sep in + let rec kont al (strm__ : _ Stream.t) = + match try Some (pt strm__) with Stream.Failure -> None with + Some v -> + let al = + try ps al strm__ with + Stream.Failure -> + raise (Stream.Error (symb_failed entry v sep symb)) + in + kont al strm__ + | _ -> al + in + (fun (strm__ : _ Stream.t) -> + match try Some (ps [] strm__) with Stream.Failure -> None with + Some al -> let a = kont al strm__ in List.rev a + | _ -> []) + | Slist0sep (symb, sep, true) -> + let ps = call_and_push (parser_of_symbol entry nlevn symb) in + let pt = parser_of_symbol entry nlevn sep in + let rec kont al (strm__ : _ Stream.t) = + match try Some (pt strm__) with Stream.Failure -> None with + Some v -> + begin match + (try Some (ps al strm__) with Stream.Failure -> None) + with + Some al -> kont al strm__ + | _ -> al + end + | _ -> al + in + (fun (strm__ : _ Stream.t) -> + match try Some (ps [] strm__) with Stream.Failure -> None with + Some al -> let a = kont al strm__ in List.rev a + | _ -> []) + | Slist1 s -> + let ps = call_and_push (parser_of_symbol entry nlevn s) in + let rec loop al (strm__ : _ Stream.t) = + match try Some (ps al strm__) with Stream.Failure -> None with + Some al -> loop al strm__ + | _ -> al + in + (fun (strm__ : _ Stream.t) -> + let al = ps [] strm__ in + let a = loop al strm__ in List.rev a) + | Slist1sep (symb, sep, false) -> + let ps = call_and_push (parser_of_symbol entry nlevn symb) in + let pt = parser_of_symbol entry nlevn sep in + let rec kont al (strm__ : _ Stream.t) = + match try Some (pt strm__) with Stream.Failure -> None with + Some v -> + let al = + try ps al strm__ with + Stream.Failure -> + let a = + try parse_top_symb entry symb strm__ with + Stream.Failure -> + raise (Stream.Error (symb_failed entry v sep symb)) + in + a :: al + in + kont al strm__ + | _ -> al + in + (fun (strm__ : _ Stream.t) -> + let al = ps [] strm__ in + let a = kont al strm__ in List.rev a) + | Slist1sep (symb, sep, true) -> + let ps = call_and_push (parser_of_symbol entry nlevn symb) in + let pt = parser_of_symbol entry nlevn sep in + let rec kont al (strm__ : _ Stream.t) = + match try Some (pt strm__) with Stream.Failure -> None with + Some v -> + begin match + (try Some (ps al strm__) with Stream.Failure -> None) + with + Some al -> kont al strm__ + | _ -> + match + try Some (parse_top_symb entry symb strm__) with + Stream.Failure -> None + with + Some a -> kont (a :: al) strm__ + | _ -> al + end + | _ -> al + in + (fun (strm__ : _ Stream.t) -> + let al = ps [] strm__ in + let a = kont al strm__ in List.rev a) + | Sopt s -> + let ps = parser_of_symbol entry nlevn s in + (fun (strm__ : _ Stream.t) -> + match try Some (ps strm__) with Stream.Failure -> None with + Some a -> Some a + | _ -> None) + | Stree t -> + let pt = parser_of_tree entry 1 0 t in + (fun (strm__ : _ Stream.t) -> + let bp = Stream.count strm__ in + let a = pt strm__ in + let ep = Stream.count strm__ in + let loc = loc_of_token_interval bp ep in a loc) + | Snterm e -> (fun (strm__ : _ Stream.t) -> e.estart 0 strm__) + | Snterml (e, l) -> + (fun (strm__ : _ Stream.t) -> e.estart (level_number e l) strm__) + | Sself -> (fun (strm__ : _ Stream.t) -> entry.estart 0 strm__) + | Snext -> (fun (strm__ : _ Stream.t) -> entry.estart nlevn strm__) + | Stoken tok -> parser_of_token entry tok +and parser_of_token : type s a. + s ty_entry -> a pattern -> a parser_t = + fun entry tok -> + let f = L.tok_match tok in + fun strm -> + match Stream.peek strm with + Some tok -> let r = f tok in Stream.junk strm; r + | None -> raise Stream.Failure +and parse_top_symb : type s tr a. s ty_entry -> (s, tr, a) ty_symbol -> a parser_t = + fun entry symb -> + parser_of_symbol entry 0 (top_symb entry symb) + +let rec start_parser_of_levels entry clevn = + function + [] -> (fun levn (strm__ : _ Stream.t) -> raise Stream.Failure) + | Level lev :: levs -> + let p1 = start_parser_of_levels entry (succ clevn) 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 tree in + match levs with + [] -> + (fun levn strm -> + (* this code should be there but is commented to preserve + compatibility with previous versions... with this code, + the grammar entry e: [[ "x"; a = e | "y" ]] should fail + because it should be: e: [RIGHTA[ "x"; a = e | "y" ]]... + if levn > clevn then match strm with parser [] + else + *) + let (strm__ : _ Stream.t) = strm in + let bp = Stream.count strm__ in + let act = p2 strm__ in + let ep = Stream.count strm__ in + let a = act (loc_of_token_interval bp ep) in + entry.econtinue levn bp a strm) + | _ -> + fun levn strm -> + if levn > clevn then p1 levn strm + else + let (strm__ : _ Stream.t) = strm in + let bp = Stream.count strm__ in + match try Some (p2 strm__) with Stream.Failure -> None with + Some act -> + let ep = Stream.count strm__ in + let a = act (loc_of_token_interval bp ep) in + entry.econtinue levn bp a strm + | _ -> p1 levn strm__ + +let rec continue_parser_of_levels entry clevn = + function + [] -> (fun levn bp a (strm__ : _ Stream.t) -> raise Stream.Failure) + | Level lev :: levs -> + let p1 = continue_parser_of_levels entry (succ clevn) 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 tree in + fun levn bp a strm -> + if levn > clevn then p1 levn bp a strm + else + let (strm__ : _ Stream.t) = strm in + try p1 levn bp a strm__ with + Stream.Failure -> + let act = p2 strm__ in + let ep = Stream.count strm__ in + let a = act a (loc_of_token_interval bp ep) in + entry.econtinue levn bp a strm + +let continue_parser_of_entry entry = + match entry.edesc with + Dlevels elev -> + let p = continue_parser_of_levels entry 0 elev in + (fun levn bp a (strm__ : _ Stream.t) -> + try p levn bp a strm__ with Stream.Failure -> a) + | Dparser p -> fun levn bp a (strm__ : _ Stream.t) -> raise Stream.Failure + +let empty_entry ename levn strm = + raise (Stream.Error ("entry [" ^ ename ^ "] is empty")) + +let start_parser_of_entry entry = + match entry.edesc with + Dlevels [] -> empty_entry entry.ename + | Dlevels elev -> start_parser_of_levels entry 0 elev + | Dparser p -> fun levn strm -> p strm + +(* Extend syntax *) + +let init_entry_functions entry = + entry.estart <- + (fun lev strm -> + let f = start_parser_of_entry entry in entry.estart <- f; f lev strm); + entry.econtinue <- + (fun lev bp a strm -> + let f = continue_parser_of_entry entry in + entry.econtinue <- f; f lev bp a strm) + +let extend_entry ~warning entry position rules = + let elev = levels_of_rules ~warning entry position rules in + entry.edesc <- Dlevels elev; init_entry_functions entry + +(* Deleting a rule *) + +let delete_rule entry sl = + match entry.edesc with + Dlevels levs -> + let levs = delete_rule_in_level_list entry sl levs in + entry.edesc <- Dlevels levs; + entry.estart <- + (fun lev strm -> + let f = start_parser_of_entry entry in + entry.estart <- f; f lev strm); + entry.econtinue <- + (fun lev bp a strm -> + let f = continue_parser_of_entry entry in + entry.econtinue <- f; f lev bp a strm) + | Dparser _ -> () + +(* Normal interface *) + +type parsable = + { pa_chr_strm : char Stream.t; + pa_tok_strm : L.te Stream.t; + pa_loc_func : Plexing.location_function } + +let parse_parsable entry p = + let efun = entry.estart 0 in + let ts = p.pa_tok_strm in + let cs = p.pa_chr_strm in + let fun_loc = p.pa_loc_func in + let restore = + let old_floc = !floc in + let old_tc = !token_count in + fun () -> floc := old_floc; token_count := old_tc + in + let get_loc () = + try + let cnt = Stream.count ts in + (* Ensure that the token at location cnt has been peeked so that + the location function knows about it *) + let _ = Stream.peek ts in + let loc = fun_loc cnt in + if !token_count - 1 <= cnt then loc + else Loc.merge loc (fun_loc (!token_count - 1)) + with Failure _ -> Ploc.make_unlined (Stream.count cs, Stream.count cs + 1) + in + floc := fun_loc; + token_count := 0; + try let r = efun ts in restore (); r with + Stream.Failure -> + let loc = get_loc () in + restore (); + Ploc.raise loc (Stream.Error ("illegal begin of " ^ entry.ename)) + | Stream.Error _ as exc -> + let loc = get_loc () in restore (); Ploc.raise loc exc + | exc -> + let loc = Stream.count cs, Stream.count cs + 1 in + restore (); Ploc.raise (Ploc.make_unlined loc) exc + +(* Unsafe *) + +let clear_entry e = + e.estart <- (fun _ (strm__ : _ Stream.t) -> raise Stream.Failure); + e.econtinue <- (fun _ _ _ (strm__ : _ Stream.t) -> raise Stream.Failure); + match e.edesc with + Dlevels _ -> e.edesc <- Dlevels [] + | Dparser _ -> () + + let parsable ?loc cs = + let (ts, lf) = L.tok_func ?loc cs in + {pa_chr_strm = cs; pa_tok_strm = ts; pa_loc_func = lf} + module Entry = + struct + type 'a e = 'a ty_entry + let create n = + { ename = n; estart = empty_entry n; + econtinue = + (fun _ _ _ (strm__ : _ Stream.t) -> raise Stream.Failure); + edesc = Dlevels []} + let parse (e : 'a e) p : 'a = + parse_parsable e p + let parse_token_stream (e : 'a e) ts : 'a = + e.estart 0 ts + let name e = e.ename + let of_parser n (p : te Stream.t -> 'a) : 'a e = + { ename = n; + estart = (fun _ -> p); + econtinue = + (fun _ _ _ (strm__ : _ Stream.t) -> raise Stream.Failure); + edesc = Dparser p} + let print ppf e = fprintf ppf "%a@." print_entry e + end + let s_nterm e = Snterm e + let s_nterml e l = Snterml (e, l) + let s_list0 s = Slist0 s + let s_list0sep s sep b = Slist0sep (s, sep, b) + let s_list1 s = Slist1 s + let s_list1sep s sep b = Slist1sep (s, sep, b) + let s_opt s = Sopt s + let s_self = Sself + let s_next = Snext + let s_token tok = Stoken tok + let s_rules ~warning (t : 'a ty_rules list) = srules ~warning t + let r_stop = TStop + let r_next r s = TNext (MayRec2, r, s) + let r_next_norec r s = TNext (NoRec2, r, s) + let rules (p, act) = TRules (p, act) + let production (p, act) = TProd (p, act) + module Unsafe = + struct + let clear_entry = clear_entry + end + let safe_extend ~warning (e : 'a Entry.e) pos + (r : + (string option * Gramext.g_assoc option * 'a ty_production list) + list) = + extend_entry ~warning e pos r + let safe_delete_rule e r = + let AnyS (symbols, _) = get_symbols r in + delete_rule e symbols + +end diff --git a/gramlib/grammar.mli b/gramlib/grammar.mli new file mode 100644 index 0000000000..ec4ec62409 --- /dev/null +++ b/gramlib/grammar.mli @@ -0,0 +1,93 @@ +(* camlp5r *) +(* grammar.mli,v *) +(* Copyright (c) INRIA 2007-2017 *) + +(** Extensible grammars. + + This module implements the Camlp5 extensible grammars system. + Grammars entries can be extended using the [EXTEND] statement, + added by loading the Camlp5 [pa_extend.cmo] file. *) + +(** {6 Functorial interface} *) + + (** Alternative for grammars use. Grammars are no more Ocaml values: + there is no type for them. Modules generated preserve the + rule "an entry cannot call an entry of another grammar" by + normal OCaml typing. *) + +module type GLexerType = Plexing.Lexer + (** The input signature for the functor [Grammar.GMake]: [te] is the + type of the tokens. *) + +module type S = + sig + type te + type 'c pattern + type parsable + val parsable : ?loc:Loc.t -> char Stream.t -> parsable + val tokens : string -> (string option * int) list + module Entry : + sig + type 'a e + val create : string -> 'a e + val parse : 'a e -> parsable -> 'a + val name : 'a e -> string + val of_parser : string -> (te Stream.t -> 'a) -> 'a e + val parse_token_stream : 'a e -> te Stream.t -> 'a + val print : Format.formatter -> 'a e -> unit + end + type ty_norec = TyNoRec + type ty_mayrec = TyMayRec + type ('self, 'trec, 'a) ty_symbol + type ('self, 'trec, 'f, 'r) ty_rule + type 'a ty_rules + type 'a ty_production + val s_nterm : 'a Entry.e -> ('self, ty_norec, 'a) ty_symbol + val s_nterml : 'a Entry.e -> string -> ('self, ty_norec, 'a) ty_symbol + val s_list0 : ('self, 'trec, 'a) ty_symbol -> ('self, 'trec, 'a list) ty_symbol + val s_list0sep : + ('self, 'trec, 'a) ty_symbol -> ('self, ty_norec, 'b) ty_symbol -> bool -> + ('self, 'trec, 'a list) ty_symbol + val s_list1 : ('self, 'trec, 'a) ty_symbol -> ('self, 'trec, 'a list) ty_symbol + val s_list1sep : + ('self, 'trec, 'a) ty_symbol -> ('self, ty_norec, 'b) ty_symbol -> bool -> + ('self, 'trec, 'a list) ty_symbol + val s_opt : ('self, 'trec, 'a) ty_symbol -> ('self, 'trec, 'a option) ty_symbol + val s_self : ('self, ty_mayrec, 'self) ty_symbol + val s_next : ('self, ty_mayrec, 'self) ty_symbol + val s_token : 'c pattern -> ('self, ty_norec, 'c) ty_symbol + val s_rules : warning:(string -> unit) option -> 'a ty_rules list -> ('self, ty_norec, 'a) ty_symbol + + val r_stop : ('self, ty_norec, 'r, 'r) ty_rule + val r_next : + ('self, _, 'a, 'r) ty_rule -> ('self, _, 'b) ty_symbol -> + ('self, ty_mayrec, 'b -> 'a, 'r) ty_rule + val r_next_norec : + ('self, ty_norec, 'a, 'r) ty_rule -> ('self, ty_norec, 'b) ty_symbol -> + ('self, ty_norec, 'b -> 'a, 'r) ty_rule + val rules : (_, ty_norec, 'f, Loc.t -> 'a) ty_rule * 'f -> 'a ty_rules + val production : ('a, _, 'f, Loc.t -> 'a) ty_rule * 'f -> 'a ty_production + + module Unsafe : + sig + val clear_entry : 'a Entry.e -> unit + end + val safe_extend : warning:(string -> unit) option -> + 'a Entry.e -> Gramext.position option -> + (string option * Gramext.g_assoc option * 'a ty_production list) + list -> + unit + val safe_delete_rule : 'a Entry.e -> ('a, _, 'f, 'r) ty_rule -> unit + end + (** Signature type of the functor [Grammar.GMake]. The types and + functions are almost the same than in generic interface, but: +- Grammars are not values. Functions holding a grammar as parameter + do not have this parameter yet. +- The type [parsable] is used in function [parse] instead of + the char stream, avoiding the possible loss of tokens. +- The type of tokens (expressions and patterns) can be any + type (instead of (string * string)); the module parameter + must specify a way to show them as (string * string) *) + +module GMake (L : GLexerType) : + S with type te = L.te and type 'c pattern = 'c L.pattern diff --git a/gramlib/plexing.ml b/gramlib/plexing.ml new file mode 100644 index 0000000000..e881ab3350 --- /dev/null +++ b/gramlib/plexing.ml @@ -0,0 +1,18 @@ +(* camlp5r *) +(* plexing.ml,v *) +(* Copyright (c) INRIA 2007-2017 *) + +type location_function = int -> Loc.t +type 'te lexer_func = ?loc:Loc.t -> char Stream.t -> 'te Stream.t * location_function + +module type Lexer = sig + type te + type 'c pattern + val tok_pattern_eq : 'a pattern -> 'b pattern -> ('a, 'b) Util.eq option + val tok_pattern_strings : 'c pattern -> string * string option + val tok_func : te lexer_func + val tok_using : 'c pattern -> unit + val tok_removing : 'c pattern -> unit + val tok_match : 'c pattern -> te -> 'c + val tok_text : 'c pattern -> string +end diff --git a/gramlib/plexing.mli b/gramlib/plexing.mli new file mode 100644 index 0000000000..521eba7446 --- /dev/null +++ b/gramlib/plexing.mli @@ -0,0 +1,28 @@ +(* camlp5r *) +(* plexing.mli,v *) +(* Copyright (c) INRIA 2007-2017 *) + +(** Lexing for Camlp5 grammars. + + This module defines the Camlp5 lexer type to be used in extensible + grammars (see module [Grammar]). It also provides some useful functions + to create lexers. *) + +(** Lexer type *) + +type 'te lexer_func = ?loc:Loc.t -> char Stream.t -> 'te Stream.t * location_function +and location_function = int -> Loc.t + (** The type of a function giving the location of a token in the + source from the token number in the stream (starting from zero). *) + +module type Lexer = sig + type te + type 'c pattern + val tok_pattern_eq : 'a pattern -> 'b pattern -> ('a, 'b) Util.eq option + val tok_pattern_strings : 'c pattern -> string * string option + val tok_func : te lexer_func + val tok_using : 'c pattern -> unit + val tok_removing : 'c pattern -> unit + val tok_match : 'c pattern -> te -> 'c + val tok_text : 'c pattern -> string +end diff --git a/gramlib/ploc.ml b/gramlib/ploc.ml new file mode 100644 index 0000000000..056a2b7ad3 --- /dev/null +++ b/gramlib/ploc.ml @@ -0,0 +1,25 @@ +(* camlp5r *) +(* ploc.ml,v *) +(* Copyright (c) INRIA 2007-2017 *) + +open Loc + +let make_unlined (bp, ep) = + {fname = InFile ""; line_nb = 1; bol_pos = 0; line_nb_last = -1; bol_pos_last = 0; + bp = bp; ep = ep; } + +let dummy = + {fname = InFile ""; line_nb = 1; bol_pos = 0; line_nb_last = -1; bol_pos_last = 0; + bp = 0; ep = 0; } + +(* *) + +let sub loc sh len = {loc with bp = loc.bp + sh; ep = loc.bp + sh + len} +let after loc sh len = {loc with bp = loc.ep + sh; ep = loc.ep + sh + len} + +exception Exc of Loc.t * exn + +let raise loc exc = + match exc with + Exc (_, _) -> raise exc + | _ -> raise (Exc (loc, exc)) diff --git a/gramlib/ploc.mli b/gramlib/ploc.mli new file mode 100644 index 0000000000..15a5a74455 --- /dev/null +++ b/gramlib/ploc.mli @@ -0,0 +1,37 @@ +(* camlp5r *) +(* ploc.mli,v *) +(* Copyright (c) INRIA 2007-2017 *) + +(* located exceptions *) + +exception Exc of Loc.t * exn + (** [Ploc.Exc loc e] is an encapsulation of the exception [e] with + the input location [loc]. To be used to specify a location + for an error. This exception must not be raised by [raise] but + rather by [Ploc.raise] (see below), to prevent the risk of several + encapsulations of [Ploc.Exc]. *) + +val raise : Loc.t -> exn -> 'a + (** [Ploc.raise loc e], if [e] is already the exception [Ploc.Exc], + re-raise it (ignoring the new location [loc]), else raise the + exception [Ploc.Exc loc e]. *) + +val make_unlined : int * int -> Loc.t + (** [Ploc.make_unlined] is like [Ploc.make] except that the line number + is not provided (to be used e.g. when the line number is unknown. *) + +val dummy : Loc.t + (** [Ploc.dummy] is a dummy location, used in situations when location + has no meaning. *) + +(* combining locations *) + +val sub : Loc.t -> int -> int -> Loc.t + (** [Ploc.sub loc sh len] is the location [loc] shifted with [sh] + characters and with length [len]. The previous ending position + of the location is lost. *) + +val after : Loc.t -> int -> int -> Loc.t + (** [Ploc.after loc sh len] is the location just after loc (starting at + the end position of [loc]) shifted with [sh] characters and of length + [len]. *) |
