/fppr2010/sourcecode/CHF/interpreter.hs
http://fppr2010.googlecode.com/ · Haskell · 107 lines · 67 code · 14 blank · 26 comment · 13 complexity · 31595157daacd4968a0ef0e9f7cb6fdb MD5 · raw file
- -- | Dieses Modul implementiert einen interaktiven Interpreter fuer Concurrent Haskell with Futures
-
- import System.IO -- benoetigt fuer hFlush
- import Control.Exception(try,IOException,SomeException,evaluate) -- benoetigt fuer evaluate/try/...
- import Data.IORef -- benoetigt fuer IORef
- import CHF.Run as CHF -- Concurrent Haskell with Futures
-
- ----------------------------------------------------------------------------------------------------------
- -- | 'getInputString' Wrapper fuer getLine. (Liefert auf jeden Fall einen String.)
- -- Als Parameter kann eine Eingabaufforderung Uebergeben werden. Der Trick mit hFlush aus System.IO
- -- stammt von http://www.haskell.org/pipermail/haskell/2006-September/018430.html
- -- und sorgt dafuer, dass sich das Programm in GHCI genauso verhaellt, wie die kompilierte .exe-Datei!
- ----------------------------------------------------------------------------------------------------------
- getInputString :: String -> IO (String)
- getInputString s = putStr s >> hFlush stdout >> getLine
-
-
- ----------------------------------------------------------------------------------------------------------
- -- | 'usage' gibt eine Hilfe-Mitteilung mit allen zur Verfuegung stehenden Kommandos aus.
- ----------------------------------------------------------------------------------------------------------
- usage :: IO ()
- usage = let
- txt = "Moegliche Kommandos sind:\n"
- ++ " :quit\t\tzum Beenden\n"
- ++ " :help\t\tfuer Hilfe\n"
- ++ " :define\tzum Definieren globaler data-Definitionen\n"
- ++ " :clear\tzum Loeschen globaler data-Definitionen\n"
- ++ " :runfile\tum eine Datei auszufuehren\n"
- in putStrLn txt
-
-
- ----------------------------------------------------------------------------------------------------------
- -- | 'run' gibt Begruessung aus und startet den interaktiven Interpreter
- ----------------------------------------------------------------------------------------------------------
- run :: IO ()
- run = do
- putStrLn "Concurrent Haskell with Futures (CHF) [Nhan/Leppin]"
- putStrLn "===================================================="
- putStrLn "Beenden :quit / Hilfe :help"
- ref <- newIORef "" -- neue IORef erzeugen mit initialem leeren String
- runInterpr ref True
-
-
- ----------------------------------------------------------------------------------------------------------
- -- | 'evalExpr' probiert, den Eingabausdruck inp auszuwerten und faengt ggf. Fehler ab.
- ----------------------------------------------------------------------------------------------------------
- evalExpr :: String -> IO ()
- evalExpr inp = do
- r <- try (CHF.runCM1 inp) :: IO (Either SomeException ())
- case r of
- Left ex -> putStr "CHF Fehler: " >> print ex >> putStrLn "\n"
- Right val -> return () -- runCM1 liefert keine Rueckgabe, sondern prodzuiert print-Seiteneffekt
-
-
- ----------------------------------------------------------------------------------------------------------
- -- | 'runInterpr' ist die eigentliche interaktive Interpreterfunktion
- -- wenn der Parameter auf False gesetzt wird, wird sie beendet, solang er True ist, laeuft die Schleife.
- ----------------------------------------------------------------------------------------------------------
- runInterpr :: IORef String -> Bool -> IO ()
- runInterpr _ False = putStrLn "So long, and thanks for all the fish."
- runInterpr ref True = do
- cmd <- getInputString "*CHF>"
- case cmd of
- "" -> runInterpr ref True -- bei Enter machen wir nix
- ":quit" -> runInterpr ref False -- Quit (set to False)
- ":define" -> do -- data-Block speichern
- s <- readIORef ref
- putStr "aktuelle Definitionen: \"" >> putStr s >> putStrLn "\""
- s' <- getInputString "neue Definition (Enter=Abbruch): "
- if null s' then do -- tu nichts
- putStrLn "abgebrochen."
- runInterpr ref True
- else do -- speichere neuen Wert
- writeIORef ref s'
- putStr "neue Definitionen \"" >> putStr s' >> putStrLn "\" gespeichert."
- runInterpr ref True
- ":clear" -> do -- data-Block loeschen
- writeIORef ref ""
- putStrLn "Data-Definitionen geloescht!"
- runInterpr ref True
- ":runfile" -> do -- Datei einlesen und ausfuehren
- fpath <- getInputString "Datei: "
- f <- catch (readFile fpath) (\e -> do let err = show (e :: IOException)
- in putStr ("Fehler beim Oeffnen der Datei " ++ err ++ "\n\n") >> return "")
- if f /= "" then evalExpr f >> runInterpr ref True else runInterpr ref True -- nur auswerten, wenn auch was zum auswerten da ist...
- ":help" -> do -- Hilfe anzeigen
- usage
- runInterpr ref True
- otherwise -> do -- Eingabe auswerten
- datas <- readIORef ref
- putStrLn ("Auswertung von \"" ++ (buildExpr datas cmd) ++ "\"...")
- evalExpr (buildExpr datas cmd)
- runInterpr ref True
-
-
- ----------------------------------------------------------------------------------------------------------
- -- | 'buildExpr' baut aus dem Data- und Expressionanweisungen einen vollstaendigen Ausdruck zusammen
- ----------------------------------------------------------------------------------------------------------
- buildExpr :: String -> String -> String
- buildExpr d e = if d == "" then "expression " ++ e
- else d ++ " expression " ++ e
-
-
- ----------------------------------------------------------------------------------------------------------
- -- | 'main' ist die main-funktion fuer den haskell-compiler. Sie ruft den interaktiven Interpreter auf.
- ----------------------------------------------------------------------------------------------------------
- main = run