@@ -29,6 +29,7 @@ import Control.Monad.Trans
29import Control.Monad.Trans.Except (ExceptT, runExceptT, throwE)
29import Control.Monad.Trans.Except (ExceptT, runExceptT, throwE)
30import Control.Monad.Trans.State.Strict
30import Control.Monad.Trans.State.Strict
31import Data.Bits
31import Data.Bits
32import qualified Data.Map as M
33import qualified Data.Map as M
33import Data.Maybe
34import Data.Maybe
34import Data.Time.Clock.POSIX (getPOSIXTime)
35import Data.Time.Clock.POSIX (getPOSIXTime)
@@ -70,6 +71,11 @@ data ExecVal = EP NameType Name ExecVal
70 | forall a. EPtr (Ptr a)
71 | forall a. EPtr (Ptr a)
71 | EThunk Context ExecEnv Term
72 | EThunk Context ExecEnv Term
72 | EHandle Handle
73 | EHandle Handle
74+ | EStringBuf (IORef String)
76+mkRaw :: ExecVal -> ExecVal
77+mkRaw arg = EApp (EApp (EP (DCon 0 1 False) (sNS (sUN "MkRaw") ["FFI_C"]) EErased)
74instance Show ExecVal where
80instance Show ExecVal where
75 show (EP _ n _) = show n
81 show (EP _ n _) = show n
@@ -83,6 +89,7 @@ instance Show ExecVal where
83 show (EPtr p) = "<<ptr " ++ show p ++ ">>"
89 show (EPtr p) = "<<ptr " ++ show p ++ ">>"
84 show (EThunk _ env tm) = "<<thunk " ++ show env ++ "||||" ++ show tm ++ ">>"
90 show (EThunk _ env tm) = "<<thunk " ++ show env ++ "||||" ++ show tm ++ ">>"
85 show (EHandle h) = "<<handle " ++ show h ++ ">>"
91 show (EHandle h) = "<<handle " ++ show h ++ ">>"
92+ show (EStringBuf h) = "<<string buffer>>"
87toTT :: ExecVal -> Exec Term
94toTT :: ExecVal -> Exec Term
88toTT (EP nt n ty) = (P nt n) <$> (toTT ty)
95toTT (EP nt n ty) = (P nt n) <$> (toTT ty)
@@ -117,6 +124,7 @@ toTT (EThunk ctxt env tm) = do env' <- mapM toBinder env
117 return (n, RigW, Let Erased v')
124 return (n, RigW, Let Erased v')
118toTT (EHandle _) = execFail $ Msg "Can't convert handles back to TT after execution."
125toTT (EHandle _) = execFail $ Msg "Can't convert handles back to TT after execution."
119toTT (EPtr ptr) = execFail $ Msg "Can't convert pointers back to TT after execution."
126toTT (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."
121unApplyV :: ExecVal -> (ExecVal, [ExecVal])
129unApplyV :: ExecVal -> (ExecVal, [ExecVal])
122unApplyV tm = ua [] tm
130unApplyV tm = ua [] tm
@@ -191,7 +199,7 @@ doExec env ctxt v@(V i) | i < length env = return (snd (env !! i))
191 | otherwise = execFail . Msg $ "env too small"
199 | otherwise = execFail . Msg $ "env too small"
192doExec env ctxt (Bind n (Let t v) body) = do v' <- doExec env ctxt v
200doExec env ctxt (Bind n (Let t v) body) = do v' <- doExec env ctxt v
193 doExec ((n, v'):env) ctxt body
201 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
195doExec env ctxt tm@(Bind n b body) = do b' <- forM b (doExec env ctxt)
203doExec env ctxt tm@(Bind n b body) = do b' <- forM b (doExec env ctxt)
197 EBind n b' (\arg -> doExec ((n, arg):env) ctxt body)
205 EBind n b' (\arg -> doExec ((n, arg):env) ctxt body)
@@ -404,6 +412,37 @@ execForeign env ctxt arity ty fn xs onfail
404 execIO $ hSetBuffering stdout NoBuffering
412 execIO $ hSetBuffering stdout NoBuffering
405 execApp env ctxt ioUnit (drop arity xs)
413 execApp env ctxt ioUnit (drop arity xs)
415+ -- Just use a Haskell String in an IORef for a string buffer
416+ | Just (FFun "idris_makeStringBuffer" [(_, len)] _) <- foreignFromTT arity ty fn xs
418+ EConstant (I _) -> do buf <- execIO $ newIORef ""
419+ let res = ioWrap (EStringBuf buf)
420+ execApp env ctxt res (drop arity xs)
422+ _ -> execFail . Msg $
423+ "The argument to idris_makeStringBuffer should be an Int, but it was " ++
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
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 " ++
443+ ". Are all cases covered?"
408-- Right now, there's no way to send command-line arguments to the executor,
447-- Right now, there's no way to send command-line arguments to the executor,
409-- so just return 0.
448-- so just return 0.
@@ -438,6 +477,7 @@ deNS (NS n _) = n
438deNS n = n
477deNS n = n
440prf = sUN "prim__readFile"
479prf = sUN "prim__readFile"
480+prc = sUN "prim__readChars"
441pwf = sUN "prim__writeFile"
481pwf = sUN "prim__writeFile"
442prs = sUN "prim__readString"
482prs = sUN "prim__readString"
443pws = sUN "prim__writeString"
483pws = sUN "prim__writeString"
@@ -479,6 +519,16 @@ getOp fn (_ : EHandle h : xs)
479 | fn == prf =
519 | fn == prf =
480 Just (do contents <- execIO $ hGetLine h
520 Just (do contents <- execIO $ hGetLine h
481 return (EConstant (Str (contents ++ "\n"))), xs)
521 return (EConstant (Str (contents ++ "\n"))), xs)
522+getOp fn (_ : EConstant (I len) : EHandle h : xs)
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
530+ rest <- hGetChars h (i - 1)
482getOp fn (_ : arg : xs)
532getOp fn (_ : arg : xs)
483 | fn == prf =
533 | fn == prf =
484 Just $ (execFail (Msg "Can't use prim__readFile on a raw pointer in the executor."), xs)
534 Just $ (execFail (Msg "Can't use prim__readFile on a raw pointer in the executor."), xs)