3Description : The default code generator for Idris, generating C code.
6Maintainer : The Idris Community.
8module IRTS.CodegenC (codegenC) where
10import Idris.AbsSyntax hiding (getBC)
13import IRTS.CodegenCommon
14import IRTS.Defunctionalise
25import Data.List (find, intercalate, nubBy, partition)
26import qualified Data.Text as T
28import System.FilePath ((<.>), (</>))
31import System.Directory
32import System.FilePath ((</>), (<.>))
34import Control.Monad.RWS
38codegenC :: CodeGenerator
39codegenC ci = do codegenC' (simpleDecls ci)
44 (map mkLib (compileLibs ci) ++
45 map incdir (importDirs ci))
50 when (interfaces ci) $
51 codegenH (exportDecls ci)
53 where mkLib l = "-l" ++ l
56codegenC' :: [(Name, SDecl)]
57 -> String -- ^ output file name
58 -> OutputType -- ^ generate executable if True, only .o if False
59 -> [FilePath] -- ^ include files
60 -> [String] -- ^ extra object files
61 -> [String] -- ^ extra compiler flags (libraries)
62 -> [String] -- ^ extra compiler flags (anything)
64 -> Bool -- ^ interfaces too (so make a .o instead)
67codegenC' defs out exec incs objs libs flags exports iface dbg
69 let bc = map toBC defs
70 let wrappers = genWrappers bc
71 let h = concatMap toDecl (map fst bc)
72 let (state, cc) = execRWS (generateSrc bc) 0
73 (CS { fnName = Nothing,
75 let hi = concatMap ifaceC (concatMap getExp exports)
77 mprog <- readFile (d </> "idris_main" <.> "c")
78 let cout = headers incs ++ debug dbg ++ h ++ wrappers ++ cc ++
79 (if (exec == Executable) then mprog else hi)
81 Raw -> writeSource out cout
83 (tmpn, tmph) <- tempfile ".c"
88 libFlags <- getLibFlags
89 incFlags <- getIncFlags
90 envFlags <- getEnvFlags
91 let stackFlag = if isWindows then ["-Wl,--stack,16777216"] else []
92 let args = [gccDbg dbg] ++
94 -- # Any flags defined here which alter the RTS API must also be added to config.mk
95 ["-DHAS_PTHREAD", "-DIDRIS_ENABLE_STATS",
96 "-I."] ++ objs ++ envFlags ++
97 (if (exec == Executable) then [] else ["-c"]) ++
99 (if not iface then libFlags else []) ++
101 (if not iface then libs else []) ++
102 flags ++ stackFlag ++
104-- putStrLn (show args)
105 exit <- rawSystem comp args
106 when (exit /= ExitSuccess) $
107 putStrLn ("FAILURE: " ++ show comp ++ " " ++ show args)
109 getExp (Export _ _ exp) = exp
113 (\h -> "#include \"" ++ h ++ "\"\n")
114 (xs ++ ["idris_rts.h", "idris_bitstring.h", "idris_stdfgn.h"])
116debug TRACE = "#define IDRIS_TRACE\n\n"
119-- We're using signed integers now. Make sure we get consistent semantics
120-- out of them from gcc. See e.g. http://thiemonagel.de/2010/01/signed-integer-overflow/
121gccFlags i = if i then ["-fwrapv"]
122 else ["-fwrapv", "-fno-strict-overflow"]
128cname :: Name -> String
129cname n = "_idris_" ++ concatMap cchar (showCG n)
130 where cchar x | isAlpha x || isDigit x = [x]
131 | otherwise = "_" ++ show (fromEnum x) ++ "_"
133indent :: Int -> String
134indent n = replicate (n*4) ' '
137creg (L i) = "LOC(" ++ show i ++ ")"
138creg (T i) = "TOP(" ++ show i ++ ")"
141toDecl :: Name -> String
142toDecl f = "void " ++ cname f ++ "(VM*, VAL*);\n"
144generateSrc :: [(Name, [BC])] -> RWS Int String CState ()
145generateSrc bc = mapM_ toC bc
147toC :: (Name, [BC]) -> RWS Int String CState ()
149 modify (\s -> s { fnName = Just f })
151 tell $ "void " ++ cname f ++ "(VM* vm, VAL* oldbase) {\n"
152 tell $ indent (level s) ++ "INITFRAME;\n"
156showCStr :: String -> String
157showCStr s = '"' : foldr ((++) . showChar) "\"" s
159 showChar :: Char -> String
160 showChar '"' = "\\\""
161 showChar '\\' = "\\\\"
163 -- Note: we need the double quotes around the codes because otherwise
164 -- "\n3" would get encoded as "\x0a3", which is incorrect.
165 -- Instead, we opt for "\x0a""3" and let the C compiler deal with it.
166 | ord c < 0x20 = showUTF8 (ord c)
167 | ord c < 0x7f = [c] -- 0x7f = \DEL
168 | otherwise = showHexes (utf8bytes (ord c))
170 showUTF8 c = "\"\"\\x" ++ pad (showHex c "") ++ "\"\""
171 showHexes = foldr ((++) . showUTF8) ""
173 utf8bytes :: Int -> [Int]
176 | x <= 0x7ff = let (y : ys) = split [] 2 x in (y .|. 0xc0) : map (.|. 0x80) ys
177 | x <= 0xffff = let (y : ys) = split [] 3 x in (y .|. 0xe0) : map (.|. 0x80) ys
178 | x <= 0x10ffff = let (y : ys) = split [] 4 x in (y .|. 0xf0) : map (.|. 0x80) ys
179 | otherwise = error $ "Invalid Unicode code point U+" ++ showHex x ""
181 split acc 1 x = x : acc
182 split acc i x = split (x .&. 0x3f : acc) (i - 1) (shiftR x 6)
184 pad :: String -> String
185 pad s = case length s of
188 _ -> error $ "Can't happen: String of invalid length " ++ show s
191 fnName :: Maybe Name,
196bcc :: [BC] -> RWS Int String CState ()
198bcc ((ASSIGN l r):xs) = do
200 tell $ indent (level i) ++ creg l ++ " = " ++ creg r ++ ";\n"
202bcc ((ASSIGNCONST l c):xs) = do
204 tell $ indent (level i) ++ creg l ++ " = " ++ mkConst c ++ ";\n"
207 mkConst (I i) = "MKINT(" ++ show i ++ ")"
208 mkConst (BI i) | i < (2^30) = "MKINT(" ++ show i ++ ")"
209 | otherwise = "MKBIGC(vm,\"" ++ show i ++ "\")"
210 mkConst (Fl f) = "MKFLOAT(vm, " ++ show f ++ ")"
211 mkConst (Ch c) = "MKINT(" ++ show (fromEnum c) ++ ")"
212 mkConst (Str s) = "MKSTR(vm, " ++ showCStr s ++ ")"
213 mkConst (B8 x) = "idris_b8const(vm, " ++ show x ++ "U)"
214 mkConst (B16 x) = "idris_b16const(vm, " ++ show x ++ "U)"
215 mkConst (B32 x) = "idris_b32const(vm, " ++ show x ++ "UL)"
216 mkConst (B64 x) = "idris_b64const(vm, " ++ show x ++ "ULL)"
217 -- if it's a type constant, we won't use it, but equally it shouldn't
218 -- report an error. These might creep into generated for various reasons
219 -- (especially if erasure is disabled).
220 mkConst c | isTypeConst c = "MKINT(42424242)"
221 mkConst c = error $ "mkConst of (" ++ show c ++ ") not implemented"
223bcc ((UPDATE l r):xs) = do
225 tell $ indent (level i) ++ creg l ++ " = " ++ creg r ++ ";\n"
227bcc ((MKCON l loc tag []):xs) | tag < 256 = do
229 tell $ indent (level i) ++ creg l ++ " = NULL_CON(" ++ show tag ++ ");\n"
231bcc ((MKCON l loc tag args):xs) = do
233 let tab = indent (level i)
234 tell $ tab ++ alloc loc tag ++
235 tab ++ setArgs 0 args ++ "\n" ++
236 tab ++ creg l ++ " = " ++ creg Tmp ++ ";\n"
238 where showArg r = ", " ++ creg r
240 setArgs i (x : xs) = "SETARG(" ++ creg Tmp ++ ", " ++ show i ++ ", " ++ creg x ++
241 "); " ++ setArgs (i + 1) xs
243 = "allocCon(" ++ creg Tmp ++ ", vm, " ++ show tag ++ ", " ++
244 show (length args) ++ ", 0);\n"
246 = "updateCon(" ++ creg Tmp ++ ", " ++ creg old ++ ", " ++ show tag ++ ", " ++
247 show (length args) ++ ");\n"
249bcc ((PROJECT l loc a):xs) = do
251 tell $ indent (level i) ++ "PROJECT(vm, " ++ creg l ++ ", "
252 ++ show loc ++ ", " ++ show a ++ ");\n"
254bcc ((PROJECTINTO r t idx):xs) = do
256 tell $ indent (level i) ++ creg r ++ " = GETARG(" ++ creg t
257 ++ ", " ++ show idx ++ ");\n"
259bcc ((CASE True r code def):xs)
260 | length code < 4 = do
267 tell $ "{\n" ++ w ++ indent (level i) ++ "}\n"
269 showCases Nothing [(t, c)] = do
271 tell $ indent (level i)
273 showCases (Just def) [] = do
275 tell $ indent (level i)
277 showCases def ((t, c) : cs) = do
279 tell $ indent (level i) ++ "if (CTAG(" ++ creg r ++ ") == "
282 tell $ indent (level i) ++ "else\n"
285bcc ((CASE safe r code def):xs) = do
287 tell $ indent (level i) ++ "switch(" ++ ctag safe ++ "(" ++ creg r ++ ")) {\n"
290 tell $ indent (level i) ++ "}\n"
296 showCase (t, bc) = do
300 tell $ indent i ++ "case " ++ show t ++ ":\n"
301 ++ w ++ indent (i + 1) ++ "break;\n"
302 showDef Nothing = return $ ()
303 showDef (Just c) = do
307 tell $ indent i ++ "default:\n" ++ w ++ indent (i + 1) ++ "break;\n"
309bcc ((CONSTCASE r code def):xs)
314 codes <- mapM getCode code
316 tell $ concatMap (iCase i (creg r)) codes
317 tell $ indent i ++ "{\n" ++ defs ++ indent i ++ "}\n"
323 codes <- mapM getCode code
325 tell $ concatMap (strCase i ("GETSTR(" ++ creg r ++ ")")) codes
326 ++ indent i ++ "{\n" ++ defs ++ indent i ++ "}\n"
332 codes <- mapM getCode code
334 tell $ concatMap (biCase i (creg r)) codes ++
335 indent i ++ "{\n" ++ defs ++ indent i ++ "}\n"
337 | otherwise = error $ "Can't happen: Can't compile const case " ++ show code
339 intConsts ((I _, _ ) : _) = True
340 intConsts ((Ch _, _ ) : _) = True
341 intConsts ((B8 _, _ ) : _) = True
342 intConsts ((B16 _, _ ) : _) = True
343 intConsts ((B32 _, _ ) : _) = True
344 intConsts ((B64 _, _ ) : _) = True
347 bigintConsts ((BI _, _ ) : _) = True
348 bigintConsts _ = False
350 strConsts ((Str _, _ ) : _) = True
353 getCode (x, code) = do
357 strCase i sv (s, bc) =
358 indent i ++ "if (strcmp(" ++ sv ++ ", " ++ show s ++ ") == 0) {\n" ++
359 bc ++ indent i ++ "} else\n"
360 biCase i bv (BI b, bc) =
361 indent i ++ "if (bigEqConst(" ++ bv ++ ", " ++ show b ++ ")) {\n"
362 ++ bc ++ indent i ++ "} else\n"
363 iCase i v (I b, bc) =
364 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show b ++ ") {\n"
365 ++ bc ++ indent i ++ "} else\n"
366 iCase i v (Ch b, bc) =
367 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show (fromEnum b) ++ ") {\n"
368 ++ bc ++ indent i ++ "} else\n"
369 iCase i v (B8 w, bc) =
370 indent i ++ "if (GETBITS8(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
371 ++ bc ++ indent i ++ "} else\n"
372 iCase i v (B16 w, bc) =
373 indent i ++ "if (GETBITS16(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
374 ++ bc ++ indent i ++ "} else\n"
375 iCase i v (B32 w, bc) =
376 indent i ++ "if (GETBITS32(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
377 ++ bc ++ indent i ++ "} else\n"
378 iCase i v (B64 w, bc) =
379 indent i ++ "if (GETBITS64(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
380 ++ bc ++ indent i ++ "} else\n"
382 showDefS Nothing = return ""
383 showDefS (Just c) = getBC c xs
387 tell $ indent (level i) ++ "CALL(" ++ cname n ++ ");\n"
389bcc (TAILCALL n:xs) = do
391 tell $ indent (level i) ++ "TAILCALL(" ++ cname n ++ ");\n"
393bcc ((SLIDE n):xs) = do
395 tell $ indent (level i) ++ "SLIDE(vm, " ++ show n ++ ");\n"
399 tell $ indent (level i)++ "REBASE;\n"
401bcc ((RESERVE 0):xs) = bcc xs
402bcc ((RESERVE n):xs) = do
404 tell $ indent (level i) ++ "RESERVE(" ++ show n ++ ");\n"
406bcc ((ADDTOP 0):xs) = bcc xs
407bcc ((ADDTOP n):xs) = do
409 tell $ indent (level i) ++ "ADDTOP(" ++ show n ++ ");\n"
411bcc ((TOPBASE n):xs) = do
413 tell $ indent (level i) ++ "TOPBASE(" ++ show n ++ ");\n"
415bcc ((BASETOP n):xs) = do
417 tell $ indent (level i) ++ "BASETOP(" ++ show n ++ ");\n"
419bcc (STOREOLD:xs) = do
421 tell $ indent (level i) ++ "STOREOLD;\n"
423bcc ((OP l fn args):xs) = do
425 tell $ indent (level i) ++ doOp (creg l ++ " = ") fn args ++ ";\n"
427bcc ((FOREIGNCALL l rty (FStr fn@('&':name)) []):xs) = do
429 tell $ indent (level i) ++ c_irts (toFType rty) (creg l ++ " = ") fn ++ ";\n"
431bcc ((FOREIGNCALL l rty (FStr fn) (x:xs)):zs) | fn == "%wrapper"
434 tell $ indent (level i) ++ c_irts (toFType rty) (creg l ++ " = ")
435 ("_idris_get_wrapper(" ++ creg (snd x) ++ ")") ++ ";\n"
437bcc ((FOREIGNCALL l rty (FStr fn) (x:xs)):zs) | fn == "%dynamic"
440 tell $ indent (level i) ++ c_irts (toFType rty) (creg l ++ " = ")
441 ("(*(" ++ cFnSig "" rty xs ++ ") GETPTR(" ++ creg (snd x) ++ "))" ++
442 "(" ++ showSep "," (map fcall xs) ++ ")") ++ ";\n"
444bcc ((FOREIGNCALL l rty (FStr fn) args):xs) = do
446 tell $ indent (level i) ++ c_irts (toFType rty) (creg l ++ " = ")
447 (fn ++ "(" ++ showSep "," (map fcall args) ++ ")") ++ ";\n"
449bcc ((FOREIGNCALL l rty _ args):_) = error "Foreign Function calls cannot be partially applied, without being inlined."
450bcc ((NULL r):xs) = do
452 tell $ indent (level i) ++ creg r ++ " = NULL;\n" -- clear, so it'll be GCed
454bcc ((ERROR str):xs) = do
456 tell $ indent (level i) ++ "fprintf(stderr, "
457 ++ show str ++ "); fprintf(stderr, \"\\n\"); exit(-1);\n"
459-- bcc i c = error (show c) -- indent i ++ "// not done yet\n"
463 let (a, s, w) = runRWS (bcc code) 0 (i { level = level i + 1 })
466fcall (t, arg) = irts_c (toFType t) (creg arg)
467-- Deconstruct the Foreign type in the defunctionalised expression and build
468-- a foreign type description for c_irts and irts_c
470 | i == sUN "C_IntChar" = ATInt ITChar
471 | i == sUN "C_IntNative" = ATInt ITNative
472 | i == sUN "C_IntBits8" = ATInt (ITFixed IT8)
473 | i == sUN "C_IntBits16" = ATInt (ITFixed IT16)
474 | i == sUN "C_IntBits32" = ATInt (ITFixed IT32)
475 | i == sUN "C_IntBits64" = ATInt (ITFixed IT64)
476toAType t = error (show t ++ " not defined in toAType")
479 | c == sUN "C_Str" = FString
480 | c == sUN "C_Float" = FArith ATFloat
481 | c == sUN "C_Ptr" = FPtr
482 | c == sUN "C_MPtr" = FManagedPtr
483 | c == sUN "C_CData" = FCData
484 | c == sUN "C_Unit" = FUnit
485toFType (FApp c [_,ity])
486 | c == sUN "C_IntT" = FArith (toAType ity)
487 | c == sUN "C_FnT" = toFunType ity
489 | c == sUN "C_Any" = FAny
492toFunType (FApp c [_,ity])
493 | c == sUN "C_FnBase" = FFunction
494 | c == sUN "C_FnIO" = FFunctionIO
495toFunType (FApp c [_,_,_,ity])
496 | c == sUN "C_Fn" = toFunType ity
499c_irts (FArith (ATInt ITNative)) l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
500c_irts (FArith (ATInt ITChar)) l x = c_irts (FArith (ATInt ITNative)) l x
501c_irts (FArith (ATInt (ITFixed ity))) l x
502 = l ++ "idris_b" ++ show (nativeTyWidth ity) ++ "const(vm, " ++ x ++ ")"
503c_irts FString l x = l ++ "MKSTR(vm, " ++ x ++ ")"
505c_irts FPtr l x = l ++ "MKPTR(vm, " ++ x ++ ")"
506c_irts FManagedPtr l x = l ++ "MKMPTR(vm, " ++ x ++ ")"
507c_irts (FArith ATFloat) l x = l ++ "MKFLOAT(vm, " ++ x ++ ")"
508c_irts FCData l x = l ++ "MKCDATA(vm, " ++ x ++ ")"
509c_irts FAny l x = l ++ x
510c_irts FFunction l x = error "Return of function from foreign call is not supported"
511c_irts FFunctionIO l x = error "Return of function from foreign call is not supported"
513irts_c (FArith (ATInt ITNative)) x = "GETINT(" ++ x ++ ")"
514irts_c (FArith (ATInt ITChar)) x = irts_c (FArith (ATInt ITNative)) x
515irts_c (FArith (ATInt (ITFixed ity))) x
516 = "(" ++ x ++ "->info.bits" ++ show (nativeTyWidth ity) ++ ")"
517irts_c FString x = "GETSTR(" ++ x ++ ")"
519irts_c FPtr x = "GETPTR(" ++ x ++ ")"
520irts_c FManagedPtr x = "GETMPTR(" ++ x ++ ")"
521irts_c (FArith ATFloat) x = "GETFLOAT(" ++ x ++ ")"
522irts_c FCData x = "GETCDATA(" ++ x ++ ")"
524irts_c FFunctionIO x = wrapped x
525irts_c FFunction x = wrapped x
527cFnSig name rty [] = ctype rty ++ " (*" ++ name ++ ")(void) "
528cFnSig name rty args = ctype rty ++ " (*" ++ name ++ ")("
529 ++ showSep "," (map (ctype . fst) args) ++ ") "
531wrapped x = "_idris_get_wrapper(" ++ x ++ ")"
533bitOp v op ty args = v ++ "idris_b" ++ show (nativeTyWidth ty) ++ op ++ "(vm, " ++ intercalate ", " (map creg args) ++ ")"
535bitCoerce v op input output arg
536 = v ++ "idris_b" ++ show (nativeTyWidth input) ++ op ++ show (nativeTyWidth output) ++ "(vm, " ++ creg arg ++ ")"
538signedTy :: NativeTy -> String
539signedTy t = "int" ++ show (nativeTyWidth t) ++ "_t"
541doOp v (LPlus (ATInt ITNative)) [l, r] = v ++ "ADD(" ++ creg l ++ ", " ++ creg r ++ ")"
542doOp v (LMinus (ATInt ITNative)) [l, r] = v ++ "INTOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
543doOp v (LTimes (ATInt ITNative)) [l, r] = v ++ "MULT(" ++ creg l ++ ", " ++ creg r ++ ")"
544doOp v (LUDiv ITNative) [l, r] = v ++ "UINTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
545doOp v (LSDiv (ATInt ITNative)) [l, r] = v ++ "INTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
546doOp v (LURem ITNative) [l, r] = v ++ "UINTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
547doOp v (LSRem (ATInt ITNative)) [l, r] = v ++ "INTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
548doOp v (LAnd ITNative) [l, r] = v ++ "INTOP(&," ++ creg l ++ ", " ++ creg r ++ ")"
549doOp v (LOr ITNative) [l, r] = v ++ "INTOP(|," ++ creg l ++ ", " ++ creg r ++ ")"
550doOp v (LXOr ITNative) [l, r] = v ++ "INTOP(^," ++ creg l ++ ", " ++ creg r ++ ")"
551doOp v (LSHL ITNative) [l, r] = v ++ "INTOP(<<," ++ creg l ++ ", " ++ creg r ++ ")"
552doOp v (LLSHR ITNative) [l, r] = v ++ "UINTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
553doOp v (LASHR ITNative) [l, r] = v ++ "INTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
554doOp v (LCompl ITNative) [x] = v ++ "INTOP(~," ++ creg x ++ ")"
555doOp v (LEq (ATInt ITNative)) [l, r] = v ++ "INTOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
556doOp v (LSLt (ATInt ITNative)) [l, r] = v ++ "INTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
557doOp v (LSLe (ATInt ITNative)) [l, r] = v ++ "INTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
558doOp v (LSGt (ATInt ITNative)) [l, r] = v ++ "INTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
559doOp v (LSGe (ATInt ITNative)) [l, r] = v ++ "INTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
560doOp v (LLt ITNative) [l, r] = v ++ "UINTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
561doOp v (LLe ITNative) [l, r] = v ++ "UINTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
562doOp v (LGt ITNative) [l, r] = v ++ "UINTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
563doOp v (LGe ITNative) [l, r] = v ++ "UINTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
565doOp v (LPlus (ATInt ITChar)) [l, r] = doOp v (LPlus (ATInt ITNative)) [l, r]
566doOp v (LMinus (ATInt ITChar)) [l, r] = doOp v (LMinus (ATInt ITNative)) [l, r]
567doOp v (LTimes (ATInt ITChar)) [l, r] = doOp v (LTimes (ATInt ITNative)) [l, r]
568doOp v (LUDiv ITChar) [l, r] = doOp v (LUDiv ITNative) [l, r]
569doOp v (LSDiv (ATInt ITChar)) [l, r] = doOp v (LSDiv (ATInt ITNative)) [l, r]
570doOp v (LURem ITChar) [l, r] = doOp v (LURem ITNative) [l, r]
571doOp v (LSRem (ATInt ITChar)) [l, r] = doOp v (LSRem (ATInt ITNative)) [l, r]
572doOp v (LAnd ITChar) [l, r] = doOp v (LAnd ITNative) [l, r]
573doOp v (LOr ITChar) [l, r] = doOp v (LOr ITNative) [l, r]
574doOp v (LXOr ITChar) [l, r] = doOp v (LXOr ITNative) [l, r]
575doOp v (LSHL ITChar) [l, r] = doOp v (LSHL ITNative) [l, r]
576doOp v (LLSHR ITChar) [l, r] = doOp v (LLSHR ITNative) [l, r]
577doOp v (LASHR ITChar) [l, r] = doOp v (LASHR ITNative) [l, r]
578doOp v (LCompl ITChar) [x] = doOp v (LCompl ITNative) [x]
579doOp v (LEq (ATInt ITChar)) [l, r] = doOp v (LEq (ATInt ITNative)) [l, r]
580doOp v (LSLt (ATInt ITChar)) [l, r] = doOp v (LSLt (ATInt ITNative)) [l, r]
581doOp v (LSLe (ATInt ITChar)) [l, r] = doOp v (LSLe (ATInt ITNative)) [l, r]
582doOp v (LSGt (ATInt ITChar)) [l, r] = doOp v (LSGt (ATInt ITNative)) [l, r]
583doOp v (LSGe (ATInt ITChar)) [l, r] = doOp v (LSGe (ATInt ITNative)) [l, r]
584doOp v (LLt ITChar) [l, r] = doOp v (LLt ITNative) [l, r]
585doOp v (LLe ITChar) [l, r] = doOp v (LLe ITNative) [l, r]
586doOp v (LGt ITChar) [l, r] = doOp v (LGt ITNative) [l, r]
587doOp v (LGe ITChar) [l, r] = doOp v (LGe ITNative) [l, r]
589doOp v (LPlus ATFloat) [l, r] = v ++ "FLOATOP(+," ++ creg l ++ ", " ++ creg r ++ ")"
590doOp v (LMinus ATFloat) [l, r] = v ++ "FLOATOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
591doOp v (LTimes ATFloat) [l, r] = v ++ "FLOATOP(*," ++ creg l ++ ", " ++ creg r ++ ")"
592doOp v (LSDiv ATFloat) [l, r] = v ++ "FLOATOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
593doOp v (LEq ATFloat) [l, r] = v ++ "FLOATBOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
594doOp v (LSLt ATFloat) [l, r] = v ++ "FLOATBOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
595doOp v (LSLe ATFloat) [l, r] = v ++ "FLOATBOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
596doOp v (LSGt ATFloat) [l, r] = v ++ "FLOATBOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
597doOp v (LSGe ATFloat) [l, r] = v ++ "FLOATBOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
599doOp v (LIntFloat ITBig) [x] = v ++ "idris_castBigFloat(vm, " ++ creg x ++ ")"
600doOp v (LFloatInt ITBig) [x] = v ++ "idris_castFloatBig(vm, " ++ creg x ++ ")"
601doOp v (LPlus (ATInt ITBig)) [l, r] = v ++ "idris_bigPlus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
602doOp v (LMinus (ATInt ITBig)) [l, r] = v ++ "idris_bigMinus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
603doOp v (LTimes (ATInt ITBig)) [l, r] = v ++ "idris_bigTimes(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
604doOp v (LSDiv (ATInt ITBig)) [l, r] = v ++ "idris_bigDivide(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
605doOp v (LSRem (ATInt ITBig)) [l, r] = v ++ "idris_bigMod(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
606doOp v (LAnd ITBig) [l, r] = v ++ "idris_bigAnd(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
607doOp v (LOr ITBig) [l, r] = v ++ "idris_bigOr(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
608doOp v (LSHL ITBig) [l, r] = v ++ "idris_bigShiftLeft(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
609doOp v (LLSHR ITBig) [l, r] = v ++ "idris_bigLShiftRight(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
610doOp v (LASHR ITBig) [l, r] = v ++ "idris_bigAShiftRight(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
611doOp v (LEq (ATInt ITBig)) [l, r] = v ++ "idris_bigEq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
612doOp v (LSLt (ATInt ITBig)) [l, r] = v ++ "idris_bigLt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
613doOp v (LSLe (ATInt ITBig)) [l, r] = v ++ "idris_bigLe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
614doOp v (LSGt (ATInt ITBig)) [l, r] = v ++ "idris_bigGt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
615doOp v (LSGe (ATInt ITBig)) [l, r] = v ++ "idris_bigGe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
617doOp v (LIntFloat ITNative) [x] = v ++ "idris_castIntFloat(" ++ creg x ++ ")"
618doOp v (LFloatInt ITNative) [x] = v ++ "idris_castFloatInt(" ++ creg x ++ ")"
619doOp v (LSExt ITNative ITBig) [x] = v ++ "idris_castIntBig(vm, " ++ creg x ++ ")"
620doOp v (LTrunc ITBig ITNative) [x] = v ++ "idris_castBigInt(vm, " ++ creg x ++ ")"
621doOp v (LStrInt ITBig) [x] = v ++ "idris_castStrBig(vm, " ++ creg x ++ ")"
622doOp v (LIntStr ITBig) [x] = v ++ "idris_castBigStr(vm, " ++ creg x ++ ")"
623doOp v (LIntStr ITNative) [x] = v ++ "idris_castIntStr(vm, " ++ creg x ++ ")"
624doOp v (LStrInt ITNative) [x] = v ++ "idris_castStrInt(vm, " ++ creg x ++ ")"
625doOp v (LIntStr (ITFixed _)) [x] = v ++ "idris_castBitsStr(vm, " ++ creg x ++ ")"
626doOp v LFloatStr [x] = v ++ "idris_castFloatStr(vm, " ++ creg x ++ ")"
627doOp v LStrFloat [x] = v ++ "idris_castStrFloat(vm, " ++ creg x ++ ")"
629doOp v (LSLt (ATInt (ITFixed ty))) [x, y] = bitOp v "SLt" ty [x, y]
630doOp v (LSLe (ATInt (ITFixed ty))) [x, y] = bitOp v "SLte" ty [x, y]
631doOp v (LEq (ATInt (ITFixed ty))) [x, y] = bitOp v "Eq" ty [x, y]
632doOp v (LSGe (ATInt (ITFixed ty))) [x, y] = bitOp v "SGte" ty [x, y]
633doOp v (LSGt (ATInt (ITFixed ty))) [x, y] = bitOp v "SGt" ty [x, y]
634doOp v (LLt (ITFixed ty)) [x, y] = bitOp v "Lt" ty [x, y]
635doOp v (LLe (ITFixed ty)) [x, y] = bitOp v "Lte" ty [x, y]
636doOp v (LGe (ITFixed ty)) [x, y] = bitOp v "Gte" ty [x, y]
637doOp v (LGt (ITFixed ty)) [x, y] = bitOp v "Gt" ty [x, y]
639doOp v (LSHL (ITFixed ty)) [x, y] = bitOp v "Shl" ty [x, y]
640doOp v (LLSHR (ITFixed ty)) [x, y] = bitOp v "LShr" ty [x, y]
641doOp v (LASHR (ITFixed ty)) [x, y] = bitOp v "AShr" ty [x, y]
642doOp v (LAnd (ITFixed ty)) [x, y] = bitOp v "And" ty [x, y]
643doOp v (LOr (ITFixed ty)) [x, y] = bitOp v "Or" ty [x, y]
644doOp v (LXOr (ITFixed ty)) [x, y] = bitOp v "Xor" ty [x, y]
645doOp v (LCompl (ITFixed ty)) [x] = bitOp v "Compl" ty [x]
647doOp v (LPlus (ATInt (ITFixed ty))) [x, y] = bitOp v "Plus" ty [x, y]
648doOp v (LMinus (ATInt (ITFixed ty))) [x, y] = bitOp v "Minus" ty [x, y]
649doOp v (LTimes (ATInt (ITFixed ty))) [x, y] = bitOp v "Times" ty [x, y]
650doOp v (LUDiv (ITFixed ty)) [x, y] = bitOp v "UDiv" ty [x, y]
651doOp v (LSDiv (ATInt (ITFixed ty))) [x, y] = bitOp v "SDiv" ty [x, y]
652doOp v (LURem (ITFixed ty)) [x, y] = bitOp v "URem" ty [x, y]
653doOp v (LSRem (ATInt (ITFixed ty))) [x, y] = bitOp v "SRem" ty [x, y]
655doOp v (LSExt (ITFixed from) ITBig) [x]
656 = v ++ "MKBIGSI(vm, (" ++ signedTy from ++ ")" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
657doOp v (LSExt ITNative (ITFixed to)) [x]
658 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
659doOp v (LSExt ITChar (ITFixed to)) [x]
660 = doOp v (LSExt ITNative (ITFixed to)) [x]
661doOp v (LSExt (ITFixed from) ITNative) [x]
662 = v ++ "MKINT((i_int)((" ++ signedTy from ++ ")" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ "))"
663doOp v (LSExt (ITFixed from) ITChar) [x]
664 = doOp v (LSExt (ITFixed from) ITNative) [x]
665doOp v (LSExt (ITFixed from) (ITFixed to)) [x]
666 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "S" from to x
667doOp v (LZExt ITNative (ITFixed to)) [x]
668 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
669doOp v (LZExt ITChar (ITFixed to)) [x]
670 = doOp v (LZExt ITNative (ITFixed to)) [x]
671doOp v (LZExt (ITFixed from) ITNative) [x]
672 = v ++ "MKINT((i_int)" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
673doOp v (LZExt (ITFixed from) ITChar) [x]
674 = doOp v (LZExt (ITFixed from) ITNative) [x]
675doOp v (LZExt (ITFixed from) ITBig) [x]
676 = v ++ "MKBIGUI(vm, " ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
677doOp v (LZExt ITNative ITBig) [x]
678 = v ++ "MKBIGUI(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
679doOp v (LZExt (ITFixed from) (ITFixed to)) [x]
680 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "Z" from to x
681doOp v (LTrunc ITNative (ITFixed to)) [x]
682 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
683doOp v (LTrunc ITChar (ITFixed to)) [x]
684 = doOp v (LTrunc ITNative (ITFixed to)) [x]
685doOp v (LTrunc (ITFixed from) ITNative) [x]
686 = v ++ "MKINT((i_int)" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
687doOp v (LTrunc (ITFixed from) ITChar) [x]
688 = doOp v (LTrunc (ITFixed from) ITNative) [x]
689doOp v (LTrunc ITBig (ITFixed IT64)) [x]
690 = v ++ "idris_b64const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : idris_truncBigB64(GETMPZ(" ++ creg x ++ ")))"
691doOp v (LTrunc ITBig (ITFixed to)) [x]
692 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : mpz_get_ui(GETMPZ(" ++ creg x ++ ")))"
693doOp v (LTrunc (ITFixed from) (ITFixed to)) [x]
694 | nativeTyWidth from > nativeTyWidth to = bitCoerce v "T" from to x
696doOp v LFExp [x] = v ++ flUnOp "exp" (creg x)
697doOp v LFLog [x] = v ++ flUnOp "log" (creg x)
698doOp v LFSin [x] = v ++ flUnOp "sin" (creg x)
699doOp v LFCos [x] = v ++ flUnOp "cos" (creg x)
700doOp v LFTan [x] = v ++ flUnOp "tan" (creg x)
701doOp v LFASin [x] = v ++ flUnOp "asin" (creg x)
702doOp v LFACos [x] = v ++ flUnOp "acos" (creg x)
703doOp v LFATan [x] = v ++ flUnOp "atan" (creg x)
704doOp v LFSqrt [x] = v ++ flUnOp "sqrt" (creg x)
705doOp v LFFloor [x] = v ++ flUnOp "floor" (creg x)
706doOp v LFCeil [x] = v ++ flUnOp "ceil" (creg x)
707doOp v LFNegate [x] = v ++ "MKFLOAT(vm, -GETFLOAT(" ++ (creg x) ++ "))"
709-- String functions which don't need to know we're UTF8
710doOp v LStrConcat [l,r] = v ++ "idris_concat(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
711doOp v LStrLt [l,r] = v ++ "idris_strlt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
712doOp v LStrEq [l,r] = v ++ "idris_streq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
714doOp v LReadStr [_] = v ++ "idris_readStr(vm, stdin)"
715doOp v LWriteStr [_,s]
716 = v ++ "MKINT((i_int)(idris_writeStr(stdout"
721-- String functions which need to know we're UTF8
722doOp v LStrHead [x] = v ++ "idris_strHead(vm, " ++ creg x ++ ")"
723doOp v LStrTail [x] = v ++ "idris_strTail(vm, " ++ creg x ++ ")"
724doOp v LStrCons [x, y] = v ++ "idris_strCons(vm, " ++ creg x ++ "," ++ creg y ++ ")"
725doOp v LStrIndex [x, y] = v ++ "idris_strIndex(vm, " ++ creg x ++ "," ++ creg y ++ ")"
726doOp v LStrRev [x] = v ++ "idris_strRev(vm, " ++ creg x ++ ")"
727doOp v LStrLen [x] = v ++ "idris_strlen(vm, " ++ creg x ++ ")"
728doOp v LStrSubstr [x,y,z] = v ++ "idris_substr(vm, " ++ creg x ++ "," ++ creg y ++ "," ++ creg z ++ ")"
730doOp v LFork [x] = v ++ "MKPTR(vm, vmThread(vm, " ++ cname (sMN 0 "EVAL") ++ ", " ++ creg x ++ "))"
731doOp v LPar [x] = v ++ creg x -- "MKPTR(vm, vmThread(vm, " ++ cname (MN 0 "EVAL") ++ ", " ++ creg x ++ "))"
732doOp v (LChInt ITNative) args = v ++ creg (last args)
733doOp v (LChInt ITChar) args = doOp v (LChInt ITNative) args
734doOp v (LIntCh ITNative) args = v ++ creg (last args)
735doOp v (LIntCh ITChar) args = doOp v (LIntCh ITNative) args
737doOp v LSystemInfo [x] = v ++ "idris_systemInfo(vm, " ++ creg x ++ ")"
738doOp v LCrash [x] = "idris_crash(GETSTR(" ++ creg x ++ "))"
739doOp v LNoOp args = v ++ creg (last args)
741-- Pointer primitives (declared as %extern in Builtins.idr)
742doOp v (LExternal rf) [_,x]
743 | rf == sUN "prim__readFile"
744 = v ++ "idris_readStr(vm, GETPTR(" ++ creg x ++ "))"
745doOp v (LExternal rf) [_,len,x]
746 | rf == sUN "prim__readChars"
747 = v ++ "idris_readChars(vm, GETINT(" ++ creg len ++
748 "), GETPTR(" ++ creg x ++ "))"
749doOp v (LExternal wf) [_,x,s]
750 | wf == sUN "prim__writeFile"
751 = v ++ "MKINT((i_int)(idris_writeStr(GETPTR(" ++ creg x
754doOp v (LExternal si) [] | si == sUN "prim__stdin" = v ++ "MKPTR(vm, stdin)"
755doOp v (LExternal so) [] | so == sUN "prim__stdout" = v ++ "MKPTR(vm, stdout)"
756doOp v (LExternal se) [] | se == sUN "prim__stderr" = v ++ "MKPTR(vm, stderr)"
758doOp v (LExternal vm) [_] | vm == sUN "prim__vm" = v ++ "MKPTR(vm, vm)"
759doOp v (LExternal nul) [] | nul == sUN "prim__null" = v ++ "MKPTR(vm, NULL)"
760doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqPtr"
761 = v ++ "MKINT((i_int)(GETPTR(" ++ creg x ++ ") == GETPTR(" ++ creg y ++ ")))"
762doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqManagedPtr"
763 = v ++ "MKINT((i_int)(GETMPTR(" ++ creg x ++ ") == GETMPTR(" ++ creg y ++ ")))"
764doOp v (LExternal rp) [p, i] | rp == sUN "prim__registerPtr"
765 = v ++ "MKMPTR(vm, GETPTR(" ++ creg p ++ "), GETINT(" ++ creg i ++ "))"
766doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek8"
767 = v ++ "idris_peekB8(vm," ++ creg p ++ "," ++ creg o ++")"
768doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke8"
769 = v ++ "idris_pokeB8(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
770doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek16"
771 = v ++ "idris_peekB16(vm," ++ creg p ++ "," ++ creg o ++")"
772doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke16"
773 = v ++ "idris_pokeB16(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
774doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek32"
775 = v ++ "idris_peekB32(vm," ++ creg p ++ "," ++ creg o ++")"
776doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke32"
777 = v ++ "idris_pokeB32(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
778doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek64"
779 = v ++ "idris_peekB64(vm," ++ creg p ++ "," ++ creg o ++")"
780doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke64"
781 = v ++ "idris_pokeB64(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
782doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekPtr"
783 = v ++ "idris_peekPtr(vm," ++ creg p ++ "," ++ creg o ++")"
784doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokePtr"
785 = v ++ "idris_pokePtr(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
786doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokeDouble"
787 = v ++ "idris_pokeDouble(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
788doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekDouble"
789 = v ++ "idris_peekDouble(vm," ++ creg p ++ "," ++ creg o ++")"
790doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokeSingle"
791 = v ++ "idris_pokeSingle(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
792doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekSingle"
793 = v ++ "idris_peekSingle(vm," ++ creg p ++ "," ++ creg o ++")"
794doOp v (LExternal pk) [] | pk == sUN "prim__sizeofPtr"
795 = v ++ "MKINT(sizeof(void*))"
796doOp v (LExternal mpt) [p] | mpt == sUN "prim__asPtr"
797 = v ++ "MKPTR(vm, GETMPTR("++ creg p ++"))"
798doOp v (LExternal offs) [p, n] | offs == sUN "prim__ptrOffset"
799 = v ++ "MKPTR(vm, (void *)((char *)GETPTR(" ++ creg p ++ ") + GETINT(" ++ creg n ++ ")))"
800doOp _ op args = error $ "doOp not implemented (" ++ show (op, args) ++ ")"
803flUnOp :: String -> String -> String
804flUnOp name val = "MKFLOAT(vm, " ++ name ++ "(GETFLOAT(" ++ val ++ ")))"
806-------------------- Interface file generation
808-- First, the wrappers in the C file
810ifaceC :: Export -> String
811ifaceC (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
812ifaceC (ExportFun n cn ret args)
813 = ctype ret ++ " " ++ cdesc cn ++
814 "(VM* vm" ++ showArgs (zip argNames args) ++ ") {\n"
815 ++ mkBody n (zip argNames args) ret ++ "}\n\n"
816 where showArgs [] = ""
817 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
820 argNames = zipWith (++) (repeat "arg") (map show [0..])
822mkBody n as t = indent 1 ++ "INITFRAME;\n" ++
823 indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
824 push 0 as ++ call n ++ retval t
826 push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
827 ("TOP(" ++ show i ++ ") = ") n
828 ++ ";\n" ++ push (i + 1) ts
830 call _ = indent 1 ++ "STOREOLD;\n" ++
831 indent 1 ++ "BASETOP(0);\n" ++
832 indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
833 indent 1 ++ "CALL(" ++ cname n ++ ");\n"
836 = indent 1 ++ "TOP(0) = NULL;\n" ++
837 indent 1 ++ "TOP(1) = NULL;\n" ++
838 indent 1 ++ "TOP(2) = RVAL;\n" ++
839 indent 1 ++ "STOREOLD;\n" ++
840 indent 1 ++ "BASETOP(0);\n" ++
841 indent 1 ++ "ADDTOP(3);\n" ++
842 indent 1 ++ "CALL(" ++ cname (sUN "call__IO") ++ ");\n" ++
844 retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
847 | c == sUN "C_Str" = "char*"
848 | c == sUN "C_Float" = "float"
849 | c == sUN "C_Ptr" = "void*"
850 | c == sUN "C_MPtr" = "void*"
851 | c == sUN "C_Unit" = "void"
852ctype (FApp c [_,ity])
853 | c == sUN "C_IntT" = carith ity
855 | c == sUN "C_Any" = "VAL"
857ctype FUnknown = "void*"
858ctype (FIO t) = ctype t
859ctype t = error "Can't happen: Not a valid interface type " ++ show t
862 | i == sUN "C_IntChar" = "char"
863 | i == sUN "C_IntNative" = "int"
864 | i == sUN "C_IntBits8" = "uint8_t"
865 | i == sUN "C_IntBits16" = "uint16_t"
866 | i == sUN "C_IntBits32" = "uint32_t"
867 | i == sUN "C_IntBits64" = "uint64_t"
868carith t = error $ "Can't happen: Not an exportable arithmetic type " ++ show t
871cdesc s = error "Can't happen: Not a valid C name"
873-- Then, the header files
875codegenH :: [ExportIFace] -> IO ()
876codegenH es = mapM_ writeIFace es
878writeIFace :: ExportIFace -> IO ()
879writeIFace (Export ffic hdr exps)
880 | ffic == sNS (sUN "FFI_C") ["FFI_C"]
881 = do let hfile = "#ifndef " ++ hdr_guard hdr ++ "\n" ++
882 "#define " ++ hdr_guard hdr ++ "\n\n" ++
883 "#include <idris_rts.h>\n\n" ++
884 concatMap hdr_export exps ++ "\n" ++
887 | otherwise = return ()
889hdr_guard x = "__" ++ map hchar x
890 where hchar x | isAlphaNum x = toUpper x
893hdr_export :: Export -> String
894hdr_export (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
895hdr_export (ExportFun n cn ret args)
896 = ctype ret ++ " " ++ cdesc cn ++
897 "(VM* vm" ++ showArgs (zip argNames args) ++ ");\n"
898 where showArgs [] = ""
899 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
902 argNames = zipWith (++) (repeat "arg") (map show [0..])
904------------------ Callback wrapper generation ----------------
905-- Generate callback wrappers and a function to select the
906-- correct wrapper function to pass.
907-- TODO: This is limited to functions that are specified in
908-- the foreign call. Otherwise we would have to generate wrappers for all
909-- functions with correct arity or do flow analysis
910-- to find all possible inputs to the foreign call.
911genWrappers :: [(Name, [BC])] -> String
913 tags = nubBy (\x y -> snd x == snd y) $ concatMap (getCallback . snd) bcs
917 t -> concatMap genWrapper t ++ genDispatcher t
919genDispatcher :: [(FDesc, Int)] -> String
920genDispatcher tags = "void* _idris_get_wrapper(VAL con)\n" ++
922 indent 1 ++ "switch(TAG(con)) {\n" ++
923 concatMap makeSwitch tags ++
925 indent 1 ++ "fprintf(stderr, \"No wrapper for callback\");\n" ++
926 indent 1 ++ "exit(-1);\n" ++
929 makeSwitch (_, tag) =
930 indent 1 ++ "case " ++ show tag ++ ":\n" ++
931 indent 2 ++ "return (void*) &" ++ wrapperName tag ++ ";\n"
933genWrapper :: (FDesc, Int) -> String
934genWrapper (desc, tag) | (toFType desc) == FFunctionIO =
935 error "Cannot create C callbacks for IO functions, wrap them with unsafePerformIO.\n"
936genWrapper (desc, tag) = ret ++ " " ++ wrapperName tag ++ "(" ++
937 renderArgs argList ++")\n" ++
939 (if ret /= "void" then indent 1 ++ ret ++ " ret;\n" else "") ++
940 indent 1 ++ "VM* vm = get_vm();\n" ++
941 indent 1 ++ "if (vm == NULL) {\n" ++
942 indent 2 ++ "vm = idris_vm();\n" ++
944 indent 1 ++ "INITFRAME;\n" ++
945 indent 1 ++ "RESERVE(" ++ show (len + 1) ++ ");\n" ++
946 indent 1 ++ "allocCon(REG1, vm, " ++ show tag ++ ",0 , 0);\n" ++
947 indent 1 ++ "TOP(0) = REG1;\n" ++
950 then indent 1 ++ "ret = " ++ irts_c (toFType ft) "RVAL" ++ ";\n"
951 ++ indent 1 ++ "return ret;\n}\n\n"
955 argList = zip (args desc) [0..]
958 applyArgs (x:y:xs) = push 1 [x] ++
959 indent 1 ++ "STOREOLD;\n" ++
960 indent 1 ++ "BASETOP(0);\n" ++
961 indent 1 ++ "ADDTOP(2);\n" ++
962 indent 1 ++ "CALL(_idris__123_APPLY_95_0_125_);\n" ++
963 indent 1 ++ "TOP(0)=REG1;\n" ++
965 applyArgs x = push 1 x ++
966 indent 1 ++ "STOREOLD;\n" ++
967 indent 1 ++ "BASETOP(0);\n" ++
968 indent 1 ++ "ADDTOP(" ++ show (length x + 1) ++ ");\n" ++
969 indent 1 ++ "CALL(_idris__123_APPLY_95_0_125_);\n"
970 renderArgs [] = "void"
971 renderArgs [((s, _), n)] = s ++ " a" ++ (show n)
972 renderArgs (((s, _), n):xs) = s ++ " a" ++ (show n) ++ ", " ++
975 | c == sUN "C_FnBase" = (ctype ty, ty)
976 | c == sUN "C_FnIO" = (ctype ty, ty)
977 | c == sUN "C_FnT" = rty ty
978 rty (FApp c [_,_,ty,fn])
979 | c == sUN "C_Fn" = rty fn
982 | c == sUN "C_FnBase" = []
983 | c == sUN "C_FnIO" = []
984 | c == sUN "C_FnT" = args ty
985 args (FApp c [_,_,ty,fn])
986 | toFType ty == FUnit = []
987 | c == sUN "C_Fn" = (ctype ty, ty) : args fn
990 push i (((c, t), n) : ts) = indent 1 ++ c_irts (toFType t)
991 ("TOP(" ++ show i ++ ") = ") ("a" ++ show n)
992 ++ ";\n" ++ push (i + 1) ts
994wrapperName :: Int -> String
995wrapperName tag = "_idris_wrapper_" ++ show tag
997getCallback :: [BC] -> [(FDesc, Int)]
998getCallback bc = getCallback' (reverse bc)
1000 getCallback' (x:xs) = case hasCallback x of
1001 [] -> getCallback' xs
1002 cbs -> case findCons cbs xs of
1003 [] -> error "Idris function couldn't be wrapped."
1005 getCallback' [] = []
1006 findCons (c:cs) xs = findCon c xs ++ findCons cs xs
1008 findCon c ((MKCON l loc tag args):xs) | snd c == l = [(fst c, tag)]
1009 findCon c (_:xs) = findCon c xs
1012hasCallback :: BC -> [(FDesc, Reg)]
1013hasCallback (FOREIGNCALL l rty (FStr fn) args) = filter isFn args
1015 isFn (desc,_) = case toFType desc of
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