module MOO.Verb ( Verb(..)
, ObjSpec(..)
, PrepSpec(..)
, initVerb
, obj2string
, string2obj
, objMatch
, prep2string
, string2prep
, prepMatch
, prepPhrases
, verbNameMatch
) where
import Control.Applicative ((<$>), (<*>))
import Data.Typeable (Typeable)
import Database.VCache (VCacheable(put, get))
import MOO.AST
import MOO.Object (nothing)
import MOO.Types
import qualified MOO.String as Str
data Verb = Verb {
verbNames :: StrT
, verbProgram :: Program
, verbOwner :: ObjId
, verbPermR :: Bool
, verbPermW :: Bool
, verbPermX :: Bool
, verbPermD :: Bool
, verbDirectObject :: ObjSpec
, verbPreposition :: PrepSpec
, verbIndirectObject :: ObjSpec
} deriving Typeable
instance VCacheable Verb where
put verb = do
put $ verbNames verb
put $ verbProgram verb
put $ verbOwner verb
put $ verbPermR verb
put $ verbPermW verb
put $ verbPermX verb
put $ verbPermD verb
put $ verbDirectObject verb
put $ verbPreposition verb
put $ verbIndirectObject verb
get = Verb <$> get <*> get
<*> get <*> get <*> get <*> get <*> get
<*> get <*> get <*> get
instance Sizeable Verb where
storageBytes verb =
storageBytes (verbNames verb) +
storageBytes (verbProgram verb) * 2 +
storageBytes (verbOwner verb) +
storageBytes (verbPermR verb) +
storageBytes (verbPermW verb) +
storageBytes (verbPermX verb) +
storageBytes (verbPermD verb) +
storageBytes (verbDirectObject verb) +
storageBytes (verbPreposition verb) +
storageBytes (verbIndirectObject verb)
initVerb = Verb {
verbNames = ""
, verbProgram = Program []
, verbOwner = nothing
, verbPermR = False
, verbPermW = False
, verbPermX = False
, verbPermD = False
, verbDirectObject = ObjNone
, verbPreposition = PrepNone
, verbIndirectObject = ObjNone
}
data ObjSpec = ObjNone
| ObjAny
| ObjThis
deriving (Enum, Bounded, Typeable)
instance VCacheable ObjSpec where
put = put . fromEnum
get = toEnum <$> get
instance Sizeable ObjSpec where
storageBytes _ = storageBytes ()
obj2string :: ObjSpec -> StrT
obj2string ObjNone = "none"
obj2string ObjAny = "any"
obj2string ObjThis = "this"
string2obj :: StrT -> Maybe ObjSpec
string2obj = flip lookup $ map mkAssoc [minBound ..]
where mkAssoc :: ObjSpec -> (StrT, ObjSpec)
mkAssoc objSpec = (obj2string objSpec, objSpec)
objMatch :: ObjId -> ObjSpec -> ObjId -> Bool
objMatch _ ObjNone oid = oid == nothing
objMatch _ ObjAny _ = True
objMatch this ObjThis oid = oid == this
data PrepSpec = PrepAny
| PrepNone
| PrepWithUsing
| PrepAtTo
| PrepInfrontof
| PrepInInsideInto
| PrepOntopofOnOntoUpon
| PrepOutofFrominsideFrom
| PrepOver
| PrepThrough
| PrepUnderUnderneathBeneath
| PrepBehind
| PrepBeside
| PrepForAbout
| PrepIs
| PrepAs
| PrepOffofOff
deriving (Enum, Bounded, Eq, Typeable)
instance VCacheable PrepSpec where
put = put . fromEnum
get = toEnum <$> get
instance Sizeable PrepSpec where
storageBytes _ = storageBytes ()
prep2string :: PrepSpec -> StrT
prep2string PrepAny = "any"
prep2string PrepNone = "none"
prep2string PrepWithUsing = "with/using"
prep2string PrepAtTo = "at/to"
prep2string PrepInfrontof = "in front of"
prep2string PrepInInsideInto = "in/inside/into"
prep2string PrepOntopofOnOntoUpon = "on top of/on/onto/upon"
prep2string PrepOutofFrominsideFrom = "out of/from inside/from"
prep2string PrepOver = "over"
prep2string PrepThrough = "through"
prep2string PrepUnderUnderneathBeneath = "under/underneath/beneath"
prep2string PrepBehind = "behind"
prep2string PrepBeside = "beside"
prep2string PrepForAbout = "for/about"
prep2string PrepIs = "is"
prep2string PrepAs = "as"
prep2string PrepOffofOff = "off of/off"
string2prep :: StrT -> Maybe PrepSpec
string2prep = flip lookup $ concatMap mkAssoc [minBound ..]
where mkAssoc :: PrepSpec -> [(StrT, PrepSpec)]
mkAssoc prepSpec =
[ (prep, prepSpec) | prep <- Str.splitOn "/" $
prep2string prepSpec ] ++
[ (Str.fromString $ show index, prepSpec)
| let index = fromEnum prepSpec fromEnum (succ PrepNone)
, index >= 0
]
prepMatch :: PrepSpec -> PrepSpec -> Bool
prepMatch PrepAny _ = True
prepMatch vp cp = vp == cp
prepPhrases :: [(PrepSpec, [StrT])]
prepPhrases = [ (prepSpec, Str.words prepPhrase)
| prepSpec <- [succ PrepNone ..]
, prepPhrase <- Str.splitOn "/" $ prep2string prepSpec
]
verbNameMatch :: StrT -> [StrT] -> Bool
verbNameMatch name = any matchName
where matchName :: StrT -> Bool
matchName vname
| post == "" = name == vname
| post == "*" = preName == pre
| otherwise = preName == pre &&
postName `Str.isPrefixOf` Str.tail post
where (pre, post) = Str.breakOn "*" vname
(preName, postName) = Str.splitAt (Str.length pre) name