packages feed

mystem-0.1.0.0: src/NLP/Mystem/Parser.hs

{-# LANGUAGE OverloadedStrings #-}

module NLP.Mystem.Parser where

  import           Control.Applicative
  import           Control.Monad
  import           Data.Attoparsec.Text ((<?>))
  import qualified Data.Attoparsec.Text as P
  import           Data.Default
  import qualified Data.Text            as T

  import           NLP.Mystem.Types

  parserMystems :: P.Parser [MSRes]
  parserMystems = P.sepBy parserMystem P.endOfLine

  parserMystem :: P.Parser MSRes
  parserMystem = do
    P.skipMany P.endOfLine
    sw <- getSWord
    P.skipMany1 (P.char '{') <?> "open sym"
    rws <- P.sepBy1 getRWord (P.char '|') <?> "words"
    P.skipMany1 (P.char '}') <?> "closing sym"
    return $ MSRes sw rws

  getRWord :: P.Parser RWord
  getRWord = do
    rw <- getResultWord
    P.skipMany $ P.char '?'
    gs <- optional $ P.char '='
    flip (maybe (return $ RWord rw (Pos Nothing) def [])) gs $ \_ -> do
      rPos <- getPos
      rGramm <- optional getGramm
      void (P.char '=' <?> "gramm end")
      cs <- P.char '(' *> P.sepBy1 getGramm (P.char '|') <* P.char ')'
              <|> flip (:) [] <$> getGramm
                <|> pure []
      return $ RWord rw rPos rGramm cs

  getGramm :: P.Parser Grams
  getGramm = do
    l <- gsList
    case l of
      [] -> fail "no gramms"
      xs -> return $ fillGrams def xs

  getPos :: P.Parser Pos
  getPos = do
    p <- P.many1 msWChar <?> "pos"
    P.skipMany $ P.char ','
    return $ Pos . readG $ p

  getResultWord :: P.Parser WordT
  getResultWord = T.pack <$> (P.many1 msWChar <?> "rword")

  getSWord :: P.Parser SWord
  getSWord = T.pack <$> (P.many1 msWChar <?> "sword")

  gsList :: P.Parser [String]
  gsList = P.sepBy gsWString (P.char ',')

  gsWString :: P.Parser String
  gsWString = P.many1 (P.letter <|> P.digit)

  gsWChar :: P.Parser Char
  gsWChar = P.letter <|> P.digit

  msWChar :: P.Parser Char
  msWChar = P.letter <|> P.digit <|> P.char '-'