146 lines
4 KiB
OCaml
146 lines
4 KiB
OCaml
|
|
(*
|
||
|
|
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
|
||
|
|
*)
|
||
|
|
|
||
|
|
module Re = Core
|
||
|
|
|
||
|
|
exception Parse_error
|
||
|
|
exception Not_supported
|
||
|
|
|
||
|
|
let by_code f c c' =
|
||
|
|
let c = Char.code c in
|
||
|
|
let c' = Char.code c' in
|
||
|
|
Char.chr (f c c')
|
||
|
|
;;
|
||
|
|
|
||
|
|
let parse ~emacs_only s =
|
||
|
|
let buf = Parse_buffer.create s in
|
||
|
|
let accept = Parse_buffer.accept buf in
|
||
|
|
let eos () = Parse_buffer.eos buf in
|
||
|
|
let test2 = Parse_buffer.test2 buf in
|
||
|
|
let get () = Parse_buffer.get buf in
|
||
|
|
let rec regexp () = regexp' [ branch () ]
|
||
|
|
and regexp' left =
|
||
|
|
if Parse_buffer.accept_s buf {|\||}
|
||
|
|
then regexp' (branch () :: left)
|
||
|
|
else Re.alt (List.rev left)
|
||
|
|
and branch () = branch' []
|
||
|
|
and branch' left =
|
||
|
|
if eos () || test2 '\\' '|' || test2 '\\' ')'
|
||
|
|
then Re.seq (List.rev left)
|
||
|
|
else branch' (piece () :: left)
|
||
|
|
and piece () =
|
||
|
|
let r = atom () in
|
||
|
|
if accept '*'
|
||
|
|
then Re.rep r
|
||
|
|
else if accept '+'
|
||
|
|
then Re.rep1 r
|
||
|
|
else if accept '?'
|
||
|
|
then Re.opt r
|
||
|
|
else r
|
||
|
|
and atom () =
|
||
|
|
if accept '.'
|
||
|
|
then Re.notnl
|
||
|
|
else if accept '^'
|
||
|
|
then Re.bol
|
||
|
|
else if accept '$'
|
||
|
|
then Re.eol
|
||
|
|
else if accept '['
|
||
|
|
then if accept '^' then Re.compl (bracket []) else Re.alt (bracket [])
|
||
|
|
else if accept '\\'
|
||
|
|
then
|
||
|
|
if accept '('
|
||
|
|
then (
|
||
|
|
let r = regexp () in
|
||
|
|
if not (Parse_buffer.accept_s buf {|\)|}) then raise Parse_error;
|
||
|
|
Re.group r)
|
||
|
|
else if emacs_only && accept '`'
|
||
|
|
then Re.bos
|
||
|
|
else if emacs_only && accept '\''
|
||
|
|
then Re.eos
|
||
|
|
else if accept '='
|
||
|
|
then Re.start
|
||
|
|
else if accept 'b'
|
||
|
|
then Re.alt [ Re.bow; Re.eow ]
|
||
|
|
else if emacs_only && accept 'B'
|
||
|
|
then Re.not_boundary
|
||
|
|
else if emacs_only && accept '<'
|
||
|
|
then Re.bow
|
||
|
|
else if emacs_only && accept '>'
|
||
|
|
then Re.eow
|
||
|
|
else if accept 'w'
|
||
|
|
then Re.alt [ Re.alnum; Re.char '_' ]
|
||
|
|
else if accept 'W'
|
||
|
|
then Re.compl [ Re.alnum; Re.char '_' ]
|
||
|
|
else (
|
||
|
|
if eos () then raise Parse_error;
|
||
|
|
match get () with
|
||
|
|
| ('*' | '+' | '?' | '[' | ']' | '.' | '^' | '$' | '\\') as c -> Re.char c
|
||
|
|
| '0' .. '9' -> raise Not_supported
|
||
|
|
| c -> if emacs_only then raise Parse_error else Re.char c)
|
||
|
|
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 (
|
||
|
|
let c = char () in
|
||
|
|
if accept '-'
|
||
|
|
then
|
||
|
|
if accept ']'
|
||
|
|
then Re.char c :: Re.char '-' :: s
|
||
|
|
else (
|
||
|
|
let c' = char () in
|
||
|
|
let c' = by_code Int.max c c' in
|
||
|
|
bracket (Re.rg c c' :: s))
|
||
|
|
else bracket (Re.char c :: s))
|
||
|
|
and char () =
|
||
|
|
if eos () then raise Parse_error;
|
||
|
|
get ()
|
||
|
|
in
|
||
|
|
let res = regexp () in
|
||
|
|
if not (eos ()) then raise Parse_error;
|
||
|
|
res
|
||
|
|
;;
|
||
|
|
|
||
|
|
let re ?(case = true) s =
|
||
|
|
let r = parse s ~emacs_only:true in
|
||
|
|
if case then r else Re.no_case r
|
||
|
|
;;
|
||
|
|
|
||
|
|
let re_no_emacs ~case s =
|
||
|
|
let r = parse s ~emacs_only:false in
|
||
|
|
if case then r else Re.no_case r
|
||
|
|
;;
|
||
|
|
|
||
|
|
let re_result ?case s =
|
||
|
|
match re ?case s with
|
||
|
|
| s -> Ok s
|
||
|
|
| exception Not_supported -> Error `Not_supported
|
||
|
|
| exception Parse_error -> Error `Parse_error
|
||
|
|
;;
|
||
|
|
|
||
|
|
let compile = Re.compile
|
||
|
|
let compile_pat ?(case = true) s = compile (re ~case s)
|