diff --git a/src/FSharpPlus/Parsing.fs b/src/FSharpPlus/Parsing.fs index fab78fc1a..a694c1075 100644 --- a/src/FSharpPlus/Parsing.fs +++ b/src/FSharpPlus/Parsing.fs @@ -4,27 +4,69 @@ [] module Parsing = - open System open System.Text.RegularExpressions open FSharpPlus open FSharpPlus.Internals - open FSharpPlus.Internals.Prelude - - let inline private getGroups (pf: PrintfFormat<_,_,_,_,_>) s = - let formatters = [|"%A"; "%b"; "%B"; "%c"; "%d"; "%e"; "%E"; "%f"; "%F"; "%g"; "%G"; "%i"; "%M"; "%o"; "%O"; "%s"; "%u"; "%x"; "%X"|] - let formatStr = replace "%%" "%" pf.Value - let constants = split formatters formatStr - let regex = Regex ("^" + String.Join ("(.*?)", constants |> Array.map Regex.Escape) + "$") - let getGroup x = - let groups = - regex.Match(x).Groups - |> Seq.cast - |> Seq.skip 1 - groups - |> Seq.map (fun g -> g.Value) - |> Seq.toArray - (getGroup s, getGroup pf.Value) ||> Array.zipShortest + open Prelude + + let inline private getGroups (pf: PrintfFormat<_,_,_,_,_>) = + let format = pf.Value + let regex = System.Text.StringBuilder "^" + let groups = ResizeArray(format.Length / 2) // worst case, there are only format specifiers + let mutable i = 0 + while i < String.length format do + match format[i] with + | '%' -> + i <- i + 1 + let mutable consumeSpacesAfter = false // consume spaces after if '-' specified + let mutable consumeNumericPlus = false // consume plus before numeric values if '+' specified + while + match format[i] with + | ' ' -> regex.Append @"\s*" |> ignore; true // consume spaces before if ' ' specified + | '-' -> consumeSpacesAfter <- true; true + | '+' -> consumeNumericPlus <- true; true + | '*' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' -> true + | _ -> false + do i <- i + 1 + if format[i] <> '%' then groups.Add format[i] // %% does not capture a group + match format[i] with + | 'A' | 'O' -> "(.*?)" + | 'b' -> "([Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee])" + | 'B' -> + if consumeNumericPlus then regex.Append @"\+?" |> ignore + "([01]+)" + | 'c' -> "(.)" + | 'd' | 'i' -> + regex.Append (if consumeNumericPlus then "([+-]?" else "(-?") |> ignore + "[0-9]+)" + | 'e' | 'E' | 'f' | 'F' | 'g' | 'G' | 'M' -> + regex.Append (if consumeNumericPlus then "([+-]?" else "(-?") |> ignore + @"(?:[0-9]+\.?[0-9]*|\.[0-9]+)(?:[eE][+-]?[0-9]+)?)" + | 'o' -> + if consumeNumericPlus then regex.Append @"\+?" |> ignore + "([0-7]+)" + | 'u' -> + if consumeNumericPlus then regex.Append @"\+?" |> ignore + "([0-9]+)" + | 's' -> "(.*?)" + | 'x' | 'X' -> + if consumeNumericPlus then regex.Append @"\+?" |> ignore + "([0-9a-fA-F]+)" + | '%' -> "%" + | x -> failwith $"Unknown format specifier: {x}" + |> regex.Append |> ignore + if consumeSpacesAfter then regex.Append @"\s*" else regex + | '\\' | '*' | '+' | '?' | '|' | '{' | '[' | '(' | ')' | '^' | '$' | '.' | '#' | ' ' as escape -> + regex.Append('\\').Append escape + | c -> regex.Append c + |> ignore + i <- i + 1 + let regex = regex.Append '$' |> string + fun str -> + let m = Regex.Match(str, regex) + if not m.Success then [||] else + Array.init (m.Groups.Count - 1) <| fun i -> struct(m.Groups[i + 1].Value, groups[i]) let inline private conv (destType: System.Type) (b: int) (s: string) = match destType with @@ -38,29 +80,29 @@ module Parsing = | t when t = typeof -> Convert.ToInt64 (s, b) |> box | _ -> invalidOp (sprintf "Type conversion from string to type %A with base %i is not supported" destType b) - let inline private parse (s: string, f: string) : 'r = + let inline private parse struct(s: string, f: char) : 'r = match f with - | "%B" -> conv typeof<'r> 2 s |> string |> parse - | "%o" -> conv typeof<'r> 8 s |> string |> parse - | "%x" | "%X" -> conv typeof<'r> 16 s |> string |> parse + | 'B' -> conv typeof<'r> 2 s |> string |> parse + | 'o' -> conv typeof<'r> 8 s |> string |> parse + | 'x' | 'X' -> conv typeof<'r> 16 s |> string |> parse | _ -> parse s - let inline private tryParse (s: string, f: string) : 'r option = + let inline private tryParse struct(s: string, f: char) : 'r option = match f with - | "%B" -> Option.protect (conv typeof<'r> 2) s |> Option.map string |> Option.bind tryParse - | "%o" -> Option.protect (conv typeof<'r> 8) s |> Option.map string |> Option.bind tryParse - | "%x" | "%X" -> Option.protect (conv typeof<'r> 16) s |> Option.map string |> Option.bind tryParse + | 'B' -> Option.protect (conv typeof<'r> 2) s |> Option.map string |> Option.bind tryParse + | 'o' -> Option.protect (conv typeof<'r> 8) s |> Option.map string |> Option.bind tryParse + | 'x' | 'X' -> Option.protect (conv typeof<'r> 16) s |> Option.map string |> Option.bind tryParse | _ -> tryParse s type ParseArray = - static member inline ParseArray (_: 't , _: obj) = fun (g: (string * string) []) -> (parse (g.[0])) : 't + static member inline ParseArray (_: 't , _: obj) = fun (g: struct(string * char) []) -> (parse (g.[0])) : 't - static member inline Invoke (g: (string * string) []) = + static member inline Invoke (g: struct(string * char) []) = let inline call_2 (a: ^a, b: ^b) = ((^a or ^b) : (static member ParseArray: _*_ -> _) b, a) g let inline call (a: 'a) = call_2 (a, Unchecked.defaultof<'r>) : 'r call Unchecked.defaultof - static member inline ParseArray (t: 't, _: ParseArray) = fun (g: (string * string) []) -> + static member inline ParseArray (t: 't, _: ParseArray) = fun (g: struct(string * char) []) -> let _f _ = Constraints.whenNestedTuple t : ('t1*'t2*'t3*'t4*'t5*'t6*'t7*'tr) let (t1: 't1) = parse (g.[0]) let (t2: 't2) = parse (g.[1]) @@ -72,29 +114,29 @@ module Parsing = let (tr: 'tr) = ParseArray.Invoke (g.[7..]) Tuple<_,_,_,_,_,_,_,_> (t1, t2, t3, t4, t5, t6, t7, tr) |> retype : 't - static member inline ParseArray (_: unit , _: ParseArray) = fun (_: (string * string) []) -> () - static member inline ParseArray (_: Tuple<'t1> , _: ParseArray) = fun (g: (string * string) []) -> Tuple<_> (parse g.[0]) : Tuple<'t1> - static member inline ParseArray (_: Id<'t1> , _: ParseArray) = fun (g: (string * string) []) -> Id<_> (parse g.[0]) - static member inline ParseArray (_: 't1*'t2 , _: ParseArray) = fun (g: (string * string) []) -> parse g.[0], parse g.[1] - static member inline ParseArray (_: 't1*'t2'*'t3 , _: ParseArray) = fun (g: (string * string) []) -> parse g.[0], parse g.[1], parse g.[2] - static member inline ParseArray (_: 't1*'t2'*'t3*'t4 , _: ParseArray) = fun (g: (string * string) []) -> parse g.[0], parse g.[1], parse g.[2], parse g.[3] - static member inline ParseArray (_: 't1*'t2'*'t3*'t4*'t5 , _: ParseArray) = fun (g: (string * string) []) -> parse g.[0], parse g.[1], parse g.[2], parse g.[3], parse g.[4] - static member inline ParseArray (_: 't1*'t2'*'t3*'t4*'t5*'t6 , _: ParseArray) = fun (g: (string * string) []) -> parse g.[0], parse g.[1], parse g.[2], parse g.[3], parse g.[4], parse g.[5] - static member inline ParseArray (_: 't1*'t2'*'t3*'t4*'t5*'t6*'t7, _: ParseArray) = fun (g: (string * string) []) -> parse g.[0], parse g.[1], parse g.[2], parse g.[3], parse g.[4], parse g.[5], parse g.[6] - - let inline private tryParseElemAt i (g: (string * string) []) = + static member inline ParseArray (_: unit , _: ParseArray) = fun (_: struct(string * char) []) -> () + static member inline ParseArray (_: Tuple<'t1> , _: ParseArray) = fun (g: struct(string * char) []) -> Tuple<_> (parse g.[0]) : Tuple<'t1> + static member inline ParseArray (_: Id<'t1> , _: ParseArray) = fun (g: struct(string * char) []) -> Id<_> (parse g.[0]) + static member inline ParseArray (_: 't1*'t2 , _: ParseArray) = fun (g: struct(string * char) []) -> parse g.[0], parse g.[1] + static member inline ParseArray (_: 't1*'t2'*'t3 , _: ParseArray) = fun (g: struct(string * char) []) -> parse g.[0], parse g.[1], parse g.[2] + static member inline ParseArray (_: 't1*'t2'*'t3*'t4 , _: ParseArray) = fun (g: struct(string * char) []) -> parse g.[0], parse g.[1], parse g.[2], parse g.[3] + static member inline ParseArray (_: 't1*'t2'*'t3*'t4*'t5 , _: ParseArray) = fun (g: struct(string * char) []) -> parse g.[0], parse g.[1], parse g.[2], parse g.[3], parse g.[4] + static member inline ParseArray (_: 't1*'t2'*'t3*'t4*'t5*'t6 , _: ParseArray) = fun (g: struct(string * char) []) -> parse g.[0], parse g.[1], parse g.[2], parse g.[3], parse g.[4], parse g.[5] + static member inline ParseArray (_: 't1*'t2'*'t3*'t4*'t5*'t6*'t7, _: ParseArray) = fun (g: struct(string * char) []) -> parse g.[0], parse g.[1], parse g.[2], parse g.[3], parse g.[4], parse g.[5], parse g.[6] + + let inline private tryParseElemAt i (g: struct(string * char) []) = if i < Array.length g then tryParse (g.[i]) else None type TryParseArray = - static member inline TryParseArray (_:'t, _:obj) = fun (g: (string * string) []) -> tryParseElemAt 0 g : 't option + static member inline TryParseArray (_:'t, _:obj) = fun (g: struct(string * char) []) -> tryParseElemAt 0 g : 't option - static member inline Invoke (g: (string * string) []) = + static member inline Invoke (g: struct(string * char) []) = let inline call_2 (a: ^a, b: ^b) = ((^a or ^b) : (static member TryParseArray: _*_ -> _) b, a) g let inline call (a: 'a) = call_2 (a, Unchecked.defaultof<'r>) : 'r option call Unchecked.defaultof - static member inline TryParseArray (t: 't, _: TryParseArray) = fun (g: (string * string) []) -> + static member inline TryParseArray (t: 't, _: TryParseArray) = fun (g: struct(string * char) []) -> let _f _ = Constraints.whenNestedTuple t : ('t1*'t2*'t3*'t4*'t5*'t6*'t7*'tr) let (t1: 't1 option) = tryParseElemAt 0 g let (t2: 't2 option) = tryParseElemAt 1 g @@ -108,31 +150,31 @@ module Parsing = | Some t1, Some t2, Some t3, Some t4, Some t5, Some t6, Some t7, Some tr -> Some (Tuple<_,_,_,_,_,_,_,_> (t1, t2, t3, t4, t5, t6, t7, tr) |> retype : 't) | _ -> None - static member inline TryParseArray (_: unit , _: TryParseArray) = fun (_: (string * string) []) -> () - static member inline TryParseArray (_: Tuple<'t1> , _: TryParseArray) = fun (g: (string * string) []) -> Tuple<_> tryParseElemAt 0 g : Tuple<'t1> option - static member inline TryParseArray (_: Id<'t1> , _: TryParseArray) = fun (g: (string * string) []) -> Id<_> tryParseElemAt 0 g - static member inline TryParseArray (_: 't1*'t2 , _: TryParseArray) = fun (g: (string * string) []) -> tuple2 tryParseElemAt 0 g <*> tryParseElemAt 1 g - static member inline TryParseArray (_: 't1*'t2'*'t3 , _: TryParseArray) = fun (g: (string * string) []) -> tuple3 tryParseElemAt 0 g <*> tryParseElemAt 1 g <*> tryParseElemAt 2 g - static member inline TryParseArray (_: 't1*'t2'*'t3*'t4 , _: TryParseArray) = fun (g: (string * string) []) -> tuple4 tryParseElemAt 0 g <*> tryParseElemAt 1 g <*> tryParseElemAt 2 g <*> tryParseElemAt 3 g - static member inline TryParseArray (_: 't1*'t2'*'t3*'t4*'t5 , _: TryParseArray) = fun (g: (string * string) []) -> tuple5 tryParseElemAt 0 g <*> tryParseElemAt 1 g <*> tryParseElemAt 2 g <*> tryParseElemAt 3 g <*> tryParseElemAt 4 g - static member inline TryParseArray (_: 't1*'t2'*'t3*'t4*'t5*'t6 , _: TryParseArray) = fun (g: (string * string) []) -> tuple6 tryParseElemAt 0 g <*> tryParseElemAt 1 g <*> tryParseElemAt 2 g <*> tryParseElemAt 3 g <*> tryParseElemAt 4 g <*> tryParseElemAt 5 g - static member inline TryParseArray (_: 't1*'t2'*'t3*'t4*'t5*'t6*'t7, _: TryParseArray) = fun (g: (string * string) []) -> tuple7 tryParseElemAt 0 g <*> tryParseElemAt 1 g <*> tryParseElemAt 2 g <*> tryParseElemAt 3 g <*> tryParseElemAt 4 g <*> tryParseElemAt 5 g <*> tryParseElemAt 6 g + static member inline TryParseArray (_: unit , _: TryParseArray) = fun (_: struct(string * char) []) -> () + static member inline TryParseArray (_: Tuple<'t1> , _: TryParseArray) = fun (g: struct(string * char) []) -> Tuple<_> tryParseElemAt 0 g : Tuple<'t1> option + static member inline TryParseArray (_: Id<'t1> , _: TryParseArray) = fun (g: struct(string * char) []) -> Id<_> tryParseElemAt 0 g + static member inline TryParseArray (_: 't1*'t2 , _: TryParseArray) = fun (g: struct(string * char) []) -> tuple2 tryParseElemAt 0 g <*> tryParseElemAt 1 g + static member inline TryParseArray (_: 't1*'t2'*'t3 , _: TryParseArray) = fun (g: struct(string * char) []) -> tuple3 tryParseElemAt 0 g <*> tryParseElemAt 1 g <*> tryParseElemAt 2 g + static member inline TryParseArray (_: 't1*'t2'*'t3*'t4 , _: TryParseArray) = fun (g: struct(string * char) []) -> tuple4 tryParseElemAt 0 g <*> tryParseElemAt 1 g <*> tryParseElemAt 2 g <*> tryParseElemAt 3 g + static member inline TryParseArray (_: 't1*'t2'*'t3*'t4*'t5 , _: TryParseArray) = fun (g: struct(string * char) []) -> tuple5 tryParseElemAt 0 g <*> tryParseElemAt 1 g <*> tryParseElemAt 2 g <*> tryParseElemAt 3 g <*> tryParseElemAt 4 g + static member inline TryParseArray (_: 't1*'t2'*'t3*'t4*'t5*'t6 , _: TryParseArray) = fun (g: struct(string * char) []) -> tuple6 tryParseElemAt 0 g <*> tryParseElemAt 1 g <*> tryParseElemAt 2 g <*> tryParseElemAt 3 g <*> tryParseElemAt 4 g <*> tryParseElemAt 5 g + static member inline TryParseArray (_: 't1*'t2'*'t3*'t4*'t5*'t6*'t7, _: TryParseArray) = fun (g: struct(string * char) []) -> tuple7 tryParseElemAt 0 g <*> tryParseElemAt 1 g <*> tryParseElemAt 2 g <*> tryParseElemAt 3 g <*> tryParseElemAt 4 g <*> tryParseElemAt 5 g <*> tryParseElemAt 6 g /// Gets a tuple with the result of parsing each element of a string array. - let inline parseArray (source: string []) : '``(T1 * T2 * ... * Tn)`` = ParseArray.Invoke (Array.map (fun x -> (x, "")) source) + let inline parseArray (source: string []) : '``(T1 * T2 * ... * Tn)`` = ParseArray.Invoke (Array.map (fun x -> (x, '\000')) source) /// Gets a tuple with the result of parsing each element of a formatted text. - let inline sscanf (pf: PrintfFormat<_,_,_,_,'``(T1 * T2 * ... * Tn)``>) s : '``(T1 * T2 * ... * Tn)`` = getGroups pf s |> ParseArray.Invoke + let inline sscanf (pf: PrintfFormat<_,_,_,_,'``(T1 * T2 * ... * Tn)``>) : string -> '``(T1 * T2 * ... * Tn)`` = getGroups pf >> ParseArray.Invoke /// Gets a tuple with the result of parsing each element of a formatted text from the Console. let inline scanfn pf : '``(T1 * T2 * ... * Tn)`` = sscanf pf (Console.ReadLine ()) /// Gets a tuple with the result of parsing each element of a string array. Returns None in case of failure. - let inline tryParseArray (source: string []) : '``(T1 * T2 * ... * Tn)`` option = TryParseArray.Invoke (Array.map (fun x -> (x, "")) source) + let inline tryParseArray (source: string []) : '``(T1 * T2 * ... * Tn)`` option = TryParseArray.Invoke (Array.map (fun x -> x, '\000') source) /// Gets a tuple with the result of parsing each element of a formatted text. Returns None in case of failure. - let inline trySscanf (pf: PrintfFormat<_,_,_,_,'``(T1 * T2 * ... * Tn)``>) s : '``(T1 * T2 * ... * Tn)`` option = getGroups pf s |> TryParseArray.Invoke + let inline trySscanf (pf: PrintfFormat<_,_,_,_,'``(T1 * T2 * ... * Tn)``>) : string -> '``(T1 * T2 * ... * Tn)`` option = getGroups pf >> TryParseArray.Invoke /// Gets a tuple with the result of parsing each element of a formatted text from the Console. Returns None in case of failure. let inline tryScanfn pf : '``(T1 * T2 * ... * Tn)`` option = trySscanf pf (Console.ReadLine ()) diff --git a/tests/FSharpPlus.Tests/Parsing.fs b/tests/FSharpPlus.Tests/Parsing.fs index 37f0029e2..234534083 100644 --- a/tests/FSharpPlus.Tests/Parsing.fs +++ b/tests/FSharpPlus.Tests/Parsing.fs @@ -87,7 +87,11 @@ module Parsing = let _ccx: int * uint32 * float * float32 * int * uint32 * float * float32 * int * uint32 * float * float32 * int * uint32 * float * float32 * int = parseArray [|"34"; "24"; "34"; "4"; "5"; "6"; "7"; "8"; "9"; "10"; "11"; "12"; "13"; "14"; "15"; "16"; "17"|] let _t = sscanf "(%i-%i-%f-%i-%i-%i-%i-%i-%i)" "(32-66-888-4-5-6-7-8-9)" - let (_a,_b) = sscanf "(%%%s,%M)" "(%hello, 4.53)" + let (_a,_b) = sscanf "(%%%s,%M)" "(%hello,4.53)" + let (_a1,_b1) = sscanf "(%%%s,% M)" "(%hello, 4.53)" + let (_a2,_b2) = sscanf "(%%%s,%-M)" "(%hello,4.53 )" + let (_a3,_b3) = sscanf "(%%%s,% -M)" "(%hello, 4.53 )" + let (_a4,_b4,_ab) = sscanf "(%%%s,% d%-M)" "(%hello, 4.53 )" let (_x,_y,_z) = sscanf "%s-%s-%s" "test-this-string" let (_j,_k,_l,_m,_n,_o,_p) = sscanf "%f %F %g %G %e %E %c" "1 2.1 3.4 .3 43.2e32 0 f" @@ -100,19 +104,70 @@ module Parsing = let _zzz = sscanf "(%%%s)" "(%hello)" + let _zzz1 = sscanf "%%(%s)" "%(hello)" let (_x1,_y1,_z1) = sscanf "%s--%s-%s" "test--this-string" - - let _f1 = trySscanf "(%%%s)" "(%hello)" - let _f2 = trySscanf "%s--%s-%s" "test--this-gg" - let _f3 = trySscanf "%f %F %g %G %e %E %c %c" "1 2.1 3.4 .3 43.2e32 0 f f" - let _f4 = trySscanf "%f %F %g %G %e %E %c %c %c" "1 2.1 3.4 .3 43.2e32 0 f f f" - let _f5 = trySscanf "%f %F %g %G %e %E %c %c %c %c" "1 2.1 3.4 .3 43.2e32 0 f f f f" - let _f6 = trySscanf "%f %F %g %G %e %E %c %c %c %c %c %c %c %c %c" "1 2.1 3.4 .3 43.2e32 0 f f f f f f f f" - let _f7 = trySscanf "%f %F %g %G %e %E %c %c %c %c %c %c %c %c %c %i" "1 2.1 3.4 .3 43.2e32 0 f f f f f f f f f 16" - let _f8 = trySscanf "%f %F %g %G %e %E %c %c %c %c %c %c %c %c %c %i %f" "1 2.1 3.4 .3 43.2e32 0 f f f f f f f f f 16 17" - + let inline (|Parsedf|_|) pf = trySscanf pf + match "ab" with Parsedf "%c" _ -> failwith "wrong match" | Parsedf "%c%c" ('a', 'b') -> () | _ -> failwith "didn't match" + match "abc" with Parsedf "%c%c" ('a', 'b') -> failwith "wrong match" | Parsedf "%c%c%c%s" ('a', 'b', 'c', "") -> () | _ -> failwith "didn't match" + match "(%hello)" with + | Parsedf "%d" _ | Parsedf "%f" _ | Parsedf "%x" _ -> failwith "wrong match" + | Parsedf "%%(%%%s)" _ | Parsedf "(%%%sa" _ | Parsedf "(%%hel%c" _ | Parsedf "%%h%cllo)" _ -> failwith "wrong match" + | Parsedf "(%%%s)" "hello" -> () + | _ -> failwith "didn't match" + match " 3" with Parsedf "% d" 3 -> () | _ -> failwith "didn't match" + match " 3" with Parsedf "% d" 3 -> () | _ -> failwith "didn't match" + match " 3" with Parsedf "% d" 3 -> () | _ -> failwith "didn't match" // em space + match "3 " with Parsedf "%-d" 3 -> () | _ -> failwith "didn't match" + match "3 " with Parsedf "%-d" 3 -> () | _ -> failwith "didn't match" + match "3 " with Parsedf "%-d" 3 -> () | _ -> failwith "didn't match" // em space + match " 3 " with Parsedf "% -d" 3 -> () | _ -> failwith "didn't match" + match " 3 " with Parsedf "% -d" 3 -> () | _ -> failwith "didn't match" + match " 3 " with Parsedf "% -d" 3 -> () | _ -> failwith "didn't match" // em space + match "test--this-gg" with Parsedf "%s--%s-%s" ("test", "this", "gg") -> () | _ -> failwith "didn't match" + match "1 2.1 3.4 .3 43.2e32 0 f f" with Parsedf "%f %F %g %G %e %E %c %c" (1f, 2.1, 3.4m, 0.3, 43.2e32, 0., 'f', 'f') -> () | _ -> failwith "didn't match" + match "1 2.1 3.4 .3 43.2e32 0 f f f" with Parsedf "%f% F %g %G %e %E %c %c %c" (1m, 2.1, 3.4, 0.3m, 43.2e32, 0., 'f', 'f', 'f') -> () | _ -> failwith "didn't match" + match "1 2.1 3.4.3 43.2e32 0 f f ff" with Parsedf "%B %F %-g%G %e %E %c %c %c%c" (1, 2.1, 3.4, 0.3, 43.2e32, 0., 'f', 'f', 'f', 'f') -> () | _ -> failwith "didn't match" + match "1 2.1 3.4.3 43.2e32 0 f f fff" with Parsedf "%o %F % g%-G %e %E %c %c %c%c%c" (1y, 2.1, 3.4, 0.3, 43.2e32, 0., 'f', 'f', 'f', 'f', 'f') -> () | _ -> failwith "didn't match" + match "1 2.1 3.4.3 43.2e32 0 f f fff16" with Parsedf "%x %F %- g%- G %e %E %c %c %c%c%c%i" (1us, 2.1, 3.4, 0.3, 43.2e32, 0., 'f', 'f', 'f', 'f', 'f', 16) -> () | _ -> failwith "didn't match" + match "1 2.1 3.4.3 43.2e32 0 f f fff16 17" with Parsedf "%X %F %g% G %e %E %c %c %c%c%c%i %f" (1s, 2.1, 3.4, 0.3, 43.2e32, 0., 'f', 'f', 'f', 'f', 'f', 16L, 17.) -> () | _ -> failwith "didn't match" + match "13 43 AA 77A" with Parsedf "%x %X %x %o%X" (0x13, 0x43, 0xAA, 0o77, 0xA) -> () | _ -> failwith "didn't match" + match "13 43 AA 77A" with Parsedf "%B%x %X %x %o%X" (0b1, 0x3, 0x43, 0xAA, 0o77, 0xA) -> () | _ -> failwith "didn't match" + match "111AAA" with Parsedf "%B%s" (0b111, "AAA") -> () | _ -> failwith "didn't match" + match "100700 100 100" with Parsedf "%B%o %x %X" (0b100, 0o700, 0x100, 0x100) -> () | _ -> failwith "didn't match" + + match "1+1-2+2-8+8" with + | Parsedf "%s%o" _ -> failwith "wrong match" + | Parsedf "%+u%+u%+d%+u%+u%+u" _ -> failwith "wrong match" + | Parsedf "%+u%+u%+d%+u%+d%o" _ -> failwith "wrong match" + | Parsedf "%+u%+u%+d%+u%-d%u" _ -> failwith "wrong match" + | Parsedf "%+u%+u%+d%+u%u%+d" _ -> failwith "wrong match" + | Parsedf "%+u%+u%+d%+u%+o%+u" _ -> failwith "wrong match" + | Parsedf "%+u%+u%+d%+u%+B%+u" _ -> failwith "wrong match" + | Parsedf "%+u%+u%+d%+u%+x%+X" _ -> failwith "wrong match" + | Parsedf "%+u%+u%+d%+u%+d%+X" (a, b, c, d, e, f) -> + areEqual (a |> box |> unbox) 1 + areEqual (b |> box |> unbox) 1 + areEqual (c |> box |> unbox) -2 + areEqual (d |> box |> unbox) 2 + areEqual (e |> box |> unbox) -8 + areEqual (f |> box |> unbox) 8 + | _ -> failwith "didn't match" + match "1+1-2+2-8+8" with Parsedf "%+-d%+d%+-d%+d%+-d%+d" (1,1,-2,2,-8,8) -> () | _ -> failwith "didn't match" + match "1+1-2+2-8+8" with Parsedf "%d+%d%d%+d%d%+d" (1,1,-2,2,-8,8) -> () | _ -> failwith "didn't match" + match "1+1-2+2-8+8" with Parsedf "%+B%+B-%+o%+o-%+X%+X" (1,1,2,2,8,8) -> () | _ -> failwith "didn't match" + match "1+1-2+2-8+8e" with Parsedf "%+f%+F%+e%+E%+g%+G%+X" (1f,1.,-2m,2f,-8.,8M,0xE) -> () | _ -> failwith "didn't match" + match "1+1-2+2-8+8e1a" with Parsedf "%+f%+F%+e%+E%+g%+G%+X" (1f,1.,-2m,2f,-8.,80M,0xA) -> () | _ -> failwith "didn't match" + match "1+1-2+2-8+8e-1a" with Parsedf "%+f%+F%+e%+E%+g%+G%+X" (1f,1.,-2m,2f,-8.,0.8M,0xA) -> () | _ -> failwith "didn't match" + match "1+1-2+2-8+8ea" with Parsedf "%+-f%+-F%+-e%+-E%+-g%+-G%+-X" (1f,1.,-2m,2f,-8.,8M,0xEA) -> () | _ -> failwith "didn't match" + let _date: (DayOfWeek * string * uint16 * int) option = trySscanf "%A %A %A %A" "Saturday March 25 1989" + let _date1: DateTime option = trySscanf "%A" "Saturday March 25 1989" + + match "12:34" with Parsedf "%A" (x: TimeSpan) -> areEqual (TimeSpan(12, 34, 0)) x | _ -> failwith "Pattern match failed" + match "12:34:56" with Parsedf "%O" (x: TimeSpan) -> areEqual (TimeSpan(12, 34, 56)) x | _ -> failwith "Pattern match failed" + match "9876-5-4 3:2:1" with Parsedf "%A" (x: DateTime) -> areEqual (DateTime(9876,5,4,3,2,1)) x | _ -> failwith "Pattern match failed" + match "9876-5-4 3:2:1 a" with Parsedf "%O %x" (x: DateTime, y) -> areEqual (DateTime(9876,5,4,3,2,1)) x; areEqual 0xA y | _ -> failwith "Pattern match failed" let x = trySscanf "%X %x" "13 43" let o = trySscanf "%o" "10" @@ -122,4 +177,4 @@ module Parsing = areEqual (Some (19, 67)) x areEqual (Some 8) o areEqual (Some 5) b - areEqual (Some (4, 64, 256, 256)) a \ No newline at end of file + areEqual (Some (4, 64, 256, 256)) a