packages feed

LslPlus-0.1.2: src/Language/Lsl/Internal/SystemTester.hs

{-# OPTIONS_GHC -XFlexibleContexts #-}
module Language.Lsl.Internal.SystemTester where

import Control.Monad(MonadPlus(..))
import Control.Monad.Error(MonadError(..),ErrorT(..))
import Control.Monad.State(evalState)
import qualified Data.Map as M
import IO
import Language.Lsl.Internal.BreakpointsDeserialize(breakpointsElement)
import Language.Lsl.Internal.Compiler(compile)
import Language.Lsl.Internal.DOMProcessing(Content(..),Document(..),Element(..),ElemAcceptor(..),
                         elementList,simple,findElement,findOptionalElement,match,xmlParse)
import Language.Lsl.Internal.DOMSourceDescriptor(sourceFilesElement)
import Language.Lsl.Internal.ExecInfo(emitExecutionInfo)
import Language.Lsl.Internal.Log(LogMessage(..),logLevelToName)
import Language.Lsl.Syntax(libFromAugLib)
import Language.Lsl.Internal.Util(unescape,processLinesS)
import Language.Lsl.Sim(SimCommand(..),SimEvent(..),SimEventArg(..),SimStatus(..),SimStateInfo(..),simStep)
import Language.Lsl.WorldDef(worldElement)
import Language.Lsl.Internal.XmlCreate(emit,emitList,emitSimple)

initializationFromXML xml = let doc = xmlParse "" xml in parseInitialization doc

parseInitialization (Document _ _ root _) = match initSimElement root

--initSimElement :: MonadError String m => ElemAcceptor m (([(String,String)],[(String,String)]),FullWorldDef)
initSimElement =
    let f (Elem _ _ contents) =
            do (sources,contents1) <- findElement sourceFilesElement [ e | e@(CElem _ _) <- contents]
               (worldDef,[]) <- findElement worldElement contents1
               return (sources,worldDef)
    in ElemAcceptor "sim-descriptor" f

commandFromXML xml = 
     let (Document _ _ root _) = xmlParse "" xml in 
         case simCommand root of
             Left s -> error s
             Right command -> command

--simCommand e = match (ElemAcceptor "sim-continue" simple) e >> return (SimContinue [] [])
simCommand e = --execCmd "sim-continue" SimContinue e
    (matchSimContinue e) `mplus` (matchSimStep e) `mplus` (matchSimStepOver e) `mplus` (matchSimStepOut e)
    
matchSimContinue e = execCmd "sim-continue" SimContinue e
matchSimStep e = execCmd "sim-step" SimStep e
matchSimStepOver e = execCmd "sim-step-over" SimStepOver e
matchSimStepOut e = execCmd "sim-step-out" SimStepOut e

execCmd s f e = do
    (bp,events) <- match (ElemAcceptor s commandContent) e
    return (f bp events)
  
commandContent (Elem _ _ contents) = do
    (breakpoints,contents1) <- findOptionalElement  breakpointsElement [ e | e@(CElem _ _) <- contents]
    (events,[]) <- findOptionalElement  (elementList "events" simEventElement) contents1
    return $ (maybe [] id breakpoints, maybe [] id events)

simEventElement :: MonadError String m => ElemAcceptor m SimEvent
simEventElement =
    let f (Elem _ _ contents) = 
             do (name,contents1) <- findElement (ElemAcceptor "name" simple) [ e | e@(CElem _ _) <- contents]
                (delay,contents2) <- findElement (ElemAcceptor "delay" simple) contents1
                (args,[]) <- findOptionalElement (elementList "args" simArgElement) contents2
                case reads delay of
                    [] -> fail "invalid delay: expected integer"
                    ((i,_):_) -> return $ SimEvent name (maybe [] id args) i
    in ElemAcceptor "event" f

simArgElement :: MonadError String m => ElemAcceptor m SimEventArg
simArgElement = 
    let f (Elem _ _ contents) =
            do (name,contents1) <- findElement (ElemAcceptor "name" simple) [ e | e@(CElem _ _) <- contents]
               (value,[]) <- findElement (ElemAcceptor "value" simple) contents1
               return $ SimEventArg name value
    in ElemAcceptor "arg" f
    
outputToXML (SimInfo _ log state) = (emit "sim-info" [] [emitLog log,emitState state]) ""
outputToXML (SimEnded _ log state) = (emit "sim-ended" [] [emitLog log,emitState state]) ""
outputToXML (SimSuspended _ suspendInfo log state) = (emit "sim-suspended" [] [emitExecutionInfo suspendInfo,
                                                                               emitLog log,
                                                                               emitState state]) ""
                                                                               
emitLog log =
    emit "messages" [] $ map emitMessage (log)

emitMessage logMessage =
    emit "message" [] [ emitSimple "time" [] (show $ logMessageTime logMessage),
                        emitSimple "level" [] (logLevelToName $ logMessageLevel logMessage),
                        emitSimple "source" [] (logMessageSource logMessage),
                        emitSimple "text" [] (logMessageText logMessage)]

emitState state =
    emit "state" [] [ emitSimple "time" [] (show $ simStateInfoTime state),
                      emitPrims (simStateInfoPrims state),
                      emitAvatars (simStateInfoAvatars state),
                      emitScripts (simStateInfoScripts state) ]
emitPrims prims = emitList "prims" emitPrim prims
emitAvatars avatars = emitList "avatars" emitAvatar avatars
emitScripts scripts = emitList "scripts" emitScript scripts

emitPrim (key,name) = emit "prim" [] [emitSimple "key" [] key, emitSimple "name" [] name]
emitAvatar (key,name) = emit "avatar" [] [emitSimple "key" [] key, emitSimple "name" [] name]
emitScript (pk,sname) = emit "script" [] [emitSimple "primKey" [] pk, emitSimple "scriptName" [] sname]

testSystem :: IO ()
testSystem = 
    do  input <- getLine
        --hPutStrLn stderr input
        let result = (evalState . runErrorT) (initializationFromXML  (unescape input)) (M.empty,1)
        case result of
            Left s -> fail s
            Right (src,worldDef) -> do
                (augLib,scripts) <- compile src
                let runStep state s =
                        let command = commandFromXML s
                            (e,state') = simStep state command
                        in (state',outputToXML e)
                processLinesS (Left (worldDef,scripts,libFromAugLib augLib)) "quit" runStep