packages feed

haskelisp-0.1.0.0: src/Emacs/Type.hs

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
module Emacs.Type where

import Prelude(Show(..))
import Protolude hiding (show)
import Data.IORef
import GHC.Ptr
import Foreign.C.Types
import Foreign.StablePtr
import Control.Monad.Log
import Control.Monad.Reader
import Data.Data hiding(typeOf)

data PState = PState
  { symbolMap :: IORef (Map Text GlobalEmacsValue)
  }

data Ctx = Ctx
  { pstateStablePtr :: StablePtr PState
  , pstate :: PState
  , emacsEnv :: EmacsEnv
  }

type EmacsM =
  LoggingT Text (ReaderT Ctx IO)


-- | nil について
--
-- emacs 内部では nil は文字列で表現できないシンボルとして定義されている。
-- globals.h
--
-- #define Qnil builtin_lisp_symbol (0)
--
-- type-of では取得できない。nil は型ではない?かな。多分 type_of に渡
-- すとエラーになる。
--
-- haskell では不便なので ENil という型を導入する。
data EmacsType = ESymbol
               | EInteger
               | EFunction
               | EString
               | ECons
               | ENil
  deriving (Show, Eq, Data)

-- これは emacs 側での正式な名前である必要がある。typeOf が依存してい
-- る。nil は若干嘘が入っている。nil という型は存在しない。
emacsTypeSymbolName :: EmacsType -> Text
emacsTypeSymbolName ESymbol   = "symbol"
emacsTypeSymbolName EInteger  = "integer"
emacsTypeSymbolName EFunction = "function"
emacsTypeSymbolName EString   = "string"
emacsTypeSymbolName ECons     = "cons"
emacsTypeSymbolName ENil      = "nil" -- lie

emacsTypes :: [EmacsType]
emacsTypes = fromConstr <$> dataTypeConstrs (dataTypeOf ESymbol)

-- Singlton Types テクニック
-- 値と型を結び付けている
-- 現在は tagAs のところでしか使っていないのでオーバーキルかな。。
-- export しないほうがいいかも。internal だけに留めるかな?
-- data SEmacsType (et :: EmacsType) where
--     SESymbol  :: SEmacsType 'ESymbol
--     SEInteger :: SEmacsType 'EInteger
--     SECons    :: SEmacsType 'ECons
--     SENil     :: SEmacsType 'ENil

-- emacsTypeValue :: SEmacsType b -> EmacsType
-- emacsTypeValue SESymbol = ESymbol
-- emacsTypeValue SEInteger = EInteger


newtype EmacsEnv   = EmacsEnv (Ptr ())
  deriving (Storable)
newtype EmacsValue = EmacsValue (Ptr ())
  deriving (Storable)
newtype GlobalEmacsValue = GlobalEmacsValue (Ptr ())
  deriving (Storable)

castGlobalToEmacsValue :: GlobalEmacsValue -> EmacsValue
castGlobalToEmacsValue (GlobalEmacsValue p) =
  EmacsValue p

-- type ESymbol       = Tagged 'ESymbol EmacsValue
-- type EInteger      = Tagged 'EInteger EmacsValue
-- type EFunction     = Tagged 'EFunction EmacsValue
-- type EString       = Tagged 'EString EmacsValue
-- type ECons         = Tagged 'ECons EmacsValue
-- type ENil          = Tagged 'ENil EmacsValue

-- | Emacs の値に対する Haskell の型
-- 数値や文字列は素直なんだけど、他
-- Nil は空 [] でいいのかな?
newtype Symbol = Symbol Text
data Nil       = Nil
data Cons      = Cons EmacsValue EmacsValue
newtype List   = List [EmacsValue]

-- | 例外機構

data EmacsFuncallExit
  = EmacsFuncallExitReturn
  | EmacsFuncallExitSignal
  | EmacsFuncallExitThrow
  deriving (Show,Eq,Enum)

data EmacsException
  = EmacsException EmacsFuncallExit EmacsValue EmacsValue

instance Show EmacsException where
  show (EmacsException funcallExit _ _) =
    "EmacsException(" <> show funcallExit <> ")"

instance Exception EmacsException

-- | 関数定義のため必要な型

type EFunctionStub
  = EmacsEnv
  -> CPtrdiff
  -> Ptr (Ptr ())
  -> StablePtr PState
  -> IO EmacsValue

data InteractiveForm = InteractiveNoArgs

newtype Doc   = Doc Text   -- ドキュメント(関数など)
newtype Arity = Arity Int  -- 関数アリティ