{-# LANGUAGE ConstraintKinds       #-}
{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude     #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeFamilies          #-}

-- | Wrapper over the "HaXPath" module which supports stronger type gurantuees such that XPaths must be valid with
-- respect to the document schema. This module should be used as a qualified import.
module HaXPath.Schematic (
  -- * Basic data types
  ToNonSchematic(..),
  Bool',
  Bool,
  false,
  true,
  Number',
  Number,
  Text',
  Text,
  text,
  -- * Nodes
  Node',
  Node,
  IsNode(..),
  namedNode,
  DocumentRoot',
  root',
  DocumentRoot,
  root,
  Attributes,
  AttributesUsed,
  IsAttribute(..),
  at,
  -- * Basic combinators
  not,
  (&&.),
  (||.),
  (=.),
  (/=.),
  (<.),
  (<=.),
  (>.),
  (>=.),
  contains,
  doesNotContain,
  position,
  -- * Paths
  Path',
  Path,
  AbsolutePath',
  AbsolutePath,
  RelativePath',
  RelativePath,
  PathLike,
  SelectNode,
  ReturnNode,
  Relatives,
  show',
  show,
  -- * Axes
  Axis,
  Ancestor,
  ancestor,
  Child,
  child,
  Descendant,
  descendant,
  DescendantOrSelf,
  descendantOrSelf,
  Following,
  following,
  FollowingSibling,
  followingSibling,
  Parent,
  parent,
  -- * Path combinators
  (/.),
  (//.),
  (#),
  count,
  -- * Utilities
  Member
) where

import           Data.HList.CommonMain (HMember)
import           Data.Proxy            (Proxy (Proxy))
import qualified Data.String           as S
import           Data.Kind             (Type)
import qualified HaXPath               as X
import           Prelude               (($), (*), (+), (.), (<$>))
import qualified Prelude               as P

-- | Type level membership constraint indicating that the type @x@ is a member of the type-level list @xs@.
type Member x xs = HMember x xs 'P.True

-- | The type of boolean expressions which depend on the value of the attribute(s) @as@ and can be showed as the string
-- type @s@.
newtype Bool' (as :: [Type]) s = Bool { forall (as :: [*]) s. Bool' as s -> Bool' s
unBool :: X.Bool' s }

-- | 'Bool'' specialised so it can be shown as 'P.String'.
type Bool as = Bool' as P.String

-- | XPath @true()@ value.
true :: S.IsString s => Bool' as s
true :: forall s (as :: [*]). IsString s => Bool' as s
true = forall (as :: [*]) s. Bool' s -> Bool' as s
Bool forall s. IsString s => Bool' s
X.true

-- | XPath @false()@ value.
false :: S.IsString s => Bool' as s
false :: forall s (as :: [*]). IsString s => Bool' as s
false = forall (as :: [*]) s. Bool' s -> Bool' as s
Bool forall s. IsString s => Bool' s
X.false

-- | The type of simple numeric expressions which depend on the value of the attribute(s) @as@ and can be showed as the
-- string type @s@.
newtype Number' (as :: [Type]) s = Number { forall (as :: [*]) s. Number' as s -> Number' s
unNumber :: X.Number' s }

-- | 'Number'' specialised so it can be shown as 'P.String'
type Number as = Number' as P.String

-- | The type of simple text expressions which depend on the value of the attribute(s) @as@ and can be showed as the
-- string type @s@.
newtype Text' (as :: [Type]) s = Text { forall (as :: [*]) s. Text' as s -> Text' s
unText :: X.Text' s }

-- | 'Text'' specialised so it can be shown as 'P.String'
type Text as = Text' as P.String

-- | The type of path expressions which can be showed as the string type @s@ and are formed by these steps:
--
-- 1. Starting from the context @c@ and moving through the given @axis@.
-- 1. Selecting node(s) of type @n@.
-- 1. Performing zero or more location steps.
-- 1. Finally returning the node(s) of type @rn@.
newtype Path' c axis n rn s = Path { forall c axis n rn s. Path' c axis n rn s -> Path' c s
unPath :: X.Path' c s }

-- | 'Path'' specialised so it can be shown as 'P.String'.
type Path c axis n rn = Path' c axis n rn P.String

-- | An XPath beginning from the document root for the schema @sc@, returning a node of type @rn@.
type AbsolutePath' sc rn = Path' X.RootContext Self (DocumentRoot sc) rn

-- | 'AbsolutePath'' specialised so it can be shown as 'P.String'
type AbsolutePath sc rn = (AbsolutePath' sc rn) P.String

-- | An XPath beginning from the current context.
type RelativePath' = Path' X.CurrentContext

-- | 'RelativePath'' specialised so it can be shown as 'P.String'
type RelativePath axis n rn = RelativePath' axis n rn P.String

instance S.IsString s => S.IsString (Text' as s) where
  fromString :: String -> Text' as s
fromString = forall (as :: [*]) s. Text' s -> Text' as s
Text forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IsString a => String -> a
S.fromString

-- | Type class for conversion from a schematic value to its underlying, non-schematic version.
class ToNonSchematic t where
  -- | Corresponding non-schematic type.
  type NonSchematic t

  -- | Convert from the schematic to the non-schematic version.
  toNonSchematic :: t -> NonSchematic t

instance ToNonSchematic (Bool' as s) where
  type NonSchematic (Bool' as s) = X.Bool' s

  toNonSchematic :: Bool' as s -> NonSchematic (Bool' as s)
toNonSchematic = forall (as :: [*]) s. Bool' as s -> Bool' s
unBool

instance ToNonSchematic (Number' as s) where
  type NonSchematic (Number' as s) = X.Number' s

  toNonSchematic :: Number' as s -> NonSchematic (Number' as s)
toNonSchematic = forall (as :: [*]) s. Number' as s -> Number' s
unNumber

instance ToNonSchematic (Text' as s) where
  type NonSchematic (Text' as s) = X.Text' s

  toNonSchematic :: Text' as s -> NonSchematic (Text' as s)
toNonSchematic = forall (as :: [*]) s. Text' as s -> Text' s
unText

instance ToNonSchematic (Path' c axis n rn s) where
  type NonSchematic (Path' c axis n rn s) = X.Path' c s

  toNonSchematic :: Path' c axis n rn s -> NonSchematic (Path' c axis n rn s)
toNonSchematic = forall c axis n rn s. Path' c axis n rn s -> Path' c s
unPath

instance ToNonSchematic (Node' n s) where
  type NonSchematic (Node' n s) = X.Node' s

  toNonSchematic :: Node' n s -> NonSchematic (Node' n s)
toNonSchematic = forall n s. Node' n s -> Node' s
unNode

instance ToNonSchematic (DocumentRoot' sc s) where
  type NonSchematic (DocumentRoot' sc s) = X.DocumentRoot' s

  toNonSchematic :: DocumentRoot' sc s -> NonSchematic (DocumentRoot' sc s)
toNonSchematic = forall sc s. DocumentRoot' sc s -> DocumentRoot' s
unDocumentRoot

-- This type class is not exposed as this would allow for arbitrary, non-schematic expression to be converted to
-- a schematic version when the underlying expression does not actually conform to the schema.
class FromNonSchematic x t where
  fromNonSchematic :: x -> t

instance FromNonSchematic (X.Bool' s) (Bool' as s) where
  fromNonSchematic :: Bool' s -> Bool' as s
fromNonSchematic = forall (as :: [*]) s. Bool' s -> Bool' as s
Bool

instance FromNonSchematic (X.Number' s) (Number' as s) where
  fromNonSchematic :: Number' s -> Number' as s
fromNonSchematic = forall (as :: [*]) s. Number' s -> Number' as s
Number

instance FromNonSchematic (X.Text' s) (Text' as s) where
  fromNonSchematic :: Text' s -> Text' as s
fromNonSchematic = forall (as :: [*]) s. Text' s -> Text' as s
Text

instance FromNonSchematic (X.Path' c s) (Path' c axis n rn s) where
  fromNonSchematic :: Path' c s -> Path' c axis n rn s
fromNonSchematic = forall c axis n rn s. Path' c s -> Path' c axis n rn s
Path

instance FromNonSchematic (X.Node' s) (Node' n s) where
  fromNonSchematic :: Node' s -> Node' n s
fromNonSchematic = forall n s. Node' s -> Node' n s
Node

instance FromNonSchematic (X.DocumentRoot' s) (DocumentRoot' sc s) where
  fromNonSchematic :: DocumentRoot' s -> DocumentRoot' sc s
fromNonSchematic = forall sc s. DocumentRoot' s -> DocumentRoot' sc s
DocumentRoot

-- | The XPath @text()@ function.
text :: forall (as :: [Type]) s. S.IsString s => Text' as s
text :: forall (as :: [*]) s. IsString s => Text' as s
text = forall (as :: [*]) s. Text' s -> Text' as s
Text forall s. IsString s => Text' s
X.text

-- | The XPath @contains()@ function.
contains :: S.IsString s => Text' as s -> Text' as s -> Bool' as s
contains :: forall s (as :: [*]).
IsString s =>
Text' as s -> Text' as s -> Bool' as s
contains = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall s. IsString s => Text' s -> Text' s -> Bool' s
X.contains

-- | The opposite of 'contains'.
doesNotContain :: S.IsString s => Text' as s -> Text' as s -> Bool' as s
doesNotContain :: forall s (as :: [*]).
IsString s =>
Text' as s -> Text' as s -> Bool' as s
doesNotContain = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall s. IsString s => Text' s -> Text' s -> Bool' s
X.doesNotContain

-- | The XPath @count()@ function.
count :: (X.IsContext c, S.IsString s) => Path' c axis n rn s -> Number' as s
count :: forall c s axis n rn (as :: [*]).
(IsContext c, IsString s) =>
Path' c axis n rn s -> Number' as s
count = forall (as :: [*]) s. Number' s -> Number' as s
Number forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall c s. (IsContext c, IsString s) => Path' c s -> Number' s
X.count forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall c axis n rn s. Path' c axis n rn s -> Path' c s
unPath

-- | The XPath @position()@ function.
position :: S.IsString s => Number' as s
position :: forall s (as :: [*]). IsString s => Number' as s
position = forall (as :: [*]) s. Number' s -> Number' as s
Number forall s. IsString s => Number' s
X.position

unary :: (ToNonSchematic t, ToNonSchematic u, FromNonSchematic (NonSchematic u) u) =>
         (NonSchematic t -> NonSchematic u) ->
          t ->
          u
unary :: forall t u.
(ToNonSchematic t, ToNonSchematic u,
 FromNonSchematic (NonSchematic u) u) =>
(NonSchematic t -> NonSchematic u) -> t -> u
unary NonSchematic t -> NonSchematic u
op t
x = forall x t. FromNonSchematic x t => x -> t
fromNonSchematic (NonSchematic t -> NonSchematic u
op forall a b. (a -> b) -> a -> b
$ forall t. ToNonSchematic t => t -> NonSchematic t
toNonSchematic t
x)

binary :: (ToNonSchematic t, ToNonSchematic u, ToNonSchematic v, FromNonSchematic (NonSchematic v) v) =>
          (NonSchematic t -> NonSchematic u -> NonSchematic v) ->
          t ->
          u ->
          v
binary :: forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary NonSchematic t -> NonSchematic u -> NonSchematic v
op t
x u
y = forall x t. FromNonSchematic x t => x -> t
fromNonSchematic (forall t. ToNonSchematic t => t -> NonSchematic t
toNonSchematic t
x NonSchematic t -> NonSchematic u -> NonSchematic v
`op` forall t. ToNonSchematic t => t -> NonSchematic t
toNonSchematic u
y)

-- | The XPath @or@ operator.
(||.) :: S.IsString s => Bool' as s -> Bool' as s -> Bool' as s
||. :: forall s (as :: [*]).
IsString s =>
Bool' as s -> Bool' as s -> Bool' as s
(||.) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall s. IsString s => Bool' s -> Bool' s -> Bool' s
(X.||.)
infixr 2 ||.

-- | The XPath @and@ operator.
(&&.) :: S.IsString s => Bool' as s -> Bool' as s -> Bool' as s
&&. :: forall s (as :: [*]).
IsString s =>
Bool' as s -> Bool' as s -> Bool' as s
(&&.) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall s. IsString s => Bool' s -> Bool' s -> Bool' s
(X.&&.)
infixr 3 &&.

-- | The XPath @not()@ function.
not :: S.IsString s => Bool' as s -> Bool' as s
not :: forall s (as :: [*]). IsString s => Bool' as s -> Bool' as s
not = forall (as :: [*]) s. Bool' s -> Bool' as s
Bool forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s. IsString s => Bool' s -> Bool' s
X.not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (as :: [*]) s. Bool' as s -> Bool' s
unBool

-- | Access the value of the attribute @a@ of a node (equivalent to XPath's @\@@).
at :: (IsAttribute a, Member a as, S.IsString s) => proxy a -> Text' as s
at :: forall a (as :: [*]) s (proxy :: * -> *).
(IsAttribute a, Member a as, IsString s) =>
proxy a -> Text' as s
at proxy a
proxy = forall (as :: [*]) s. Text' s -> Text' as s
Text (forall s. s -> Text' s
X.at forall a b. (a -> b) -> a -> b
$ forall a s (proxy :: * -> *).
(IsAttribute a, IsString s) =>
proxy a -> s
attributeName proxy a
proxy)

-- | Type class for node attributes.
class IsAttribute a where
  -- | Return the name of the attribute.
  attributeName :: S.IsString s => proxy a -> s

-- | Type family which returns the node attribute(s) used within a given expression.
type family AttributesUsed t where
  AttributesUsed (Bool' as s) = as
  AttributesUsed (Text' as s) = as
  AttributesUsed (Number' as s) = as

-- | The XPath @=@ operator.
(=.) :: (ToNonSchematic t,
         X.Eq (NonSchematic t),
         S.IsString (X.Showed (NonSchematic t))) =>
         t -> t -> Bool' (AttributesUsed t) (X.Showed (NonSchematic t))
=. :: forall t.
(ToNonSchematic t, Eq (NonSchematic t),
 IsString (Showed (NonSchematic t))) =>
t -> t -> Bool' (AttributesUsed t) (Showed (NonSchematic t))
(=.) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall a. (Eq a, IsString (Showed a)) => a -> a -> Bool' (Showed a)
(X.=.)
infix 4 =.

-- | The XPath @!=@ operator.
(/=.) :: (ToNonSchematic t,
          X.Eq (NonSchematic t),
          S.IsString (X.Showed (NonSchematic t))) =>
          t -> t -> Bool' (AttributesUsed t) (X.Showed (NonSchematic t))
/=. :: forall t.
(ToNonSchematic t, Eq (NonSchematic t),
 IsString (Showed (NonSchematic t))) =>
t -> t -> Bool' (AttributesUsed t) (Showed (NonSchematic t))
(/=.) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall a. (Eq a, IsString (Showed a)) => a -> a -> Bool' (Showed a)
(X./=.)
infix 4 /=.

-- | The XPath @<@ operator.
(<.) :: (ToNonSchematic t,
         X.Ord (NonSchematic t),
         S.IsString (X.Showed (NonSchematic t))) =>
         t -> t -> Bool' (AttributesUsed t) (X.Showed (NonSchematic t))
<. :: forall t.
(ToNonSchematic t, Ord (NonSchematic t),
 IsString (Showed (NonSchematic t))) =>
t -> t -> Bool' (AttributesUsed t) (Showed (NonSchematic t))
(<.) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall a.
(Ord a, IsString (Showed a)) =>
a -> a -> Bool' (Showed a)
(X.<.)
infix 4 <.

-- | The XPath @<=@ operator.
(<=.) :: (ToNonSchematic t,
         X.Ord (NonSchematic t),
         S.IsString (X.Showed (NonSchematic t))) =>
         t -> t -> Bool' (AttributesUsed t) (X.Showed (NonSchematic t))
<=. :: forall t.
(ToNonSchematic t, Ord (NonSchematic t),
 IsString (Showed (NonSchematic t))) =>
t -> t -> Bool' (AttributesUsed t) (Showed (NonSchematic t))
(<=.) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall a.
(Ord a, IsString (Showed a)) =>
a -> a -> Bool' (Showed a)
(X.<=.)
infix 4 <=.

-- | The XPath @>@ operator.
(>.) :: (ToNonSchematic t,
         X.Ord (NonSchematic t),
         S.IsString (X.Showed (NonSchematic t))) =>
         t -> t -> Bool' (AttributesUsed t) (X.Showed (NonSchematic t))
>. :: forall t.
(ToNonSchematic t, Ord (NonSchematic t),
 IsString (Showed (NonSchematic t))) =>
t -> t -> Bool' (AttributesUsed t) (Showed (NonSchematic t))
(>.) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall a.
(Ord a, IsString (Showed a)) =>
a -> a -> Bool' (Showed a)
(X.>.)
infix 4 >.

-- | The XPath @>=@ operator.
(>=.) :: (ToNonSchematic t,
         X.Ord (NonSchematic t),
         S.IsString (X.Showed (NonSchematic t))) =>
         t -> t -> Bool' (AttributesUsed t) (X.Showed (NonSchematic t))
>=. :: forall t.
(ToNonSchematic t, Ord (NonSchematic t),
 IsString (Showed (NonSchematic t))) =>
t -> t -> Bool' (AttributesUsed t) (Showed (NonSchematic t))
(>=.) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall a.
(Ord a, IsString (Showed a)) =>
a -> a -> Bool' (Showed a)
(X.>=.)
infix 4 >=.

instance S.IsString s => P.Num (Number' a s) where
  + :: Number' a s -> Number' a s -> Number' a s
(+) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall a. Num a => a -> a -> a
(+)
  * :: Number' a s -> Number' a s -> Number' a s
(*) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall a. Num a => a -> a -> a
(*)
  abs :: Number' a s -> Number' a s
abs = forall t u.
(ToNonSchematic t, ToNonSchematic u,
 FromNonSchematic (NonSchematic u) u) =>
(NonSchematic t -> NonSchematic u) -> t -> u
unary forall a. Num a => a -> a
P.abs
  signum :: Number' a s -> Number' a s
signum = forall t u.
(ToNonSchematic t, ToNonSchematic u,
 FromNonSchematic (NonSchematic u) u) =>
(NonSchematic t -> NonSchematic u) -> t -> u
unary forall a. Num a => a -> a
P.signum
  fromInteger :: Integer -> Number' a s
fromInteger = forall (as :: [*]) s. Number' s -> Number' as s
Number forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Num a => Integer -> a
P.fromInteger
  negate :: Number' a s -> Number' a s
negate = forall t u.
(ToNonSchematic t, ToNonSchematic u,
 FromNonSchematic (NonSchematic u) u) =>
(NonSchematic t -> NonSchematic u) -> t -> u
unary forall a. Num a => a -> a
P.negate

-- | Type of an XPath node of type @n@ which can be showed as the string type @s@.
newtype Node' (n :: Type) s = Node { forall n s. Node' n s -> Node' s
unNode :: X.Node' s }

-- | 'Node'' specialised so it can be shown as 'P.String'.
type Node n = Node' n P.String

-- | Type class of node types.
class IsNode n where
  -- | Return the name of the node.
  nodeName :: S.IsString s => proxy n -> s

-- | Create a node expression of the given type.
namedNode :: forall n s. (IsNode n, S.IsString s) => Node' n s
namedNode :: forall n s. (IsNode n, IsString s) => Node' n s
namedNode = forall n s. Node' s -> Node' n s
Node forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s. IsString s => s -> Node' s
X.namedNode forall a b. (a -> b) -> a -> b
$ forall n s (proxy :: * -> *).
(IsNode n, IsString s) =>
proxy n -> s
nodeName (forall {k} (t :: k). Proxy t
Proxy :: Proxy n)

-- | Type family to constrain the possible relatives of nodes of type @n@ through the given axis.
type family Relatives n axis :: [Type]

-- | Type of the XPath @ancestor::@ axis.
data Ancestor

-- | Type of the XPath @child::@ axis.
data Child

-- | Type of the XPath @descendant::@ axis.
data Descendant

-- | Type of the XPath @descendant-or-self::@ axis.
data DescendantOrSelf

-- | Type of the XPath @following::@ axis.
data Following

-- | Type of the XPath @following-sibling::@ axis.
data FollowingSibling

-- | Type of the XPath @parent::@ axis.
data Parent

-- | Type of the XPath @self::@ axis.
data Self

type instance Relatives n Self = '[n]

-- | Type of the document root for the schema @sc@ which can be showed as the string type @s@. Useful in forming an
-- XPaths which must begin from the root.
newtype DocumentRoot' sc s = DocumentRoot { forall sc s. DocumentRoot' sc s -> DocumentRoot' s
unDocumentRoot :: X.DocumentRoot' s }

-- | 'DocumentRoot'' specialised so it can be shown as 'P.String'.
type DocumentRoot sc = DocumentRoot' sc P.String

type instance Relatives (DocumentRoot' sc s) Ancestor = '[]
type instance Relatives (DocumentRoot' sc s) Following = '[]
type instance Relatives (DocumentRoot' sc s) FollowingSibling = '[]
type instance Relatives (DocumentRoot' sc s) Parent = '[]

-- | The root of the document for the schema @s@.
root' :: DocumentRoot' sc s
root' :: forall sc s. DocumentRoot' sc s
root' = forall sc s. DocumentRoot' s -> DocumentRoot' sc s
DocumentRoot forall s. DocumentRoot' s
X.root'

-- | 'root'' specialised so it can be shown as 'P.String'.
root :: DocumentRoot sc
root :: forall sc. DocumentRoot sc
root = forall sc s. DocumentRoot' sc s
root'

-- | Type family to infer of the axis of a location step based on the type of the step.
type family Axis p where
  Axis (Path' c axis n rn s) = axis
  Axis (Node' n s) = Child
  Axis (DocumentRoot' sc s) = Self

-- | Type family to infer the type of the node selected by the first location step in a path.
type family SelectNode p where
  SelectNode (Path' c axis n rn s) = n
  SelectNode (Node' n s) = n
  SelectNode (DocumentRoot' sc s) = DocumentRoot' sc s

-- | Type family to infer the node selected by the last location step in a path.
type family ReturnNode p where
  ReturnNode (Path' c axis n rn s) = rn
  ReturnNode (Node' n s) = n
  ReturnNode (DocumentRoot' sc s) = DocumentRoot' sc s

-- | Constraint for types from which a path can be inferred.
type PathLike p = (ToNonSchematic p, X.PathLike (NonSchematic p))

-- | The XPath @/@ operator.
(/.) :: (Member (SelectNode q) (Relatives (ReturnNode p) (Axis q)),
          PathLike p,
          PathLike q,
          X.SlashOperator (NonSchematic p) (NonSchematic q)) =>
          p ->
          q ->
          Path' (X.Context (NonSchematic p)) (Axis p) (SelectNode p) (ReturnNode q) (X.Showed (NonSchematic q))
/. :: forall q p.
(Member (SelectNode q) (Relatives (ReturnNode p) (Axis q)),
 PathLike p, PathLike q,
 SlashOperator (NonSchematic p) (NonSchematic q)) =>
p
-> q
-> Path'
     (Context (NonSchematic p))
     (Axis p)
     (SelectNode p)
     (ReturnNode q)
     (Showed (NonSchematic q))
(/.) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall p q.
SlashOperator p q =>
p -> q -> Path' (Context p) (Showed q)
(X./.)
infixl 8 /.

-- | The XPath @//@ operator.
(//.) :: (Member (SelectNode q) (Relatives (ReturnNode p) Descendant),
          PathLike p,
          PathLike q,
          X.DoubleSlashOperator (NonSchematic p) (NonSchematic q)) =>
          p ->
          q ->
          Path' (X.Context (NonSchematic p)) (Axis p) (SelectNode p) (ReturnNode q) (X.Showed (NonSchematic q))
//. :: forall q p.
(Member (SelectNode q) (Relatives (ReturnNode p) Descendant),
 PathLike p, PathLike q,
 DoubleSlashOperator (NonSchematic p) (NonSchematic q)) =>
p
-> q
-> Path'
     (Context (NonSchematic p))
     (Axis p)
     (SelectNode p)
     (ReturnNode q)
     (Showed (NonSchematic q))
(//.) = forall t u v.
(ToNonSchematic t, ToNonSchematic u, ToNonSchematic v,
 FromNonSchematic (NonSchematic v) v) =>
(NonSchematic t -> NonSchematic u -> NonSchematic v) -> t -> u -> v
binary forall p q.
DoubleSlashOperator p q =>
p -> q -> Path' (Context p) (Showed q)
(X.//.)
infixl 8 //.

-- | Type family which contrains the possible attributes a node of type @n@ may have.
type family Attributes n :: [Type]

-- | Filter the path-like expression using the given predicate(s). The predicates must only make use of the attributes
-- of the type of node selected by the path, otherwise it will not type check.
(#) :: (PathLike p,
        ToNonSchematic p,
        FromNonSchematic (NonSchematic p) p,
        X.Filterable (NonSchematic p)) =>
        p -> [Bool' (Attributes (ReturnNode p)) (X.Showed (NonSchematic p))] -> p
p
p # :: forall p.
(PathLike p, ToNonSchematic p, FromNonSchematic (NonSchematic p) p,
 Filterable (NonSchematic p)) =>
p
-> [Bool' (Attributes (ReturnNode p)) (Showed (NonSchematic p))]
-> p
# [Bool' (Attributes (ReturnNode p)) (Showed (NonSchematic p))]
preds = forall x t. FromNonSchematic x t => x -> t
fromNonSchematic forall a b. (a -> b) -> a -> b
$ forall t. ToNonSchematic t => t -> NonSchematic t
toNonSchematic p
p forall p s. (Filterable p, Showed p ~ s) => p -> [Bool' s] -> p
X.# (forall t. ToNonSchematic t => t -> NonSchematic t
toNonSchematic forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Bool' (Attributes (ReturnNode p)) (Showed (NonSchematic p))]
preds)
infixl 9 #

-- | The XPath @ancestor::@ axis.
ancestor :: Node' n s -> Path' X.CurrentContext Ancestor n n s
ancestor :: forall n s. Node' n s -> Path' CurrentContext Ancestor n n s
ancestor (Node Node' s
n) = forall c axis n rn s. Path' c s -> Path' c axis n rn s
Path forall a b. (a -> b) -> a -> b
$ forall s. Node' s -> Path' CurrentContext s
X.ancestor Node' s
n

-- | The XPath @child::@ axis.
child :: Node' n s -> Path' X.CurrentContext Child n n s
child :: forall n s. Node' n s -> Path' CurrentContext Child n n s
child (Node Node' s
n) = forall c axis n rn s. Path' c s -> Path' c axis n rn s
Path forall a b. (a -> b) -> a -> b
$ forall s. Node' s -> Path' CurrentContext s
X.child Node' s
n

-- | The XPath @descendant::@ axis.
descendant :: Node' n s -> Path' X.CurrentContext Descendant n n s
descendant :: forall n s. Node' n s -> Path' CurrentContext Descendant n n s
descendant (Node Node' s
n) = forall c axis n rn s. Path' c s -> Path' c axis n rn s
Path forall a b. (a -> b) -> a -> b
$ forall s. Node' s -> Path' CurrentContext s
X.descendant Node' s
n

-- | The XPath @descendant-or-self::@ axis.
descendantOrSelf :: Node' n s -> Path' X.CurrentContext DescendantOrSelf n n s
descendantOrSelf :: forall n s.
Node' n s -> Path' CurrentContext DescendantOrSelf n n s
descendantOrSelf (Node Node' s
n) = forall c axis n rn s. Path' c s -> Path' c axis n rn s
Path forall a b. (a -> b) -> a -> b
$ forall s. Node' s -> Path' CurrentContext s
X.descendantOrSelf Node' s
n

-- | The XPath @following::@ axis.
following :: Node' n s -> Path' X.CurrentContext Following n n s
following :: forall n s. Node' n s -> Path' CurrentContext Following n n s
following (Node Node' s
n) = forall c axis n rn s. Path' c s -> Path' c axis n rn s
Path forall a b. (a -> b) -> a -> b
$ forall s. Node' s -> Path' CurrentContext s
X.following Node' s
n

-- | The XPath @following-sibling::@ axis.
followingSibling :: Node' n s -> Path' X.CurrentContext FollowingSibling n n s
followingSibling :: forall n s.
Node' n s -> Path' CurrentContext FollowingSibling n n s
followingSibling (Node Node' s
n) = forall c axis n rn s. Path' c s -> Path' c axis n rn s
Path forall a b. (a -> b) -> a -> b
$ forall s. Node' s -> Path' CurrentContext s
X.followingSibling Node' s
n

-- | The XPath @parent::@ axis.
parent :: Node' n s -> Path' X.CurrentContext Parent n n s
parent :: forall n s. Node' n s -> Path' CurrentContext Parent n n s
parent (Node Node' s
n) = forall c axis n rn s. Path' c s -> Path' c axis n rn s
Path forall a b. (a -> b) -> a -> b
$ forall s. Node' s -> Path' CurrentContext s
X.parent Node' s
n

-- | Display an XPath expression. This is useful for sending the XPath expression to a separate XPath evaluator e.g.
-- a web browser.
show' :: (PathLike p,
          X.IsExpression (NonSchematic p),
          P.Monoid (X.Showed (NonSchematic p)),
          S.IsString (X.Showed (NonSchematic p)),
          P.Show (X.Showed (NonSchematic p))) =>
          p -> X.Showed (NonSchematic p)
show' :: forall p.
(PathLike p, IsExpression (NonSchematic p),
 Monoid (Showed (NonSchematic p)),
 IsString (Showed (NonSchematic p)),
 Show (Showed (NonSchematic p))) =>
p -> Showed (NonSchematic p)
show' = forall p.
(PathLike p, IsExpression p, Monoid (Showed p),
 IsString (Showed p), Show (Showed p)) =>
p -> Showed p
X.show' forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. ToNonSchematic t => t -> NonSchematic t
toNonSchematic

-- | 'show'' specialised to generate 'P.String's.
show :: (PathLike p,
        X.Showed (NonSchematic p) ~ P.String,
        X.IsExpression (NonSchematic p)) =>
        p -> P.String
show :: forall p.
(PathLike p, Showed (NonSchematic p) ~ String,
 IsExpression (NonSchematic p)) =>
p -> String
show = forall p.
(PathLike p, IsExpression (NonSchematic p),
 Monoid (Showed (NonSchematic p)),
 IsString (Showed (NonSchematic p)),
 Show (Showed (NonSchematic p))) =>
p -> Showed (NonSchematic p)
show'