packages feed

visual-graphrewrite-0.4.0.1: GraphRewrite/Main.hs

import Paths_visual_graphrewrite (version, getDataFileName)

import GraphRewrite
import GraphRewrite.Main.Welcome
import GraphRewrite.Main.CmdLineOpts
import GraphRewrite.Main.Utils
import GraphRewrite.Main.Visualize


import qualified Graphics.UI.Gtk as G
import qualified Graphics.UI.Gtk.Glade as G
import qualified Graphics.Rendering.Cairo.SVG as C

import Data.GraphViz

import Language.Haskell.Parser -- parseModule
import IPPrint --pprint
import System.Environment --getArgs
import Data.Supply
import qualified Data.Version

import qualified Data.IntMap as I
import Data.Maybe

import Control.Concurrent (forkIO, yield)
import Control.Arrow hiding (left)
import Control.Monad

import Control.Parallel.Strategies
import Control.Concurrent.MVar.Strict
import System.Directory

import Prelude hiding (exp)

--------------------------------------

data State = State
    { current  :: RewriteTree
    , history  :: Context
    , rewrsys  :: RewriteSystem
    , idsupp   :: Supply Int
    , sWindow  :: G.Window
    , sDrawing :: G.DrawingArea
    , sMap     :: G.DrawingArea
    , dotexe   :: FilePath
    , opts     :: Options
    }


instance NFData State where
    rnf = flip seq ()

predef :: [String]
predef = map snd deltaNames

main :: IO ()
main = do
  args <- getArgs
  options <- parseOptions args
  if showVersion options
    then putStrLn $ "version " ++ Data.Version.showVersion version
    else do
      tmp <- readInput (inputFile options)
      let sh = convParse $ parseModuleWithMode (ParseMode (fromMaybe "stdin" $ inputFile options)) tmp
      when (debug options) $ pprint sh
      ids <- newEnumSupply
      let (deltaIds: ids1: ids2: ids3:_) = split ids
      let (Ok (predefBinds,_,_)) = distributeIds predef deltaIds        -- distribute delta function ids
      case rename' predefBinds sh ids2 of -- scope analysis
        Error f   -> error $ "Error: " ++ f
        Ok (names,module_) -> do
           let rs = makeRewriteSystem module_ names
           when (debug options) $ pprint rs

           let rewritetree = case mainTerm options of
                               Nothing -> startRuleDefs rs
                               Just tm -> startRewriting tm rs ids3

           mstate <- newState options rs ids1 rewritetree

           runGUI mstate
--           configureWindow basicKeyBindings mstate msession

cleanup :: MVar State -> IO ()
cleanup mstate = do
  takeMVar mstate
  G.mainQuit

configureBindings :: G.GladeXML -> MVar State -> IO ()
configureBindings xml mstate = do
  window <- G.xmlGetWidget xml G.castToWindow "visual-graphrewrite"

  quitbutton <- G.xmlGetWidget xml G.castToButton "quitbutton"
  leftbutton <- G.xmlGetWidget xml G.castToButton "leftbutton"
  rightbutton <- G.xmlGetWidget xml G.castToButton "rightbutton"
  upbutton <- G.xmlGetWidget xml G.castToButton "upbutton"
  downbutton <- G.xmlGetWidget xml G.castToButton "downbutton"

  aboutmenu <- G.xmlGetWidget xml G.castToImageMenuItem "aboutmenuitem"
  quitmenu <- G.xmlGetWidget xml G.castToImageMenuItem "quitmenuitem"

  aboutwidget <- G.xmlGetWidget xml G.castToAboutDialog "aboutdialog"

  G.onClicked quitbutton $ G.widgetDestroy window
  G.onActivateLeaf quitmenu $ G.widgetDestroy window

  G.onClicked leftbutton $ moveLeft mstate >> refresh mstate >> return ()
  G.onClicked rightbutton $ moveRight mstate >> refresh mstate >> return ()
  G.onClicked upbutton $ moveUp mstate >> refresh mstate >> return ()
  G.onClicked downbutton $ moveDown mstate >> refresh mstate >> return ()

  G.onActivateLeaf aboutmenu $ G.dialogRun aboutwidget >> return ()

  return ()


runGUI :: MVar State -> IO ()
runGUI mstate = do
  G.initGUI
  uipath <- getDataFileName "ui.glade"
  Just xml <- G.xmlNew uipath
  window <- G.xmlGetWidget xml G.castToWindow "visual-graphrewrite"
  G.onDestroy window (cleanup mstate)

  canvas <- G.xmlGetWidget xml G.castToDrawingArea "drawingarea"
  maparea <- G.xmlGetWidget xml G.castToDrawingArea "map"

  modifyMVar_ mstate $ \ state ->
      return state { sWindow = window, sDrawing = canvas, sMap = maparea }

  configureBindings xml mstate

  G.widgetShowAll window
  G.timeoutAddFull (yield >> return True) G.priorityDefaultIdle 50
  forkIO G.mainGUI

  svg <- C.svgNewFromString welcome
  updateCanvas svg canvas

  G.onExposeRect canvas (const $ refresh mstate >> return ())
  G.onExposeRect maparea (const $ refresh mstate >> return ())

  return ()

startRewriting :: String -> RewriteSystem -> Supply Int -> RewriteTree
startRewriting term rs ids = tree
    where
      tree = rewriteStepFine rs expr gra
      gra = I.fromList []
      binds = namesToBinds (names rs)
      sh = rename' binds (convParse $ parseModuleWithMode (ParseMode "CmdLine Argument") ("tHiSiSaVeRyBaDaNDuGLyHaCK = " ++ term)) ids
      expr = case sh of
               Ok (_, m) -> exp $ head $ I.findMin $ rules $ makeRewriteRules m
               Error err -> error $ "Error during parsing CmdLine argument: " ++ err


{-case I.toList (I.filter (== term) (names rs)) of
                       [(tid, _)] -> case I.lookup tid (rules rs) of
                                      Just [r] -> (exp r, graph r)
                                      Just _ -> error $ "Ambiguous reference to term: " ++ term ++ ". Make sure there is only one rule associated with it in the source file. (Maybe you want to examine another term?)"
                                      Nothing -> error $ "No such term `" ++ term ++ "' found in the source file, it is probably defined elsewhere. (Did you want to examine a delta function?)"
                       [] -> error $ "Absolutely nothing found about this term: " ++ term ++ ". You probably have a typo somewhere."
                       _  -> error $ "Ambiguous reference to term: " ++ term ++ ". This shouldn't happen if your source file compiles with a Haskell compiler."
-}

startRuleDefs :: RewriteSystem -> RewriteTree
startRuleDefs rs = tree
    where
      tree = Step start pgtrees
      start = (SLit "Move down to see rule definitions", I.fromList [])
      pgs = map (exp &&& graph) $ concatMap snd $ I.toList $ rules rs
      pgtrees = map (\pg -> Step pg []) pgs


moveDown :: MVar State -> IO ()
moveDown = flip modifyMVar_ $ \ state ->
             case current state of
               Step _ [] -> return state
               Step g (h:t) -> return state { current = h
                                           , history = RewriteBranch g [] t : history state
                                           }


moveUp :: MVar State -> IO ()
moveUp = flip modifyMVar_ $ \ state ->
           case history state of
             [] -> return state
             (h:t) -> return state { current = Step (node h) (left h ++ [current state] ++ rght h)
                                  , history = t
                                  }

moveRight :: MVar State -> IO ()
moveRight = flip modifyMVar_ $ \ state ->
              case history state of
                []                            -> return state
                (RewriteBranch _ _ []:_)      -> return state
                (RewriteBranch n l (rh:rt):t) ->
                    return state { current = rh
                                 , history = RewriteBranch n (current state : l) rt : t
                                 }

moveLeft :: MVar State -> IO ()
moveLeft = flip modifyMVar_ $ \ state ->
             case history state of
               [] -> return state
               (RewriteBranch _ [] _ : _) -> return state
               (RewriteBranch n (lh:lt) r : t) ->
                   return state { current = lh
                                , history = RewriteBranch n lt (current state : r) : t
                                }

refresh :: MVar State -> IO Bool
refresh mstate = do
  state <- takeMVar mstate
  let (ids, ids') = split2 (idsupp state)
  putMVar mstate (state { idsupp = ids' })

  let (Step pg _) = current state

  when (debug $ opts state) (putStr "DEBUG: " >> pprint pg)

  updateCanvasTo (sDrawing state) pg (dotexe state) (rewrsys state) ids

  dg <- stateToDot (current state) (history state)

  when (debug $ opts state) (putStrLn $ "DEBUG: isValidGraph: " ++ (show $ isValidGraph dg))
  when (debug $ opts state) (putStrLn $ "DEBUG: " ++ show dg)


  svgmap <- dotToSVG (dotexe state) (show dg)
  updateCanvas svgmap (sMap state)

newState :: Options -> RewriteSystem -> Supply Int -> RewriteTree -> IO (MVar State)
newState opts rs ids tree = do
  mdot <- findExecutable "dot"
  let exe = case mdot of
              Nothing -> error "dot binary not found. Please install graphviz"
              Just p -> p



  let s = State { history = []
                , current = tree
                , rewrsys = rs
                , idsupp = ids
                , opts = opts
                , dotexe = exe
                }
  newMVar s