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(..))
11 import Control.Monad (Monad(..))
13 import Data.Default.Class (Default(..))
14 import Data.Either (Either(..))
15 import Data.Eq (Eq(..))
16 import Data.Foldable (Foldable(..), all)
17 import Data.Function (($), (.), const, id)
18 import Data.Functor ((<$>), (<$))
20 import Data.List.NonEmpty (NonEmpty(..))
21 import Data.Maybe (Maybe(..), maybe)
22 import Data.Monoid (Monoid(..), First(..))
23 import Data.Ord (Ord(..))
24 import Data.Proxy (Proxy(..))
25 import Data.Ratio ((%))
26 import Data.Semigroup (Semigroup(..))
27 import Data.Sequence (ViewL(..), (|>))
28 import Data.String (String)
29 import Data.Tuple (fst, snd)
30 import Text.Read (readMaybe, Read(..))
31 import Text.Show (Show(..))
32 import qualified Control.Monad.Trans.State as S
33 import qualified Data.Char as Char
34 import qualified Data.List as List
35 import qualified Data.Map.Strict as Map
36 import qualified Data.Ratio as Ratio
37 import qualified Data.Sequence as Seq
38 import qualified Data.Set as Set
39 import qualified Data.Text.Lazy as TL
40 import qualified GHC.Read as Read (expectP)
41 import qualified Text.Megaparsec as P
42 import qualified Text.Megaparsec.Perm as P
43 import qualified Text.Read as Read
45 import Language.Symantic.XML (XML, XMLs)
46 import qualified Language.Symantic.XML as XML
47 import qualified Language.Symantic.RNC.Sym as RNC
49 validateXML :: Ord e => P.Parsec e XMLs a -> XMLs -> Either (P.ParseError (P.Token XMLs) e) a
50 validateXML p = XML.runParser p (P.initialPos "":|[])
52 type instance RNC.Perm (P.ParsecT e XMLs m) = P.PermParser XMLs (P.ParsecT e XMLs m)
53 instance Ord e => RNC.Sym_Interleaved (P.ParsecT e XMLs m) where
54 interleaved = P.makePermParser
59 f <$*> a = f P.<$?> ([],P.some a)
60 f <|*> a = f P.<|?> ([],P.some a)
61 instance Ord e => RNC.Sym_Rule (P.ParsecT e XMLs m) where
62 -- rule n p = P.dbg s p {-(p P.<?> s)-} where s = Text.unpack n
66 -- | Like 'P.satisfy' but with a predicate returning 'Maybe' instead of 'Bool'.
67 p_satisfyMaybe :: P.MonadParsec e s m => (P.Token s -> Maybe a) -> m a
68 p_satisfyMaybe f = check `P.token` Nothing
73 Nothing -> Left (Just $ P.Tokens $ c:|[], Set.empty)
75 instance Ord e => RNC.Sym_RNC (P.Parsec e XMLs) where
77 none = P.label "none" $ P.eof
79 namespace _p _n = pure ()
81 ts <- P.token check $ Just expected
84 expected = XML.Tree (XML.notSourced $ XML.NodeElem n) mempty
85 check (XML.Tree (XML.unSourced -> XML.NodeElem e) ts)
87 = Right $ removePI $ removeXMLNS $ removeSpaces ts
90 (`Seq.filter` xs) $ \case
91 XML.Tree (XML.unSourced -> XML.NodePI{}) _ts -> False
95 XML.Tree (XML.unSourced -> XML.NodeText txt) _ts ->
96 TL.all Char.isSpace txt
98 then (`Seq.filter` xs) $ \case
99 XML.Tree (XML.unSourced -> XML.NodeText{}) _ts -> False
103 let (attrs,rest) = (`Seq.spanl` xs) $ \case
104 XML.Tree (XML.unSourced -> XML.NodeAttr{}) _ts -> True
106 let attrs' = (`Seq.filter` attrs) $ \case
107 XML.Tree (XML.unSourced -> XML.NodeAttr a) _ts ->
109 XML.QName "" "xmlns" -> False
110 XML.QName ns _l -> ns /= XML.xmlns_xmlns
114 ( Just $ P.Tokens $ pure t
115 , Set.singleton $ P.Tokens $ pure expected )
117 v <- P.token check $ Just expected
120 expected = XML.Tree0 (XML.notSourced $ XML.NodeAttr n)
121 check (XML.Tree (XML.unSourced -> XML.NodeAttr k)
122 v@(toList -> [XML.Tree0 (XML.unSourced -> XML.NodeText _v)])) | k == n =
125 ( Just $ P.Tokens $ pure t
126 , Set.singleton $ P.Tokens $ pure expected )
127 any = P.label "any" $ p_satisfyMaybe $ const $ Just ()
128 anyElem ns p = P.label "anyElem" $ do
129 (n,ts) <- P.token check $ Just expected
130 parserElement n (p $ XML.qNameLocal n) ts
132 expected = XML.Tree (XML.notSourced $ XML.NodeElem $ XML.QName ns $ XML.NCName "*") mempty
133 check (XML.Tree (XML.unSourced -> XML.NodeElem e) ts)
134 | XML.qNameSpace e == ns
137 ( Just $ P.Tokens $ pure t
138 , Set.singleton $ P.Tokens $ pure expected )
143 XML.Tree0 (XML.unSourced -> XML.NodeComment c) :< ts -> do
145 c <$ XML.setFilePosToNextNode
146 t :< _ts -> P.failure (Just $ P.Tokens $ pure t) ex
147 EmptyL -> P.failure Nothing ex
149 ex = Set.singleton $ P.Tokens $ pure expected
150 expected = XML.Tree0 (XML.notSourced $ XML.NodeComment "")
153 P.token check (Just expected)
154 <* XML.setFilePosToNextNode
156 expected = XML.Tree0 (XML.notSourced $ XML.NodeText "")
157 check (XML.Tree0 (XML.unSourced -> XML.NodeText t)) = Right t
159 ( Just $ P.Tokens $ pure t
160 , Set.singleton $ P.Tokens $ pure expected )
161 optional = P.optional
165 fail = P.label "fail" $ P.failure Nothing mempty
167 parserElement :: Ord e => XML.QName -> P.Parsec e XMLs a -> XMLs -> P.Parsec e XMLs a
168 parserElement _n = XML.parser
173 { state_posXML :: XML.Pos
174 , state_source :: XML.FileSource
175 -- ^ Unfortunately Megaparsec's 'P.statePos'
176 -- is not a good fit to encode 'XML.Source'.
178 instance Default State where
185 type Parser = S.StateT State (P.Parsec ErrorRead XMLs)
187 instance RNC.Sym_Rule Parser where
188 -- rule n p = P.dbg s p {-(p P.<?> s)-} where s = Text.unpack n
190 instance RNC.Sym_RNC Parser where
192 none = P.label "none" $ P.eof
194 fail = P.label "fail" $ P.failure Nothing mempty
195 any = P.label "any" $ p_satisfyMaybe $ const $ Just ()
196 anyElem p = P.label "anyElem" $ do
197 XML.Sourced state_source (n,ts) <- P.token check $ Just expected
198 parserElement n (p n) (XML.Sourced state_source ts)
200 expected = XML.Tree (XML.notSourced $ XML.NodeElem "*") mempty
201 check (XML.Tree cell@(XML.unSourced -> XML.NodeElem e) ts) = Right $ (e,ts) <$ cell
203 ( Just $ P.Tokens $ pure t
204 , Set.singleton $ P.Tokens $ pure expected )
206 ts <- P.token check $ Just expected
209 expected = XML.Tree (XML.notSourced $ XML.NodeElem n) mempty
210 check (XML.Tree cell@(XML.unSourced -> XML.NodeElem e) ts) | e == n = Right (ts <$ cell)
212 ( Just $ P.Tokens $ pure t
213 , Set.singleton $ P.Tokens $ pure expected )
215 v <- P.token check $ Just expected
216 stateParser p $ Seq.singleton $ Tree0 v
218 expected = Tree0 (XML.notSourced $ XML.NodeAttr n "")
219 check (XML.Tree0 cell@(XML.unSourced -> XML.NodeAttr k v)) | k == n =
220 Right $ XML.NodeText v <$ cell
222 ( Just $ P.Tokens $ pure t
223 , Set.singleton $ P.Tokens $ pure expected )
228 XML.Tree0 (XML.unSourced -> XML.NodeComment c) :< ts -> do
230 c <$ setFilePosToNextNode
231 t :< _ts -> P.failure (Just $ P.Tokens $ pure t) ex
232 EmptyL -> P.failure Nothing ex
234 ex = Set.singleton $ P.Tokens $ pure expected
235 expected = Tree0 (XML.notSourced $ XML.NodeComment "")
238 P.token check (Just expected)
239 <* setFilePosToNextNode
241 expected = Tree0 (XML.notSourced $ XML.NodeText "")
242 check (XML.Tree0 (XML.unSourced -> XML.NodeText t)) = Right t
244 ( Just $ P.Tokens $ pure t
245 , Set.singleton $ P.Tokens $ pure expected )
246 optional = P.optional
251 parserElement :: XML.Name -> Parser a -> XML.Sourced XMLs -> Parser a
252 parserElement n p (XML.Sourced state_source ts) = do
253 let mayNameOrFigureName
254 | n == "aside" = Nothing
257 -- NOTE: special case renaming the current XML.XmlPos
258 -- using the @type attribute to have positions like this:
266 , Just ty <- getFirst $ (`foldMap` ts) $ \case
267 XML.Tree0 (XML.unSourced -> XML.NodeAttr "type" ty) -> First $ Just ty
269 = Just $ XML.qName $ ty
271 case mayNameOrFigureName of
274 S.put st{state_source}
275 res <- stateParser p ts
278 Just nameOrFigureName -> do
279 st@State{state_posXML} <- S.get
280 let incrPrecedingSibling name =
281 maybe (Nat1 1) succNat1 $
283 XML.pos_precedingSiblings state_posXML
285 { state_posXML = state_posXML
286 -- NOTE: in children, push current name incremented on ancestors
287 -- and reset preceding siblings.
288 { XML.pos_precedingSiblings = mempty
289 , XML.pos_ancestors = XML.pos_ancestors state_posXML |> (n, incrPrecedingSibling n)
290 , XML.pos_ancestorsWithFigureNames =
291 XML.pos_ancestorsWithFigureNames state_posXML |>
293 , incrPrecedingSibling nameOrFigureName )
297 res <- stateParser p ts
299 { state_posXML = state_posXML
300 -- NOTE: after current, increment current name
301 -- and reset ancestors.
302 { XML.pos_precedingSiblings =
303 (if n == nameOrFigureName then id
304 else Map.insertWith (const succNat1) nameOrFigureName (Nat1 1)) $
305 Map.insertWith (const succNat1) n (Nat1 1) $
306 XML.pos_precedingSiblings state_posXML
311 type instance RNC.Perm Parser = P.PermParser XMLs Parser
312 instance RNC.Sym_Interleaved Parser where
313 interleaved = P.makePermParser
318 f <$*> a = f P.<$?> ([],P.some a)
319 f <|*> a = f P.<|?> ([],P.some a)
321 instance DTC.Sym_DTC Parser where
322 positionXML = S.gets state_posXML
323 locationTCT = S.gets state_source
329 -- ** Type 'ErrorRead'
331 = ErrorRead_EndOfInput
332 | ErrorRead_Not_Bool TL.Text
333 | ErrorRead_Not_Int TL.Text
334 | ErrorRead_Not_Nat Int
335 | ErrorRead_Not_Nat1 Int
336 | ErrorRead_Not_Rational TL.Text
337 | ErrorRead_Not_Positive TL.Text
338 {- ErrorRead_Unexpected P.sourcePos XML -}
339 deriving (Eq,Ord,Show)
340 instance P.ShowErrorComponent ErrorRead where
341 showErrorComponent = show