{-# LANGUAGE ExistentialQuantification #-} ----------------------------------------------------------------------------- -- | -- Module : Sindre.KeyVal -- License : MIT-style (see LICENSE) -- -- Stability : provisional -- Portability : portable -- -- A simple language for mapping keys to either a single string-value -- or a list of strings. The syntax is line-oriented and extremely -- simple. A line consists of key-value pairs, which are written as -- the key, followed by an equals sign, followed by a double-quoted -- string. Several double-quoted strings can follow the equal sign, -- in which case they will be treated as a list. Space characters -- separate elements, as so: -- -- @foo="string" bar="another string" baz="s1" "s2" "this is a list" "s4"@ -- -- Literal double-quotes can be included in a string by doubling them. -- -- @foo="this string contains ""quotes""" -- ----------------------------------------------------------------------------- module Sindre.KeyVal( parseKV , value , values , (<$?>) , (<||>) , (<$$>) , (<|?>) ) where import Control.Applicative hiding (many, empty) import Control.Monad.Identity import Data.Attoparsec.Combinator import Data.Attoparsec.Text import qualified Data.Text as T import Text.ParserCombinators.Perm import Prelude hiding (takeWhile) -- | Parse a key-value string wrapper constructed via the permutation -- parser combinators from 'Text.Parsec.Perm' and the parsers @value@ -- and @values@. parseKV :: PermParser Parser a -> T.Text -> Either String a parseKV p s = eitherResult $ parse (permute p <* endOfInput) s `feed` T.empty -- | @value k@ is a parser for the single-valued key @k@. value :: T.Text -> Parser T.Text value k = try (string k) *> realSpaces *> char '=' *> realSpaces *> quotedString <* realSpaces -- | @values k@ is a parser for the list-valued key @k@. At least a -- single value is required. values :: T.Text -> Parser [T.Text] values k = try (string k) *> realSpaces *> char '=' *> realSpaces *> many1 quotedString <* realSpaces quotedString :: Parser T.Text quotedString = char '"' *> inner <* realSpaces where inner = do s <- takeWhile (/='"') char '\"' *> (char '\"' *> (T.append (T.snoc s '"') <$> inner) <|> return s) realSpaces :: Parser T.Text realSpaces = takeWhile (==' ')