packages feed

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

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}

module Language.REST.Types (
    prettyPrint
  , PPArgs(..)
  , Relation(..)
  , toOrderedSet
  ) where

import GHC.Generics (Generic)
import Prelude hiding (GT, EQ)

import           Data.Hashable
import qualified Data.List as L
import qualified Data.HashSet as S
import qualified Data.Set as OS
import qualified Data.Map as M
import qualified Data.Text as T
import           Text.Printf

import           Language.REST.Op
import           Language.REST.MetaTerm as MT
import           Language.REST.RuntimeTerm as MT

data PPArgs = PPArgs
  { ppReplace  :: [(T.Text, T.Text)]
  , ppInfixOps :: [(T.Text, T.Text)]
  , ppCustom   :: MetaTerm -> Maybe T.Text
  }

prettyPrint :: ToMetaTerm a => PPArgs -> a -> String
prettyPrint (PPArgs substs infixOps custom) t = T.unpack $ go $ replaceAll $ toMetaTerm t where

  replace s | Just (from, to) <- L.find ((`T.isPrefixOf` s) . fst) substs
            = T.append to $ T.drop (T.length from) s
  replace s | otherwise = s

  replaceAll :: MT.MetaTerm -> MT.MetaTerm
  replaceAll (MT.Var x)            = MT.Var x
  replaceAll (MT.RWApp (Op op) ts) = MT.RWApp (Op (replace op)) (map replaceAll ts)



  go :: MT.MetaTerm -> T.Text
  go (MT.Var x) = T.pack x
  go t | Just s <- custom t      = s
  go (MT.RWApp (Op op) [t1, t2]) | Just op' <- L.lookup op infixOps
    = T.pack $ printf "%s %s %s" (goParens t1) op' (goParens t2)
  go (MT.RWApp (Op op) [])       = op
  go (MT.RWApp (Op op) xs)       = T.concat [op, "(" , T.intercalate ", " (map go xs) , ")"]

  goParens t | needsParens t = T.pack $ printf "(%s)" (go t)
  goParens t | otherwise     = go t

  needsParens (MT.RWApp (Op op) _) = op `elem` (map fst infixOps)
  needsParens _                    = False

data Relation = GT | GTE | EQ deriving (Eq, Generic, Hashable)

instance Show Relation where
  show GT  = ">"
  show GTE = "≥"
  show EQ  = "≅"

instance Hashable a => Hashable (OS.Set a) where
  hashWithSalt i s = hashWithSalt i (OS.toList s)

instance (Hashable a, Hashable b) => Hashable (M.Map a b) where
  hashWithSalt i s = hashWithSalt i (M.toList s)

toOrderedSet :: (Eq a, Hashable a, Ord a) => S.HashSet a -> OS.Set a
toOrderedSet = OS.fromList . S.toList