packages feed

EtaMOO-0.1.0.0: src/MOO/Verb.hs

{-# LANGUAGE OverloadedStrings #-}

module MOO.Verb ( Verb(..)
                , ObjSpec(..)
                , PrepSpec(..)
                , initVerb
                , obj2text
                , text2obj
                , objMatch
                , prep2text
                , text2prep
                , prepMatch
                , prepPhrases
                , verbNameMatch
                ) where

import Data.Text (Text)

import MOO.Types
import MOO.AST
import {-# SOURCE #-} MOO.Task

import qualified Data.Text as T

data Verb = Verb {
    verbNames          :: StrT
  , verbProgram        :: Program
  , verbCode           :: MOO Value

  , verbOwner          :: ObjId
  , verbPermR          :: Bool
  , verbPermW          :: Bool
  , verbPermX          :: Bool
  , verbPermD          :: Bool

  , verbDirectObject   :: ObjSpec
  , verbPreposition    :: PrepSpec
  , verbIndirectObject :: ObjSpec
}

instance Sizeable Verb where
  storageBytes verb =
    storageBytes (verbNames          verb) +
    storageBytes (verbProgram        verb) * 2 +
    -- storageBytes (verbCode           verb) +
    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 []
  , verbCode           = return nothing

  , verbOwner          = -1
  , verbPermR          = False
  , verbPermW          = False
  , verbPermX          = False
  , verbPermD          = False

  , verbDirectObject   = ObjNone
  , verbPreposition    = PrepNone
  , verbIndirectObject = ObjNone
}

data ObjSpec = ObjNone
             | ObjAny
             | ObjThis
             deriving (Enum, Bounded, Show)

instance Sizeable ObjSpec where
  storageBytes _ = storageBytes ()

obj2text :: ObjSpec -> Text
obj2text ObjNone = "none"
obj2text ObjAny  = "any"
obj2text ObjThis = "this"

text2obj :: Text -> Maybe ObjSpec
text2obj = flip lookup $ map mkAssoc [minBound ..]
  where mkAssoc objSpec = (obj2text objSpec, objSpec)

objMatch :: ObjId -> ObjSpec -> ObjId -> Bool
objMatch _    ObjNone (-1) = True
objMatch _    ObjNone _    = False
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
              | PrepOffOffof
              deriving (Enum, Bounded, Eq, Show)

instance Sizeable PrepSpec where
  storageBytes _ = storageBytes ()

prep2text :: PrepSpec -> Text
prep2text PrepAny                    = "any"
prep2text PrepNone                   = "none"
prep2text PrepWithUsing              = "with/using"
prep2text PrepAtTo                   = "at/to"
prep2text PrepInfrontof              = "in front of"
prep2text PrepInInsideInto           = "in/inside/into"
prep2text PrepOntopofOnOntoUpon      = "on top of/on/onto/upon"
prep2text PrepOutofFrominsideFrom    = "out of/from inside/from"
prep2text PrepOver                   = "over"
prep2text PrepThrough                = "through"
prep2text PrepUnderUnderneathBeneath = "under/underneath/beneath"
prep2text PrepBehind                 = "behind"
prep2text PrepBeside                 = "beside"
prep2text PrepForAbout               = "for/about"
prep2text PrepIs                     = "is"
prep2text PrepAs                     = "as"
prep2text PrepOffOffof               = "off/off of"

text2prep :: Text -> Maybe PrepSpec
text2prep = flip lookup $ concatMap mkAssoc [minBound ..]
  where mkAssoc prepSpec =
          [ (prep, prepSpec) | prep <- T.splitOn "/" $ prep2text prepSpec ] ++
          [ (T.pack $ 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, [Text])]
prepPhrases = [ (prepSpec, T.words prepPhrase)
              | prepSpec   <- [succ PrepNone ..]
              , prepPhrase <- T.splitOn "/" $ prep2text prepSpec
              ]

verbNameMatch :: StrT -> [StrT] -> Bool
verbNameMatch name = any matchName
  where matchName vname
          | post == ""  = name     == vname
          | post == "*" = preName  == pre
          | otherwise   = preName  == pre &&
                          postName == T.take (T.length postName) (T.tail post)
          where (pre, post)         = T.breakOn "*" vname
                (preName, postName) = T.splitAt (T.length pre) name