#include "BerpDebug.h"
module Berp.Base.Object
(lookupAttribute, lookupSpecialAttribute, lookupAttributeMaybe,
typeOf, identityOf, objectEquality, dictOf, dir) where
import Berp.Base.Truth (truth)
import Berp.Base.Prims (callMethod, showObject)
import Data.List (nub)
import Control.Monad (zipWithM)
import Control.Applicative ((<$>))
import Data.Maybe (isJust, catMaybes)
import Berp.Base.SemanticTypes (Object (..), Eval)
import Berp.Base.Mangle (deMangle)
import Berp.Base.Identity (Identity)
import Berp.Base.Hash (Hashed)
import Berp.Base.StdNames (eqName, cmpName)
import Berp.Base.LiftedIO as LIO (MonadIO)
#ifdef DEBUG
import Berp.Base.LiftedIO as LIO (putStrLn)
#endif
import Berp.Base.HashTable (stringLookup, keys)
import Berp.Base.StdTypes.Integer (intClass, int)
import Berp.Base.StdTypes.Bool (boolClass)
import Berp.Base.StdTypes.Tuple (tupleClass, getTupleElements)
import Berp.Base.StdTypes.Function (functionClass)
import Berp.Base.StdTypes.String (stringClass)
import Berp.Base.StdTypes.None (noneClass, noneIdentity)
import Berp.Base.StdTypes.Dictionary (dictionaryClass)
import Berp.Base.StdTypes.List (listClass, list)
import Berp.Base.StdTypes.Generator (generatorClass)
import Berp.Base.StdTypes.String (string)
instance Num Object where
fromInteger = int
(+) = undefined
(*) = undefined
abs = undefined
signum = undefined
typeOf :: Object -> Object
typeOf obj@(Object {}) = object_type obj
typeOf obj@(Type {}) = object_type obj
typeOf (Integer {}) = intClass
typeOf (Bool {}) = boolClass
typeOf (Tuple {}) = tupleClass
typeOf (List {}) = listClass
typeOf (Function {}) = functionClass
typeOf (String {}) = stringClass
typeOf (None {}) = noneClass
typeOf (Dictionary {}) = dictionaryClass
typeOf (Generator {}) = generatorClass
identityOf :: Object -> Identity
identityOf None = noneIdentity
identityOf object = object_identity object
dictOf :: Object -> Maybe Object
dictOf obj@(Object {}) = Just $ object_dict obj
dictOf obj@(Type {}) = Just $ object_dict obj
dictOf obj@(Function {}) = Just $ object_dict obj
dictOf _other = Nothing
lookupAttribute :: Object -> Hashed String -> Eval Object
lookupAttribute obj ident = do
lookupResult <- lookupAttributeMaybe obj ident
checkLookup obj ident lookupResult
lookupSpecialAttribute :: Object -> Hashed String -> Eval Object
lookupSpecialAttribute obj ident = do
lookupResult <- lookupSpecialAttributeMaybe obj ident
checkLookup obj ident lookupResult
checkLookup :: Object -> Hashed String -> Maybe Object -> Eval Object
checkLookup obj (_, identStr) lookupResult =
case lookupResult of
Nothing -> do
objStr <- showObject obj
fail $ objStr ++ " has no attribute called " ++ deMangle identStr
Just attributeObj -> do
case attributeObj of
Function { object_procedure = proc, object_arity = arity } ->
return attributeObj { object_procedure = \args -> proc (obj:args), object_arity = arity 1 }
_other -> do
return attributeObj
lookupSpecialAttributeMaybe :: MonadIO m => Object -> Hashed String -> m (Maybe Object)
lookupSpecialAttributeMaybe object ident = do
BELCH("Looking for special attribute: " ++ show ident ++ " in: " ++ show object)
lookupAttributeType object ident
lookupAttributeMaybe :: MonadIO m => Object -> Hashed String -> m (Maybe Object)
lookupAttributeMaybe object ident = do
BELCH("Looking for: " ++ show ident ++ " in: " ++ show object)
BELCH("Looking in dictionary of object")
case dictOf object of
Just dict -> do
BELCH("Object has a dictionary")
dictResult <- stringLookup ident $ object_hashTable dict
case dictResult of
Nothing -> do
BELCH("Ident not found in dictionary of object")
lookupAttributeType object ident
Just _ -> do
BELCH("Ident was found in dictionary of object")
return dictResult
Nothing -> do
BELCH("Object does not have a dictionary")
lookupAttributeType object ident
lookupAttributeType :: MonadIO m => Object -> Hashed String -> m (Maybe Object)
lookupAttributeType object ident = do
BELCH("Looking in dict of the type: " ++ show objectType)
let mroList = getTupleElements $ object_mro objectType
searchMRO mroList
where
objectType :: Object
objectType = typeOf object
searchMRO :: MonadIO m => [Object] -> m (Maybe Object)
searchMRO [] = do
BELCH("Ident was not found in the mro of the type of the object")
return Nothing
searchMRO (klass:rest) = do
BELCH("Looking in the dict of the type: " ++ show klass)
case dictOf klass of
Nothing -> do
BELCH("Type does not have a dictionary")
searchMRO rest
Just dict -> do
BELCH("Type does have a dictionary")
dictResult <- stringLookup ident $ object_hashTable dict
case dictResult of
Nothing -> do
BELCH("Ident not found in dictionary of type")
searchMRO rest
Just _ -> do
BELCH("Ident was found in dictionary of type")
return dictResult
hasAttribute :: (Functor m, MonadIO m) => Object -> Hashed String -> m Bool
hasAttribute object ident = isJust <$> lookupAttributeMaybe object ident
objectEquality :: Object -> Object -> Eval Bool
objectEquality obj1@(Integer {}) obj2@(Integer {})
= return (object_integer obj1 == object_integer obj2)
objectEquality obj1@(Bool {}) obj2@(Bool {})
= return (object_bool obj1 == object_bool obj2)
objectEquality obj1@(Tuple {}) obj2@(Tuple {})
| object_identity obj1 == object_identity obj2 = return True
| object_length obj1 == object_length obj2 =
and <$> zipWithM objectEquality (object_tuple obj1) (object_tuple obj2)
| otherwise = return False
objectEquality obj1@(String {}) obj2@(String {})
= return (object_string obj1 == object_string obj2)
objectEquality None None = return True
objectEquality obj1 obj2
| object_identity obj1 == object_identity obj2 = return True
| otherwise = do
canEq <- hasAttribute obj1 eqName
if canEq
then truth <$> callMethod obj1 eqName [obj2]
else do
canCmp <- hasAttribute obj1 cmpName
if canCmp
then do
cmpResult <- callMethod obj1 cmpName [obj2]
case cmpResult of
Integer {} -> return $ object_integer cmpResult == 0
_other -> fail $ "__cmp__ method on object does not return an integer: " ++ show obj1
else return False
dir :: Object -> Eval Object
dir object = do
let maybeObjDict = dictOf object
let objectBasesDicts = map dictOf $ getTupleElements $ object_mro $ typeOf object
let allDicts = catMaybes (maybeObjDict : objectBasesDicts)
let hashTables = map object_hashTable allDicts
keyObjects <- concat <$> mapM keys hashTables
let keyStrings = nub $ map (deMangle . object_string) keyObjects
list $ map string keyStrings