@@ -3,7 +3,7 @@ module Idris.Core.Execute (execute) where
33
44import Idris.AbsSyntax
55import Idris.AbsSyntaxTree
6−import IRTS.Lang(FType(..))
6+import IRTS.Lang(FDesc(..), FType(..))
77
88import Idris.Primitives(Prim(..), primitives)
99
@@ -231,52 +231,85 @@ execApp env ctxt con@(EP _ fp _) args@(tp:v:rest)
231231 | fp == pioret = execApp env ctxt (mkEApp con [tp, v]) rest
232232
233233-- 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')
235235 | fp == mkfprim,
236− Just (FFun "putStr" _ _) <- foreignFromTT fn
237− = case str of
238− EConstant (Str arg) -> do execIO (putStr arg)
239− execApp env ctxt ioUnit rest
240− _ -> execFail . Msg $
241− "The argument to putStr should be a constant string, but it was " ++
242− show str ++
243− ". Are all cases covered?"
244−execApp env ctxt (EP _ fp _) (_:fn:ch:_:rest)
245− | fp == mkfprim,
246− Just (FFun "putchar" _ _) <- foreignFromTT fn
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
240+ _ -> 0
241+
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
246+
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
251+
252+execApp env ctxt f@(EP _ n _) args =
253+ do let val = lookupDef n ctxt
254+ case val of
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)
277+
278+execForeign env ctxt arity ty fn xs onfail
279+ | Just (FFun "putStr" [(_, str)] _) <- foreignFromTT arity ty fn xs
280+ = case str of
281+ EConstant (Str arg) -> do execIO (putStr arg)
282+ execApp env ctxt ioUnit (drop arity xs)
283+ _ -> execFail . Msg $
284+ "The argument to putStr should be a constant string, but it was " ++
285+ show str ++
286+ ". Are all cases covered?"
287+ | Just (FFun "putchar" [(_, ch)] _) <- foreignFromTT arity ty fn xs
247288 = case ch of
248289 EConstant (Ch c) -> do execIO (putChar c)
249− execApp env ctxt ioUnit rest
290+ execApp env ctxt ioUnit (drop arity xs)
250291 EConstant (I i) -> do execIO (putChar (toEnum i))
251− execApp env ctxt ioUnit rest
292+ execApp env ctxt ioUnit (drop arity xs)
252293 _ -> execFail . Msg $
253294 "The argument to putchar should be a constant character, but it was " ++
254295 show str ++
255296 ". Are all cases covered?"
256−execApp env ctxt (EP _ fp _) (_:fn:_:handle:_:rest)
257− | fp == mkfprim,
258− Just (FFun "idris_readStr" _ _) <- foreignFromTT fn
297+ | Just (FFun "idris_readStr" [_, (_, handle)] _) <- foreignFromTT arity ty fn xs
259298 = case handle of
260299 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)
262301 _ -> execFail . Msg $
263302 "The argument to idris_readStr should be a handle, but it was " ++
264303 show handle ++
265304 ". Are all cases covered?"
266−execApp env ctxt (EP _ fp _) (_:fn:_:rest)
267− | fp == mkfprim,
268− Just (FFun "getchar" _ _) <- foreignFromTT fn
305+ | Just (FFun "getchar" _ _) <- foreignFromTT arity ty fn xs
269306 = do -- The C API returns an Int which Idris library code
270307 -- converts; thus, we must make an int here.
271308 ch <- execIO $ fmap (ioWrap . EConstant . I . fromEnum) getChar
272− execApp env ctxt ch rest
273−execApp env ctxt (EP _ fp _) (_:fn:rest)
274− | fp == mkfprim,
275− Just (FFun "idris_time" _ _) <- foreignFromTT fn
309+ execApp env ctxt ch xs
310+ | Just (FFun "idris_time" _ _) <- foreignFromTT arity ty fn xs
276311 = do execIO $ fmap (ioWrap . EConstant . I . round) getPOSIXTime
277−execApp env ctxt (EP _ fp _) (_:fn:fileStr:modeStr:rest)
278− | fp == mkfprim,
279− Just (FFun "fileOpen" _ _) <- foreignFromTT fn
312+ | Just (FFun "fileOpen" [(_,fileStr), (_,modeStr)] _) <- foreignFromTT arity ty fn xs
280313 = case (fileStr, modeStr) of
281314 (EConstant (Str f), EConstant (Str mode)) ->
282315 do f <- execIO $
@@ -291,10 +324,10 @@ execApp env ctxt (EP _ fp _) (_:fn:fileStr:modeStr:rest)
291324 case fmap (openFile f) m of
292325 Right h -> do h' <- h
293326 hSetBinaryMode h' True
294− return $ Right (ioWrap (EHandle h'), tail rest)
327+ return $ Right (ioWrap (EHandle h'), drop arity xs)
295328 Left err -> return $ Left err)
296329 (\e -> let _ = ( e::SomeException)
297− in return $ Right (ioWrap (EPtr nullPtr), tail rest))
330+ in return $ Right (ioWrap (EPtr nullPtr), drop arity xs))
298331 case f of
299332 Left err -> execFail . Msg $ err
300333 Right (res, rest) -> execApp env ctxt res rest
@@ -302,105 +335,72 @@ execApp env ctxt (EP _ fp _) (_:fn:fileStr:modeStr:rest)
302335 "The arguments to fileOpen should be constant strings, but they were " ++
303336 show fileStr ++ " and " ++ show modeStr ++
304337 ". Are all cases covered?"
305−
306−execApp env ctxt (EP _ fp _) (_:fn:handle:rest)
307− | fp == mkfprim,
308− Just (FFun "fileEOF" _ _) <- foreignFromTT fn
338+ | Just (FFun "fileEOF" [(_,handle)] _) <- foreignFromTT arity ty fn xs
309339 = case handle of
310340 EHandle h -> do eofp <- execIO $ hIsEOF h
311341 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)
313343 _ -> execFail . Msg $
314344 "The argument to fileEOF should be a file handle, but it was " ++
315345 show handle ++
316346 ". Are all cases covered?"
317−
318−execApp env ctxt (EP _ fp _) (_:fn:handle:rest)
319− | fp == mkfprim,
320− Just (FFun "fileClose" _ _) <- foreignFromTT fn
347+ | Just (FFun "fileClose" [(_,handle)] _) <- foreignFromTT arity ty fn xs
321348 = case handle of
322349 EHandle h -> do execIO $ hClose h
323− execApp env ctxt ioUnit (tail rest)
350+ execApp env ctxt ioUnit (drop arity xs)
324351 _ -> execFail . Msg $
325352 "The argument to fileClose should be a file handle, but it was " ++
326353 show handle ++
327354 ". Are all cases covered?"
328355
329−execApp env ctxt (EP _ fp _) (_:fn:ptr:rest)
330− | fp == mkfprim,
331− Just (FFun "isNull" _ _) <- foreignFromTT fn
356+ | Just (FFun "isNull" [(_, ptr)] _) <- foreignFromTT arity ty fn xs
332357 = case ptr of
333358 EPtr p -> let res = ioWrap . EConstant . I $
334359 if p == nullPtr then 1 else 0
335− in execApp env ctxt res (tail rest)
360+ in execApp env ctxt res (drop arity xs)
336361 -- Handles will be checked as null pointers sometimes - but if we got a
337362 -- real Handle, then it's valid, so just return 1.
338363 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)
340365 -- A foreign-returned char* has to be tested for NULL sometimes
341366 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)
343368 _ -> execFail . Msg $
344369 "The argument to isNull should be a pointer or file handle or string, but it was " ++
345370 show ptr ++
346371 ". Are all cases covered?"
347372
348−
349373-- Right now, there's no way to send command-line arguments to the executor,
350374-- so just return 0.
351−execApp env ctxt (EP _ fp _) (_:fn:rest)
352− | fp == mkfprim,
353− Just (FFun "idris_numArgs" _ _) <- foreignFromTT fn
375+execForeign env ctxt arity ty fn xs onfail
376+ | Just (FFun "idris_numArgs" _ _) <- foreignFromTT arity ty fn xs
354377 = let res = ioWrap . EConstant . I $ 0
355− in execApp env ctxt res (tail rest)
356−
357−execApp env ctxt f@(EP _ fp _) args@(ty:fn:xs) | fp == mkfprim
358− = case foreignFromTT fn of
359− Just (FFun f argTs retT) | length xs >= length argTs ->
360− do let (args', xs') = (take (length argTs) xs, -- foreign args
361− drop (length argTs + 1) xs) -- rest
362− res <- stepForeign (ty:fn:args')
378+ in execApp env ctxt res (drop arity xs)
379+
380+execForeign env ctxt arity ty fn xs onfail
381+ = case foreignFromTT arity ty fn xs of
382+ Just ffun@(FFun f argTs retT) | length xs >= arity ->
383+ do let (args', xs') = (take arity xs, -- foreign args
384+ drop arity xs) -- rest
385+ res <- call ffun (map snd argTs)
363386 case res of
364387 Nothing -> fail $ "Could not call foreign function \"" ++ f ++
365− "\" with args " ++ show args
388+ "\" with args " ++ show (map snd argTs)
366389 Just r -> return (mkEApp r xs')
367− Nothing -> return (mkEApp f args)
390+ Nothing -> return onfail
391+
368392
369−execApp env ctxt c@(EP (DCon _ arity _) n _) args =
370− do let args' = take arity args
371− let restArgs = drop arity args
372− execApp env ctxt (mkEApp c args') restArgs
393+splitArg tm | (_, [_,_,l,r]) <- unApplyV tm -- pair, two implicits
394+ = Just (toFDesc l, r)
395+splitArg _ = Nothing
373396
374−execApp env ctxt c@(EP (TCon _ arity) n _) args =
375− do let args' = take arity args
376− let restArgs = drop arity args
377− execApp env ctxt (mkEApp c args') restArgs
397+toFDesc tm
398+ | (EP _ n _, []) <- unApplyV tm = FCon (deNS n)
399+ | (EP _ n _, as) <- unApplyV tm = FApp (deNS n) (map toFDesc as)
400+toFDesc _ = FUnknown
378401
379−execApp env ctxt f@(EP _ n _) args =
380− do let val = lookupDef n ctxt
381− case val of
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)
402+deNS (NS n _) = n
403+deNS n = n
404404
405405prs = sUN "prim__readString"
406406pbm = sUN "prim__believe_me"
@@ -494,13 +494,35 @@ idrisType ft = EConstant (idr ft)
494494 idr FString = StrType
495495 idr FPtr = PtrType
496496
497−data Foreign = FFun String [FType] FType deriving Show
498−
497+data Foreign = FFun String [(FDesc, ExecVal)] FDesc deriving Show
498+
499+toFType :: FDesc -> FType
500+toFType (FCon c)
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")
516+
517+toFType (FApp c [_])
518+ | c == sUN "C_Any" = FAny
519+toFType t = error (show t ++ " not defined in toFType")
499520
500521call :: Foreign -> [ExecVal] -> Exec (Maybe ExecVal)
501522call (FFun name argTypes retType) args =
502523 do fn <- findForeign name
503− maybe (return Nothing) (\f -> Just . ioWrap <$> call' f args retType) fn
524+ maybe (return Nothing)
525+ (\f -> Just . ioWrap <$> call' f args (toFType retType)) fn
504526 where call' :: ForeignFun -> [ExecVal] -> FType -> Exec ExecVal
505527 call' (Fun _ h) args (FArith (ATInt ITNative)) = do
506528 res <- execIO $ callFFI h retCInt (prepArgs args)
@@ -549,15 +571,11 @@ call (FFun name argTypes retType) args =
549571 prepArg other = trace ("Could not use " ++ take 100 (show other) ++ " as FFI arg.") undefined
550572
551573
552−
553−foreignFromTT :: ExecVal -> Maybe Foreign
554−foreignFromTT t = case (unApplyV t) of
555− (_, [(EConstant (Str name)), args, ret]) ->
556− do argTy <- unEList args
557− argFTy <- sequence $ map getFTy argTy
558− retFTy <- getFTy ret
559− return $ FFun name argFTy retFTy
560− _ -> trace ("failed to construct ffun") Nothing
574+foreignFromTT :: Int -> ExecVal -> ExecVal -> [ExecVal] -> Maybe Foreign
575+foreignFromTT arity ty (EConstant (Str name)) args
576+ = do argFTyVals <- mapM splitArg (take arity args)
577+ return $ FFun name argFTyVals (toFDesc ty)
578+foreignFromTT arity ty fn args = trace ("failed to construct ffun from " ++ show (ty,fn,args)) Nothing
561579
562580getFTy :: ExecVal -> Maybe FType
563581getFTy (EApp (EP _ (UN fi) _) (EP _ (UN intTy) _))
@@ -592,13 +610,6 @@ toConst :: Term -> Maybe Const
592610toConst (Constant c) = Just c
593611toConst _ = Nothing
594612
595−stepForeign :: [ExecVal] -> Exec (Maybe ExecVal)
596−stepForeign (ty:fn:args) = let ffun = foreignFromTT fn
597− in case (call <$> ffun) of
598− Just f -> f args
599− Nothing -> return Nothing
600−stepForeign _ = fail "Tried to call foreign function that wasn't mkForeignPrim"
601−
602613mapMaybeM :: (Functor m, Monad m) => (a -> m (Maybe b)) -> [a] -> m [b]
603614mapMaybeM f [] = return []
604615mapMaybeM f (x:xs) = do rest <- mapMaybeM f xs