hiccup-0.35: TclObj.hs
module TclObj where
import Test.HUnit -- IGNORE
import qualified BSParse as P
import qualified Data.ByteString.Char8 as BS
import System.IO
import Data.Unique
data TclChan = TclChan { chanHandle :: Handle, chanName :: BS.ByteString } deriving (Eq,Show)
tclStdChans = [ mkChan' stdout "stdout", mkChan' stdin "stdin", mkChan' stderr "stderr" ]
mkChan h = do n <- uniqueNum
return (mkChan' h ("file" ++ show n))
where uniqueNum = newUnique >>= return . hashUnique
mkChan' h n = TclChan h (BS.pack n)
data TclObj = TclInt !Int BS.ByteString |
TclBStr !BS.ByteString (Maybe Int) (Either String [[P.TclWord]]) deriving (Show,Eq)
mkTclStr s = mkTclBStr (BS.pack s)
mkTclBStr s = mkTclBStrP s (doParse s)
mkTclBStrP s p = TclBStr s mayint p
where mayint = case BS.readInt (P.dropWhite s) of
Nothing -> Nothing
Just (i,_) -> Just i
doParse s = case P.runParse s of
Nothing -> Left "parse failed"
Just (r,rs) -> if BS.null rs then Right r else Left ("Incomplete parse: " ++ show rs)
mkTclInt i = TclInt i (BS.pack (show i))
empty = TclBStr BS.empty Nothing (Left "bad parse")
tclTrue = mkTclInt 1
tclFalse = mkTclInt 0
fromBool b = if b then tclTrue else tclFalse
trim :: TclObj -> BS.ByteString
trim = BS.reverse . P.dropWhite . BS.reverse . P.dropWhite . asBStr
class ITObj o where
asStr :: o -> String
asBool :: o -> Bool
asInt :: (Monad m) => o -> m Int
asBStr :: o -> BS.ByteString
asParsed :: (Monad m) => o -> m [[P.TclWord]]
instance ITObj BS.ByteString where
asStr = BS.unpack
asBool bs = (bs `elem` trueValues)
asInt bs = maybe (fail ("Bad int: " ++ show bs)) (return . fst) (BS.readInt bs)
asBStr = id
asParsed s = case P.runParse s of
Nothing -> fail $ "parse failed: " ++ show s
Just (r,rs) -> if BS.null rs then return r
else fail $ "incomplete parse: " ++ show rs
instance ITObj TclObj where
asStr (TclInt _ b) = BS.unpack b
asStr (TclBStr bs _ _) = asStr bs
asBool (TclInt i _) = i /= 0
asBool (TclBStr bs _ _) = asBool bs
asInt (TclInt i _) = return i
asInt (TclBStr _ (Just i) _) = return i
asInt (TclBStr v Nothing _) = fail $ "Bad int: " ++ show v
asBStr (TclBStr s _ _) = s
asBStr (TclInt _ b) = b
asParsed (TclBStr _ _ (Left f)) = fail f
asParsed (TclBStr _ _ (Right r)) = return r
asParsed (TclInt _ _) = fail "Can't parse an int value"
trueValues = map BS.pack ["1", "true", "yes", "on"]
-- # TESTS # --
testTrim = TestList [
trim (int 10) ?=> "10",
trim (str "10") ?=> "10",
trim (str " 10 ") ?=> "10",
trim (str "\t10\t") ?=> "10",
trim (str " \t ") ?=> "",
trim (str " 10 ") ?=> "10"
]
where (?=>) s e = s ~=? (BS.pack e)
int i = mkTclInt i
str s = mkTclStr s
testAsBool = TestList [
tclTrue `is` True,
tclFalse `is` False,
(fromBool True) `is` True,
(int 1) `is` True,
(int 0) `is` False,
(int 2) `is` True,
(int (-1)) `is` True,
(str "true") `is` True,
(str "yes") `is` True,
(str "on") `is` True,
(fromBool False) `is` False
]
where is a b = asBool a ~=? b
int i = mkTclInt i
str s = mkTclStr s
tclObjTests = TestList [ testTrim, testAsBool ]
-- # ENDTESTS # --