{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Language.Symantic.XML.Parser where import Control.Applicative (Applicative(..)) import Control.Monad (Monad(..)) import Data.Bool import Data.Either (Either(..)) import Data.Foldable (Foldable(..)) import Data.Function (($), (.)) import Data.Functor ((<$>), (<$)) import Data.Functor.Identity (Identity(..)) import Data.List.NonEmpty (NonEmpty(..)) import Data.Maybe (Maybe(..)) import Data.Monoid (Monoid(..)) import Data.Ord (Ord(..)) import Data.Proxy (Proxy(..)) import Data.Semigroup (Semigroup(..)) import Data.Sequence (ViewL(..)) import Data.String (String) import Data.Tuple (snd) import Text.Show (Show(..)) import qualified Control.Monad.Trans.State as S import qualified Data.List as List import qualified Data.Sequence as Seq import qualified Text.Megaparsec as P import Language.Symantic.XML.Read.Parser (XML, XMLs) import qualified Language.Symantic.XML.Document as XML import qualified Language.Symantic.XML.Read as XML -- | Whether the given 'XML.Node' must be ignored by the parser. isIgnoredNode :: XML.Node -> Bool isIgnoredNode = \case XML.NodeComment{} -> True XML.NodePI{} -> True XML.NodeCDATA{} -> True _ -> False instance P.Stream XMLs where type Token XMLs = XML type Tokens XMLs = XMLs take1_ s = case Seq.viewl s of EmptyL -> Nothing t@(XML.Tree XML.Sourced{XML.unSourced=n} _) :< ts | isIgnoredNode n -> P.take1_ ts | otherwise -> Just (t, ts) positionAt1 _s pos (XML.Tree (XML.Sourced (XML.FileRange{XML.fileRange_begin=XML.FilePos l c}:|_) _n) _ts) = pos{ P.sourceLine = P.mkPos l , P.sourceColumn = P.mkPos c } positionAtN s pos ts = case Seq.viewl ts of t :< _ -> P.positionAt1 s pos t EmptyL -> pos advance1 _s _indent pos (XML.Tree (XML.Sourced (XML.FileRange{XML.fileRange_end=XML.FilePos l c}:|_) _n) _ts) = -- WARNING: the end of a 'FileRange' is not necessarily -- the beginning of the next 'FileRange'. pos{ P.sourceLine = P.mkPos l , P.sourceColumn = P.mkPos c } advanceN s = foldl' . P.advance1 s takeN_ n s | n <= 0 = Just (mempty, s) | null s = Nothing | otherwise = let (ns,rs) = Seq.splitAt n s in let (ko,ok) = Seq.partition (isIgnoredNode . XML.unSourced . XML.unTree) ns in case P.takeN_ (Seq.length ko) rs of Nothing -> Just (ok, rs) Just (ns',rs') -> Just (ok<>ns', rs') tokensToChunk _s = Seq.fromList chunkToTokens _s = toList chunkLength _s = Seq.length takeWhile_ = Seq.spanl instance P.ShowToken XML where showTokens toks = List.intercalate ", " $ toList $ showTree <$> toks where showTree :: XML -> String showTree (XML.Tree a _ts) = showCell a $ \case XML.NodeElem n -> "<"<>show n XML.NodeAttr n -> show n<>"=" XML.NodeText _t -> "text" XML.NodeComment _c -> "