@@ -3,7 +3,7 @@ module Idris.Core.Execute (execute) where
4import Idris.AbsSyntax
4import Idris.AbsSyntax
5import Idris.AbsSyntaxTree
5import Idris.AbsSyntaxTree
6−import IRTS.Lang(FType(..))
6+import IRTS.Lang(FDesc(..), FType(..))
8import Idris.Primitives(Prim(..), primitives)
8import Idris.Primitives(Prim(..), primitives)
@@ -231,52 +231,85 @@ execApp env ctxt con@(EP _ fp _) args@(tp:v:rest)
231 | fp == pioret = execApp env ctxt (mkEApp con [tp, v]) rest
231 | fp == pioret = execApp env ctxt (mkEApp con [tp, v]) rest
233-- Special cases arising from not having access to the C RTS in the interpreter
233-- Special cases arising from not having access to the C RTS in the interpreter
234−execApp env ctxt (EP _ fp _) (_:fn:str:_:rest)
234+execApp env ctxt f@(EP _ fp _) args@(xs:_:_:_:args')
235 | fp == mkfprim,
235 | fp == mkfprim,
236+ (ty : fn : w : rest) <- reverse args' =
237+ execForeign env ctxt getArity ty fn rest (mkEApp f args)
238+ where getArity = case unEList xs of
239+ Just as -> length as
242+execApp env ctxt c@(EP (DCon _ arity _) n _) args =
243+ do let args' = take arity args
244+ let restArgs = drop arity args
245+ execApp env ctxt (mkEApp c args') restArgs
247+execApp env ctxt c@(EP (TCon _ arity) n _) args =
248+ do let args' = take arity args
249+ let restArgs = drop arity args
250+ execApp env ctxt (mkEApp c args') restArgs
252+execApp env ctxt f@(EP _ n _) args =
253+ do let val = lookupDef n ctxt
255+ [Function _ tm] -> fail "should already have been eval'd"
256+ [TyDecl nt ty] -> return $ mkEApp f args
257+ [Operator tp arity op] ->
258+ if length args >= arity
259+ then let args' = take arity args in
260+ case getOp n args' of
261+ Just res -> do r <- res
262+ execApp env ctxt r (drop arity args)
263+ Nothing -> return (mkEApp f args)
264+ else return (mkEApp f args)
265+ [CaseOp _ _ _ _ _ (CaseDefs _ ([], STerm tm) _ _)] -> -- nullary fun
266+ do rhs <- doExec env ctxt tm
267+ execApp env ctxt rhs args
268+ [CaseOp _ _ _ _ _ (CaseDefs _ (ns, sc) _ _)] ->
269+ do res <- execCase env ctxt ns sc args
270+ return $ fromMaybe (mkEApp f args) res
271+ thing -> return $ mkEApp f args
272+execApp env ctxt bnd@(EBind n b body) (arg:args) = do ret <- body arg
273+ let (f', as) = unApplyV ret
274+ execApp env ctxt f' (as ++ args)
275+execApp env ctxt app@(EApp _ _) args2 | (f, args1) <- unApplyV app = execApp env ctxt f (args1 ++ args2)
276+execApp env ctxt f args = return (mkEApp f args)
278+execForeign env ctxt arity ty fn xs onfail
236− Just (FFun "putStr" _ _) <- foreignFromTT fn
279+ | Just (FFun "putStr" [(_, str)] _) <- foreignFromTT arity ty fn xs
237− = case str of
280+ = case str of
238− EConstant (Str arg) -> do execIO (putStr arg)
281+ EConstant (Str arg) -> do execIO (putStr arg)
239− execApp env ctxt ioUnit rest
282+ execApp env ctxt ioUnit (drop arity xs)
240− _ -> execFail . Msg $
283+ _ -> execFail . Msg $
241− "The argument to putStr should be a constant string, but it was " ++
284+ "The argument to putStr should be a constant string, but it was " ++
242− show str ++
285+ show str ++
243− ". Are all cases covered?"
286+ ". Are all cases covered?"
244−execApp env ctxt (EP _ fp _) (_:fn:ch:_:rest)
246− Just (FFun "putchar" _ _) <- foreignFromTT fn
287+ | Just (FFun "putchar" [(_, ch)] _) <- foreignFromTT arity ty fn xs
247 = case ch of
288 = case ch of
248 EConstant (Ch c) -> do execIO (putChar c)
289 EConstant (Ch c) -> do execIO (putChar c)
249− execApp env ctxt ioUnit rest
290+ execApp env ctxt ioUnit (drop arity xs)
250 EConstant (I i) -> do execIO (putChar (toEnum i))
291 EConstant (I i) -> do execIO (putChar (toEnum i))
251− execApp env ctxt ioUnit rest
292+ execApp env ctxt ioUnit (drop arity xs)
252 _ -> execFail . Msg $
293 _ -> execFail . Msg $
253 "The argument to putchar should be a constant character, but it was " ++
294 "The argument to putchar should be a constant character, but it was " ++
254 show str ++
295 show str ++
255 ". Are all cases covered?"
296 ". Are all cases covered?"
256−execApp env ctxt (EP _ fp _) (_:fn:_:handle:_:rest)
258− Just (FFun "idris_readStr" _ _) <- foreignFromTT fn
297+ | Just (FFun "idris_readStr" [_, (_, handle)] _) <- foreignFromTT arity ty fn xs
259 = case handle of
298 = case handle of
260 EHandle h -> do contents <- execIO $ hGetLine h
299 EHandle h -> do contents <- execIO $ hGetLine h
261− execApp env ctxt (EConstant (Str (contents ++ "\n"))) rest
300+ execApp env ctxt (EConstant (Str (contents ++ "\n"))) (drop arity xs)
262 _ -> execFail . Msg $
301 _ -> execFail . Msg $
263 "The argument to idris_readStr should be a handle, but it was " ++
302 "The argument to idris_readStr should be a handle, but it was " ++
264 show handle ++
303 show handle ++
265 ". Are all cases covered?"
304 ". Are all cases covered?"
266−execApp env ctxt (EP _ fp _) (_:fn:_:rest)
268− Just (FFun "getchar" _ _) <- foreignFromTT fn
305+ | Just (FFun "getchar" _ _) <- foreignFromTT arity ty fn xs
269 = do -- The C API returns an Int which Idris library code
306 = do -- The C API returns an Int which Idris library code
270 -- converts; thus, we must make an int here.
307 -- converts; thus, we must make an int here.
271 ch <- execIO $ fmap (ioWrap . EConstant . I . fromEnum) getChar
308 ch <- execIO $ fmap (ioWrap . EConstant . I . fromEnum) getChar
272− execApp env ctxt ch rest
309+ execApp env ctxt ch xs
273−execApp env ctxt (EP _ fp _) (_:fn:rest)
275− Just (FFun "idris_time" _ _) <- foreignFromTT fn
310+ | Just (FFun "idris_time" _ _) <- foreignFromTT arity ty fn xs
276 = do execIO $ fmap (ioWrap . EConstant . I . round) getPOSIXTime
311 = do execIO $ fmap (ioWrap . EConstant . I . round) getPOSIXTime
277−execApp env ctxt (EP _ fp _) (_:fn:fileStr:modeStr:rest)
279− Just (FFun "fileOpen" _ _) <- foreignFromTT fn
312+ | Just (FFun "fileOpen" [(_,fileStr), (_,modeStr)] _) <- foreignFromTT arity ty fn xs
280 = case (fileStr, modeStr) of
313 = case (fileStr, modeStr) of
281 (EConstant (Str f), EConstant (Str mode)) ->
314 (EConstant (Str f), EConstant (Str mode)) ->
282 do f <- execIO $
315 do f <- execIO $
@@ -291,10 +324,10 @@ execApp env ctxt (EP _ fp _) (_:fn:fileStr:modeStr:rest)
291 case fmap (openFile f) m of
324 case fmap (openFile f) m of
292 Right h -> do h' <- h
325 Right h -> do h' <- h
293 hSetBinaryMode h' True
326 hSetBinaryMode h' True
294− return $ Right (ioWrap (EHandle h'), tail rest)
327+ return $ Right (ioWrap (EHandle h'), drop arity xs)
295 Left err -> return $ Left err)
328 Left err -> return $ Left err)
296 (\e -> let _ = ( e::SomeException)
329 (\e -> let _ = ( e::SomeException)
297− in return $ Right (ioWrap (EPtr nullPtr), tail rest))
330+ in return $ Right (ioWrap (EPtr nullPtr), drop arity xs))
298 case f of
331 case f of
299 Left err -> execFail . Msg $ err
332 Left err -> execFail . Msg $ err
300 Right (res, rest) -> execApp env ctxt res rest
333 Right (res, rest) -> execApp env ctxt res rest
@@ -302,105 +335,72 @@ execApp env ctxt (EP _ fp _) (_:fn:fileStr:modeStr:rest)
302 "The arguments to fileOpen should be constant strings, but they were " ++
335 "The arguments to fileOpen should be constant strings, but they were " ++
303 show fileStr ++ " and " ++ show modeStr ++
336 show fileStr ++ " and " ++ show modeStr ++
304 ". Are all cases covered?"
337 ". Are all cases covered?"
306−execApp env ctxt (EP _ fp _) (_:fn:handle:rest)
308− Just (FFun "fileEOF" _ _) <- foreignFromTT fn
338+ | Just (FFun "fileEOF" [(_,handle)] _) <- foreignFromTT arity ty fn xs
309 = case handle of
339 = case handle of
310 EHandle h -> do eofp <- execIO $ hIsEOF h
340 EHandle h -> do eofp <- execIO $ hIsEOF h
311 let res = ioWrap (EConstant (I $ if eofp then 1 else 0))
341 let res = ioWrap (EConstant (I $ if eofp then 1 else 0))
312− execApp env ctxt res (tail rest)
342+ execApp env ctxt res (drop arity xs)
313 _ -> execFail . Msg $
343 _ -> execFail . Msg $
314 "The argument to fileEOF should be a file handle, but it was " ++
344 "The argument to fileEOF should be a file handle, but it was " ++
315 show handle ++
345 show handle ++
316 ". Are all cases covered?"
346 ". Are all cases covered?"
318−execApp env ctxt (EP _ fp _) (_:fn:handle:rest)
320− Just (FFun "fileClose" _ _) <- foreignFromTT fn
347+ | Just (FFun "fileClose" [(_,handle)] _) <- foreignFromTT arity ty fn xs
321 = case handle of
348 = case handle of
322 EHandle h -> do execIO $ hClose h
349 EHandle h -> do execIO $ hClose h
323− execApp env ctxt ioUnit (tail rest)
350+ execApp env ctxt ioUnit (drop arity xs)
324 _ -> execFail . Msg $
351 _ -> execFail . Msg $
325 "The argument to fileClose should be a file handle, but it was " ++
352 "The argument to fileClose should be a file handle, but it was " ++
326 show handle ++
353 show handle ++
327 ". Are all cases covered?"
354 ". Are all cases covered?"
329−execApp env ctxt (EP _ fp _) (_:fn:ptr:rest)
331− Just (FFun "isNull" _ _) <- foreignFromTT fn
356+ | Just (FFun "isNull" [(_, ptr)] _) <- foreignFromTT arity ty fn xs
332 = case ptr of
357 = case ptr of
333 EPtr p -> let res = ioWrap . EConstant . I $
358 EPtr p -> let res = ioWrap . EConstant . I $
334 if p == nullPtr then 1 else 0
359 if p == nullPtr then 1 else 0
335− in execApp env ctxt res (tail rest)
360+ in execApp env ctxt res (drop arity xs)
336 -- Handles will be checked as null pointers sometimes - but if we got a
361 -- Handles will be checked as null pointers sometimes - but if we got a
337 -- real Handle, then it's valid, so just return 1.
362 -- real Handle, then it's valid, so just return 1.
338 EHandle h -> let res = ioWrap . EConstant . I $ 0
363 EHandle h -> let res = ioWrap . EConstant . I $ 0
339− in execApp env ctxt res (tail rest)
364+ in execApp env ctxt res (drop arity xs)
340 -- A foreign-returned char* has to be tested for NULL sometimes
365 -- A foreign-returned char* has to be tested for NULL sometimes
341 EConstant (Str s) -> let res = ioWrap . EConstant . I $ 0
366 EConstant (Str s) -> let res = ioWrap . EConstant . I $ 0
342− in execApp env ctxt res (tail rest)
367+ in execApp env ctxt res (drop arity xs)
343 _ -> execFail . Msg $
368 _ -> execFail . Msg $
344 "The argument to isNull should be a pointer or file handle or string, but it was " ++
369 "The argument to isNull should be a pointer or file handle or string, but it was " ++
345 show ptr ++
370 show ptr ++
346 ". Are all cases covered?"
371 ". Are all cases covered?"
349-- Right now, there's no way to send command-line arguments to the executor,
373-- Right now, there's no way to send command-line arguments to the executor,
350-- so just return 0.
374-- so just return 0.
351−execApp env ctxt (EP _ fp _) (_:fn:rest)
375+execForeign env ctxt arity ty fn xs onfail
353− Just (FFun "idris_numArgs" _ _) <- foreignFromTT fn
376+ | Just (FFun "idris_numArgs" _ _) <- foreignFromTT arity ty fn xs
354 = let res = ioWrap . EConstant . I $ 0
377 = let res = ioWrap . EConstant . I $ 0
355− in execApp env ctxt res (tail rest)
378+ in execApp env ctxt res (drop arity xs)
357−execApp env ctxt f@(EP _ fp _) args@(ty:fn:xs) | fp == mkfprim
380+execForeign env ctxt arity ty fn xs onfail
358− = case foreignFromTT fn of
381+ = case foreignFromTT arity ty fn xs of
359− Just (FFun f argTs retT) | length xs >= length argTs ->
382+ Just ffun@(FFun f argTs retT) | length xs >= arity ->
360− do let (args', xs') = (take (length argTs) xs, -- foreign args
383+ do let (args', xs') = (take arity xs, -- foreign args
361− drop (length argTs + 1) xs) -- rest
384+ drop arity xs) -- rest
362− res <- stepForeign (ty:fn:args')
385+ res <- call ffun (map snd argTs)
363 case res of
386 case res of
364 Nothing -> fail $ "Could not call foreign function \"" ++ f ++
387 Nothing -> fail $ "Could not call foreign function \"" ++ f ++
365− "\" with args " ++ show args
388+ "\" with args " ++ show (map snd argTs)
366 Just r -> return (mkEApp r xs')
389 Just r -> return (mkEApp r xs')
367− Nothing -> return (mkEApp f args)
390+ Nothing -> return onfail
369−execApp env ctxt c@(EP (DCon _ arity _) n _) args =
393+splitArg tm | (_, [_,_,l,r]) <- unApplyV tm -- pair, two implicits
370− do let args' = take arity args
394+ = Just (toFDesc l, r)
371− let restArgs = drop arity args
395+splitArg _ = Nothing
372− execApp env ctxt (mkEApp c args') restArgs
374−execApp env ctxt c@(EP (TCon _ arity) n _) args =
397+toFDesc tm
375− do let args' = take arity args
398+ | (EP _ n _, []) <- unApplyV tm = FCon (deNS n)
376− let restArgs = drop arity args
399+ | (EP _ n _, as) <- unApplyV tm = FApp (deNS n) (map toFDesc as)
377− execApp env ctxt (mkEApp c args') restArgs
400+toFDesc _ = FUnknown
379−execApp env ctxt f@(EP _ n _) args =
402+deNS (NS n _) = n
380− do let val = lookupDef n ctxt
403+deNS n = n
382− [Function _ tm] -> fail "should already have been eval'd"
383− [TyDecl nt ty] -> return $ mkEApp f args
384− [Operator tp arity op] ->
385− if length args >= arity
386− then let args' = take arity args in
387− case getOp n args' of
388− Just res -> do r <- res
389− execApp env ctxt r (drop arity args)
390− Nothing -> return (mkEApp f args)
391− else return (mkEApp f args)
392− [CaseOp _ _ _ _ _ (CaseDefs _ ([], STerm tm) _ _)] -> -- nullary fun
393− do rhs <- doExec env ctxt tm
394− execApp env ctxt rhs args
395− [CaseOp _ _ _ _ _ (CaseDefs _ (ns, sc) _ _)] ->
396− do res <- execCase env ctxt ns sc args
397− return $ fromMaybe (mkEApp f args) res
398− thing -> return $ mkEApp f args
399−execApp env ctxt bnd@(EBind n b body) (arg:args) = do ret <- body arg
400− let (f', as) = unApplyV ret
401− execApp env ctxt f' (as ++ args)
402−execApp env ctxt app@(EApp _ _) args2 | (f, args1) <- unApplyV app = execApp env ctxt f (args1 ++ args2)
403−execApp env ctxt f args = return (mkEApp f args)
405prs = sUN "prim__readString"
405prs = sUN "prim__readString"
406pbm = sUN "prim__believe_me"
406pbm = sUN "prim__believe_me"
@@ -494,13 +494,35 @@ idrisType ft = EConstant (idr ft)
494 idr FString = StrType
494 idr FString = StrType
495 idr FPtr = PtrType
495 idr FPtr = PtrType
497−data Foreign = FFun String [FType] FType deriving Show
497+data Foreign = FFun String [(FDesc, ExecVal)] FDesc deriving Show
499+toFType :: FDesc -> FType
501+ | c == sUN "C_Str" = FString
502+ | c == sUN "C_Float" = FArith ATFloat
503+ | c == sUN "C_Ptr" = FPtr
504+ | c == sUN "C_MPtr" = FManagedPtr
505+ | c == sUN "C_Unit" = FUnit
506+toFType (FApp c [_,ity])
507+ | c == sUN "C_IntT" = FArith (toAType ity)
508+ where toAType (FCon i)
509+ | i == sUN "C_IntChar" = ATInt ITChar
510+ | i == sUN "C_IntNative" = ATInt ITNative
511+ | i == sUN "C_IntBits8" = ATInt (ITFixed IT8)
512+ | i == sUN "C_IntBits16" = ATInt (ITFixed IT16)
513+ | i == sUN "C_IntBits32" = ATInt (ITFixed IT32)
514+ | i == sUN "C_IntBits64" = ATInt (ITFixed IT64)
515+ toAType t = error (show t ++ " not defined in toAType")
518+ | c == sUN "C_Any" = FAny
519+toFType t = error (show t ++ " not defined in toFType")
500call :: Foreign -> [ExecVal] -> Exec (Maybe ExecVal)
521call :: Foreign -> [ExecVal] -> Exec (Maybe ExecVal)
501call (FFun name argTypes retType) args =
522call (FFun name argTypes retType) args =
502 do fn <- findForeign name
523 do fn <- findForeign name
524+ maybe (return Nothing)
503− maybe (return Nothing) (\f -> Just . ioWrap <$> call' f args retType) fn
525+ (\f -> Just . ioWrap <$> call' f args (toFType retType)) fn
504 where call' :: ForeignFun -> [ExecVal] -> FType -> Exec ExecVal
526 where call' :: ForeignFun -> [ExecVal] -> FType -> Exec ExecVal
505 call' (Fun _ h) args (FArith (ATInt ITNative)) = do
527 call' (Fun _ h) args (FArith (ATInt ITNative)) = do
506 res <- execIO $ callFFI h retCInt (prepArgs args)
528 res <- execIO $ callFFI h retCInt (prepArgs args)
@@ -549,15 +571,11 @@ call (FFun name argTypes retType) args =
549 prepArg other = trace ("Could not use " ++ take 100 (show other) ++ " as FFI arg.") undefined
571 prepArg other = trace ("Could not use " ++ take 100 (show other) ++ " as FFI arg.") undefined
553−foreignFromTT :: ExecVal -> Maybe Foreign
574+foreignFromTT :: Int -> ExecVal -> ExecVal -> [ExecVal] -> Maybe Foreign
554−foreignFromTT t = case (unApplyV t) of
555− (_, [(EConstant (Str name)), args, ret]) ->
575+foreignFromTT arity ty (EConstant (Str name)) args
556− do argTy <- unEList args
576+ = do argFTyVals <- mapM splitArg (take arity args)
557− argFTy <- sequence $ map getFTy argTy
558− retFTy <- getFTy ret
559− return $ FFun name argFTy retFTy
577+ return $ FFun name argFTyVals (toFDesc ty)
560− _ -> trace ("failed to construct ffun") Nothing
578+foreignFromTT arity ty fn args = trace ("failed to construct ffun from " ++ show (ty,fn,args)) Nothing
562getFTy :: ExecVal -> Maybe FType
580getFTy :: ExecVal -> Maybe FType
563getFTy (EApp (EP _ (UN fi) _) (EP _ (UN intTy) _))
581getFTy (EApp (EP _ (UN fi) _) (EP _ (UN intTy) _))
@@ -592,13 +610,6 @@ toConst :: Term -> Maybe Const
592toConst (Constant c) = Just c
610toConst (Constant c) = Just c
593toConst _ = Nothing
611toConst _ = Nothing
595−stepForeign :: [ExecVal] -> Exec (Maybe ExecVal)
596−stepForeign (ty:fn:args) = let ffun = foreignFromTT fn
597− in case (call <$> ffun) of
599− Nothing -> return Nothing
600−stepForeign _ = fail "Tried to call foreign function that wasn't mkForeignPrim"
602mapMaybeM :: (Functor m, Monad m) => (a -> m (Maybe b)) -> [a] -> m [b]
613mapMaybeM :: (Functor m, Monad m) => (a -> m (Maybe b)) -> [a] -> m [b]
603mapMaybeM f [] = return []
614mapMaybeM f [] = return []
604mapMaybeM f (x:xs) = do rest <- mapMaybeM f xs
615mapMaybeM f (x:xs) = do rest <- mapMaybeM f xs