{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE BangPatterns #-}
{-# OPTIONS_HADDOCK hide #-}
module Text.HTML.Scalpel.Internal.Select (
SelectContext (..)
, TagSpec
, TagInfo (..)
, select
, tagsToSpec
) where
import Text.HTML.Scalpel.Internal.Select.Types
import Control.Applicative ((<$>), (<|>))
import Data.Maybe (catMaybes, isJust, fromJust, fromMaybe)
import qualified Data.Map.Strict as Map
import qualified Data.Text as T
import qualified Data.Tree as Tree
import qualified Data.Vector as Vector
import qualified Text.HTML.TagSoup as TagSoup
import qualified Text.StringLike as TagSoup
type Index = Int
type Name = Maybe T.Text
type CloseOffset = Maybe Index
data Span = Span !Int !Int
type TagForest = Tree.Forest Span
data TagInfo str = TagInfo {
forall str. TagInfo str -> Tag str
infoTag :: !(TagSoup.Tag str)
, forall str. TagInfo str -> Name
infoName :: !Name
, forall str. TagInfo str -> CloseOffset
infoOffset :: !CloseOffset
}
type TagVector str = Vector.Vector (TagInfo str)
data SelectContext = SelectContext {
SelectContext -> Index
ctxPosition :: !Index
, SelectContext -> Bool
ctxInChroot :: !Bool
}
type TagSpec str = (TagVector str, TagForest, SelectContext)
select :: (TagSoup.StringLike str)
=> Selector -> TagSpec str -> [TagSpec str]
select :: forall str.
StringLike str =>
Selector -> TagSpec str -> [TagSpec str]
select Selector
s TagSpec str
tagSpec = [TagSpec str]
newSpecs
where
(MkSelector [(SelectNode, SelectSettings)]
nodes) = Selector
s
newSpecs :: [TagSpec str]
newSpecs =
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith forall {a} {b} {c}. Index -> (a, b, c) -> (a, b, SelectContext)
applyPosition [Index
0..] (forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes [(SelectNode, SelectSettings)]
nodes TagSpec str
tagSpec TagSpec str
tagSpec [])
applyPosition :: Index -> (a, b, c) -> (a, b, SelectContext)
applyPosition Index
p (a
tags, b
f, c
_) = (a
tags, b
f, Index -> Bool -> SelectContext
SelectContext Index
p Bool
True)
tagsToSpec :: forall str. (TagSoup.StringLike str)
=> [TagSoup.Tag str] -> TagSpec str
tagsToSpec :: forall str. StringLike str => [Tag str] -> TagSpec str
tagsToSpec [Tag str]
tags = (TagVector str
vector, TagForest
tree, SelectContext
ctx)
where
vector :: TagVector str
vector = forall str. StringLike str => [Tag str] -> TagVector str
tagsToVector [Tag str]
tags
tree :: TagForest
tree = forall str. StringLike str => TagVector str -> TagForest
vectorToTree TagVector str
vector
ctx :: SelectContext
ctx = Index -> Bool -> SelectContext
SelectContext Index
0 Bool
False
tagsToVector :: forall str. (TagSoup.StringLike str)
=> [TagSoup.Tag str] -> TagVector str
tagsToVector :: forall str. StringLike str => [Tag str] -> TagVector str
tagsToVector [Tag str]
tags = let indexed :: [(Tag str, Index)]
indexed = forall a b. [a] -> [b] -> [(a, b)]
zip [Tag str]
tags [Index
0..]
total :: Index
total = forall (t :: * -> *) a. Foldable t => t a -> Index
length [(Tag str, Index)]
indexed
unsorted :: [(Index, TagInfo str)]
unsorted = [(Tag str, Index)]
-> Map Text [(Tag str, Index)] -> [(Index, TagInfo str)]
go [(Tag str, Index)]
indexed forall k a. Map k a
Map.empty
emptyVec :: Vector a
emptyVec = forall a. Index -> a -> Vector a
Vector.replicate Index
total forall a. HasCallStack => a
undefined
in forall {a}. Vector a
emptyVec forall a. Vector a -> [(Index, a)] -> Vector a
Vector.// [(Index, TagInfo str)]
unsorted
where
go :: [(TagSoup.Tag str, Index)]
-> Map.Map T.Text [(TagSoup.Tag str, Index)]
-> [(Index, TagInfo str)]
go :: [(Tag str, Index)]
-> Map Text [(Tag str, Index)] -> [(Index, TagInfo str)]
go [] Map Text [(Tag str, Index)]
state =
forall a b. (a -> b) -> [a] -> [b]
map (\(Tag str
t, Index
i) -> (Index
i, forall str. Tag str -> Name -> CloseOffset -> TagInfo str
TagInfo Tag str
t (forall {str}. StringLike str => Tag str -> Name
maybeName Tag str
t) forall a. Maybe a
Nothing))
forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
forall a b. (a -> b) -> a -> b
$ forall k a. Map k a -> [a]
Map.elems Map Text [(Tag str, Index)]
state
where
maybeName :: Tag str -> Name
maybeName Tag str
t | forall str. Tag str -> Bool
TagSoup.isTagOpen Tag str
t = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall str. StringLike str => Tag str -> Text
getTagName Tag str
t
| forall str. Tag str -> Bool
TagSoup.isTagClose Tag str
t = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall str. StringLike str => Tag str -> Text
getTagName Tag str
t
| Bool
otherwise = forall a. Maybe a
Nothing
go ((Tag str
tag, Index
index) : [(Tag str, Index)]
xs) Map Text [(Tag str, Index)]
state
| forall str. Tag str -> Bool
TagSoup.isTagClose Tag str
tag =
let maybeOpen :: Maybe (Tag str, Index)
maybeOpen = forall a. [a] -> a
head forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
tagName Map Text [(Tag str, Index)]
state
state' :: Map Text [(Tag str, Index)]
state' = forall k a.
Ord k =>
(Maybe a -> Maybe a) -> k -> Map k a -> Map k a
Map.alter forall a. Maybe [a] -> Maybe [a]
popTag Text
tagName Map Text [(Tag str, Index)]
state
info :: TagInfo str
info = forall str. Tag str -> Name -> CloseOffset -> TagInfo str
TagInfo Tag str
tag (forall a. a -> Maybe a
Just Text
tagName) forall a. Maybe a
Nothing
res :: [(Index, TagInfo str)]
res = forall a. [Maybe a] -> [a]
catMaybes [
forall a. a -> Maybe a
Just (Index
index, TagInfo str
info)
, (Tag str, Index) -> (Index, TagInfo str)
calcOffset forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Tag str, Index)
maybeOpen
]
in [(Index, TagInfo str)]
res forall a. [a] -> [a] -> [a]
++ [(Tag str, Index)]
-> Map Text [(Tag str, Index)] -> [(Index, TagInfo str)]
go [(Tag str, Index)]
xs Map Text [(Tag str, Index)]
state'
| forall str. Tag str -> Bool
TagSoup.isTagOpen Tag str
tag =
[(Tag str, Index)]
-> Map Text [(Tag str, Index)] -> [(Index, TagInfo str)]
go [(Tag str, Index)]
xs (forall k a.
Ord k =>
(Maybe a -> Maybe a) -> k -> Map k a -> Map k a
Map.alter Maybe [(Tag str, Index)] -> Maybe [(Tag str, Index)]
appendTag Text
tagName Map Text [(Tag str, Index)]
state)
| Bool
otherwise =
let info :: TagInfo str
info = forall str. Tag str -> Name -> CloseOffset -> TagInfo str
TagInfo Tag str
tag forall a. Maybe a
Nothing forall a. Maybe a
Nothing
in (Index
index, TagInfo str
info) forall a. a -> [a] -> [a]
: [(Tag str, Index)]
-> Map Text [(Tag str, Index)] -> [(Index, TagInfo str)]
go [(Tag str, Index)]
xs Map Text [(Tag str, Index)]
state
where
tagName :: Text
tagName = forall str. StringLike str => Tag str -> Text
getTagName Tag str
tag
appendTag :: Maybe [(TagSoup.Tag str, Index)]
-> Maybe [(TagSoup.Tag str, Index)]
appendTag :: Maybe [(Tag str, Index)] -> Maybe [(Tag str, Index)]
appendTag Maybe [(Tag str, Index)]
m = ((Tag str
tag, Index
index) forall a. a -> [a] -> [a]
:) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Maybe [(Tag str, Index)]
m forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall a. a -> Maybe a
Just [])
calcOffset :: (TagSoup.Tag str, Index) -> (Index, TagInfo str)
calcOffset :: (Tag str, Index) -> (Index, TagInfo str)
calcOffset (Tag str
t, Index
i) =
let offset :: Index
offset = Index
index forall a. Num a => a -> a -> a
- Index
i
info :: TagInfo str
info = forall str. Tag str -> Name -> CloseOffset -> TagInfo str
TagInfo Tag str
t (forall a. a -> Maybe a
Just Text
tagName) (forall a. a -> Maybe a
Just Index
offset)
in Index
offset seq :: forall a b. a -> b -> b
`seq` (Index
i, TagInfo str
info)
popTag :: Maybe [a] -> Maybe [a]
popTag :: forall a. Maybe [a] -> Maybe [a]
popTag (Just (a
_ : a
y : [a]
xs)) = let s :: [a]
s = a
y forall a. a -> [a] -> [a]
: [a]
xs in [a]
s seq :: forall a b. a -> b -> b
`seq` forall a. a -> Maybe a
Just [a]
s
popTag Maybe [a]
_ = forall a. Maybe a
Nothing
getTagName :: TagSoup.StringLike str => TagSoup.Tag str -> T.Text
getTagName :: forall str. StringLike str => Tag str -> Text
getTagName (TagSoup.TagOpen str
name [Attribute str]
_) = forall a b. (StringLike a, StringLike b) => a -> b
TagSoup.castString str
name
getTagName (TagSoup.TagClose str
name) = forall a b. (StringLike a, StringLike b) => a -> b
TagSoup.castString str
name
getTagName Tag str
_ = forall a. HasCallStack => a
undefined
vectorToTree :: TagSoup.StringLike str => TagVector str -> TagForest
vectorToTree :: forall str. StringLike str => TagVector str -> TagForest
vectorToTree TagVector str
tags = TagForest -> TagForest
fixup forall a b. (a -> b) -> a -> b
$ Index -> Index -> TagForest
forestWithin Index
0 (forall a. Vector a -> Index
Vector.length TagVector str
tags)
where
forestWithin :: Int -> Int -> TagForest
forestWithin :: Index -> Index -> TagForest
forestWithin !Index
lo !Index
hi
| Index
hi forall a. Ord a => a -> a -> Bool
<= Index
lo = []
| Bool
shouldSkip = Index -> Index -> TagForest
forestWithin (Index
lo forall a. Num a => a -> a -> a
+ Index
1) Index
hi
| Bool
otherwise = forall a. a -> [Tree a] -> Tree a
Tree.Node (Index -> Index -> Span
Span Index
lo Index
closeIndex) TagForest
subForest
forall a. a -> [a] -> [a]
: Index -> Index -> TagForest
forestWithin (Index
closeIndex forall a. Num a => a -> a -> a
+ Index
1) Index
hi
where
info :: TagInfo str
info = TagVector str
tags forall a. Vector a -> Index -> a
Vector.! Index
lo
isOpen :: Bool
isOpen = forall str. Tag str -> Bool
TagSoup.isTagOpen forall a b. (a -> b) -> a -> b
$ forall str. TagInfo str -> Tag str
infoTag TagInfo str
info
isText :: Bool
isText = forall str. Tag str -> Bool
TagSoup.isTagText forall a b. (a -> b) -> a -> b
$ forall str. TagInfo str -> Tag str
infoTag TagInfo str
info
shouldSkip :: Bool
shouldSkip = Bool -> Bool
not Bool
isOpen Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
isText
closeIndex :: Index
closeIndex = Index
lo forall a. Num a => a -> a -> a
+ forall a. a -> Maybe a -> a
fromMaybe Index
0 (forall str. TagInfo str -> CloseOffset
infoOffset TagInfo str
info)
subForest :: TagForest
subForest = Index -> Index -> TagForest
forestWithin (Index
lo forall a. Num a => a -> a -> a
+ Index
1) Index
closeIndex
fixup :: TagForest -> TagForest
fixup :: TagForest -> TagForest
fixup [] = []
fixup (Tree.Node (Span Index
lo Index
hi) TagForest
subForest : TagForest
siblings)
= forall a. a -> [Tree a] -> Tree a
Tree.Node (Index -> Index -> Span
Span Index
lo Index
hi) TagForest
ok forall a. a -> [a] -> [a]
: TagForest
bad
where
(TagForest
ok, TagForest
bad) = TagForest -> TagForest -> (TagForest, TagForest)
malformed (TagForest -> TagForest
fixup TagForest
siblings) forall a b. (a -> b) -> a -> b
$ TagForest -> TagForest
fixup TagForest
subForest
malformed :: TagForest
-> TagForest
-> (TagForest, TagForest)
malformed :: TagForest -> TagForest -> (TagForest, TagForest)
malformed TagForest
preBad [] = ([], TagForest
preBad)
malformed TagForest
preBad (n :: Tree Span
n@(Tree.Node (Span Index
_ Index
nHi) TagForest
_) : TagForest
ns)
| Index
hi forall a. Ord a => a -> a -> Bool
< Index
nHi = (TagForest
ok, Tree Span
n forall a. a -> [a] -> [a]
: TagForest
bad)
| Bool
otherwise = (Tree Span
n forall a. a -> [a] -> [a]
: TagForest
ok, TagForest
bad)
where (TagForest
ok, TagForest
bad) = TagForest -> TagForest -> (TagForest, TagForest)
malformed TagForest
preBad TagForest
ns
selectNodes :: TagSoup.StringLike str
=> [(SelectNode, SelectSettings)]
-> TagSpec str
-> TagSpec str
-> [TagSpec str]
-> [TagSpec str]
selectNodes :: forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes [] TagSpec str
_ TagSpec str
_ [TagSpec str]
acc = [TagSpec str]
acc
selectNodes [(SelectNode, SelectSettings)
_] (TagVector str
_, [], SelectContext
_) TagSpec str
_ [TagSpec str]
acc = [TagSpec str]
acc
selectNodes [(SelectNode, SelectSettings)
n] cur :: TagSpec str
cur@(TagVector str
tags, Tree Span
f : TagForest
fs, SelectContext
ctx) TagSpec str
root [TagSpec str]
acc
| MatchResult
MatchOk forall a. Eq a => a -> a -> Bool
== MatchResult
matchResult
= (TagSpec str
shrunkSpec forall a. a -> [a] -> [a]
:)
forall a b. (a -> b) -> a -> b
$ forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes [(SelectNode, SelectSettings)
n] (TagVector str
tags, TagForest
fs, SelectContext
ctx) TagSpec str
root
forall a b. (a -> b) -> a -> b
$ forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes [(SelectNode, SelectSettings)
n] (TagVector str
tags, forall a. Tree a -> [Tree a]
Tree.subForest Tree Span
f, SelectContext
ctx) TagSpec str
root [TagSpec str]
acc
| MatchResult
MatchCull forall a. Eq a => a -> a -> Bool
== MatchResult
matchResult
= forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes [(SelectNode, SelectSettings)
n] (TagVector str
tags, TagForest
fs, SelectContext
ctx) TagSpec str
root [TagSpec str]
acc
| Bool
otherwise
= forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes [(SelectNode, SelectSettings)
n] (TagVector str
tags, forall a. Tree a -> [Tree a]
Tree.subForest Tree Span
f, SelectContext
ctx) TagSpec str
root
forall a b. (a -> b) -> a -> b
$ forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes [(SelectNode, SelectSettings)
n] (TagVector str
tags, TagForest
fs, SelectContext
ctx) TagSpec str
root [TagSpec str]
acc
where
Span Index
lo Index
hi = forall a. Tree a -> a
Tree.rootLabel Tree Span
f
shrunkSpec :: TagSpec str
shrunkSpec = (
forall a. Index -> Index -> Vector a -> Vector a
Vector.slice Index
lo (Index
hi forall a. Num a => a -> a -> a
- Index
lo forall a. Num a => a -> a -> a
+ Index
1) TagVector str
tags
, [forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Span -> Span
recenter Tree Span
f]
, SelectContext
ctx
)
recenter :: Span -> Span
recenter (Span Index
nLo Index
nHi) = Index -> Index -> Span
Span (Index
nLo forall a. Num a => a -> a -> a
- Index
lo) (Index
nHi forall a. Num a => a -> a -> a
- Index
lo)
info :: TagInfo str
info = TagVector str
tags forall a. Vector a -> Index -> a
Vector.! Index
lo
matchResult :: MatchResult
matchResult = forall str.
StringLike str =>
(SelectNode, SelectSettings)
-> TagInfo str -> TagSpec str -> TagSpec str -> MatchResult
nodeMatches (SelectNode, SelectSettings)
n TagInfo str
info TagSpec str
cur TagSpec str
root
selectNodes ((SelectNode, SelectSettings)
_ : [(SelectNode, SelectSettings)]
_) (TagVector str
_, [], SelectContext
_) TagSpec str
_ [TagSpec str]
acc = [TagSpec str]
acc
selectNodes ((SelectNode, SelectSettings)
n : [(SelectNode, SelectSettings)]
ns) cur :: TagSpec str
cur@(TagVector str
tags, Tree Span
f : TagForest
fs, SelectContext
ctx) TagSpec str
root [TagSpec str]
acc
| MatchResult
MatchOk forall a. Eq a => a -> a -> Bool
== MatchResult
matchResult
= forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes [(SelectNode, SelectSettings)]
ns (TagVector str
tags, forall a. Tree a -> [Tree a]
Tree.subForest Tree Span
f forall a. [a] -> [a] -> [a]
++ TagForest
siblings, SelectContext
ctx)
(TagVector str
tags, Tree Span
f forall a. a -> [a] -> [a]
: TagForest
siblings, SelectContext
ctx)
forall a b. (a -> b) -> a -> b
$ forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes ((SelectNode, SelectSettings)
n forall a. a -> [a] -> [a]
: [(SelectNode, SelectSettings)]
ns) (TagVector str
tags, TagForest
fs, SelectContext
ctx) TagSpec str
root [TagSpec str]
acc
| MatchResult
MatchCull forall a. Eq a => a -> a -> Bool
== MatchResult
matchResult
= forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes ((SelectNode, SelectSettings)
n forall a. a -> [a] -> [a]
: [(SelectNode, SelectSettings)]
ns) (TagVector str
tags, TagForest
fs, SelectContext
ctx) TagSpec str
root [TagSpec str]
acc
| Bool
otherwise
= forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes ((SelectNode, SelectSettings)
n forall a. a -> [a] -> [a]
: [(SelectNode, SelectSettings)]
ns) (TagVector str
tags, forall a. Tree a -> [Tree a]
Tree.subForest Tree Span
f, SelectContext
ctx) TagSpec str
root
forall a b. (a -> b) -> a -> b
$ forall str.
StringLike str =>
[(SelectNode, SelectSettings)]
-> TagSpec str -> TagSpec str -> [TagSpec str] -> [TagSpec str]
selectNodes ((SelectNode, SelectSettings)
n forall a. a -> [a] -> [a]
: [(SelectNode, SelectSettings)]
ns) (TagVector str
tags, TagForest
fs, SelectContext
ctx) TagSpec str
root [TagSpec str]
acc
where
Span Index
lo Index
hi = forall a. Tree a -> a
Tree.rootLabel Tree Span
f
info :: TagInfo str
info = TagVector str
tags forall a. Vector a -> Index -> a
Vector.! Index
lo
matchResult :: MatchResult
matchResult = forall str.
StringLike str =>
(SelectNode, SelectSettings)
-> TagInfo str -> TagSpec str -> TagSpec str -> MatchResult
nodeMatches (SelectNode, SelectSettings)
n TagInfo str
info TagSpec str
cur TagSpec str
root
treeLo :: Tree Span -> Index
treeLo Tree Span
tree | (Span Index
lo Index
_) <- forall a. Tree a -> a
Tree.rootLabel Tree Span
tree = Index
lo
treeHi :: Tree Span -> Index
treeHi Tree Span
tree | (Span Index
_ Index
hi) <- forall a. Tree a -> a
Tree.rootLabel Tree Span
tree = Index
hi
liftSiblings :: TagForest -> TagForest -> TagForest
liftSiblings [] TagForest
acc = TagForest
acc
liftSiblings (Tree Span
t : TagForest
ts) TagForest
acc
| Index
lo forall a. Ord a => a -> a -> Bool
< Tree Span -> Index
treeLo Tree Span
t Bool -> Bool -> Bool
&& Tree Span -> Index
treeHi Tree Span
t forall a. Ord a => a -> a -> Bool
< Index
hi = Tree Span
t forall a. a -> [a] -> [a]
: TagForest -> TagForest -> TagForest
liftSiblings TagForest
ts TagForest
acc
| Index
hi forall a. Ord a => a -> a -> Bool
< Tree Span -> Index
treeLo Tree Span
t Bool -> Bool -> Bool
|| Tree Span -> Index
treeHi Tree Span
t forall a. Ord a => a -> a -> Bool
< Index
lo = TagForest -> TagForest -> TagForest
liftSiblings TagForest
ts TagForest
acc
| Bool
otherwise = TagForest -> TagForest -> TagForest
liftSiblings (forall a. Tree a -> [Tree a]
Tree.subForest Tree Span
t)
forall a b. (a -> b) -> a -> b
$ TagForest -> TagForest -> TagForest
liftSiblings TagForest
ts TagForest
acc
siblings :: TagForest
siblings = TagForest -> TagForest -> TagForest
liftSiblings TagForest
fs []
data MatchResult = MatchOk | MatchFail | MatchCull
deriving (MatchResult -> MatchResult -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MatchResult -> MatchResult -> Bool
$c/= :: MatchResult -> MatchResult -> Bool
== :: MatchResult -> MatchResult -> Bool
$c== :: MatchResult -> MatchResult -> Bool
Eq)
andMatch :: MatchResult -> MatchResult -> MatchResult
andMatch :: MatchResult -> MatchResult -> MatchResult
andMatch MatchResult
MatchOk MatchResult
MatchOk = MatchResult
MatchOk
andMatch MatchResult
MatchCull MatchResult
_ = MatchResult
MatchCull
andMatch MatchResult
_ MatchResult
MatchCull = MatchResult
MatchCull
andMatch MatchResult
_ MatchResult
_ = MatchResult
MatchFail
boolMatch :: Bool -> MatchResult
boolMatch :: Bool -> MatchResult
boolMatch Bool
True = MatchResult
MatchOk
boolMatch Bool
False = MatchResult
MatchFail
nodeMatches :: TagSoup.StringLike str
=> (SelectNode, SelectSettings)
-> TagInfo str
-> TagSpec str
-> TagSpec str
-> MatchResult
nodeMatches :: forall str.
StringLike str =>
(SelectNode, SelectSettings)
-> TagInfo str -> TagSpec str -> TagSpec str -> MatchResult
nodeMatches (SelectNode Text
node [AttributePredicate]
preds, SelectSettings
settings) TagInfo str
info TagSpec str
cur TagSpec str
root =
forall str.
StringLike str =>
SelectSettings -> TagSpec str -> TagSpec str -> MatchResult
checkSettings SelectSettings
settings TagSpec str
cur TagSpec str
root MatchResult -> MatchResult -> MatchResult
`andMatch` forall str.
StringLike str =>
Text -> [AttributePredicate] -> TagInfo str -> MatchResult
checkTag Text
node [AttributePredicate]
preds TagInfo str
info
nodeMatches (SelectAny [AttributePredicate]
preds , SelectSettings
settings) TagInfo str
info TagSpec str
cur TagSpec str
root =
forall str.
StringLike str =>
SelectSettings -> TagSpec str -> TagSpec str -> MatchResult
checkSettings SelectSettings
settings TagSpec str
cur TagSpec str
root MatchResult -> MatchResult -> MatchResult
`andMatch` forall str.
StringLike str =>
[AttributePredicate] -> Tag str -> MatchResult
checkPreds [AttributePredicate]
preds (forall str. TagInfo str -> Tag str
infoTag TagInfo str
info)
nodeMatches (SelectNode
SelectText , SelectSettings
settings) TagInfo str
info TagSpec str
cur TagSpec str
root =
forall str.
StringLike str =>
SelectSettings -> TagSpec str -> TagSpec str -> MatchResult
checkSettings SelectSettings
settings TagSpec str
cur TagSpec str
root MatchResult -> MatchResult -> MatchResult
`andMatch`
Bool -> MatchResult
boolMatch (forall str. Tag str -> Bool
TagSoup.isTagText forall a b. (a -> b) -> a -> b
$ forall str. TagInfo str -> Tag str
infoTag TagInfo str
info)
checkSettings :: TagSoup.StringLike str
=> SelectSettings -> TagSpec str -> TagSpec str -> MatchResult
checkSettings :: forall str.
StringLike str =>
SelectSettings -> TagSpec str -> TagSpec str -> MatchResult
checkSettings (SelectSettings (Just Index
depth))
(TagVector str
_, Tree Span
curRoot : TagForest
_, SelectContext
_)
(TagVector str
_, TagForest
root, SelectContext
_)
| Index
depthOfCur forall a. Ord a => a -> a -> Bool
< Index
depth = MatchResult
MatchFail
| Index
depthOfCur forall a. Ord a => a -> a -> Bool
> Index
depth = MatchResult
MatchCull
| Bool
otherwise = MatchResult
MatchOk
where
Span Index
curLo Index
curHi = forall a. Tree a -> a
Tree.rootLabel Tree Span
curRoot
mapTree :: (a -> b) -> t (Tree a) -> [b]
mapTree a -> b
f = forall a b. (a -> b) -> [a] -> [b]
map a -> b
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall a. Tree a -> [a]
Tree.flatten
depthOfCur :: Index
depthOfCur = forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum forall a b. (a -> b) -> a -> b
$ forall {t :: * -> *} {a} {b}.
Foldable t =>
(a -> b) -> t (Tree a) -> [b]
mapTree forall {a}. Num a => Span -> a
oneIfContainsCur TagForest
root
oneIfContainsCur :: Span -> a
oneIfContainsCur (Span Index
lo Index
hi)
| Index
lo forall a. Ord a => a -> a -> Bool
< Index
curLo Bool -> Bool -> Bool
&& Index
curHi forall a. Ord a => a -> a -> Bool
< Index
hi = a
1
| Bool
otherwise = a
0
checkSettings (SelectSettings CloseOffset
_) (TagVector str, TagForest, SelectContext)
_ (TagVector str, TagForest, SelectContext)
_ = MatchResult
MatchOk
checkTag :: TagSoup.StringLike str
=> T.Text -> [AttributePredicate] -> TagInfo str -> MatchResult
checkTag :: forall str.
StringLike str =>
Text -> [AttributePredicate] -> TagInfo str -> MatchResult
checkTag Text
name [AttributePredicate]
preds (TagInfo Tag str
tag Name
tagName CloseOffset
_)
= Bool -> MatchResult
boolMatch (
forall str. Tag str -> Bool
TagSoup.isTagOpen Tag str
tag
Bool -> Bool -> Bool
&& forall a. Maybe a -> Bool
isJust Name
tagName
Bool -> Bool -> Bool
&& Text
name forall a. Eq a => a -> a -> Bool
== forall a. HasCallStack => Maybe a -> a
fromJust Name
tagName
) MatchResult -> MatchResult -> MatchResult
`andMatch` forall str.
StringLike str =>
[AttributePredicate] -> Tag str -> MatchResult
checkPreds [AttributePredicate]
preds Tag str
tag
checkPreds :: TagSoup.StringLike str
=> [AttributePredicate] -> TagSoup.Tag str -> MatchResult
checkPreds :: forall str.
StringLike str =>
[AttributePredicate] -> Tag str -> MatchResult
checkPreds [] Tag str
tag = Bool -> MatchResult
boolMatch
forall a b. (a -> b) -> a -> b
$ forall str. Tag str -> Bool
TagSoup.isTagOpen Tag str
tag Bool -> Bool -> Bool
|| forall str. Tag str -> Bool
TagSoup.isTagText Tag str
tag
checkPreds [AttributePredicate]
preds Tag str
tag = Bool -> MatchResult
boolMatch
forall a b. (a -> b) -> a -> b
$ forall str. Tag str -> Bool
TagSoup.isTagOpen Tag str
tag Bool -> Bool -> Bool
&& forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (forall str.
StringLike str =>
AttributePredicate -> [Attribute str] -> Bool
`checkPred` [Attribute str]
attrs) [AttributePredicate]
preds
where (TagSoup.TagOpen str
_ [Attribute str]
attrs) = Tag str
tag