1{-# LANGUAGE PatternGuards, ExistentialQuantification, CPP #-}
2{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
3module Idris.Core.Execute (execute) where
6import Idris.AbsSyntaxTree
7import IRTS.Lang(FDesc(..), FType(..))
9import Idris.Primitives(Prim(..), primitives)
12import Idris.Core.Evaluate
13import Idris.Core.CaseTree
19import Util.DynamicLinker
22import Control.Applicative hiding (Const)
23import Control.Exception
24import Control.Monad.Trans
25import Control.Monad.Trans.State.Strict
26import Control.Monad.Trans.Except (ExceptT, runExceptT, throwE)
27import Control.Monad hiding (forM)
30import Data.Traversable (forM)
31import Data.Time.Clock.POSIX (getPOSIXTime)
32import qualified Data.Map as M
36import Foreign.C.String
37import Foreign.Marshal.Alloc (free)
44execute :: Term -> Idris Term
45execute tm = fail "libffi not supported, rebuild Idris with -f FFI"
47-- else is rest of file
48readMay :: (Read a) => String -> Maybe a
49readMay s = case reads s of
53data Lazy = Delayed ExecEnv Context Term | Forced ExecVal deriving Show
55data ExecState = ExecState { exec_dynamic_libs :: [DynamicLib] -- ^ Dynamic libs from idris monad
56 , binderNames :: [Name] -- ^ Used to uniquify binders when converting to TT
59data ExecVal = EP NameType Name ExecVal
61 | EBind Name (Binder ExecVal) (ExecVal -> Exec ExecVal)
62 | EApp ExecVal ExecVal
67 | forall a. EPtr (Ptr a)
68 | EThunk Context ExecEnv Term
71instance Show ExecVal where
72 show (EP _ n _) = show n
73 show (EV i) = "!!V" ++ show i ++ "!!"
74 show (EBind n b body) = "EBind " ++ show b ++ " <<fn>>"
75 show (EApp e1 e2) = show e1 ++ " (" ++ show e2 ++ ")"
76 show (EType _) = "Type"
77 show (EUType _) = "UType"
79 show (EConstant c) = show c
80 show (EPtr p) = "<<ptr " ++ show p ++ ">>"
81 show (EThunk _ env tm) = "<<thunk " ++ show env ++ "||||" ++ show tm ++ ">>"
82 show (EHandle h) = "<<handle " ++ show h ++ ">>"
84toTT :: ExecVal -> Exec Term
85toTT (EP nt n ty) = (P nt n) <$> (toTT ty)
86toTT (EV i) = return $ V i
87toTT (EBind n b body) = do n' <- newN n
88 body' <- body $ EP Bound n' EErased
90 Bind n' b' <$> toTT body'
91 where fixBinder (Lam t) = Lam <$> toTT t
92 fixBinder (Pi i t k) = Pi i <$> toTT t <*> toTT k
93 fixBinder (Let t1 t2) = Let <$> toTT t1 <*> toTT t2
94 fixBinder (NLet t1 t2) = NLet <$> toTT t1 <*> toTT t2
95 fixBinder (Hole t) = Hole <$> toTT t
96 fixBinder (GHole i t) = GHole i <$> toTT t
97 fixBinder (Guess t1 t2) = Guess <$> toTT t1 <*> toTT t2
98 fixBinder (PVar t) = PVar <$> toTT t
99 fixBinder (PVTy t) = PVTy <$> toTT t
100 newN n = do (ExecState hs ns) <- lift get
101 let n' = uniqueName n ns
102 lift (put (ExecState hs (n':ns)))
104toTT (EApp e1 e2) = do e1' <- toTT e1
106 return $ App Complete e1' e2'
107toTT (EType u) = return $ TType u
108toTT (EUType u) = return $ UType u
109toTT EErased = return Erased
110toTT (EConstant c) = return (Constant c)
111toTT (EThunk ctxt env tm) = do env' <- mapM toBinder env
112 return $ normalise ctxt env' tm
113 where toBinder (n, v) = do v' <- toTT v
114 return (n, Let Erased v')
115toTT (EHandle _) = execFail $ Msg "Can't convert handles back to TT after execution."
116toTT (EPtr ptr) = execFail $ Msg "Can't convert pointers back to TT after execution."
118unApplyV :: ExecVal -> (ExecVal, [ExecVal])
119unApplyV tm = ua [] tm
120 where ua args (EApp f a) = ua (a:args) f
121 ua args t = (t, args)
123mkEApp :: ExecVal -> [ExecVal] -> ExecVal
125mkEApp f (a:args) = mkEApp (EApp f a) args
127initState :: Idris ExecState
128initState = do ist <- getIState
129 return $ ExecState (idris_dynamic_libs ist) []
131type Exec = ExceptT Err (StateT ExecState IO)
133runExec :: Exec a -> ExecState -> IO (Either Err a)
134runExec ex st = fst <$> runStateT (runExceptT ex) st
136getExecState :: Exec ExecState
137getExecState = lift get
139putExecState :: ExecState -> Exec ()
140putExecState = lift . put
142execFail :: Err -> Exec a
145execIO :: IO a -> Exec a
149execute :: Term -> Idris Term
150execute tm = do est <- initState
152 res <- lift . lift . flip runExec est $
153 do res <- doExec [] ctxt tm
156 Left err -> ierror err
157 Right tm' -> return tm'
159ioWrap :: ExecVal -> ExecVal
160ioWrap tm = mkEApp (EP (DCon 0 2 False) (sUN "prim__IO") EErased) [EErased, tm]
163ioUnit = ioWrap (EP Ref unitCon EErased)
165type ExecEnv = [(Name, ExecVal)]
167doExec :: ExecEnv -> Context -> Term -> Exec ExecVal
168doExec env ctxt p@(P Ref n ty) | Just v <- lookup n env = return v
169doExec env ctxt p@(P Ref n ty) =
170 do let val = lookupDef n ctxt
172 [Function _ tm] -> doExec env ctxt tm
173 [TyDecl _ _] -> return (EP Ref n EErased) -- abstract def
174 [Operator tp arity op] -> return (EP Ref n EErased) -- will be special-cased later
175 [CaseOp _ _ _ _ _ (CaseDefs _ ([], STerm tm) _ _)] -> -- nullary fun
177 [CaseOp _ _ _ _ _ (CaseDefs _ (ns, sc) _ _)] -> return (EP Ref n EErased)
178 [] -> execFail . Msg $ "Could not find " ++ show n ++ " in definitions."
179 other | length other > 1 -> execFail . Msg $ "Multiple definitions found for " ++ show n
180 | otherwise -> execFail . Msg . take 500 $ "got to " ++ show other ++ " lookup up " ++ show n
181doExec env ctxt p@(P Bound n ty) =
183 Nothing -> execFail . Msg $ "not found"
185doExec env ctxt (P (DCon a b u) n _) = return (EP (DCon a b u) n EErased)
186doExec env ctxt (P (TCon a b) n _) = return (EP (TCon a b) n EErased)
187doExec env ctxt v@(V i) | i < length env = return (snd (env !! i))
188 | otherwise = execFail . Msg $ "env too small"
189doExec env ctxt (Bind n (Let t v) body) = do v' <- doExec env ctxt v
190 doExec ((n, v'):env) ctxt body
191doExec env ctxt (Bind n (NLet t v) body) = trace "NLet" $ undefined
192doExec env ctxt tm@(Bind n b body) = do b' <- forM b (doExec env ctxt)
194 EBind n b' (\arg -> doExec ((n, arg):env) ctxt body)
195doExec env ctxt a@(App _ _ _) =
196 do let (f, args) = unApply a
197 f' <- doExec env ctxt f
199 (EP _ d _) | d == delay ->
201 [t,a,tm] -> do t' <- doExec env ctxt t
202 a' <- doExec env ctxt a
203 return [t', a', EThunk ctxt env tm]
204 _ -> mapM (doExec env ctxt) args -- partial applications are fine to evaluate
205 fun' -> do mapM (doExec env ctxt) args
206 execApp env ctxt f' args'
207doExec env ctxt (Constant c) = return (EConstant c)
208doExec env ctxt (Proj tm i) = let (x, xs) = unApply tm in
209 doExec env ctxt ((x:xs) !! i)
210doExec env ctxt Erased = return EErased
211doExec env ctxt Impossible = fail "Tried to execute an impossible case"
212doExec env ctxt (TType u) = return (EType u)
213doExec env ctxt (UType u) = return (EUType u)
215execApp :: ExecEnv -> Context -> ExecVal -> [ExecVal] -> Exec ExecVal
216execApp env ctxt v [] = return v -- no args is just a constant! can result from function calls
217execApp env ctxt (EP _ f _) (t:a:delayed:rest)
219 , (_, [_, _, EThunk tmCtxt tmEnv tm]) <- unApplyV delayed =
220 do tm' <- doExec tmEnv tmCtxt tm
221 execApp env ctxt tm' rest
222execApp env ctxt (EP _ fp _) (ty:action:rest)
224 (prim__IO, [_, v]) <- unApplyV action
225 = execApp env ctxt v rest
227execApp env ctxt (EP _ fp _) args@(_:_:v:k:rest)
229 (prim__IO, [_, v']) <- unApplyV v =
230 do res <- execApp env ctxt k [v']
231 execApp env ctxt res rest
232execApp env ctxt con@(EP _ fp _) args@(tp:v:rest)
233 | fp == pioret = execApp env ctxt (mkEApp con [tp, v]) rest
235-- Special cases arising from not having access to the C RTS in the interpreter
236execApp env ctxt f@(EP _ fp _) args@(xs:_:_:_:args')
238 (ty : fn : w : rest) <- reverse args' =
239 execForeign env ctxt getArity ty fn rest (mkEApp f args)
240 where getArity = case unEList xs of
244execApp env ctxt c@(EP (DCon _ arity _) n _) args =
245 do let args' = take arity args
246 let restArgs = drop arity args
247 execApp env ctxt (mkEApp c args') restArgs
249execApp env ctxt c@(EP (TCon _ arity) n _) args =
250 do let args' = take arity args
251 let restArgs = drop arity args
252 execApp env ctxt (mkEApp c args') restArgs
254execApp env ctxt f@(EP _ n _) args
255 | Just (res, rest) <- getOp n args = do r <- res
256 execApp env ctxt r rest
257execApp env ctxt f@(EP _ n _) args =
258 do let val = lookupDef n ctxt
260 [Function _ tm] -> fail "should already have been eval'd"
261 [TyDecl nt ty] -> return $ mkEApp f args
262 [Operator tp arity op] ->
263 if length args >= arity
264 then let args' = take arity args in
265 case getOp n args' of
266 Just (res, []) -> do r <- res
267 execApp env ctxt r (drop arity args)
268 _ -> return (mkEApp f args)
269 else return (mkEApp f args)
270 [CaseOp _ _ _ _ _ (CaseDefs _ ([], STerm tm) _ _)] -> -- nullary fun
271 do rhs <- doExec env ctxt tm
272 execApp env ctxt rhs args
273 [CaseOp _ _ _ _ _ (CaseDefs _ (ns, sc) _ _)] ->
274 do res <- execCase env ctxt ns sc args
275 return $ fromMaybe (mkEApp f args) res
276 thing -> return $ mkEApp f args
277execApp env ctxt bnd@(EBind n b body) (arg:args) = do ret <- body arg
278 let (f', as) = unApplyV ret
279 execApp env ctxt f' (as ++ args)
280execApp env ctxt app@(EApp _ _) args2 | (f, args1) <- unApplyV app = execApp env ctxt f (args1 ++ args2)
281execApp env ctxt f args = return (mkEApp f args)
283execForeign env ctxt arity ty fn xs onfail
284 | Just (FFun "putStr" [(_, str)] _) <- foreignFromTT arity ty fn xs
286 EConstant (Str arg) -> do execIO (putStr arg)
287 execApp env ctxt ioUnit (drop arity xs)
288 _ -> execFail . Msg $
289 "The argument to putStr should be a constant string, but it was " ++
291 ". Are all cases covered?"
292 | Just (FFun "putchar" [(_, ch)] _) <- foreignFromTT arity ty fn xs
294 EConstant (Ch c) -> do execIO (putChar c)
295 execApp env ctxt ioUnit (drop arity xs)
296 EConstant (I i) -> do execIO (putChar (toEnum i))
297 execApp env ctxt ioUnit (drop arity xs)
298 _ -> execFail . Msg $
299 "The argument to putchar should be a constant character, but it was " ++
301 ". Are all cases covered?"
302 | Just (FFun "idris_readStr" [_, (_, handle)] _) <- foreignFromTT arity ty fn xs
304 EHandle h -> do contents <- execIO $ hGetLine h
305 execApp env ctxt (EConstant (Str (contents ++ "\n"))) (drop arity xs)
306 _ -> execFail . Msg $
307 "The argument to idris_readStr should be a handle, but it was " ++
309 ". Are all cases covered?"
310 | Just (FFun "getchar" _ _) <- foreignFromTT arity ty fn xs
311 = do -- The C API returns an Int which Idris library code
312 -- converts; thus, we must make an int here.
313 ch <- execIO $ fmap (ioWrap . EConstant . I . fromEnum) getChar
314 execApp env ctxt ch xs
315 | Just (FFun "idris_time" _ _) <- foreignFromTT arity ty fn xs
316 = do execIO $ fmap (ioWrap . EConstant . I . round) getPOSIXTime
317 | Just (FFun "fileOpen" [(_,fileStr), (_,modeStr)] _) <- foreignFromTT arity ty fn xs
318 = case (fileStr, modeStr) of
319 (EConstant (Str f), EConstant (Str mode)) ->
321 catch (do let m = case mode of
322 "r" -> Right ReadMode
323 "w" -> Right WriteMode
324 "a" -> Right AppendMode
325 "rw" -> Right ReadWriteMode
326 "wr" -> Right ReadWriteMode
327 "r+" -> Right ReadWriteMode
328 _ -> Left ("Invalid mode for " ++ f ++ ": " ++ mode)
329 case fmap (openFile f) m of
330 Right h -> do h' <- h
331 hSetBinaryMode h' True
332 return $ Right (ioWrap (EHandle h'), drop arity xs)
333 Left err -> return $ Left err)
334 (\e -> let _ = ( e::SomeException)
335 in return $ Right (ioWrap (EPtr nullPtr), drop arity xs))
337 Left err -> execFail . Msg $ err
338 Right (res, rest) -> execApp env ctxt res rest
339 _ -> execFail . Msg $
340 "The arguments to fileOpen should be constant strings, but they were " ++
341 show fileStr ++ " and " ++ show modeStr ++
342 ". Are all cases covered?"
343 | Just (FFun "fileEOF" [(_,handle)] _) <- foreignFromTT arity ty fn xs
345 EHandle h -> do eofp <- execIO $ hIsEOF h
346 let res = ioWrap (EConstant (I $ if eofp then 1 else 0))
347 execApp env ctxt res (drop arity xs)
348 _ -> execFail . Msg $
349 "The argument to fileEOF should be a file handle, but it was " ++
351 ". Are all cases covered?"
352 | Just (FFun "fileClose" [(_,handle)] _) <- foreignFromTT arity ty fn xs
354 EHandle h -> do execIO $ hClose h
355 execApp env ctxt ioUnit (drop arity xs)
356 _ -> execFail . Msg $
357 "The argument to fileClose should be a file handle, but it was " ++
359 ". Are all cases covered?"
361 | Just (FFun "isNull" [(_, ptr)] _) <- foreignFromTT arity ty fn xs
363 EPtr p -> let res = ioWrap . EConstant . I $
364 if p == nullPtr then 1 else 0
365 in execApp env ctxt res (drop arity xs)
366 -- Handles will be checked as null pointers sometimes - but if we got a
367 -- real Handle, then it's valid, so just return 1.
368 EHandle h -> let res = ioWrap . EConstant . I $ 0
369 in execApp env ctxt res (drop arity xs)
370 -- A foreign-returned char* has to be tested for NULL sometimes
371 EConstant (Str s) -> let res = ioWrap . EConstant . I $ 0
372 in execApp env ctxt res (drop arity xs)
373 _ -> execFail . Msg $
374 "The argument to isNull should be a pointer or file handle or string, but it was " ++
376 ". Are all cases covered?"
378-- Right now, there's no way to send command-line arguments to the executor,
380execForeign env ctxt arity ty fn xs onfail
381 | Just (FFun "idris_numArgs" _ _) <- foreignFromTT arity ty fn xs
382 = let res = ioWrap . EConstant . I $ 0
383 in execApp env ctxt res (drop arity xs)
385execForeign env ctxt arity ty fn xs onfail
386 = case foreignFromTT arity ty fn xs of
387 Just ffun@(FFun f argTs retT) | length xs >= arity ->
388 do let (args', xs') = (take arity xs, -- foreign args
389 drop arity xs) -- rest
390 res <- call ffun (map snd argTs)
392 Nothing -> fail $ "Could not call foreign function \"" ++ f ++
393 "\" with args " ++ show (map snd argTs)
394 Just r -> return (mkEApp r xs')
398splitArg tm | (_, [_,_,l,r]) <- unApplyV tm -- pair, two implicits
399 = Just (toFDesc l, r)
403 | (EP _ n _, []) <- unApplyV tm = FCon (deNS n)
404 | (EP _ n _, as) <- unApplyV tm = FApp (deNS n) (map toFDesc as)
410prf = sUN "prim__readFile"
411pwf = sUN "prim__writeFile"
412prs = sUN "prim__readString"
413pws = sUN "prim__writeString"
414pbm = sUN "prim__believe_me"
415pstdin = sUN "prim__stdin"
416pstdout = sUN "prim__stdout"
417mkfprim = sUN "mkForeignPrim"
418pioret = sUN "prim_io_return"
419piobind = sUN "prim_io_bind"
420upio = sUN "unsafePerformPrimIO"
424-- | Look up primitive operations in the global table and transform
425-- them into ExecVal functions
426getOp :: Name -> [ExecVal] -> Maybe (Exec ExecVal, [ExecVal])
427getOp fn (_ : _ : x : xs) | fn == pbm = Just (return x, xs)
428getOp fn (_ : EConstant (Str n) : xs)
430 Just (do execIO $ putStr n
431 return (EConstant (I 0)), xs)
434 Just (do line <- execIO getLine
435 return (EConstant (Str line)), xs)
436getOp fn (_ : EP _ fn' _ : EConstant (Str n) : xs)
437 | fn == pwf && fn' == pstdout =
438 Just (do execIO $ putStr n
439 return (EConstant (I 0)), xs)
440getOp fn (_ : EP _ fn' _ : xs)
441 | fn == prf && fn' == pstdin =
442 Just (do line <- execIO getLine
443 return (EConstant (Str line)), xs)
444getOp fn (_ : EHandle h : EConstant (Str n) : xs)
446 Just (do execIO $ hPutStr h n
447 return (EConstant (I 0)), xs)
448getOp fn (_ : EHandle h : xs)
450 Just (do contents <- execIO $ hGetLine h
451 return (EConstant (Str (contents ++ "\n"))), xs)
452getOp fn (_ : arg : xs)
454 Just $ (execFail (Msg "Can't use prim__readFile on a raw pointer in the executor."), xs)
455getOp n args = do (arity, prim) <- getPrim n primitives
456 if (length args >= arity)
457 then do res <- applyPrim prim (take arity args)
458 Just (res, drop arity args)
460 where getPrim :: Name -> [Prim] -> Maybe (Int, [ExecVal] -> Maybe ExecVal)
461 getPrim n [] = Nothing
462 getPrim n ((Prim pn _ arity def _ _) : prims)
463 | n == pn = Just (arity, execPrim def)
464 | otherwise = getPrim n prims
466 execPrim :: ([Const] -> Maybe Const) -> [ExecVal] -> Maybe ExecVal
467 execPrim f args = EConstant <$> (mapM getConst args >>= f)
469 getConst (EConstant c) = Just c
472 applyPrim :: ([ExecVal] -> Maybe ExecVal) -> [ExecVal] -> Maybe (Exec ExecVal)
473 applyPrim fn args = return <$> fn args
478-- | Overall wrapper for case tree execution. If there are enough arguments, it takes them,
479-- evaluates them, then begins the checks for matching cases.
480execCase :: ExecEnv -> Context -> [Name] -> SC -> [ExecVal] -> Exec (Maybe ExecVal)
481execCase env ctxt ns sc args =
482 let arity = length ns in
483 if arity <= length args
484 then do let amap = zip ns args
485-- trace ("Case " ++ show sc ++ "\n in " ++ show amap ++"\n in env " ++ show env ++ "\n\n" ) $ return ()
486 caseRes <- execCase' env ctxt amap sc
488 Just res -> Just <$> execApp (map (\(n, tm) -> (n, tm)) amap ++ env) ctxt res (drop arity args)
489 Nothing -> return Nothing
492-- | Take bindings and a case tree and examines them, executing the matching case if possible.
493execCase' :: ExecEnv -> Context -> [(Name, ExecVal)] -> SC -> Exec (Maybe ExecVal)
494execCase' env ctxt amap (UnmatchedCase _) = return Nothing
495execCase' env ctxt amap (STerm tm) =
496 Just <$> doExec (map (\(n, v) -> (n, v)) amap ++ env) ctxt tm
497execCase' env ctxt amap (Case sh n alts) | Just tm <- lookup n amap =
498 case chooseAlt tm alts of
499 Just (newCase, newBindings) ->
500 let amap' = newBindings ++ (filter (\(x,_) -> not (elem x (map fst newBindings))) amap) in
501 execCase' env ctxt amap' newCase
502 Nothing -> return Nothing
503execCase' _ _ _ cse = fail $ "The impossible happened: tried to exec " ++ show cse
505chooseAlt :: ExecVal -> [CaseAlt] -> Maybe (SC, [(Name, ExecVal)])
506chooseAlt tm (DefaultCase sc : alts) | ok tm = Just (sc, [])
507 | otherwise = Nothing
508 where -- Default cases should only work on applications of constructors or on constants
510 ok (EP Bound _ _) = False
511 ok (EP Ref _ _) = False
515chooseAlt (EConstant c) (ConstCase c' sc : alts) | c == c' = Just (sc, [])
516chooseAlt tm (ConCase n i ns sc : alts) | ((EP _ cn _), args) <- unApplyV tm
517 , cn == n = Just (sc, zip ns args)
518 | otherwise = chooseAlt tm alts
519chooseAlt tm (_:alts) = chooseAlt tm alts
520chooseAlt _ [] = Nothing
523data Foreign = FFun String [(FDesc, ExecVal)] FDesc deriving Show
525toFType :: FDesc -> FType
527 | c == sUN "C_Str" = FString
528 | c == sUN "C_Float" = FArith ATFloat
529 | c == sUN "C_Ptr" = FPtr
530 | c == sUN "C_MPtr" = FManagedPtr
531 | c == sUN "C_Unit" = FUnit
532toFType (FApp c [_,ity])
533 | c == sUN "C_IntT" = FArith (toAType ity)
534 where toAType (FCon i)
535 | i == sUN "C_IntChar" = ATInt ITChar
536 | i == sUN "C_IntNative" = ATInt ITNative
537 | i == sUN "C_IntBits8" = ATInt (ITFixed IT8)
538 | i == sUN "C_IntBits16" = ATInt (ITFixed IT16)
539 | i == sUN "C_IntBits32" = ATInt (ITFixed IT32)
540 | i == sUN "C_IntBits64" = ATInt (ITFixed IT64)
541 toAType t = error (show t ++ " not defined in toAType")
544 | c == sUN "C_Any" = FAny
545toFType t = error (show t ++ " not defined in toFType")
547call :: Foreign -> [ExecVal] -> Exec (Maybe ExecVal)
548call (FFun name argTypes retType) args =
549 do fn <- findForeign name
550 maybe (return Nothing)
551 (\f -> Just . ioWrap <$> call' f args (toFType retType)) fn
552 where call' :: ForeignFun -> [ExecVal] -> FType -> Exec ExecVal
553 call' (Fun _ h) args (FArith (ATInt ITNative)) = do
554 res <- execIO $ callFFI h retCInt (prepArgs args)
555 return (EConstant (I (fromIntegral res)))
556 call' (Fun _ h) args (FArith (ATInt (ITFixed IT8))) = do
557 res <- execIO $ callFFI h retCChar (prepArgs args)
558 return (EConstant (B8 (fromIntegral res)))
559 call' (Fun _ h) args (FArith (ATInt (ITFixed IT16))) = do
560 res <- execIO $ callFFI h retCWchar (prepArgs args)
561 return (EConstant (B16 (fromIntegral res)))
562 call' (Fun _ h) args (FArith (ATInt (ITFixed IT32))) = do
563 res <- execIO $ callFFI h retCInt (prepArgs args)
564 return (EConstant (B32 (fromIntegral res)))
565 call' (Fun _ h) args (FArith (ATInt (ITFixed IT64))) = do
566 res <- execIO $ callFFI h retCLong (prepArgs args)
567 return (EConstant (B64 (fromIntegral res)))
568 call' (Fun _ h) args (FArith ATFloat) = do
569 res <- execIO $ callFFI h retCDouble (prepArgs args)
570 return (EConstant (Fl (realToFrac res)))
571 call' (Fun _ h) args (FArith (ATInt ITChar)) = do
572 res <- execIO $ callFFI h retCChar (prepArgs args)
573 return (EConstant (Ch (castCCharToChar res)))
574 call' (Fun _ h) args FString = do res <- execIO $ callFFI h retCString (prepArgs args)
576 then return (EPtr res)
577 else do hStr <- execIO $ peekCString res
578 return (EConstant (Str hStr))
580 call' (Fun _ h) args FPtr = EPtr <$> (execIO $ callFFI h (retPtr retVoid) (prepArgs args))
581 call' (Fun _ h) args FUnit = do _ <- execIO $ callFFI h retVoid (prepArgs args)
582 return $ EP Ref unitCon EErased
583 call' _ _ _ = fail "the impossible happened in call' in Execute.hs"
585 prepArgs = map prepArg
586 prepArg (EConstant (I i)) = argCInt (fromIntegral i)
587 prepArg (EConstant (B8 i)) = argCChar (fromIntegral i)
588 prepArg (EConstant (B16 i)) = argCWchar (fromIntegral i)
589 prepArg (EConstant (B32 i)) = argCInt (fromIntegral i)
590 prepArg (EConstant (B64 i)) = argCLong (fromIntegral i)
591 prepArg (EConstant (Fl f)) = argCDouble (realToFrac f)
592 prepArg (EConstant (Ch c)) = argCChar (castCharToCChar c) -- FIXME - castCharToCChar only safe for first 256 chars
593 -- Issue #1720 on the issue tracker.
594 -- https://github.com/idris-lang/Idris-dev/issues/1720
595 prepArg (EConstant (Str s)) = argString s
596 prepArg (EPtr p) = argPtr p
597 prepArg other = trace ("Could not use " ++ take 100 (show other) ++ " as FFI arg.") undefined
600foreignFromTT :: Int -> ExecVal -> ExecVal -> [ExecVal] -> Maybe Foreign
601foreignFromTT arity ty (EConstant (Str name)) args
602 = do argFTyVals <- mapM splitArg (take arity args)
603 return $ FFun name argFTyVals (toFDesc ty)
604foreignFromTT arity ty fn args = trace ("failed to construct ffun from " ++ show (ty,fn,args)) Nothing
606getFTy :: ExecVal -> Maybe FType
607getFTy (EApp (EP _ (UN fi) _) (EP _ (UN intTy) _))
608 | fi == txt "FIntT" =
610 "ITNative" -> Just (FArith (ATInt ITNative))
611 "ITChar" -> Just (FArith (ATInt ITChar))
612 "IT8" -> Just (FArith (ATInt (ITFixed IT8)))
613 "IT16" -> Just (FArith (ATInt (ITFixed IT16)))
614 "IT32" -> Just (FArith (ATInt (ITFixed IT32)))
615 "IT64" -> Just (FArith (ATInt (ITFixed IT64)))
617getFTy (EP _ (UN t) _) =
619 "FFloat" -> Just (FArith ATFloat)
620 "FString" -> Just FString
622 "FUnit" -> Just FUnit
626unEList :: ExecVal -> Maybe [ExecVal]
627unEList tm = case unApplyV tm of
628 (nil, [_]) -> Just []
629 (cons, ([_, x, xs])) ->
630 do rest <- unEList xs
635toConst :: Term -> Maybe Const
636toConst (Constant c) = Just c
639mapMaybeM :: (Functor m, Monad m) => (a -> m (Maybe b)) -> [a] -> m [b]
640mapMaybeM f [] = return []
641mapMaybeM f (x:xs) = do rest <- mapMaybeM f xs
642 maybe rest (:rest) <$> f x
643findForeign :: String -> Exec (Maybe ForeignFun)
644findForeign fn = do est <- getExecState
645 let libs = exec_dynamic_libs est
646 fns <- mapMaybeM getFn libs
648 [f] -> return (Just f)
649 [] -> do execIO . putStrLn $ "Symbol \"" ++ fn ++ "\" not found"
651 fs -> do execIO . putStrLn $ "Symbol \"" ++ fn ++ "\" is ambiguous. Found " ++
652 show (length fs) ++ " occurrences."
654 where getFn lib = execIO $ catchIO (tryLoadFn fn lib) (\_ -> return Nothing)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list