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