As a small part of a larger University project, I need to write what is essentially an extremely crude IDE. The idea is to to take input from a gtk text box, treat that string as if it is in a .hs file, and evaluate a function within it.
My main approach has been to use the GHC API to compile and evaluate a test function. I had already managed to get a toy example working for compiling from a .hs file. GHC's Target data type had an optional constructor for getting a target from a StringBuffer, so I decided to try and alter my code to get it to work from a String Buffer:
compileText :: SourceView -> IO ()
compileText tview = do
txtBuff <- textViewGetBuffer tview
startIt <- textBufferGetStartIter txtBuff
endIt <- textBufferGetEndIter txtBuff
compTime <- getClockTime
srcString <- textBufferGetText txtBuff startIt endIt False
defaultErrorHandler defaultLogAction $ do
func <- runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
setSessionDynFlags dflags
addTarget $ haskellFileFromText srcString compTime
r <- load LoadAllTargets
case r of
Failed -> error "Compilation failed"
Succeeded -> do
m <- findModule (mkModuleName "Test") Nothing
setContext [IIModule m]
value <- compileExpr ("Test.print")
do let value' = (unsafeCoerce value) :: String -> IO ()
return value'
func "Hello"
return ()
haskellFileFromText :: String -> ClockTime -> GHC.Target
haskellFileFromText codeStr cTime = GHC.Target (TargetModule (mkModuleName "Test")) False (Just ((stringToStringBuffer codeStr), cTime))
The following code being in the text box at the time:
module Test (Test.print) where
print :: String -> IO ()
print x = putStrLn x
However, this does not seem to work. I get the error:
textEdit: panic! (the 'impossible' happened)
(GHC version 7.4.1 for x86_64-unknown-linux):
Could not find module `Test'
Use -v to see a list of the files searched for.
Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug
What am I doing wrong? I feel I am crucially misunderstanding something about the way this code works.
An alternative to this method which has been suggested to me is to use something like hint or mueval to evaluate the text in the textbox. This would appear to work fine if i simply want to evaluate a single function in isolation, but would this scale if I wanted to evaluate a function which depended on the context of running 4 other functions defined within the same source file?
As C.A. McCann notes,
hint
does lots of this work for you. It's a wrapper around the GHC api, not just a standalone evaluator like mueval.Even if it is missing something you need, it will be far easier to learn from it and extend it than start from scratch.