@@ -29,6 +29,7 @@ import Control.Monad.Trans
2929import Control.Monad.Trans.Except (ExceptT, runExceptT, throwE)
3030import Control.Monad.Trans.State.Strict
3131import Data.Bits
32+import Data.IORef
3233import qualified Data.Map as M
3334import Data.Maybe
3435import Data.Time.Clock.POSIX (getPOSIXTime)
@@ -70,6 +71,11 @@ data ExecVal = EP NameType Name ExecVal
7071 | forall a. EPtr (Ptr a)
7172 | EThunk Context ExecEnv Term
7273 | EHandle Handle
74+ | EStringBuf (IORef String)
75+
76+mkRaw :: ExecVal -> ExecVal
77+mkRaw arg = EApp (EApp (EP (DCon 0 1 False) (sNS (sUN "MkRaw") ["FFI_C"]) EErased)
78+ EErased) arg
7379
7480instance Show ExecVal where
7581 show (EP _ n _) = show n
@@ -83,6 +89,7 @@ instance Show ExecVal where
8389 show (EPtr p) = "<<ptr " ++ show p ++ ">>"
8490 show (EThunk _ env tm) = "<<thunk " ++ show env ++ "||||" ++ show tm ++ ">>"
8591 show (EHandle h) = "<<handle " ++ show h ++ ">>"
92+ show (EStringBuf h) = "<<string buffer>>"
8693
8794toTT :: ExecVal -> Exec Term
8895toTT (EP nt n ty) = (P nt n) <$> (toTT ty)
@@ -117,6 +124,7 @@ toTT (EThunk ctxt env tm) = do env' <- mapM toBinder env
117124 return (n, RigW, Let Erased v')
118125toTT (EHandle _) = execFail $ Msg "Can't convert handles back to TT after execution."
119126toTT (EPtr ptr) = execFail $ Msg "Can't convert pointers back to TT after execution."
127+toTT (EStringBuf ptr) = execFail $ Msg "Can't convert string buffers back to TT after execution."
120128
121129unApplyV :: ExecVal -> (ExecVal, [ExecVal])
122130unApplyV tm = ua [] tm
@@ -191,7 +199,7 @@ doExec env ctxt v@(V i) | i < length env = return (snd (env !! i))
191199 | otherwise = execFail . Msg $ "env too small"
192200doExec env ctxt (Bind n (Let t v) body) = do v' <- doExec env ctxt v
193201 doExec ((n, v'):env) ctxt body
194−doExec env ctxt (Bind n (NLet t v) body) = trace "NLet" $ undefined
202+doExec env ctxt (Bind n (NLet t v) body) = undefined
195203doExec env ctxt tm@(Bind n b body) = do b' <- forM b (doExec env ctxt)
196204 return $
197205 EBind n b' (\arg -> doExec ((n, arg):env) ctxt body)
@@ -404,6 +412,37 @@ execForeign env ctxt arity ty fn xs onfail
404412 execIO $ hSetBuffering stdout NoBuffering
405413 execApp env ctxt ioUnit (drop arity xs)
406414
415+ -- Just use a Haskell String in an IORef for a string buffer
416+ | Just (FFun "idris_makeStringBuffer" [(_, len)] _) <- foreignFromTT arity ty fn xs
417+ = case len of
418+ EConstant (I _) -> do buf <- execIO $ newIORef ""
419+ let res = ioWrap (EStringBuf buf)
420+ execApp env ctxt res (drop arity xs)
421+
422+ _ -> execFail . Msg $
423+ "The argument to idris_makeStringBuffer should be an Int, but it was " ++
424+ show len ++
425+ ". Are all cases covered?"
426+ | Just (FFun "idris_addToString" [(_, strBuf), (_, str)] _) <- foreignFromTT arity ty fn xs
427+ = case (strBuf, str) of
428+ (EStringBuf ref, EConstant (Str add)) ->
429+ do execIO $ modifyIORef ref (++add)
430+ execApp env ctxt ioUnit (drop arity xs)
431+ _ -> execFail . Msg $
432+ "The arguments to idris_addToString should be a StringBuffer and a String, but were " ++
433+ show strBuf ++ " and " ++ show str ++
434+ ". Are all cases covered?"
435+ | Just (FFun "idris_getString" [_, (_, str)] _) <- foreignFromTT arity ty fn xs
436+ = case str of
437+ EStringBuf ref -> do str <- execIO $ readIORef ref
438+ let res = ioWrap (mkRaw (EConstant (Str str)))
439+ execApp env ctxt res (drop arity xs)
440+ _ -> execFail . Msg $
441+ "The argument to idris_getString should be a StringBuffer, but it was " ++
442+ show str ++
443+ ". Are all cases covered?"
444+
445+
407446
408447-- Right now, there's no way to send command-line arguments to the executor,
409448-- so just return 0.
@@ -438,6 +477,7 @@ deNS (NS n _) = n
438477deNS n = n
439478
440479prf = sUN "prim__readFile"
480+prc = sUN "prim__readChars"
441481pwf = sUN "prim__writeFile"
442482prs = sUN "prim__readString"
443483pws = sUN "prim__writeString"
@@ -479,6 +519,16 @@ getOp fn (_ : EHandle h : xs)
479519 | fn == prf =
480520 Just (do contents <- execIO $ hGetLine h
481521 return (EConstant (Str (contents ++ "\n"))), xs)
522+getOp fn (_ : EConstant (I len) : EHandle h : xs)
523+ | fn == prc =
524+ Just (do contents <- execIO $ hGetChars h len
525+ return (EConstant (Str contents)), xs)
526+ where hGetChars h 0 = return ""
527+ hGetChars h i = do eof <- hIsEOF h
528+ if eof then return "" else do
529+ c <- hGetChar h
530+ rest <- hGetChars h (i - 1)
531+ return (c : rest)
482532getOp fn (_ : arg : xs)
483533 | fn == prf =
484534 Just $ (execFail (Msg "Can't use prim__readFile on a raw pointer in the executor."), xs)