hiccup-0.40: Core.hs
{-# LANGUAGE BangPatterns #-}
module Core (evalTcl, doCond, subst, callProc, coreTests) where
import Common
import qualified TclObj as T
import qualified Data.ByteString.Char8 as B
import RToken
import Util
import VarName (arrName, NSQual(..))
import Test.HUnit
evalTcl :: T.TclObj -> TclM RetVal
evalTcl s = runCmds =<< asParsed s
{-# INLINE evalTcl #-}
runCmds [x] = runCmd x
runCmds (x:xs) = runCmd x >> runCmds xs
runCmds [] = ret
getSubst s = do
case asParsed s of
Just cmds -> do
let toks = concatMap uncmd cmds
if all noInterp toks
then return (Left (T.asBStr s))
else return (Right toks)
Nothing -> tclErr "subst failed: currently, doesn't work on stuff that we can't tokenize" -- TODO
where uncmd (Right n,args) = (n:args)
uncmd (Left (NSQual nst n), args) = if nst == Nothing then ((Lit n):args) else error (show (nst,n))
subst s = getSubst s >>= doeval
where doeval (Right t) = evalRTokens t [] >>= return . B.concat . map T.asBStr
doeval (Left s) = return s
callProc :: BString -> [T.TclObj] -> TclM T.TclObj
callProc pn args = do
getProc pn >>= \pr -> doCall pn pr args
evalRTokens :: [RToken] -> [T.TclObj] -> TclM [T.TclObj]
evalRTokens [] !acc = return $! reverse acc
evalRTokens (x:xs) !acc = case x of
Lit s -> evalRTokens xs ((T.mkTclBStr s):acc)
LitInt i -> evalRTokens xs ((T.mkTclInt i):acc)
CmdTok t -> nextWith (runCmd t)
VarRef vn -> nextWith (varGetNS vn)
Block s p -> evalRTokens xs ((T.fromBlock s p):acc)
ArrRef ns n i -> do
ni <- evalRTokens [i] [] >>= return . T.asBStr . head
nextWith (varGetNS (NSQual ns (arrName n ni)))
CatLst l -> nextWith (evalRTokens l [] >>= treturn . B.concat . map T.asBStr)
ExpTok t -> do
[rs] <- evalRTokens [t] []
l <- T.asList rs
evalRTokens xs ((reverse l) ++ acc)
where nextWith f = f >>= \r -> evalRTokens xs (r:acc)
runCmd :: Cmd -> TclM RetVal
runCmd (n,args) = do
evArgs <- evalRTokens args []
res <- evArgs `seq` go n evArgs
return $! res
where go (Left p@(NSQual _ name)) a = getProcNS p >>= \pr -> doCall name pr a
go (Right rt) a = do lst <- evalRTokens [rt] []
let (o:rs) = lst ++ a
let name = T.asBStr o
getProc name >>= \pr -> doCall name pr rs
doCall !pn !mproc args = do
case mproc of
Nothing -> do ukproc <- getProc (pack "unknown")
case ukproc of
Nothing -> tclErr $ "invalid command name " ++ show pn
Just uk -> uk `applyTo` ((T.mkTclBStr pn):args)
Just proc -> proc `applyTo` args
{-# INLINE doCall #-}
doCond :: T.TclObj -> TclM Bool
doCond str = do
p <- asParsed str
case p of
[x] -> do r <- runCmd x
return $! T.asBool r
_ -> tclErr "Too many statements in conditional"
{-# INLINE doCond #-}
coreTests = TestList []