module XParsec #if INTERACTIVE #r "System.Xml.Linq.dll" #endif open System open System.Xml.Linq open System.Collections.Generic type X = XElement type XS = XElement IEnumerator type 'a Reply = S of 'a | F type 'a Reply with static member inline FromBool b = if b then S () else F static member inline Negate r = match r with F -> S () | S _ -> F static member inline Map f r = match r with F -> F | S x -> S <| f x static member inline Put x r = match r with F -> F | S _ -> S x static member inline Choose f r = match r with F -> F | S x -> match f x with Some v -> S v | None -> F type 'a Parser = XS -> 'a Reply let inline pzero (_ : XS) = S <| Unchecked.defaultof<_> let inline preturn x (_ : XS) = S x module Operators = let inline (-!-) a b = (a : string).Contains b |> not let inline (-?-) a b = (a : string).Contains b let inline (~~) s = s |> String.IsNullOrWhiteSpace let inline (!>) x = ( ^a : (static member op_Implicit : ^b -> ^a) x ) let inline (@) (x : XElement) n = let a = x.Attribute(!> n) in if a <> null then a.Value else String.Empty let inline (@<) (x : XElement) n v = x.SetAttributeValue(!> n, v) let inline (@~) x a = ~~(x @ a) let inline (@?) x a v = (x @ a) -?- v let inline (@!) x a v = (x @ a) -!- v module Primitives = open Operators let inline (!) (p : _ Parser) e = e |> p |> Reply<_>.Negate let inline (|?>) (p : _ Parser) f e = e |> p |> Reply<_>.Choose f let inline (|>>) (p : _ Parser) f e = e |> p |> Reply<_>.Map f let inline (>>.) (p : _ Parser) (q : _ Parser) e = match p e with F -> F | S _ -> q e let inline (.>>) (p : _ Parser) (q : _ Parser) e = match p e with F -> F | S p -> q e |> Reply<_>.Put p let inline (.>>.) (p : _ Parser) (q : _ Parser) e = match p e with F -> F | S p -> q e |> Reply<_>.Map (fun q -> (p,q)) let inline (.<<.) (p : _ Parser) (q : _ Parser) e = match p e with F -> F | S p -> q e |> Reply<_>.Map (fun q -> (q,p)) let inline current (e : XS) = e.Current |> S let inline one (e : XS) = e.MoveNext() |> ignore; e |> current let inline (!@) a (e : XS) = let x = e.Current.Attribute(!> a) in if x <> null then S x.Value else F let inline (!@+) a (e : XS) = (e.Current @~ a |> not) |> Reply<_>.FromBool let inline (@~?) a v (e : XS) = (e.Current @? a <| v) |> Reply<_>.FromBool let inline (@~!) a v (e : XS) = (e.Current @! a <| v) |> Reply<_>.FromBool module Test = open Operators open Primitives (* *) let x = "" |> XElement.Parse let y = "" |> XElement.Parse let o x = ([|x|] |> Array.toSeq).GetEnumerator() let e xs = (xs |> List.toSeq).GetEnumerator() let inline sbbox s = (s:string).Split [| ' ' |] |> Seq.map float |> Seq.toList let inline l x = x |> sbbox |> List.head // 1 = < font=?'Bold' bbox=F'l ..' s > ; < ~s >* // 2 = < font=!'Bold' bbox=F'l ..' s=?'(' > | [ 1.l < 2.l ] ; < ~s >* // 3 = < font=!'Bold' bbox=F'l ..' s=?')' > | [ 1.l < 3.l ] let ss : _ Parser = one .>>. ("font" @~? "Bold" >>. !@+ "s" >>. !@ "bbox" |>> l) let so : _ Parser = one .>>. ("font" @~! "Bold" >>. "s" @~? "(" >>. !@ "bbox" |>> l) let sc : _ Parser = one .>>. ("font" @~! "Bold" >>. "s" @~? ")" >>. !@ "bbox" |>> l) // let ss : _ Parser = one .>>. ("font" @~? "Bold" >>. !@+ "s" >>. !@ "bbox" |>> l) let oc : _ Parser = one .>>. ("font" @~! "Bold" >>. "s" @~? "(" >>. "s" @~? ")" >>. !@ "bbox" |>> l) let inline (|?>) (p : _ Parser) f e = e |> p |> Reply<_>.Choose f let si : _ Parser = ss .>>. oc |?> fun ((c1,l1),(c2,l2)) -> if l1 < l2 then Some (c1,c2) else None open Operators open Primitives open Test