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
type t = { int : string; frac : string; exp : string } let equal n1 n2 = String.(equal n1.int n2.int && equal n1.frac n2.frac && equal n1.exp n2.exp) let int s = { int = s; frac = ""; exp = "" } let to_string n = n.int ^ (if n.frac = "" then "" else "." ^ n.frac) ^ n.exp let parse = let buff = ref (Bytes.create 80) in let store len x = let open Bytes in if len >= length !buff then buff := cat !buff (create (length !buff)); set !buff len x; succ len in let get_buff len = Bytes.sub_string !buff 0 len in (* reads [0-9_]* *) let rec number len s = match Stream.peek s with | Some (('0'..'9' | '_') as c) -> Stream.junk s; number (store len c) s | _ -> len in fun s -> let i = get_buff (number 0 s) in let f = match Stream.npeek 2 s with | '.' :: (('0'..'9' | '_') as c) :: _ -> Stream.junk s; Stream.junk s; get_buff (number (store 0 c) s) | _ -> "" in let e = match (Stream.npeek 2 s) with | (('e'|'E') as e) :: ('0'..'9' as c) :: _ -> Stream.junk s; Stream.junk s; get_buff (number (store (store 0 e) c) s) | (('e'|'E') as e) :: (('+'|'-') as sign) :: _ -> begin match Stream.npeek 3 s with | _ :: _ :: ('0'..'9' as c) :: _ -> Stream.junk s; Stream.junk s; Stream.junk s; get_buff (number (store (store (store 0 e) sign) c) s) | _ -> "" end | _ -> "" in { int = i; frac = f; exp = e } let of_string s = if s = "" || s.[0] < '0' || s.[0] > '9' then None else let strm = Stream.of_string (s ^ " ") in let n = parse strm in if Stream.count strm >= String.length s then Some n else None