packages feed

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

module Language.Lsl.Internal.Breakpoint(
    Breakpoint,
    BreakpointManager,
    StepManager,
    mkBreakpoint,  -- :: String -> Int -> Int -> Breakpoint
    replaceBreakpoints, -- ::  [Breakpoint] -> BreakpointManager -> BreakpointManager
    checkBreakpoint, -- :: Breakpoint -> BreakpointManager -> StepManager -> (Bool,BreakpointManager,StepManager)
    addFixedBreakpoint, -- :: Breakpoint -> BreakpointManager -> BreakpointManager
    removeFixedBreakpoint, -- :: Breakpoint -> BreakpointManager -> BreakpointManager
    pushStepManagerFrame, -- :: StepManager -> StepManager
    popStepManagerFrame, -- :: StepManager -> StepManager
    setStepOutBreakpoint, -- :: StepManager -> StepManager
    setStepBreakpoint, -- :: StepManager -> StepManager
    setStepOverBreakpoint, -- :: StepManager -> StepManager
    emptyBreakpointManager, -- :: BreakpointManager
    emptyStepManager, -- :: StepManager
    breakpointFile, -- :: Breakpoint -> String
    breakpointLine -- :: Breakpoint -> Int
    ) where

import Data.Map (Map)
import qualified Data.Map as M
import Data.Set (Set)
import qualified Data.Set as S

--trace1 v = trace ("--> " ++ show v) v

data Breakpoint = Breakpoint { breakpointFile :: String, breakpointLine :: Int, breakpointColumn :: Int }
    deriving (Show,Eq,Ord)
data DynamicBreakpoint = NoDynamicBreakpoint | NextStatement | NextStatementInFrame | NextStatementAboveFrame
    deriving (Show,Eq)
    
newtype StepManager = StepManager [DynamicBreakpoint] deriving (Show)

mkBreakpoint name line col = Breakpoint name line col

data BreakpointManager = BreakpointManager { fixedBreakpoints :: (Map String (Set (Int,Int))) }
    deriving (Show)
    
emptyStepManager = StepManager []

emptyBreakpointManager = BreakpointManager M.empty

replaceBreakpoints bps bpm =
    foldl (flip addFixedBreakpoint) (bpm { fixedBreakpoints = M.empty }) bps
    
checkBreakpoint bp bpm sm@(StepManager dynBreakpts) = 
    case dynBreakpts of
        (NextStatement:frames) -> (True,bpm, StepManager (NoDynamicBreakpoint : frames))
        (NextStatementInFrame:frames) -> (True,bpm, StepManager (NoDynamicBreakpoint : frames))
        _ -> let (result,bpm') = hasFixedBreakpoint bp bpm in (result,bpm',sm)
        
hasFixedBreakpoint bp bpm =
    case M.lookup (breakpointFile bp) map of
        Nothing -> (False,bpm)
        Just set -> ((breakpointLine bp, breakpointColumn bp) `S.member` set, bpm)
    where map = fixedBreakpoints bpm
    
addFixedBreakpoint (Breakpoint file line col) bpm =
    let map = fixedBreakpoints bpm in
        case M.lookup file map of
            Nothing -> bpm { fixedBreakpoints = M.insert file (S.singleton (line,col)) map }
            Just set -> bpm { fixedBreakpoints = M.insert file (S.insert (line,col) set) map }
            
removeFixedBreakpoint (Breakpoint file line col) bpm =
    let map = fixedBreakpoints bpm in
        case M.lookup file map of
            Nothing -> bpm
            Just set -> bpm { fixedBreakpoints = M.insert file (S.delete (line,col) set) map }
            
pushStepManagerFrame (StepManager dynBps) =
    StepManager $ case dynBps of
        (NextStatement:frames) -> (NextStatement:NoDynamicBreakpoint:frames)
        frames -> (NoDynamicBreakpoint:frames)

popStepManagerFrame (StepManager dynBps) =
   StepManager $ case dynBps of
        (NoDynamicBreakpoint:NextStatementInFrame:frames) -> NextStatement:frames
        (NoDynamicBreakpoint:x:frames) -> x:frames
        (_:_:frames) -> NextStatement:frames
        _ -> []

setStepOutBreakpoint = setDynamicBreakpoint NextStatementAboveFrame
setStepBreakpoint = setDynamicBreakpoint NextStatement
setStepOverBreakpoint = setDynamicBreakpoint NextStatementInFrame
        
setDynamicBreakpoint dbp (StepManager dynBps) =
    StepManager $ case  dynBps of
        (_:frames) -> dbp:frames
        [] -> []