{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE GADTs #-} ---------------------------------------------------------------------------- -- | -- Module : Codec.Winery.Query.Parser -- Copyright : (c) Fumiaki Kinoshita 2019 -- License : BSD3 -- Stability : Experimental -- -- Maintainer : Fumiaki Kinoshita -- -- The language for winery queries -- -- See the Pretty-printing section of README.md for examples. -- ----------------------------------------------------------------------------- module Codec.Winery.Query.Parser (parseQuery) where import Prelude hiding ((.), id) import Control.Category import Codec.Winery.Query import Text.Megaparsec import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as L import qualified Data.Text as T import Prettyprinter (Doc, hsep) import Data.Typeable import Data.Void type Parser = Parsec Void T.Text symbol :: T.Text -> Parser T.Text symbol = L.symbol space name :: Parser T.Text name = fmap T.pack (some (alphaNumChar <|> oneOf ("_\'" :: [Char])) "field name") parseQuery :: Typeable a => Parser (Query (Doc a) (Doc a)) parseQuery = foldr (.) id <$> sepBy1 parseTerms (symbol "|") -- | Space-separated list of terms translate to a tabular output, applying the -- queries in parallel parseTerms :: Typeable a => Parser (Query (Doc a) (Doc a)) parseTerms = fmap hsep . sequenceA <$> sepBy1 parseTerm space parseTerm :: Typeable a => Parser (Query (Doc a) (Doc a)) parseTerm = L.lexeme space $ choice [ char '.' >> choice [ do _ <- char '[' i <- optional L.decimal j <- optional (symbol ":" >> L.decimal) _ <- char ']' return $ range (maybe 0 id i) (maybe (-1) id j) , productItem <$> L.decimal , field <$> name , return id ] ]