/fppr2010/sourcecode/CHF/interpreter.hs

http://fppr2010.googlecode.com/ · Haskell · 107 lines · 67 code · 14 blank · 26 comment · 13 complexity · 31595157daacd4968a0ef0e9f7cb6fdb MD5 · raw file

  1. -- | Dieses Modul implementiert einen interaktiven Interpreter fuer Concurrent Haskell with Futures
  2. import System.IO -- benoetigt fuer hFlush
  3. import Control.Exception(try,IOException,SomeException,evaluate) -- benoetigt fuer evaluate/try/...
  4. import Data.IORef -- benoetigt fuer IORef
  5. import CHF.Run as CHF -- Concurrent Haskell with Futures
  6. ----------------------------------------------------------------------------------------------------------
  7. -- | 'getInputString' Wrapper fuer getLine. (Liefert auf jeden Fall einen String.)
  8. -- Als Parameter kann eine Eingabaufforderung Uebergeben werden. Der Trick mit hFlush aus System.IO
  9. -- stammt von http://www.haskell.org/pipermail/haskell/2006-September/018430.html
  10. -- und sorgt dafuer, dass sich das Programm in GHCI genauso verhaellt, wie die kompilierte .exe-Datei!
  11. ----------------------------------------------------------------------------------------------------------
  12. getInputString :: String -> IO (String)
  13. getInputString s = putStr s >> hFlush stdout >> getLine
  14. ----------------------------------------------------------------------------------------------------------
  15. -- | 'usage' gibt eine Hilfe-Mitteilung mit allen zur Verfuegung stehenden Kommandos aus.
  16. ----------------------------------------------------------------------------------------------------------
  17. usage :: IO ()
  18. usage = let
  19. txt = "Moegliche Kommandos sind:\n"
  20. ++ " :quit\t\tzum Beenden\n"
  21. ++ " :help\t\tfuer Hilfe\n"
  22. ++ " :define\tzum Definieren globaler data-Definitionen\n"
  23. ++ " :clear\tzum Loeschen globaler data-Definitionen\n"
  24. ++ " :runfile\tum eine Datei auszufuehren\n"
  25. in putStrLn txt
  26. ----------------------------------------------------------------------------------------------------------
  27. -- | 'run' gibt Begruessung aus und startet den interaktiven Interpreter
  28. ----------------------------------------------------------------------------------------------------------
  29. run :: IO ()
  30. run = do
  31. putStrLn "Concurrent Haskell with Futures (CHF) [Nhan/Leppin]"
  32. putStrLn "===================================================="
  33. putStrLn "Beenden :quit / Hilfe :help"
  34. ref <- newIORef "" -- neue IORef erzeugen mit initialem leeren String
  35. runInterpr ref True
  36. ----------------------------------------------------------------------------------------------------------
  37. -- | 'evalExpr' probiert, den Eingabausdruck inp auszuwerten und faengt ggf. Fehler ab.
  38. ----------------------------------------------------------------------------------------------------------
  39. evalExpr :: String -> IO ()
  40. evalExpr inp = do
  41. r <- try (CHF.runCM1 inp) :: IO (Either SomeException ())
  42. case r of
  43. Left ex -> putStr "CHF Fehler: " >> print ex >> putStrLn "\n"
  44. Right val -> return () -- runCM1 liefert keine Rueckgabe, sondern prodzuiert print-Seiteneffekt
  45. ----------------------------------------------------------------------------------------------------------
  46. -- | 'runInterpr' ist die eigentliche interaktive Interpreterfunktion
  47. -- wenn der Parameter auf False gesetzt wird, wird sie beendet, solang er True ist, laeuft die Schleife.
  48. ----------------------------------------------------------------------------------------------------------
  49. runInterpr :: IORef String -> Bool -> IO ()
  50. runInterpr _ False = putStrLn "So long, and thanks for all the fish."
  51. runInterpr ref True = do
  52. cmd <- getInputString "*CHF>"
  53. case cmd of
  54. "" -> runInterpr ref True -- bei Enter machen wir nix
  55. ":quit" -> runInterpr ref False -- Quit (set to False)
  56. ":define" -> do -- data-Block speichern
  57. s <- readIORef ref
  58. putStr "aktuelle Definitionen: \"" >> putStr s >> putStrLn "\""
  59. s' <- getInputString "neue Definition (Enter=Abbruch): "
  60. if null s' then do -- tu nichts
  61. putStrLn "abgebrochen."
  62. runInterpr ref True
  63. else do -- speichere neuen Wert
  64. writeIORef ref s'
  65. putStr "neue Definitionen \"" >> putStr s' >> putStrLn "\" gespeichert."
  66. runInterpr ref True
  67. ":clear" -> do -- data-Block loeschen
  68. writeIORef ref ""
  69. putStrLn "Data-Definitionen geloescht!"
  70. runInterpr ref True
  71. ":runfile" -> do -- Datei einlesen und ausfuehren
  72. fpath <- getInputString "Datei: "
  73. f <- catch (readFile fpath) (\e -> do let err = show (e :: IOException)
  74. in putStr ("Fehler beim Oeffnen der Datei " ++ err ++ "\n\n") >> return "")
  75. if f /= "" then evalExpr f >> runInterpr ref True else runInterpr ref True -- nur auswerten, wenn auch was zum auswerten da ist...
  76. ":help" -> do -- Hilfe anzeigen
  77. usage
  78. runInterpr ref True
  79. otherwise -> do -- Eingabe auswerten
  80. datas <- readIORef ref
  81. putStrLn ("Auswertung von \"" ++ (buildExpr datas cmd) ++ "\"...")
  82. evalExpr (buildExpr datas cmd)
  83. runInterpr ref True
  84. ----------------------------------------------------------------------------------------------------------
  85. -- | 'buildExpr' baut aus dem Data- und Expressionanweisungen einen vollstaendigen Ausdruck zusammen
  86. ----------------------------------------------------------------------------------------------------------
  87. buildExpr :: String -> String -> String
  88. buildExpr d e = if d == "" then "expression " ++ e
  89. else d ++ " expression " ++ e
  90. ----------------------------------------------------------------------------------------------------------
  91. -- | 'main' ist die main-funktion fuer den haskell-compiler. Sie ruft den interaktiven Interpreter auf.
  92. ----------------------------------------------------------------------------------------------------------
  93. main = run