packages feed

rest-rewrite-0.1: src/Language/REST/OpOrdering.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}


module Language.REST.OpOrdering (
    empty
  , merge
  , OpOrdering
  , opInsert
  , opGT
  , opEQ
  , (=.)
  , (>.)
  , parseOO
  ) where

import Prelude hiding (GT, EQ)
import GHC.Generics (Generic)
import Data.Hashable
import Data.Maybe
import qualified Data.Text as T
import qualified Data.HashSet as S
import Text.ParserCombinators.Parsec.Char
import Text.ParserCombinators.Parsec
import Text.Parsec (parserTrace)

import qualified Language.REST.PartialOrder as PO
import           Language.REST.Op
import           Language.REST.Types
import           Language.REST.WQO as WQO


type PartialOrder = PO.PartialOrder
type OpOrdering   = WQO Op


opGT :: OpOrdering -> Op -> Op -> Bool
opGT s f g = getRelation s f g == Just QGT

opEQ :: OpOrdering -> Op -> Op -> Bool
opEQ s f g = getRelation s f g == Just QEQ


opInsert :: OpOrdering -> Op -> Op -> QORelation -> Maybe OpOrdering
opInsert o f g r =
  case WQO.insert o (f, g, r) of
    ValidExtension o' -> Just o'
    _                 -> Nothing

-- The following only are valid if f /= g.

-- precondition : f /= g
(>.) :: Op -> Op -> OpOrdering
(>.) f g = fromJust $ WQO.singleton (f, g, QGT)

-- precondition : f /= g
(=.) :: Op -> Op -> OpOrdering
(=.) f g = fromJust $ WQO.singleton (f, g, QEQ)

-- precondition : f /= g
(<.) :: Op -> Op -> OpOrdering
(<.) f g = g >. f

parseOO :: String -> Maybe OpOrdering
parseOO str =
  case parse parser "" str of
    Left err -> error (show err)
    Right t  -> t

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 '*'))