rest-rewrite-0.4.1: src/Language/REST/Internal/OpOrdering.hs
{-# LANGUAGE FlexibleInstances #-}
-- | This module defines an interface for 'WQO's on 'Op'erators,
-- for example, that are used as the precedence for an [RPQO]("Language.REST.RPO").
module Language.REST.Internal.OpOrdering (
empty
, OpOrdering
, opGT
, opEQ
, (=.)
, (>.)
, (<.)
, parseOO
) where
import Prelude hiding (GT, EQ)
import Data.Maybe
import qualified Data.Text as T
import Text.ParserCombinators.Parsec.Char
import Text.ParserCombinators.Parsec
import Text.Parsec (Parsec)
import Language.REST.Op
import Language.REST.Internal.WQO as WQO
type OpOrdering = WQO Op
-- | @opGT o f g@ returns @true@ if @f > g@ in @o@
opGT :: OpOrdering -> Op -> Op -> Bool
opGT s f g = getRelation s f g == Just QGT
-- | @opEQ o f g@ returns @true@ if @f = g@ in @o@
opEQ :: OpOrdering -> Op -> Op -> Bool
opEQ s f g = getRelation s f g == Just QEQ
-- | @f >. g@ generates a new ordering with @f@ greater than @g@.
-- This function is undefined if f == g.
(>.) :: Op -> Op -> OpOrdering
(>.) f g = fromJust $ WQO.singleton (f, g, QGT)
-- | @f =. g@ generates a new ordering with @f@ equal to @g@.
-- This function is undefined if f == g.
(=.) :: Op -> Op -> OpOrdering
(=.) f g = fromJust $ WQO.singleton (f, g, QEQ)
-- | @f <. g@ generates a new ordering with @f@ less than @g@.
-- This function is undefined if f == g.
(<.) :: Op -> Op -> OpOrdering
(<.) f g = g >. f
-- | @parseOO str@ returns the ordering defined by @str@. If the input describes
-- /any/ ordering, (i.e "f = f"), then this function returns 'Nothing'.
parseOO :: String -> Maybe OpOrdering
parseOO str =
case parse parser "" str of
Left err -> error (show err)
Right t -> t
parser :: Parsec String u (Maybe OpOrdering)
parser = fmap mergeAll' (sepBy1 atom conj) where
mergeAll' :: [Maybe OpOrdering] -> Maybe OpOrdering
mergeAll' [x] = x
mergeAll' (Just x : Just x' : xs) =
do
x'' <- merge x x'
mergeAll' (Just x'' : xs)
mergeAll' _ = Nothing
conj = spaces >> (char '\8743' <|> char '^') >> spaces
eq = spaces >> char '=' >> spaces
gt = spaces >> char '>' >> spaces
atom = try gtAtom <|> try eqAtom
eqAtom = fmap allEQ (sepBy1 sym (try eq))
where
mkEQ f g = WQO.singleton (f, g, QEQ)
allEQ syms =
let
pairs = zipWith mkEQ syms (tail syms)
in
mergeAll' pairs
gtAtom = do
left <- sym
_ <- gt
right <- sym
return $ WQO.singleton (left, right, QGT)
sym = fmap (Op . T.pack) (many (alphaNum <|> char '+' <|> char '*'))