ideas-1.9.1: src/Ideas/Common/Rewriting/Term/Decoder.hs
-----------------------------------------------------------------------------
-- Copyright 2019, Ideas project team. This file is distributed under the
-- terms of the Apache License 2.0. For more information, see the files
-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer : bastiaan.heeren@ou.nl
-- Stability : provisional
-- Portability : portable (depends on ghc)
--
-- Generic terms
--
-----------------------------------------------------------------------------
module Ideas.Common.Rewriting.Term.Decoder
( TermDecoder
, tCon, tCon0, tCon1, tCon2, tCon3, tConOf, tInteger, tDouble, tVar, tListOf, tConWithSymbol
, tListWith, tList2, tList3, tChar, tFirst
-- re-exports
, Alternative(..), MonadReader(..), throwError
) where
import Control.Monad
import Ideas.Common.Rewriting.Term.Data
import Ideas.Utils.Decoding
-----------------------------------------------------------
-- * Type class for conversion to/from terms
type TermDecoder = Decoder () (Error Term) [Term]
tFirst :: (Maybe Term -> TermDecoder a) -> TermDecoder a
tFirst f = get >>= \xs ->
case xs of
t:rest -> f (Just t) <* changeLoc nextLoc <* put rest
_ -> f Nothing
tVar :: TermDecoder String
tVar = tFirst $ \mt ->
case mt of
Just (TVar s) -> return s
_ -> raiseError "not a var" mt
tChar :: TermDecoder Char
tChar = tFirst $ \mt ->
case mt of
Just (TVar [c]) -> return c
_ -> raiseError "not a char" mt
tInteger :: TermDecoder Integer
tInteger = tFirst $ \mt ->
case mt of
Just (TNum i) -> return i
_ -> raiseError "not an integer" mt
tDouble :: TermDecoder Double
tDouble = tFirst $ \mt ->
case mt of
Just (TFloat f) -> return f
_ -> raiseError "not a double" mt
-- name tList clashes with service type
tListWith :: TermDecoder a -> TermDecoder a
tListWith p = tFirst $ \mt ->
case mt of
Just (TList xs) -> changeLoc (LocByPos 0) >> put xs *> p <* tEmpty
_ -> raiseError "not a list" mt
tCon :: Symbol -> TermDecoder a -> TermDecoder a
tCon s1 p = tFirst $ \mt ->
case mt of
Just (TCon s2 xs) | s1 == s2 -> changeLoc (LocByPos 0) >> put xs *> p <* tEmpty
_ -> raiseError ("not con '" ++ show s1 ++ "'") mt
tEmpty :: TermDecoder ()
tEmpty = get >>= \xs -> unless (null xs) (errorStr "not empty")
tCon0 :: Symbol -> TermDecoder ()
tCon0 s = tCon s (return ())
tCon1 :: Symbol -> (a -> b) -> TermDecoder a -> TermDecoder b
tCon1 s f p = tCon s (f <$> p)
tCon2 :: Symbol -> (a -> b -> c) -> TermDecoder a -> TermDecoder b -> TermDecoder c
tCon2 s f p q = tCon s (f <$> p <*> q)
tCon3 :: Symbol -> (a -> b -> c -> d) -> TermDecoder a -> TermDecoder b -> TermDecoder c -> TermDecoder d
tCon3 s f p q r = tCon s (f <$> p <*> q <*> r)
tConOf :: Symbol -> TermDecoder a -> TermDecoder [a]
tConOf s p = tCon s (many p)
tConWithSymbol :: (Symbol -> [a] -> b) -> TermDecoder a -> TermDecoder b
tConWithSymbol f p = tFirst $ \mt ->
case mt of
Just (TCon s xs) -> f s <$ changeLoc (LocByPos 0) <* put xs <*> many p <* tEmpty
_ -> raiseError "not a con" mt
tList2 :: (a -> b -> c) -> TermDecoder a -> TermDecoder b -> TermDecoder c
tList2 f p q = tListWith $ f <$> p <*> q
tList3 :: (a -> b -> c -> d) -> TermDecoder a -> TermDecoder b -> TermDecoder c -> TermDecoder d
tList3 f p q r = tListWith $ f <$> p <*> q <*> r
tListOf :: TermDecoder a -> TermDecoder [a]
tListOf p = tListWith $ many p