module Language.Egison.Types
(
EgisonTopExpr (..)
, EgisonExpr (..)
, EgisonPattern (..)
, InnerExpr (..)
, BindingExpr (..)
, MatchClause (..)
, MatcherInfo (..)
, LoopRange (..)
, PrimitivePatPattern (..)
, PrimitiveDataPattern (..)
, EgisonValue (..)
, Matcher (..)
, PrimitiveFunc (..)
, Egison (..)
, fromMatcherValue
, Object (..)
, ObjectRef (..)
, WHNFData (..)
, Intermediate (..)
, Inner (..)
, EgisonWHNF (..)
, Env (..)
, Var (..)
, Binding (..)
, nullEnv
, extendEnv
, refVar
, PMMode (..)
, MatchingState (..)
, MatchingTree (..)
, PatternBinding (..)
, LoopContext (..)
, EgisonError (..)
, liftError
, EgisonM (..)
, runEgisonM
, liftEgisonM
, fromEgisonM
, FreshT (..)
, Fresh (..)
, MonadFresh (..)
, runFreshT
, MatchM (..)
, matchFail
, MList (..)
, fromList
, fromSeq
, fromMList
, msingleton
, mfoldr
, mappend
, mconcat
, mmap
, mfor
) where
import Prelude hiding (foldr)
import Control.Exception
import Data.Typeable
import Control.Applicative
import Control.Monad.Error
import Control.Monad.State
import Control.Monad.Reader (ReaderT)
import Control.Monad.Writer (WriterT)
import Control.Monad.Identity
import Control.Monad.Trans.Maybe
import Data.Monoid (Monoid)
import qualified Data.Sequence as Sq
import Data.Sequence (Seq)
import Data.Foldable (foldr, toList)
import Data.IORef
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BL
import Data.ByteString.Lazy.Char8 ()
import qualified Data.ByteString.Lazy.Char8 as B
import System.IO
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.Ratio
import System.IO.Unsafe (unsafePerformIO)
data EgisonTopExpr =
Define String EgisonExpr
| Test EgisonExpr
| Execute EgisonExpr
| LoadFile String
| Load String
deriving (Show)
data EgisonExpr =
CharExpr Char
| StringExpr String
| BoolExpr Bool
| RationalExpr Rational
| IntegerExpr Integer
| FloatExpr Double
| VarExpr String
| IndexedExpr EgisonExpr [EgisonExpr]
| InductiveDataExpr String [EgisonExpr]
| TupleExpr [EgisonExpr]
| CollectionExpr (Seq InnerExpr)
| ArrayExpr [EgisonExpr]
| HashExpr [(EgisonExpr, EgisonExpr)]
| LambdaExpr [String] EgisonExpr
| PatternFunctionExpr [String] EgisonPattern
| IfExpr EgisonExpr EgisonExpr EgisonExpr
| LetExpr [BindingExpr] EgisonExpr
| LetRecExpr [BindingExpr] EgisonExpr
| MatchExpr EgisonExpr EgisonExpr [MatchClause]
| MatchAllExpr EgisonExpr EgisonExpr MatchClause
| MatchLambdaExpr EgisonExpr [MatchClause]
| MatcherExpr MatcherInfo
| DoExpr [BindingExpr] EgisonExpr
| IoExpr EgisonExpr
| ApplyExpr EgisonExpr EgisonExpr
| AlgebraicDataMatcherExpr [(String, [EgisonExpr])]
| GenerateArrayExpr [String] EgisonExpr EgisonExpr
| ArraySizeExpr EgisonExpr
| ArrayRefExpr EgisonExpr EgisonExpr
| ValueExpr EgisonValue
| SomethingExpr
| UndefinedExpr
deriving (Show)
data InnerExpr =
ElementExpr EgisonExpr
| SubCollectionExpr EgisonExpr
deriving (Show)
type BindingExpr = ([String], EgisonExpr)
type MatchClause = (EgisonPattern, EgisonExpr)
type MatcherInfo = [(PrimitivePatPattern, EgisonExpr, [(PrimitiveDataPattern, EgisonExpr)])]
data EgisonPattern =
WildCard
| PatVar String
| VarPat String
| ValuePat EgisonExpr
| PredPat EgisonExpr
| IndexedPat EgisonPattern [EgisonExpr]
| LetPat [BindingExpr] EgisonPattern
| NotPat EgisonPattern
| AndPat [EgisonPattern]
| OrPat [EgisonPattern]
| TuplePat [EgisonPattern]
| InductivePat String [EgisonPattern]
| ApplyPat EgisonExpr [EgisonPattern]
| LoopPat String LoopRange EgisonPattern EgisonPattern
| ContPat
deriving (Show)
data LoopRange =
LoopRangeConstant EgisonExpr EgisonExpr
| LoopRangeVariable EgisonExpr EgisonPattern
deriving (Show)
data PrimitivePatPattern =
PPWildCard
| PPPatVar
| PPValuePat String
| PPInductivePat String [PrimitivePatPattern]
deriving (Show)
data PrimitiveDataPattern =
PDWildCard
| PDPatVar String
| PDInductivePat String [PrimitiveDataPattern]
| PDEmptyPat
| PDConsPat PrimitiveDataPattern PrimitiveDataPattern
| PDSnocPat PrimitiveDataPattern PrimitiveDataPattern
| PDConstantPat EgisonExpr
deriving (Show)
data EgisonValue =
World
| Char Char
| Bool Bool
| Rational Rational
| Integer Integer
| Float Double
| InductiveData String [EgisonValue]
| Tuple [EgisonValue]
| Collection (Seq EgisonValue)
| Array (IntMap EgisonValue)
| IntHash (HashMap Integer EgisonValue)
| StrHash (HashMap ByteString EgisonValue)
| Matcher Matcher
| Func Env [String] EgisonExpr
| PatternFunc Env [String] EgisonPattern
| PrimitiveFunc PrimitiveFunc
| IOFunc (EgisonM WHNFData)
| Port Handle
| Something
| Undefined
| EOF
type Matcher = (Env, MatcherInfo)
type PrimitiveFunc = WHNFData -> EgisonM WHNFData
instance Show EgisonValue where
show (Char c) = "'" ++ [c] ++ "'"
show (Bool True) = "#t"
show (Bool False) = "#f"
show (Rational x) = show (numerator x) ++ "/" ++ show (denominator x)
show (Integer i) = show i
show (Float f) = show f
show (InductiveData name []) = "<" ++ name ++ ">"
show (InductiveData name vals) = "<" ++ name ++ " " ++ unwords (map show vals) ++ ">"
show (Tuple vals) = "[" ++ unwords (map show vals) ++ "]"
show (Collection vals) = if Sq.null vals
then "{}"
else if all isChar (toList vals)
then "\"" ++ map (\(Char c) -> c) (toList vals) ++ "\""
else "{" ++ unwords (map show (toList vals)) ++ "}"
where
isChar :: EgisonValue -> Bool
isChar (Char _) = True
isChar _ = False
show (Array vals) = "[|" ++ unwords (map show $ IntMap.elems vals) ++ "|]"
show (IntHash hash) = "{|" ++ unwords (map (\(key, val) -> "[" ++ show key ++ " " ++ show val ++ "]") $ HashMap.toList hash) ++ "|}"
show (StrHash hash) = "{|" ++ unwords (map (\(key, val) -> "[\"" ++ B.unpack key ++ "\" " ++ show val ++ "]") $ HashMap.toList hash) ++ "|}"
show (Matcher _) = "#<matcher>"
show (Func _ names _) = "(lambda [" ++ unwords names ++ "] ...)"
show (PatternFunc _ _ _) = "#<pattern-function>"
show (PrimitiveFunc _) = "#<primitive-function>"
show (IOFunc _) = "#<io-function>"
show (Port _) = "#<port>"
show Something = "something"
show Undefined = "undefined"
show World = "#<world>"
show EOF = "#<eof>"
instance Eq EgisonValue where
(Char c) == (Char c') = c == c'
(Bool b) == (Bool b') = b == b'
(Integer i) == (Integer i') = i == i'
(Float f) == (Float f') = f == f'
(InductiveData name vals) == (InductiveData name' vals') = name == name' && vals == vals'
(Tuple vals) == (Tuple vals') = vals == vals'
(Array vals) == (Array vals') = vals == vals'
(Collection vals) == (Collection vals') = vals == vals'
_ == _ = False
class Egison a where
toEgison :: a -> EgisonValue
fromEgison :: EgisonValue -> EgisonM a
instance Egison Char where
toEgison c = Char c
fromEgison = liftError . fromCharValue
instance Egison Bool where
toEgison b = Bool b
fromEgison = liftError . fromBoolValue
instance Egison Integer where
toEgison i = Integer i
fromEgison = liftError . fromIntegerValue
instance Egison Rational where
toEgison r = Rational r
fromEgison = liftError . fromRationalValue
instance Egison Double where
toEgison f = Float f
fromEgison = liftError . fromFloatValue
instance Egison Handle where
toEgison h = Port h
fromEgison = liftError . fromPortValue
instance (Egison a) => Egison [a] where
toEgison xs = Collection $ Sq.fromList (map toEgison xs)
fromEgison (Collection seq) = mapM fromEgison (toList seq)
fromEgison val = liftError $ throwError $ TypeMismatch "collection" (Value val)
instance Egison () where
toEgison () = Tuple []
fromEgison (Tuple []) = return ()
fromEgison val = liftError $ throwError $ TypeMismatch "zero element tuple" (Value val)
instance (Egison a, Egison b) => Egison (a, b) where
toEgison (x, y) = Tuple [toEgison x, toEgison y]
fromEgison (Tuple (x:y:[])) = (liftM2 (,)) (fromEgison x) (fromEgison y)
fromEgison val = liftError $ throwError $ TypeMismatch "two elements tuple" (Value val)
instance (Egison a, Egison b, Egison c) => Egison (a, b, c) where
toEgison (x, y, z) = Tuple [toEgison x, toEgison y, toEgison z]
fromEgison (Tuple (x:y:z:[])) = do
x' <- fromEgison x
y' <- fromEgison y
z' <- fromEgison z
return (x', y', z')
fromEgison val = liftError $ throwError $ TypeMismatch "two elements tuple" (Value val)
instance (Egison a, Egison b, Egison c, Egison d) => Egison (a, b, c, d) where
toEgison (x, y, z, w) = Tuple [toEgison x, toEgison y, toEgison z, toEgison w]
fromEgison (Tuple (x:y:z:w:[])) = do
x' <- fromEgison x
y' <- fromEgison y
z' <- fromEgison z
w' <- fromEgison w
return (x', y', z', w')
fromEgison val = liftError $ throwError $ TypeMismatch "two elements tuple" (Value val)
fromCharValue :: EgisonValue -> Either EgisonError Char
fromCharValue (Char c) = return c
fromCharValue val = throwError $ TypeMismatch "char" (Value val)
fromBoolValue :: EgisonValue -> Either EgisonError Bool
fromBoolValue (Bool b) = return b
fromBoolValue val = throwError $ TypeMismatch "bool" (Value val)
fromIntegerValue :: EgisonValue -> Either EgisonError Integer
fromIntegerValue (Integer i) = return i
fromIntegerValue val = throwError $ TypeMismatch "integer" (Value val)
fromRationalValue :: EgisonValue -> Either EgisonError Rational
fromRationalValue (Rational x) = return x
fromRationalValue val = throwError $ TypeMismatch "rational" (Value val)
fromFloatValue :: EgisonValue -> Either EgisonError Double
fromFloatValue (Float f) = return f
fromFloatValue val = throwError $ TypeMismatch "float" (Value val)
fromPortValue :: EgisonValue -> Either EgisonError Handle
fromPortValue (Port handle) = return handle
fromPortValue val = throwError $ TypeMismatch "port" (Value val)
fromMatcherValue :: EgisonValue -> Either EgisonError Matcher
fromMatcherValue (Matcher matcher) = return matcher
fromMatcherValue val = throwError $ TypeMismatch "matcher" (Value val)
data Object =
Thunk (EgisonM WHNFData)
| WHNF WHNFData
type ObjectRef = IORef Object
data WHNFData =
Intermediate Intermediate
| Value EgisonValue
data Intermediate =
IInductiveData String [ObjectRef]
| ITuple [ObjectRef]
| ICollection (Seq Inner)
| IArray (IntMap ObjectRef)
| IIntHash (HashMap Integer ObjectRef)
| IStrHash (HashMap ByteString ObjectRef)
data Inner =
IElement ObjectRef
| ISubCollection ObjectRef
instance Show WHNFData where
show (Value val) = show val
show (Intermediate (IInductiveData name _)) = "<" ++ name ++ " ...>"
show (Intermediate (ITuple _)) = "[...]"
show (Intermediate (ICollection _)) = "{...}"
show (Intermediate (IArray _)) = "[|...|]"
show (Intermediate (IIntHash _)) = "{|...|}"
show (Intermediate (IStrHash _)) = "{|...|}"
class EgisonWHNF a where
fromWHNF :: WHNFData -> EgisonM a
instance EgisonWHNF Char where
fromWHNF = liftError . fromCharWHNF
instance EgisonWHNF Bool where
fromWHNF = liftError . fromBoolWHNF
instance EgisonWHNF Integer where
fromWHNF = liftError . fromIntegerWHNF
instance EgisonWHNF Rational where
fromWHNF = liftError . fromRationalWHNF
instance EgisonWHNF Double where
fromWHNF = liftError . fromFloatWHNF
instance EgisonWHNF Handle where
fromWHNF = liftError . fromPortWHNF
instance EgisonWHNF Matcher where
fromWHNF = liftError . fromMatcherWHNF
fromCharWHNF :: WHNFData -> Either EgisonError Char
fromCharWHNF (Value (Char c)) = return c
fromCharWHNF whnf = throwError $ TypeMismatch "char" whnf
fromBoolWHNF :: WHNFData -> Either EgisonError Bool
fromBoolWHNF (Value (Bool b)) = return b
fromBoolWHNF whnf = throwError $ TypeMismatch "bool" whnf
fromIntegerWHNF :: WHNFData -> Either EgisonError Integer
fromIntegerWHNF (Value (Integer i)) = return i
fromIntegerWHNF whnf = throwError $ TypeMismatch "integer" whnf
fromRationalWHNF :: WHNFData -> Either EgisonError Rational
fromRationalWHNF (Value (Rational x)) = return x
fromRationalWHNF whnf = throwError $ TypeMismatch "rational" whnf
fromFloatWHNF :: WHNFData -> Either EgisonError Double
fromFloatWHNF (Value (Float f)) = return f
fromFloatWHNF whnf = throwError $ TypeMismatch "float" whnf
fromPortWHNF :: WHNFData -> Either EgisonError Handle
fromPortWHNF (Value (Port handle)) = return handle
fromPortWHNF whnf = throwError $ TypeMismatch "port" whnf
fromMatcherWHNF :: WHNFData -> Either EgisonError Matcher
fromMatcherWHNF (Value (Matcher matcher)) = return matcher
fromMatcherWHNF whnf = throwError $ TypeMismatch "matcher" whnf
type Env = [HashMap Var ObjectRef]
type Var = String
type Binding = (Var, ObjectRef)
nullEnv :: Env
nullEnv = []
extendEnv :: Env -> [Binding] -> Env
extendEnv env = (: env) . HashMap.fromList
refVar :: Env -> Var -> EgisonM ObjectRef
refVar env var = maybe (throwError $ UnboundVariable var) return
(msum $ map (HashMap.lookup var) env)
data PMMode = BFSMode | DFSMode
data MatchingState = MState Env [LoopContext] [Binding] [MatchingTree]
data MatchingTree =
MAtom EgisonPattern ObjectRef WHNFData
| MNode [PatternBinding] MatchingState
type PatternBinding = (Var, EgisonPattern)
data LoopContext =
LoopContextConstant Binding Integer EgisonPattern EgisonPattern
| LoopContextVariable Binding EgisonPattern EgisonPattern EgisonPattern
data EgisonError =
UnboundVariable Var
| TypeMismatch String WHNFData
| ArgumentsNum Int Int
| NotImplemented String
| Assertion String
| Match String
| Parser String
| Desugar String
| UserInterruption
| Default String
deriving Typeable
instance Show EgisonError where
show (Parser error) = "Parse error at: " ++ error
show (UnboundVariable var) = "Unbound variable: " ++ var
show (TypeMismatch expected found) = "Expected " ++ expected ++
", but found: " ++ show found
show (ArgumentsNum expected got) = "Wrong number of arguments: expected " ++
show expected ++ ", but got " ++ show got
show (NotImplemented message) = "Not implemented: " ++ message
show (Assertion message) = "Assertion failed: " ++ message
show (Desugar message) = "Error: " ++ message
show UserInterruption = "Aborted: User interruption"
show (Default message) = "Error: " ++ message
instance Exception EgisonError
instance Error EgisonError where
noMsg = Default "An error has occurred"
strMsg = Default
liftError :: (MonadError e m) => Either e a -> m a
liftError = either throwError return
newtype EgisonM a = EgisonM {
unEgisonM :: ErrorT EgisonError (FreshT IO) a
} deriving (Functor, Applicative, Monad, MonadIO, MonadError EgisonError, MonadFresh)
runEgisonM :: EgisonM a -> FreshT IO (Either EgisonError a)
runEgisonM = runErrorT . unEgisonM
liftEgisonM :: Fresh (Either EgisonError a) -> EgisonM a
liftEgisonM m = EgisonM $ ErrorT $ FreshT $ do
s <- get
(a, s') <- return $ runFresh s m
put s'
return $ either throwError return $ a
fromEgisonM :: EgisonM a -> IO (Either EgisonError a)
fromEgisonM = modifyCounter . runEgisonM
counter :: IORef Int
counter = unsafePerformIO (newIORef 0)
readCounter :: IO Int
readCounter = readIORef counter
updateCounter :: Int -> IO ()
updateCounter = writeIORef counter
modifyCounter :: FreshT IO a -> IO a
modifyCounter m = do
seed <- readCounter
(result, seed) <- runFreshT seed m
updateCounter seed
return result
newtype FreshT m a = FreshT { unFreshT :: StateT Int m a }
deriving (Functor, Applicative, Monad, MonadState Int, MonadTrans)
type Fresh = FreshT Identity
class (Applicative m, Monad m) => MonadFresh m where
fresh :: m String
instance (Applicative m, Monad m) => MonadFresh (FreshT m) where
fresh = FreshT $ do counter <- get; modify (+ 1)
return $ "$_" ++ show counter
instance (MonadError e m) => MonadError e (FreshT m) where
throwError = lift . throwError
catchError m h = FreshT $ catchError (unFreshT m) (unFreshT . h)
instance (MonadState s m) => MonadState s (FreshT m) where
get = lift $ get
put s = lift $ put s
instance (MonadFresh m) => MonadFresh (StateT s m) where
fresh = lift $ fresh
instance (MonadFresh m, Error e) => MonadFresh (ErrorT e m) where
fresh = lift $ fresh
instance (MonadFresh m, Monoid e) => MonadFresh (ReaderT e m) where
fresh = lift $ fresh
instance (MonadFresh m, Monoid e) => MonadFresh (WriterT e m) where
fresh = lift $ fresh
instance MonadIO (FreshT IO) where
liftIO = lift
runFreshT :: Monad m => Int -> FreshT m a -> m (a, Int)
runFreshT seed = flip (runStateT . unFreshT) seed
runFresh :: Int -> Fresh a -> (a, Int)
runFresh seed m = runIdentity $ flip runStateT seed $ unFreshT m
type MatchM = MaybeT EgisonM
matchFail :: MatchM a
matchFail = MaybeT $ return Nothing
data MList m a = MNil | MCons a (m (MList m a))
fromList :: Monad m => [a] -> MList m a
fromList = foldr f MNil
where f x xs = MCons x $ return xs
fromSeq :: Monad m => Seq a -> MList m a
fromSeq = foldr f MNil
where f x xs = MCons x $ return xs
fromMList :: Monad m => MList m a -> m [a]
fromMList = mfoldr f $ return []
where f x xs = xs >>= return . (x:)
msingleton :: Monad m => a -> MList m a
msingleton = flip MCons $ return MNil
mfoldr :: Monad m => (a -> m b -> m b) -> m b -> MList m a -> m b
mfoldr f init MNil = init
mfoldr f init (MCons x xs) = f x (xs >>= mfoldr f init)
mappend :: Monad m => MList m a -> m (MList m a) -> m (MList m a)
mappend xs ys = mfoldr ((return .) . MCons) ys xs
mconcat :: Monad m => MList m (MList m a) -> m (MList m a)
mconcat = mfoldr mappend $ return MNil
mmap :: Monad m => (a -> m b) -> MList m a -> m (MList m b)
mmap f = mfoldr g $ return MNil
where g x xs = f x >>= return . flip MCons xs
mfor :: Monad m => MList m a -> (a -> m b) -> m (MList m b)
mfor = flip mmap