(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) (* What we could (should?) do: - a* ==> longest ((shortest (no_group a)* ), a | ()) (!!!) - abc understood as (ab)c - "((a?)|b)" against "ab" should not bind the first subpattern to anything Note that it should be possible to handle "(((ab)c)d)e" efficiently *) module Re = Core exception Parse_error = Parse_buffer.Parse_error exception Not_supported let parse newline s = let buf = Parse_buffer.create s in let accept = Parse_buffer.accept buf in let eos () = Parse_buffer.eos buf in let test c = Parse_buffer.test buf c in let unget () = Parse_buffer.unget buf in let get () = Parse_buffer.get buf in let rec regexp () = regexp' [ branch () ] and regexp' left = if accept '|' then regexp' (branch () :: left) else Re.alt (List.rev left) and branch () = branch' [] and branch' left = if eos () || test '|' || test ')' then Re.seq (List.rev left) else branch' (piece () :: left) and piece () = let r = atom () in if accept '*' then Re.rep (Re.nest r) else if accept '+' then Re.rep1 (Re.nest r) else if accept '?' then Re.opt r else if accept '{' then ( match Parse_buffer.integer buf with | Some i -> let j = if accept ',' then Parse_buffer.integer buf else Some i in if not (accept '}') then raise Parse_error; (match j with | Some j when j < i -> raise Parse_error | _ -> ()); Re.repn (Re.nest r) i j | None -> unget (); r) else r and atom () = if accept '.' then if newline then Re.notnl else Re.any else if accept '(' then ( let r = regexp () in if not (accept ')') then raise Parse_error; Re.group r) else if accept '^' then if newline then Re.bol else Re.bos else if accept '$' then if newline then Re.eol else Re.eos else if accept '[' then if accept '^' then Re.diff (Re.compl (bracket [])) (Re.char '\n') else Re.alt (bracket []) else if accept '\\' then ( if eos () then raise Parse_error; match get () with | ('|' | '(' | ')' | '*' | '+' | '?' | '[' | '.' | '^' | '$' | '{' | '\\') as c -> Re.char c | _ -> raise Parse_error) else ( if eos () then raise Parse_error; match get () with | '*' | '+' | '?' | '{' | '\\' -> raise Parse_error | c -> Re.char c) and bracket s = if s <> [] && accept ']' then s else ( match char () with | `Set st -> bracket (st :: s) | `Char c -> if accept '-' then if accept ']' then Re.char c :: Re.char '-' :: s else bracket (match char () with | `Char c' -> Re.rg c c' :: s | `Set st' -> Re.char c :: Re.char '-' :: st' :: s) else bracket (Re.char c :: s)) and char () = if eos () then raise Parse_error; let c = get () in if c = '[' then ( match Posix_class.parse buf with | Some set -> `Set set | None -> if accept '.' then ( if eos () then raise Parse_error; let c = get () in if not (accept '.') then raise Not_supported; if not (accept ']') then raise Parse_error; `Char c) else `Char c) else `Char c in let res = regexp () in if not (eos ()) then raise Parse_error; res ;; type opt = [ `ICase | `NoSub | `Newline ] let re ?(opts = []) s = let r = parse (List.memq `Newline opts) s in let r = if List.memq `ICase opts then Re.no_case r else r in let r = if List.memq `NoSub opts then Re.no_group r else r in r ;; let re_result ?opts s = match re ?opts s with | s -> Ok s | exception Not_supported -> Error `Not_supported | exception Parse_error -> Error `Parse_error ;; let compile re = Re.compile (Re.longest re) let compile_pat ?(opts = []) s = compile (re ~opts s)