1 {-# LANGUAGE FlexibleContexts #-}
2 {-# LANGUAGE FlexibleInstances #-}
3 {-# LANGUAGE OverloadedStrings #-}
4 {-# LANGUAGE ScopedTypeVariables #-}
5 {-# LANGUAGE TypeFamilies #-}
6 {-# LANGUAGE ViewPatterns #-}
7 {-# OPTIONS_GHC -fno-warn-orphans #-}
8 module Language.Symantic.RNC.Validate where
10 import Control.Applicative (Applicative(..))
12 import Data.Either (Either(..))
13 import Data.Eq (Eq(..))
14 import Data.Foldable (Foldable(..), all)
15 import Data.Function (($), const, id)
16 import Data.List.NonEmpty (NonEmpty(..))
17 import Data.Maybe (Maybe(..))
18 import Data.Monoid (Monoid(..))
19 import Data.Ord (Ord(..))
20 import Data.Semigroup (Semigroup(..))
21 import qualified Data.Char as Char
22 import qualified Data.Sequence as Seq
23 import qualified Data.Set as Set
24 import qualified Data.Text.Lazy as TL
25 import qualified Text.Megaparsec as P
26 import qualified Text.Megaparsec.Perm as P
28 import Language.Symantic.XML (XMLs)
29 import qualified Language.Symantic.XML as XML
30 import qualified Language.Symantic.RNC.Sym as RNC
32 validateXML :: Ord e => P.Parsec e XMLs a -> XMLs -> Either (P.ParseError (P.Token XMLs) e) a
33 validateXML p = XML.runParser p (P.initialPos "":|[])
35 type instance RNC.Perm (P.ParsecT e XMLs m) = P.PermParser XMLs (P.ParsecT e XMLs m)
36 instance Ord e => RNC.Sym_Interleaved (P.ParsecT e XMLs m) where
37 interleaved = P.makePermParser
42 f <$*> a = f P.<$?> ([],P.some a)
43 f <|*> a = f P.<|?> ([],P.some a)
44 instance Ord e => RNC.Sym_Rule (P.ParsecT e XMLs m) where
45 -- rule n p = P.dbg s p {-(p P.<?> s)-} where s = Text.unpack n
49 -- | Like 'P.satisfy' but with a predicate returning 'Maybe' instead of 'Bool'.
50 p_satisfyMaybe :: P.MonadParsec e s m => (P.Token s -> Maybe a) -> m a
51 p_satisfyMaybe f = check `P.token` Nothing
56 Nothing -> Left (Just $ P.Tokens $ c:|[], Set.empty)
58 instance Ord e => RNC.Sym_RNC (P.Parsec e XMLs) where
60 none = P.label "none" $ P.eof
62 namespace _p _n = pure ()
64 ts <- P.token check $ Just expected
67 expected = XML.Tree (XML.notSourced $ XML.NodeElem n) mempty
68 check (XML.Tree (XML.unSourced -> XML.NodeElem e) ts)
70 = Right $ removePI $ removeXMLNS $ removeSpaces ts
73 (`Seq.filter` xs) $ \case
74 XML.Tree (XML.unSourced -> XML.NodePI{}) _ts -> False
78 XML.Tree (XML.unSourced -> XML.NodeText txt) _ts ->
80 XML.TextLexemePlain t -> TL.all Char.isSpace t
83 then (`Seq.filter` xs) $ \case
84 XML.Tree (XML.unSourced -> XML.NodeText{}) _ts -> False
88 let (attrs,rest) = (`Seq.spanl` xs) $ \case
89 XML.Tree (XML.unSourced -> XML.NodeAttr{}) _ts -> True
91 let attrs' = (`Seq.filter` attrs) $ \case
92 XML.Tree (XML.unSourced -> XML.NodeAttr a) _ts ->
94 XML.QName "" "xmlns" -> False
95 XML.QName ns _l -> ns /= XML.xmlns_xmlns
99 ( Just $ P.Tokens $ pure t
100 , Set.singleton $ P.Tokens $ pure expected )
102 v <- P.token check $ Just expected
105 expected = XML.Tree0 (XML.notSourced $ XML.NodeAttr n)
106 check (XML.Tree (XML.unSourced -> XML.NodeAttr k)
107 v@(toList -> [XML.Tree0 (XML.unSourced -> XML.NodeText _v)])) | k == n =
110 ( Just $ P.Tokens $ pure t
111 , Set.singleton $ P.Tokens $ pure expected )
112 any = P.label "any" $ p_satisfyMaybe $ const $ Just ()
113 anyElem ns p = P.label "anyElem" $ do
114 (n,ts) <- P.token check $ Just expected
115 parserElement n (p $ XML.qNameLocal n) ts
117 expected = XML.Tree (XML.notSourced $ XML.NodeElem $ XML.QName ns $ XML.NCName "*") mempty
118 check (XML.Tree (XML.unSourced -> XML.NodeElem e) ts)
119 | XML.qNameSpace e == ns
122 ( Just $ P.Tokens $ pure t
123 , Set.singleton $ P.Tokens $ pure expected )
128 XML.Tree0 (XML.unSourced -> XML.NodeComment c) :< ts -> do
130 c <$ XML.setFilePosToNextNode
131 t :< _ts -> P.failure (Just $ P.Tokens $ pure t) ex
132 EmptyL -> P.failure Nothing ex
134 ex = Set.singleton $ P.Tokens $ pure expected
135 expected = XML.Tree0 (XML.notSourced $ XML.NodeComment "")
138 P.token check (Just expected)
139 <* XML.setFilePosToNextNode
141 expected = XML.Tree0 (XML.notSourced $ XML.NodeText [])
142 check (XML.Tree0 (XML.unSourced -> XML.NodeText t)) = Right t
144 ( Just $ P.Tokens $ pure t
145 , Set.singleton $ P.Tokens $ pure expected )
146 optional = P.optional
150 fail = P.label "fail" $ P.failure Nothing mempty
152 parserElement :: Ord e => XML.QName -> P.Parsec e XMLs a -> XMLs -> P.Parsec e XMLs a
153 parserElement _n = XML.parser
158 { state_posXML :: XML.Pos
159 , state_source :: XML.FileSource
160 -- ^ Unfortunately Megaparsec's 'P.statePos'
161 -- is not a good fit to encode 'XML.Source'.
163 instance Default State where
170 type Parser = S.StateT State (P.Parsec ErrorRead XMLs)
172 instance RNC.Sym_Rule Parser where
173 -- rule n p = P.dbg s p {-(p P.<?> s)-} where s = Text.unpack n
175 instance RNC.Sym_RNC Parser where
177 none = P.label "none" $ P.eof
179 fail = P.label "fail" $ P.failure Nothing mempty
180 any = P.label "any" $ p_satisfyMaybe $ const $ Just ()
181 anyElem p = P.label "anyElem" $ do
182 XML.Sourced state_source (n,ts) <- P.token check $ Just expected
183 parserElement n (p n) (XML.Sourced state_source ts)
185 expected = XML.Tree (XML.notSourced $ XML.NodeElem "*") mempty
186 check (XML.Tree cell@(XML.unSourced -> XML.NodeElem e) ts) = Right $ (e,ts) <$ cell
188 ( Just $ P.Tokens $ pure t
189 , Set.singleton $ P.Tokens $ pure expected )
191 ts <- P.token check $ Just expected
194 expected = XML.Tree (XML.notSourced $ XML.NodeElem n) mempty
195 check (XML.Tree cell@(XML.unSourced -> XML.NodeElem e) ts) | e == n = Right (ts <$ cell)
197 ( Just $ P.Tokens $ pure t
198 , Set.singleton $ P.Tokens $ pure expected )
200 v <- P.token check $ Just expected
201 stateParser p $ Seq.singleton $ Tree0 v
203 expected = Tree0 (XML.notSourced $ XML.NodeAttr n "")
204 check (XML.Tree0 cell@(XML.unSourced -> XML.NodeAttr k v)) | k == n =
205 Right $ XML.NodeText v <$ cell
207 ( Just $ P.Tokens $ pure t
208 , Set.singleton $ P.Tokens $ pure expected )
213 XML.Tree0 (XML.unSourced -> XML.NodeComment c) :< ts -> do
215 c <$ setFilePosToNextNode
216 t :< _ts -> P.failure (Just $ P.Tokens $ pure t) ex
217 EmptyL -> P.failure Nothing ex
219 ex = Set.singleton $ P.Tokens $ pure expected
220 expected = Tree0 (XML.notSourced $ XML.NodeComment "")
223 P.token check (Just expected)
224 <* setFilePosToNextNode
226 expected = Tree0 (XML.notSourced $ XML.NodeText "")
227 check (XML.Tree0 (XML.unSourced -> XML.NodeText t)) = Right t
229 ( Just $ P.Tokens $ pure t
230 , Set.singleton $ P.Tokens $ pure expected )
231 optional = P.optional
236 parserElement :: XML.Name -> Parser a -> XML.Sourced XMLs -> Parser a
237 parserElement n p (XML.Sourced state_source ts) = do
238 let mayNameOrFigureName
239 | n == "aside" = Nothing
242 -- NOTE: special case renaming the current XML.XmlPos
243 -- using the @type attribute to have positions like this:
251 , Just ty <- getFirst $ (`foldMap` ts) $ \case
252 XML.Tree0 (XML.unSourced -> XML.NodeAttr "type" ty) -> First $ Just ty
254 = Just $ XML.qName $ ty
256 case mayNameOrFigureName of
259 S.put st{state_source}
260 res <- stateParser p ts
263 Just nameOrFigureName -> do
264 st@State{state_posXML} <- S.get
265 let incrPrecedingSibling name =
266 maybe (Nat1 1) succNat1 $
268 XML.pos_precedingSiblings state_posXML
270 { state_posXML = state_posXML
271 -- NOTE: in children, push current name incremented on ancestors
272 -- and reset preceding siblings.
273 { XML.pos_precedingSiblings = mempty
274 , XML.pos_ancestors = XML.pos_ancestors state_posXML |> (n, incrPrecedingSibling n)
275 , XML.pos_ancestorsWithFigureNames =
276 XML.pos_ancestorsWithFigureNames state_posXML |>
278 , incrPrecedingSibling nameOrFigureName )
282 res <- stateParser p ts
284 { state_posXML = state_posXML
285 -- NOTE: after current, increment current name
286 -- and reset ancestors.
287 { XML.pos_precedingSiblings =
288 (if n == nameOrFigureName then id
289 else Map.insertWith (const succNat1) nameOrFigureName (Nat1 1)) $
290 Map.insertWith (const succNat1) n (Nat1 1) $
291 XML.pos_precedingSiblings state_posXML
296 type instance RNC.Perm Parser = P.PermParser XMLs Parser
297 instance RNC.Sym_Interleaved Parser where
298 interleaved = P.makePermParser
303 f <$*> a = f P.<$?> ([],P.some a)
304 f <|*> a = f P.<|?> ([],P.some a)
306 instance DTC.Sym_DTC Parser where
307 positionXML = S.gets state_posXML
308 locationTCT = S.gets state_source
314 -- ** Type 'ErrorRead'
316 = ErrorRead_EndOfInput
317 | ErrorRead_Not_Bool TL.Text
318 | ErrorRead_Not_Int TL.Text
319 | ErrorRead_Not_Nat Int
320 | ErrorRead_Not_Nat1 Int
321 | ErrorRead_Not_Rational TL.Text
322 | ErrorRead_Not_Positive TL.Text
323 {- ErrorRead_Unexpected P.sourcePos XML -}
324 deriving (Eq,Ord,Show)
325 instance P.ShowErrorComponent ErrorRead where
326 showErrorComponent = show