{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE DeriveLift                 #-}
{-# LANGUAGE GADTs                      #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase                 #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE RankNTypes                 #-}
{-# LANGUAGE RecordWildCards            #-}
{-# LANGUAGE TemplateHaskell            #-}
module Game.Chess.Internal.ECO where

import           Control.DeepSeq                   (NFData)
import           Control.Monad.IO.Class            (MonadIO (..))
import           Data.Bifunctor                    (Bifunctor (first))
import           Data.Binary                       (Binary (get, put))
import           Data.ByteString.Char8             (ByteString)
import qualified Data.ByteString.Char8             as BS
import           Data.Char                         (chr, ord)
import           Data.Data                         ()
import           Data.Foldable                     (fold)
import           Data.Functor                      (($>))
import           Data.HashMap.Strict               (HashMap)
import qualified Data.HashMap.Strict               as HashMap
import           Data.Hashable                     (Hashable)
import           Data.Maybe                        (fromMaybe)
import           Data.MonoTraversable              (MonoFoldable (ofoldl'))
import           Data.Text                         (Text)
import qualified Data.Text                         as T
import           Data.Tree                         (foldTree)
import           Data.Vector.Binary                ()
import           Data.Vector.Instances             ()
import qualified Data.Vector.Unboxed               as Unboxed
import           Data.Void                         (Void)
import           Data.Word                         (Word8)
import           GHC.Generics                      (Generic)
import           Game.Chess.Internal               (Ply, Position (moveNumber),
                                                    startpos, unsafeDoPly)
import           Game.Chess.PGN                    (Annotated (_annPly),
                                                    Game (CG, _cgForest, _cgOutcome, _cgTags),
                                                    PGN (..), readPGNFile)
import           Game.Chess.SAN                    (relaxedSAN)
import           Instances.TH.Lift                 ()
import           Language.Haskell.TH.Syntax        (Lift)
import           Language.Haskell.TH.Syntax.Compat (Code,
                                                    IsCode (fromCode, toCode),
                                                    SpliceQ, bindCode, joinCode,
                                                    liftTypedQuote)
import           Prelude                           hiding (lookup)
import qualified Prelude
import           Text.Megaparsec                   (MonadParsec (eof), Parsec,
                                                    anySingleBut,
                                                    errorBundlePretty, many,
                                                    optional, parse, single,
                                                    (<?>), (<|>))
import           Text.Megaparsec.Byte              (alphaNumChar, digitChar,
                                                    space, space1, string)
import qualified Text.Megaparsec.Byte.Lexer        as L

-- | A Chess Opening
data Opening = CO {
  Opening -> Text
coCode      :: !Text
, Opening -> Text
coName      :: !Text
, Opening -> Maybe Text
coVariation :: !(Maybe Text)
, Opening -> Vector Ply
coPlies     :: !(Unboxed.Vector Ply)
} deriving (Opening -> Opening -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Opening -> Opening -> Bool
$c/= :: Opening -> Opening -> Bool
== :: Opening -> Opening -> Bool
$c== :: Opening -> Opening -> Bool
Eq, forall x. Rep Opening x -> Opening
forall x. Opening -> Rep Opening x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Opening x -> Opening
$cfrom :: forall x. Opening -> Rep Opening x
Generic, forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => Opening -> m Exp
forall (m :: * -> *). Quote m => Opening -> Code m Opening
liftTyped :: forall (m :: * -> *). Quote m => Opening -> Code m Opening
$cliftTyped :: forall (m :: * -> *). Quote m => Opening -> Code m Opening
lift :: forall (m :: * -> *). Quote m => Opening -> m Exp
$clift :: forall (m :: * -> *). Quote m => Opening -> m Exp
Lift, Int -> Opening -> ShowS
[Opening] -> ShowS
Opening -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Opening] -> ShowS
$cshowList :: [Opening] -> ShowS
show :: Opening -> String
$cshow :: Opening -> String
showsPrec :: Int -> Opening -> ShowS
$cshowsPrec :: Int -> Opening -> ShowS
Show)

instance Binary Opening
instance Hashable Opening
instance NFData Opening

type FileReader = forall m. MonadIO m => FilePath -> m (Either String [Opening])

-- | Parse an ECO database in .pgn format
ecoPgn :: FileReader
ecoPgn :: FileReader
ecoPgn String
fp = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap PGN -> [Opening]
fromPGN' forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *). MonadIO m => String -> m (Either String PGN)
readPGNFile String
fp

-- | Parse an ECO database in .eco format
scidEco :: FileReader
scidEco :: FileReader
scidEco String
fp = forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first forall s e.
(VisualStream s, TraversableStream s, ShowErrorComponent e) =>
ParseErrorBundle s e -> String
errorBundlePretty forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e s a.
Parsec e s a -> String -> s -> Either (ParseErrorBundle s e) a
parse Parser [Opening]
scid' String
fp forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (String -> IO ByteString
BS.readFile String
fp)

-- | Encyclopedia of Chess Openings
newtype ECO = ECO { ECO -> HashMap Position Opening
toHashMap :: HashMap Position Opening }
              deriving (ECO -> ECO -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ECO -> ECO -> Bool
$c/= :: ECO -> ECO -> Bool
== :: ECO -> ECO -> Bool
$c== :: ECO -> ECO -> Bool
Eq, ECO -> ()
forall a. (a -> ()) -> NFData a
rnf :: ECO -> ()
$crnf :: ECO -> ()
NFData, Eq ECO
Int -> ECO -> Int
ECO -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: ECO -> Int
$chash :: ECO -> Int
hashWithSalt :: Int -> ECO -> Int
$chashWithSalt :: Int -> ECO -> Int
Hashable, NonEmpty ECO -> ECO
ECO -> ECO -> ECO
forall b. Integral b => b -> ECO -> ECO
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: forall b. Integral b => b -> ECO -> ECO
$cstimes :: forall b. Integral b => b -> ECO -> ECO
sconcat :: NonEmpty ECO -> ECO
$csconcat :: NonEmpty ECO -> ECO
<> :: ECO -> ECO -> ECO
$c<> :: ECO -> ECO -> ECO
Semigroup, Semigroup ECO
ECO
[ECO] -> ECO
ECO -> ECO -> ECO
forall a.
Semigroup a -> a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
mconcat :: [ECO] -> ECO
$cmconcat :: [ECO] -> ECO
mappend :: ECO -> ECO -> ECO
$cmappend :: ECO -> ECO -> ECO
mempty :: ECO
$cmempty :: ECO
Monoid)

instance Binary ECO where
  put :: ECO -> Put
put = forall t. Binary t => t -> Put
put forall b c a. (b -> c) -> (a -> b) -> a -> c
. ECO -> [Opening]
toList
  get :: Get ECO
get = [Opening] -> ECO
fromList forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall t. Binary t => Get t
get

embedECO :: FileReader -> FilePath -> SpliceQ ECO
embedECO :: FileReader -> String -> SpliceQ ECO
embedECO FileReader
load String
fp = forall (q :: * -> *) a c. IsCode q a c => Code q a -> c
fromCode forall a b. (a -> b) -> a -> b
$
  (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmapforall b c a. (b -> c) -> (a -> b) -> a -> c
.forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) forall t (m :: * -> *). (Lift t, Quote m) => t -> Code m t
liftTypedQuote (FileReader
load String
fp) forall (m :: * -> *) a b.
Monad m =>
m a -> (a -> Code m b) -> Code m b
`bindCode` \Either String (Code Q [Opening])
x -> forall (m :: * -> *) a. Monad m => m (Code m a) -> Code m a
joinCode forall a b. (a -> b) -> a -> b
$
    case Either String (Code Q [Opening])
x of
      Right Code Q [Opening]
xs -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall (q :: * -> *) a c. IsCode q a c => c -> Code q a
toCode [|| fromList $$(fromCode xs) ||]
      Left String
err -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
err

toList :: ECO -> [Opening]
toList :: ECO -> [Opening]
toList = forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k v. HashMap k v -> [(k, v)]
HashMap.toList forall b c a. (b -> c) -> (a -> b) -> a -> c
. ECO -> HashMap Position Opening
toHashMap

fromList :: [Opening] -> ECO
fromList :: [Opening] -> ECO
fromList = HashMap Position Opening -> ECO
ECO forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Opening
co -> (Opening -> Position
pos Opening
co, Opening
co)) where
  pos :: Opening -> Position
pos = forall mono a.
MonoFoldable mono =>
(a -> Element mono -> a) -> a -> mono -> a
ofoldl' Position -> Ply -> Position
unsafeDoPly Position
startpos forall b c a. (b -> c) -> (a -> b) -> a -> c
. Opening -> Vector Ply
coPlies

-- | Convert a PGN database to ECO assuming the ECO, Opening and Variation tags are
-- being used to identify chess openings.
fromPGN :: PGN -> ECO
fromPGN :: PGN -> ECO
fromPGN = [Opening] -> ECO
fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. PGN -> [Opening]
fromPGN'

fromPGN' :: PGN -> [Opening]
fromPGN' :: PGN -> [Opening]
fromPGN' (PGN [Game]
games) = forall a b. (a -> b) -> [a] -> [b]
map Game -> Opening
mkCO [Game]
games where
  mkCO :: Game -> Opening
mkCO CG { [(Text, Text)]
[Tree (Annotated Ply)]
Outcome
_cgOutcome :: Outcome
_cgForest :: [Tree (Annotated Ply)]
_cgTags :: [(Text, Text)]
_cgTags :: Game -> [(Text, Text)]
_cgOutcome :: Game -> Outcome
_cgForest :: Game -> [Tree (Annotated Ply)]
.. } = CO { Maybe Text
Text
Vector Ply
coPlies :: Vector Ply
coVariation :: Maybe Text
coName :: Text
coCode :: Text
coPlies :: Vector Ply
coVariation :: Maybe Text
coName :: Text
coCode :: Text
.. } where
    lt :: Text -> Maybe Text
lt = (forall a b. Eq a => a -> [(a, b)] -> Maybe b
`Prelude.lookup` [(Text, Text)]
_cgTags)
    coCode :: Text
coCode = forall a. a -> Maybe a -> a
fromMaybe Text
"" forall a b. (a -> b) -> a -> b
$ Text -> Maybe Text
lt Text
"ECO"
    coName :: Text
coName = forall a. a -> Maybe a -> a
fromMaybe Text
"" forall a b. (a -> b) -> a -> b
$ Text -> Maybe Text
lt Text
"Opening"
    coVariation :: Maybe Text
coVariation = Text -> Maybe Text
lt Text
"Variation"
    coPlies :: Vector Ply
coPlies = forall a. Unbox a => [a] -> Vector a
Unboxed.fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> a
head forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (forall a b. (a -> [b] -> b) -> Tree a -> b
foldTree forall {a}. Annotated a -> [[[a]]] -> [[a]]
g) forall a b. (a -> b) -> a -> b
$ [Tree (Annotated Ply)]
_cgForest where
      g :: Annotated a -> [[[a]]] -> [[a]]
g Annotated a
a [] = [[forall a. Annotated a -> a
_annPly Annotated a
a]]
      g Annotated a
a [[[a]]]
xs = (forall a. Annotated a -> a
_annPly Annotated a
a forall a. a -> [a] -> [a]
:) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold [[[a]]]
xs

opening :: Parser Opening
opening :: Parser Opening
opening = Text -> Text -> Maybe Text -> Vector Ply -> Opening
CO forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Parser a -> Parser a
lexeme Parser Text
code forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Parser a -> Parser a
lexeme Parser Text
var forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a. Maybe a
Nothing forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall a. Parser a -> Parser a
lexeme (Position -> Parser (Vector Ply)
plies Position
startpos)

code :: Parser Text
code :: Parser Text
code = Parser Text
p forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> String -> m a
<?> String
"code" where
  p :: Parser Text
p = forall {a}. Enum a => a -> [a] -> Maybe a -> Text
f forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Word8) =>
m (Token s)
alphaNumChar forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (m :: * -> *) a. MonadPlus m => m a -> m [a]
many forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Word8) =>
m (Token s)
digitChar forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Word8) =>
m (Token s)
alphaNumChar
  f :: a -> [a] -> Maybe a -> Text
f a
x [a]
xs Maybe a
y = let s :: [a]
s = a
x forall a. a -> [a] -> [a]
: [a]
xs in String -> Text
T.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> Char
chr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> Int
fromEnum) forall a b. (a -> b) -> a -> b
$ case Maybe a
y of
    Maybe a
Nothing -> [a]
s
    Just a
y' -> [a]
s forall a. [a] -> [a] -> [a]
++ [a
y']

var :: Parser Text
var :: Parser Text
var = Parser Text
p forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> String -> m a
<?> String
"string" where
  p :: Parser Text
p = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String -> Text
T.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> Char
chr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> Int
fromEnum)) forall a b. (a -> b) -> a -> b
$ forall e s (m :: * -> *).
MonadParsec e s m =>
Token s -> m (Token s)
single Word8
quoteChar forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall (m :: * -> *) a. MonadPlus m => m a -> m [a]
many ParsecT Void ByteString Identity Word8
ch forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* forall e s (m :: * -> *).
MonadParsec e s m =>
Token s -> m (Token s)
single Word8
quoteChar
  ch :: ParsecT Void ByteString Identity Word8
ch = forall e s (m :: * -> *).
MonadParsec e s m =>
Token s -> m (Token s)
single Word8
backslashChar forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> (  forall e s (m :: * -> *).
MonadParsec e s m =>
Token s -> m (Token s)
single Word8
backslashChar forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> Word8
backslashChar
                              forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall e s (m :: * -> *).
MonadParsec e s m =>
Token s -> m (Token s)
single Word8
quoteChar forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> Word8
quoteChar
                               )
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall e s (m :: * -> *).
MonadParsec e s m =>
Token s -> m (Token s)
anySingleBut Word8
quoteChar

plies :: Position -> Parser (Unboxed.Vector Ply)
plies :: Position -> Parser (Vector Ply)
plies = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Unbox a => [a] -> Vector a
Unboxed.fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. Position -> ParsecT Void ByteString Identity [Ply]
go where
  go :: Position -> ParsecT Void ByteString Identity [Ply]
go Position
p = forall {a}. ParsecT Void ByteString Identity [a]
eol forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ParsecT Void ByteString Identity [Ply]
line where
    eol :: ParsecT Void ByteString Identity [a]
eol = forall a. Parser a -> Parser a
lexeme (forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Tokens ByteString
"*") forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> []
    line :: ParsecT Void ByteString Identity [Ply]
line = ParsecT Void ByteString Identity Ply
ply forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Ply
pl -> (Ply
pl forall a. a -> [a] -> [a]
:) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Position -> ParsecT Void ByteString Identity [Ply]
go (Position -> Ply -> Position
unsafeDoPly Position
p Ply
pl)
    ply :: ParsecT Void ByteString Identity Ply
ply = Position -> ParsecT Void ByteString Identity ()
validateMoveNumber Position
p forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall a. Parser a -> Parser a
lexeme (forall s.
(Stream s, SANToken (Token s), IsString (Tokens s)) =>
Position -> Parser s Ply
relaxedSAN Position
p)
  validateMoveNumber :: Position -> ParsecT Void ByteString Identity ()
validateMoveNumber Position
p =
    forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (forall a. Parser a -> Parser a
lexeme forall a b. (a -> b) -> a -> b
$ forall e s (m :: * -> *) a.
(MonadParsec e s m, Token s ~ Word8, Num a) =>
m a
L.decimal forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Word8) =>
m ()
space forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* forall (m :: * -> *) a. MonadPlus m => m a -> m [a]
many (forall e s (m :: * -> *).
MonadParsec e s m =>
Token s -> m (Token s)
single Word8
periodChar)) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      Just Int
n | Position -> Int
moveNumber Position
p forall a. Eq a => a -> a -> Bool
/= Int
n ->
        forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"Invalid move number: " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show Int
n forall a. Semigroup a => a -> a -> a
<> String
" /= " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show (Position -> Int
moveNumber Position
p)
      Maybe Int
_ -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

-- | A parser for opening databases in SCID .eco format
scid :: Parser ECO
scid :: Parser ECO
scid = [Opening] -> ECO
fromList forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser [Opening]
scid'

scid' :: Parser [Opening]
scid' :: Parser [Opening]
scid' = ParsecT Void ByteString Identity ()
spaceConsumer forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall (m :: * -> *) a. MonadPlus m => m a -> m [a]
many Parser Opening
opening forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* forall e s (m :: * -> *). MonadParsec e s m => m ()
eof

readECOPGNFile :: MonadIO m => FilePath -> m (Either String ECO)
readECOPGNFile :: forall (m :: * -> *). MonadIO m => String -> m (Either String ECO)
readECOPGNFile = (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) [Opening] -> ECO
fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileReader
ecoPgn

readSCIDECOFile :: MonadIO m => FilePath -> m (Either String ECO)
readSCIDECOFile :: forall (m :: * -> *). MonadIO m => String -> m (Either String ECO)
readSCIDECOFile = (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap) [Opening] -> ECO
fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileReader
scidEco

-- | Retrieve the opening for a particular position
lookup :: Position -> ECO -> Maybe Opening
lookup :: Position -> ECO -> Maybe Opening
lookup Position
pos = forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Position
pos forall b c a. (b -> c) -> (a -> b) -> a -> c
. ECO -> HashMap Position Opening
toHashMap

type Parser = Parsec Void ByteString

spaceConsumer :: Parser ()
spaceConsumer :: ParsecT Void ByteString Identity ()
spaceConsumer = forall e s (m :: * -> *).
MonadParsec e s m =>
m () -> m () -> m () -> m ()
L.space
  forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Word8) =>
m ()
space1 (forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Word8) =>
Tokens s -> m ()
L.skipLineComment Tokens ByteString
"#") (forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Word8) =>
Tokens s -> Tokens s -> m ()
L.skipBlockComment Tokens ByteString
"{" Tokens ByteString
"}")

lexeme :: Parser a -> Parser a
lexeme :: forall a. Parser a -> Parser a
lexeme = forall e s (m :: * -> *) a. MonadParsec e s m => m () -> m a -> m a
L.lexeme ParsecT Void ByteString Identity ()
spaceConsumer

periodChar, quoteChar, backslashChar :: Word8
periodChar :: Word8
periodChar    = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ Char -> Int
ord Char
'.'
quoteChar :: Word8
quoteChar     = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ Char -> Int
ord Char
'"'
backslashChar :: Word8
backslashChar = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ Char -> Int
ord Char
'\\'