on 33166ee help sign in
Idris-dev/src/IRTS/CodegenC.hs
875 lines 42 kB history raw
1module IRTS.CodegenC (codegenC) where
3import Idris.AbsSyntax
4import IRTS.Bytecode
5import IRTS.Lang
6import IRTS.Simplified
7import IRTS.Defunctionalise
8import IRTS.System
9import IRTS.CodegenCommon
10import Idris.Core.TT
11import Util.System
13import Numeric
14import Data.Char
15import Data.Bits
16import Data.List (intercalate, nubBy)
17import System.Process
18import System.Exit
19import System.IO
20import System.Directory
21import System.FilePath ((</>), (<.>))
22import Control.Monad
24import Debug.Trace
26codegenC :: CodeGenerator
27codegenC ci = do codegenC' (simpleDecls ci)
28 (outputFile ci)
29 (outputType ci)
30 (includes ci)
31 (compileObjs ci)
32 (map mkLib (compileLibs ci) ++
33 map incdir (importDirs ci))
34 (compilerFlags ci)
35 (exportDecls ci)
36 (interfaces ci)
37 (debugLevel ci)
38 when (interfaces ci) $
39 codegenH (exportDecls ci)
41 where mkLib l = "-l" ++ l
42 incdir i = "-I" ++ i
44codegenC' :: [(Name, SDecl)] ->
45 String -> -- output file name
46 OutputType -> -- generate executable if True, only .o if False
47 [FilePath] -> -- include files
48 [String] -> -- extra object files
49 [String] -> -- extra compiler flags (libraries)
50 [String] -> -- extra compiler flags (anything)
51 [ExportIFace] ->
52 Bool -> -- interfaces too (so make a .o instead)
53 DbgLevel ->
54 IO ()
55codegenC' defs out exec incs objs libs flags exports iface dbg
56 = do -- print defs
57 let bc = map toBC defs
58 let wrappers = genWrappers bc
59 let h = concatMap toDecl (map fst bc)
60 let cc = concatMap (uncurry toC) bc
61 let hi = concatMap ifaceC (concatMap getExp exports)
62 d <- getDataDir
63 mprog <- readFile (d </> "rts" </> "idris_main" <.> "c")
64 let cout = headers incs ++ debug dbg ++ h ++ wrappers ++ cc ++
65 (if (exec == Executable) then mprog else hi)
66 case exec of
67 MavenProject -> putStrLn ("FAILURE: output type not supported")
68 Raw -> writeSource out cout
69 _ -> do
70 (tmpn, tmph) <- tempfile ".c"
71 hPutStr tmph cout
72 hFlush tmph
73 hClose tmph
74 comp <- getCC
75 libFlags <- getLibFlags
76 incFlags <- getIncFlags
77 envFlags <- getEnvFlags
78 let stackFlag = if isWindows then ["-Wl,--stack,16777216"] else []
79 let args = [gccDbg dbg] ++
80 gccFlags iface ++
81 -- # Any flags defined here which alter the RTS API must also be added to config.mk
82 ["-DHAS_PTHREAD", "-DIDRIS_ENABLE_STATS",
83 "-I."] ++ objs ++ envFlags ++
84 (if (exec == Executable) then [] else ["-c"]) ++
85 [tmpn] ++
86 (if not iface then libFlags else []) ++
87 incFlags ++
88 (if not iface then libs else []) ++
89 flags ++ stackFlag ++
90 ["-o", out]
91-- putStrLn (show args)
92 exit <- rawSystem comp args
93 when (exit /= ExitSuccess) $
94 putStrLn ("FAILURE: " ++ show comp ++ " " ++ show args)
95 where
96 getExp (Export _ _ exp) = exp
98headers xs =
99 concatMap
100 (\h -> "#include \"" ++ h ++ "\"\n")
101 (xs ++ ["idris_rts.h", "idris_bitstring.h", "idris_stdfgn.h"])
103debug TRACE = "#define IDRIS_TRACE\n\n"
104debug _ = ""
106-- We're using signed integers now. Make sure we get consistent semantics
107-- out of them from gcc. See e.g. http://thiemonagel.de/2010/01/signed-integer-overflow/
108gccFlags i = if i then ["-fwrapv"]
109 else ["-fwrapv", "-fno-strict-overflow"]
111gccDbg DEBUG = "-g"
112gccDbg TRACE = "-O2"
113gccDbg _ = "-O2"
115cname :: Name -> String
116cname n = "_idris_" ++ concatMap cchar (showCG n)
117 where cchar x | isAlpha x || isDigit x = [x]
118 | otherwise = "_" ++ show (fromEnum x) ++ "_"
120indent :: Int -> String
121indent n = replicate (n*4) ' '
123creg RVal = "RVAL"
124creg (L i) = "LOC(" ++ show i ++ ")"
125creg (T i) = "TOP(" ++ show i ++ ")"
126creg Tmp = "REG1"
128toDecl :: Name -> String
129toDecl f = "void " ++ cname f ++ "(VM*, VAL*);\n"
131toC :: Name -> [BC] -> String
132toC f code
133 = -- "/* " ++ show code ++ "*/\n\n" ++
134 "void " ++ cname f ++ "(VM* vm, VAL* oldbase) {\n" ++
135 indent 1 ++ "INITFRAME;\n" ++
136 concatMap (bcc 1) code ++ "}\n\n"
138showCStr :: String -> String
139showCStr s = '"' : foldr ((++) . showChar) "\"" s
140 where
141 showChar :: Char -> String
142 showChar '"' = "\\\""
143 showChar '\\' = "\\\\"
144 showChar c
145 -- Note: we need the double quotes around the codes because otherwise
146 -- "\n3" would get encoded as "\x0a3", which is incorrect.
147 -- Instead, we opt for "\x0a""3" and let the C compiler deal with it.
148 | ord c < 0x10 = "\"\"\\x0" ++ showHex (ord c) "\"\""
149 | ord c < 0x20 = "\"\"\\x" ++ showHex (ord c) "\"\""
150 | ord c < 0x7f = [c] -- 0x7f = \DEL
151 | otherwise = showHexes (utf8bytes (ord c))
153 utf8bytes :: Int -> [Int]
154 utf8bytes x = let (h : bytes) = split [] x in
155 headHex h (length bytes) : map toHex bytes
156 where
157 split acc 0 = acc
158 split acc x = let xbits = x .&. 0x3f
159 xrest = shiftR x 6 in
160 split (xbits : acc) xrest
162 headHex h 1 = h + 0xc0
163 headHex h 2 = h + 0xe0
164 headHex h 3 = h + 0xf0
165 headHex h n = error "Can't happen: Invalid UTF8 character"
167 toHex i = i + 0x80
169 showHexes = foldr ((++) . showUTF8) ""
170 showUTF8 c = "\"\"\\x" ++ showHex c "\"\""
172bcc :: Int -> BC -> String
173bcc i (ASSIGN l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
174bcc i (ASSIGNCONST l c)
175 = indent i ++ creg l ++ " = " ++ mkConst c ++ ";\n"
176 where
177 mkConst (I i) = "MKINT(" ++ show i ++ ")"
178 mkConst (BI i) | i < (2^30) = "MKINT(" ++ show i ++ ")"
179 | otherwise = "MKBIGC(vm,\"" ++ show i ++ "\")"
180 mkConst (Fl f) = "MKFLOAT(vm, " ++ show f ++ ")"
181 mkConst (Ch c) = "MKINT(" ++ show (fromEnum c) ++ ")"
182 mkConst (Str s) = "MKSTR(vm, " ++ showCStr s ++ ")"
183 mkConst (B8 x) = "idris_b8const(vm, " ++ show x ++ "U)"
184 mkConst (B16 x) = "idris_b16const(vm, " ++ show x ++ "U)"
185 mkConst (B32 x) = "idris_b32const(vm, " ++ show x ++ "UL)"
186 mkConst (B64 x) = "idris_b64const(vm, " ++ show x ++ "ULL)"
187 -- if it's a type constant, we won't use it, but equally it shouldn't
188 -- report an error. These might creep into generated for various reasons
189 -- (especially if erasure is disabled).
190 mkConst c | isTypeConst c = "MKINT(42424242)"
191 mkConst c = error $ "mkConst of (" ++ show c ++ ") not implemented"
193bcc i (UPDATE l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
194bcc i (MKCON l loc tag []) | tag < 256
195 = indent i ++ creg l ++ " = NULL_CON(" ++ show tag ++ ");\n"
196bcc i (MKCON l loc tag args)
197 = indent i ++ alloc loc tag ++
198 indent i ++ setArgs 0 args ++ "\n" ++
199 indent i ++ creg l ++ " = " ++ creg Tmp ++ ";\n"
201-- "MKCON(vm, " ++ creg l ++ ", " ++ show tag ++ ", " ++
202-- show (length args) ++ concatMap showArg args ++ ");\n"
203 where showArg r = ", " ++ creg r
204 setArgs i [] = ""
205 setArgs i (x : xs) = "SETARG(" ++ creg Tmp ++ ", " ++ show i ++ ", " ++ creg x ++
206 "); " ++ setArgs (i + 1) xs
207 alloc Nothing tag
208 = "allocCon(" ++ creg Tmp ++ ", vm, " ++ show tag ++ ", " ++
209 show (length args) ++ ", 0);\n"
210 alloc (Just old) tag
211 = "updateCon(" ++ creg Tmp ++ ", " ++ creg old ++ ", " ++ show tag ++ ", " ++
212 show (length args) ++ ");\n"
214bcc i (PROJECT l loc a) = indent i ++ "PROJECT(vm, " ++ creg l ++ ", " ++ show loc ++
215 ", " ++ show a ++ ");\n"
216bcc i (PROJECTINTO r t idx)
217 = indent i ++ creg r ++ " = GETARG(" ++ creg t ++ ", " ++ show idx ++ ");\n"
218bcc i (CASE True r code def)
219 | length code < 4 = showCase i def code
220 where
221 showCode :: Int -> [BC] -> String
222 showCode i bc = "{\n" ++ concatMap (bcc (i + 1)) bc ++
223 indent i ++ "}\n"
225 showCase :: Int -> Maybe [BC] -> [(Int, [BC])] -> String
226 showCase i Nothing [(t, c)] = indent i ++ showCode i c
227 showCase i (Just def) [] = indent i ++ showCode i def
228 showCase i def ((t, c) : cs)
229 = indent i ++ "if (CTAG(" ++ creg r ++ ") == " ++ show t ++ ") " ++ showCode i c
230 ++ indent i ++ "else\n" ++ showCase i def cs
232bcc i (CASE safe r code def)
233 = indent i ++ "switch(" ++ ctag safe ++ "(" ++ creg r ++ ")) {\n" ++
234 concatMap (showCase i) code ++
235 showDef i def ++
236 indent i ++ "}\n"
237 where
238 ctag True = "CTAG"
239 ctag False = "TAG"
241 showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
242 ++ concatMap (bcc (i+1)) bc ++ indent (i + 1) ++ "break;\n"
243 showDef i Nothing = ""
244 showDef i (Just c) = indent i ++ "default:\n"
245 ++ concatMap (bcc (i+1)) c ++ indent (i + 1) ++ "break;\n"
246bcc i (CONSTCASE r code def)
247 | intConsts code
248-- = indent i ++ "switch(GETINT(" ++ creg r ++ ")) {\n" ++
249-- concatMap (showCase i) code ++
250-- showDef i def ++
251-- indent i ++ "}\n"
252 = concatMap (iCase (creg r)) code ++
253 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
254 | strConsts code
255 = concatMap (strCase ("GETSTR(" ++ creg r ++ ")")) code ++
256 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
257 | bigintConsts code
258 = concatMap (biCase (creg r)) code ++
259 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
260 | otherwise = error $ "Can't happen: Can't compile const case " ++ show code
261 where
262 intConsts ((I _, _ ) : _) = True
263 intConsts ((Ch _, _ ) : _) = True
264 intConsts ((B8 _, _ ) : _) = True
265 intConsts ((B16 _, _ ) : _) = True
266 intConsts ((B32 _, _ ) : _) = True
267 intConsts ((B64 _, _ ) : _) = True
268 intConsts _ = False
270 bigintConsts ((BI _, _ ) : _) = True
271 bigintConsts _ = False
273 strConsts ((Str _, _ ) : _) = True
274 strConsts _ = False
276 strCase sv (s, bc) =
277 indent i ++ "if (strcmp(" ++ sv ++ ", " ++ show s ++ ") == 0) {\n" ++
278 concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
279 biCase bv (BI b, bc) =
280 indent i ++ "if (bigEqConst(" ++ bv ++ ", " ++ show b ++ ")) {\n"
281 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
282 iCase v (I b, bc) =
283 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show b ++ ") {\n"
284 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
285 iCase v (Ch b, bc) =
286 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show (fromEnum b) ++ ") {\n"
287 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
288 iCase v (B8 w, bc) =
289 indent i ++ "if (GETBITS8(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
290 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
291 iCase v (B16 w, bc) =
292 indent i ++ "if (GETBITS16(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
293 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
294 iCase v (B32 w, bc) =
295 indent i ++ "if (GETBITS32(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
296 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
297 iCase v (B64 w, bc) =
298 indent i ++ "if (GETBITS64(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
299 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
300 showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
301 ++ concatMap (bcc (i+1)) bc ++
302 indent (i + 1) ++ "break;\n"
303 showDef i Nothing = ""
304 showDef i (Just c) = indent i ++ "default:\n"
305 ++ concatMap (bcc (i+1)) c ++
306 indent (i + 1) ++ "break;\n"
307 showDefS i Nothing = ""
308 showDefS i (Just c) = concatMap (bcc (i+1)) c
310bcc i (CALL n) = indent i ++ "CALL(" ++ cname n ++ ");\n"
311bcc i (TAILCALL n) = indent i ++ "TAILCALL(" ++ cname n ++ ");\n"
312bcc i (SLIDE n) = indent i ++ "SLIDE(vm, " ++ show n ++ ");\n"
313bcc i REBASE = indent i ++ "REBASE;\n"
314bcc i (RESERVE 0) = ""
315bcc i (RESERVE n) = indent i ++ "RESERVE(" ++ show n ++ ");\n"
316bcc i (ADDTOP 0) = ""
317bcc i (ADDTOP n) = indent i ++ "ADDTOP(" ++ show n ++ ");\n"
318bcc i (TOPBASE n) = indent i ++ "TOPBASE(" ++ show n ++ ");\n"
319bcc i (BASETOP n) = indent i ++ "BASETOP(" ++ show n ++ ");\n"
320bcc i STOREOLD = indent i ++ "STOREOLD;\n"
321bcc i (OP l fn args) = indent i ++ doOp (creg l ++ " = ") fn args ++ ";\n"
322bcc i (FOREIGNCALL l rty (FStr fn@('&':name)) [])
323 = indent i ++
324 c_irts (toFType rty) (creg l ++ " = ") fn ++ ";\n"
325bcc i (FOREIGNCALL l rty (FStr fn) (x:xs)) | fn == "%wrapper"
326 = indent i ++
327 c_irts (toFType rty) (creg l ++ " = ")
328 ("_idris_get_wrapper(" ++ creg (snd x) ++ ")") ++ ";\n"
329bcc i (FOREIGNCALL l rty (FStr fn) (x:xs)) | fn == "%dynamic"
330 = indent i ++ c_irts (toFType rty) (creg l ++ " = ")
331 ("(*(" ++ cFnSig "" rty xs ++ ") GETPTR(" ++ creg (snd x) ++ "))" ++
332 "(" ++ showSep "," (map fcall xs) ++ ")") ++ ";\n"
333bcc i (FOREIGNCALL l rty (FStr fn) args)
334 = indent i ++
335 c_irts (toFType rty) (creg l ++ " = ")
336 (fn ++ "(" ++ showSep "," (map fcall args) ++ ")") ++ ";\n"
337bcc i (NULL r) = indent i ++ creg r ++ " = NULL;\n" -- clear, so it'll be GCed
338bcc i (ERROR str) = indent i ++ "fprintf(stderr, " ++ show str ++ "); fprintf(stderr, \"\\n\"); exit(-1);\n"
339-- bcc i c = error (show c) -- indent i ++ "// not done yet\n"
341fcall (t, arg) = irts_c (toFType t) (creg arg)
342-- Deconstruct the Foreign type in the defunctionalised expression and build
343-- a foreign type description for c_irts and irts_c
344toAType (FCon i)
345 | i == sUN "C_IntChar" = ATInt ITChar
346 | i == sUN "C_IntNative" = ATInt ITNative
347 | i == sUN "C_IntBits8" = ATInt (ITFixed IT8)
348 | i == sUN "C_IntBits16" = ATInt (ITFixed IT16)
349 | i == sUN "C_IntBits32" = ATInt (ITFixed IT32)
350 | i == sUN "C_IntBits64" = ATInt (ITFixed IT64)
351toAType t = error (show t ++ " not defined in toAType")
353toFType (FCon c)
354 | c == sUN "C_Str" = FString
355 | c == sUN "C_Float" = FArith ATFloat
356 | c == sUN "C_Ptr" = FPtr
357 | c == sUN "C_MPtr" = FManagedPtr
358 | c == sUN "C_CData" = FCData
359 | c == sUN "C_Unit" = FUnit
360toFType (FApp c [_,ity])
361 | c == sUN "C_IntT" = FArith (toAType ity)
362 | c == sUN "C_FnT" = toFunType ity
363toFType (FApp c [_])
364 | c == sUN "C_Any" = FAny
365toFType t = FAny
367toFunType (FApp c [_,ity])
368 | c == sUN "C_FnBase" = FFunction
369 | c == sUN "C_FnIO" = FFunctionIO
370toFunType (FApp c [_,_,_,ity])
371 | c == sUN "C_Fn" = toFunType ity
372toFunType _ = FAny
374c_irts (FArith (ATInt ITNative)) l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
375c_irts (FArith (ATInt ITChar)) l x = c_irts (FArith (ATInt ITNative)) l x
376c_irts (FArith (ATInt (ITFixed ity))) l x
377 = l ++ "idris_b" ++ show (nativeTyWidth ity) ++ "const(vm, " ++ x ++ ")"
378c_irts FString l x = l ++ "MKSTR(vm, " ++ x ++ ")"
379c_irts FUnit l x = x
380c_irts FPtr l x = l ++ "MKPTR(vm, " ++ x ++ ")"
381c_irts FManagedPtr l x = l ++ "MKMPTR(vm, " ++ x ++ ")"
382c_irts (FArith ATFloat) l x = l ++ "MKFLOAT(vm, " ++ x ++ ")"
383c_irts FCData l x = l ++ "MKCDATA(vm, " ++ x ++ ")"
384c_irts FAny l x = l ++ x
385c_irts FFunction l x = error "Return of function from foreign call is not supported"
386c_irts FFunctionIO l x = error "Return of function from foreign call is not supported"
388irts_c (FArith (ATInt ITNative)) x = "GETINT(" ++ x ++ ")"
389irts_c (FArith (ATInt ITChar)) x = irts_c (FArith (ATInt ITNative)) x
390irts_c (FArith (ATInt (ITFixed ity))) x
391 = "(" ++ x ++ "->info.bits" ++ show (nativeTyWidth ity) ++ ")"
392irts_c FString x = "GETSTR(" ++ x ++ ")"
393irts_c FUnit x = x
394irts_c FPtr x = "GETPTR(" ++ x ++ ")"
395irts_c FManagedPtr x = "GETMPTR(" ++ x ++ ")"
396irts_c (FArith ATFloat) x = "GETFLOAT(" ++ x ++ ")"
397irts_c FCData x = "GETCDATA(" ++ x ++ ")"
398irts_c FAny x = x
399irts_c FFunctionIO x = wrapped x
400irts_c FFunction x = wrapped x
402cFnSig name rty [] = ctype rty ++ " (*" ++ name ++ ")(void) "
403cFnSig name rty args = ctype rty ++ " (*" ++ name ++ ")("
404 ++ showSep "," (map (ctype . fst) args) ++ ") "
406wrapped x = "_idris_get_wrapper(" ++ x ++ ")"
408bitOp v op ty args = v ++ "idris_b" ++ show (nativeTyWidth ty) ++ op ++ "(vm, " ++ intercalate ", " (map creg args) ++ ")"
410bitCoerce v op input output arg
411 = v ++ "idris_b" ++ show (nativeTyWidth input) ++ op ++ show (nativeTyWidth output) ++ "(vm, " ++ creg arg ++ ")"
413signedTy :: NativeTy -> String
414signedTy t = "int" ++ show (nativeTyWidth t) ++ "_t"
416doOp v (LPlus (ATInt ITNative)) [l, r] = v ++ "ADD(" ++ creg l ++ ", " ++ creg r ++ ")"
417doOp v (LMinus (ATInt ITNative)) [l, r] = v ++ "INTOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
418doOp v (LTimes (ATInt ITNative)) [l, r] = v ++ "MULT(" ++ creg l ++ ", " ++ creg r ++ ")"
419doOp v (LUDiv ITNative) [l, r] = v ++ "UINTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
420doOp v (LSDiv (ATInt ITNative)) [l, r] = v ++ "INTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
421doOp v (LURem ITNative) [l, r] = v ++ "UINTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
422doOp v (LSRem (ATInt ITNative)) [l, r] = v ++ "INTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
423doOp v (LAnd ITNative) [l, r] = v ++ "INTOP(&," ++ creg l ++ ", " ++ creg r ++ ")"
424doOp v (LOr ITNative) [l, r] = v ++ "INTOP(|," ++ creg l ++ ", " ++ creg r ++ ")"
425doOp v (LXOr ITNative) [l, r] = v ++ "INTOP(^," ++ creg l ++ ", " ++ creg r ++ ")"
426doOp v (LSHL ITNative) [l, r] = v ++ "INTOP(<<," ++ creg l ++ ", " ++ creg r ++ ")"
427doOp v (LLSHR ITNative) [l, r] = v ++ "UINTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
428doOp v (LASHR ITNative) [l, r] = v ++ "INTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
429doOp v (LCompl ITNative) [x] = v ++ "INTOP(~," ++ creg x ++ ")"
430doOp v (LEq (ATInt ITNative)) [l, r] = v ++ "INTOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
431doOp v (LSLt (ATInt ITNative)) [l, r] = v ++ "INTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
432doOp v (LSLe (ATInt ITNative)) [l, r] = v ++ "INTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
433doOp v (LSGt (ATInt ITNative)) [l, r] = v ++ "INTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
434doOp v (LSGe (ATInt ITNative)) [l, r] = v ++ "INTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
435doOp v (LLt ITNative) [l, r] = v ++ "UINTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
436doOp v (LLe ITNative) [l, r] = v ++ "UINTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
437doOp v (LGt ITNative) [l, r] = v ++ "UINTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
438doOp v (LGe ITNative) [l, r] = v ++ "UINTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
440doOp v (LPlus (ATInt ITChar)) [l, r] = doOp v (LPlus (ATInt ITNative)) [l, r]
441doOp v (LMinus (ATInt ITChar)) [l, r] = doOp v (LMinus (ATInt ITNative)) [l, r]
442doOp v (LTimes (ATInt ITChar)) [l, r] = doOp v (LTimes (ATInt ITNative)) [l, r]
443doOp v (LUDiv ITChar) [l, r] = doOp v (LUDiv ITNative) [l, r]
444doOp v (LSDiv (ATInt ITChar)) [l, r] = doOp v (LSDiv (ATInt ITNative)) [l, r]
445doOp v (LURem ITChar) [l, r] = doOp v (LURem ITNative) [l, r]
446doOp v (LSRem (ATInt ITChar)) [l, r] = doOp v (LSRem (ATInt ITNative)) [l, r]
447doOp v (LAnd ITChar) [l, r] = doOp v (LAnd ITNative) [l, r]
448doOp v (LOr ITChar) [l, r] = doOp v (LOr ITNative) [l, r]
449doOp v (LXOr ITChar) [l, r] = doOp v (LXOr ITNative) [l, r]
450doOp v (LSHL ITChar) [l, r] = doOp v (LSHL ITNative) [l, r]
451doOp v (LLSHR ITChar) [l, r] = doOp v (LLSHR ITNative) [l, r]
452doOp v (LASHR ITChar) [l, r] = doOp v (LASHR ITNative) [l, r]
453doOp v (LCompl ITChar) [x] = doOp v (LCompl ITNative) [x]
454doOp v (LEq (ATInt ITChar)) [l, r] = doOp v (LEq (ATInt ITNative)) [l, r]
455doOp v (LSLt (ATInt ITChar)) [l, r] = doOp v (LSLt (ATInt ITNative)) [l, r]
456doOp v (LSLe (ATInt ITChar)) [l, r] = doOp v (LSLe (ATInt ITNative)) [l, r]
457doOp v (LSGt (ATInt ITChar)) [l, r] = doOp v (LSGt (ATInt ITNative)) [l, r]
458doOp v (LSGe (ATInt ITChar)) [l, r] = doOp v (LSGe (ATInt ITNative)) [l, r]
459doOp v (LLt ITChar) [l, r] = doOp v (LLt ITNative) [l, r]
460doOp v (LLe ITChar) [l, r] = doOp v (LLe ITNative) [l, r]
461doOp v (LGt ITChar) [l, r] = doOp v (LGt ITNative) [l, r]
462doOp v (LGe ITChar) [l, r] = doOp v (LGe ITNative) [l, r]
464doOp v (LPlus ATFloat) [l, r] = v ++ "FLOATOP(+," ++ creg l ++ ", " ++ creg r ++ ")"
465doOp v (LMinus ATFloat) [l, r] = v ++ "FLOATOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
466doOp v (LTimes ATFloat) [l, r] = v ++ "FLOATOP(*," ++ creg l ++ ", " ++ creg r ++ ")"
467doOp v (LSDiv ATFloat) [l, r] = v ++ "FLOATOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
468doOp v (LEq ATFloat) [l, r] = v ++ "FLOATBOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
469doOp v (LSLt ATFloat) [l, r] = v ++ "FLOATBOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
470doOp v (LSLe ATFloat) [l, r] = v ++ "FLOATBOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
471doOp v (LSGt ATFloat) [l, r] = v ++ "FLOATBOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
472doOp v (LSGe ATFloat) [l, r] = v ++ "FLOATBOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
474doOp v (LIntFloat ITBig) [x] = v ++ "idris_castBigFloat(vm, " ++ creg x ++ ")"
475doOp v (LFloatInt ITBig) [x] = v ++ "idris_castFloatBig(vm, " ++ creg x ++ ")"
476doOp v (LPlus (ATInt ITBig)) [l, r] = v ++ "idris_bigPlus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
477doOp v (LMinus (ATInt ITBig)) [l, r] = v ++ "idris_bigMinus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
478doOp v (LTimes (ATInt ITBig)) [l, r] = v ++ "idris_bigTimes(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
479doOp v (LSDiv (ATInt ITBig)) [l, r] = v ++ "idris_bigDivide(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
480doOp v (LSRem (ATInt ITBig)) [l, r] = v ++ "idris_bigMod(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
481doOp v (LAnd ITBig) [l, r] = v ++ "idris_bigAnd(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
482doOp v (LOr ITBig) [l, r] = v ++ "idris_bigOr(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
483doOp v (LSHL ITBig) [l, r] = v ++ "idris_bigShiftLeft(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
484doOp v (LLSHR ITBig) [l, r] = v ++ "idris_bigLShiftRight(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
485doOp v (LASHR ITBig) [l, r] = v ++ "idris_bigAShiftRight(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
486doOp v (LEq (ATInt ITBig)) [l, r] = v ++ "idris_bigEq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
487doOp v (LSLt (ATInt ITBig)) [l, r] = v ++ "idris_bigLt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
488doOp v (LSLe (ATInt ITBig)) [l, r] = v ++ "idris_bigLe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
489doOp v (LSGt (ATInt ITBig)) [l, r] = v ++ "idris_bigGt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
490doOp v (LSGe (ATInt ITBig)) [l, r] = v ++ "idris_bigGe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
492doOp v (LIntFloat ITNative) [x] = v ++ "idris_castIntFloat(" ++ creg x ++ ")"
493doOp v (LFloatInt ITNative) [x] = v ++ "idris_castFloatInt(" ++ creg x ++ ")"
494doOp v (LSExt ITNative ITBig) [x] = v ++ "idris_castIntBig(vm, " ++ creg x ++ ")"
495doOp v (LTrunc ITBig ITNative) [x] = v ++ "idris_castBigInt(vm, " ++ creg x ++ ")"
496doOp v (LStrInt ITBig) [x] = v ++ "idris_castStrBig(vm, " ++ creg x ++ ")"
497doOp v (LIntStr ITBig) [x] = v ++ "idris_castBigStr(vm, " ++ creg x ++ ")"
498doOp v (LIntStr ITNative) [x] = v ++ "idris_castIntStr(vm, " ++ creg x ++ ")"
499doOp v (LStrInt ITNative) [x] = v ++ "idris_castStrInt(vm, " ++ creg x ++ ")"
500doOp v (LIntStr (ITFixed _)) [x] = v ++ "idris_castBitsStr(vm, " ++ creg x ++ ")"
501doOp v LFloatStr [x] = v ++ "idris_castFloatStr(vm, " ++ creg x ++ ")"
502doOp v LStrFloat [x] = v ++ "idris_castStrFloat(vm, " ++ creg x ++ ")"
504doOp v (LSLt (ATInt (ITFixed ty))) [x, y] = bitOp v "SLt" ty [x, y]
505doOp v (LSLe (ATInt (ITFixed ty))) [x, y] = bitOp v "SLte" ty [x, y]
506doOp v (LEq (ATInt (ITFixed ty))) [x, y] = bitOp v "Eq" ty [x, y]
507doOp v (LSGe (ATInt (ITFixed ty))) [x, y] = bitOp v "SGte" ty [x, y]
508doOp v (LSGt (ATInt (ITFixed ty))) [x, y] = bitOp v "SGt" ty [x, y]
509doOp v (LLt (ITFixed ty)) [x, y] = bitOp v "Lt" ty [x, y]
510doOp v (LLe (ITFixed ty)) [x, y] = bitOp v "Lte" ty [x, y]
511doOp v (LGe (ITFixed ty)) [x, y] = bitOp v "Gte" ty [x, y]
512doOp v (LGt (ITFixed ty)) [x, y] = bitOp v "Gt" ty [x, y]
514doOp v (LSHL (ITFixed ty)) [x, y] = bitOp v "Shl" ty [x, y]
515doOp v (LLSHR (ITFixed ty)) [x, y] = bitOp v "LShr" ty [x, y]
516doOp v (LASHR (ITFixed ty)) [x, y] = bitOp v "AShr" ty [x, y]
517doOp v (LAnd (ITFixed ty)) [x, y] = bitOp v "And" ty [x, y]
518doOp v (LOr (ITFixed ty)) [x, y] = bitOp v "Or" ty [x, y]
519doOp v (LXOr (ITFixed ty)) [x, y] = bitOp v "Xor" ty [x, y]
520doOp v (LCompl (ITFixed ty)) [x] = bitOp v "Compl" ty [x]
522doOp v (LPlus (ATInt (ITFixed ty))) [x, y] = bitOp v "Plus" ty [x, y]
523doOp v (LMinus (ATInt (ITFixed ty))) [x, y] = bitOp v "Minus" ty [x, y]
524doOp v (LTimes (ATInt (ITFixed ty))) [x, y] = bitOp v "Times" ty [x, y]
525doOp v (LUDiv (ITFixed ty)) [x, y] = bitOp v "UDiv" ty [x, y]
526doOp v (LSDiv (ATInt (ITFixed ty))) [x, y] = bitOp v "SDiv" ty [x, y]
527doOp v (LURem (ITFixed ty)) [x, y] = bitOp v "URem" ty [x, y]
528doOp v (LSRem (ATInt (ITFixed ty))) [x, y] = bitOp v "SRem" ty [x, y]
530doOp v (LSExt (ITFixed from) ITBig) [x]
531 = v ++ "MKBIGSI(vm, (" ++ signedTy from ++ ")" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
532doOp v (LSExt ITNative (ITFixed to)) [x]
533 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
534doOp v (LSExt ITChar (ITFixed to)) [x]
535 = doOp v (LSExt ITNative (ITFixed to)) [x]
536doOp v (LSExt (ITFixed from) ITNative) [x]
537 = v ++ "MKINT((i_int)((" ++ signedTy from ++ ")" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ "))"
538doOp v (LSExt (ITFixed from) ITChar) [x]
539 = doOp v (LSExt (ITFixed from) ITNative) [x]
540doOp v (LSExt (ITFixed from) (ITFixed to)) [x]
541 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "S" from to x
542doOp v (LZExt ITNative (ITFixed to)) [x]
543 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
544doOp v (LZExt ITChar (ITFixed to)) [x]
545 = doOp v (LZExt ITNative (ITFixed to)) [x]
546doOp v (LZExt (ITFixed from) ITNative) [x]
547 = v ++ "MKINT((i_int)" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
548doOp v (LZExt (ITFixed from) ITChar) [x]
549 = doOp v (LZExt (ITFixed from) ITNative) [x]
550doOp v (LZExt (ITFixed from) ITBig) [x]
551 = v ++ "MKBIGUI(vm, " ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
552doOp v (LZExt ITNative ITBig) [x]
553 = v ++ "MKBIGUI(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
554doOp v (LZExt (ITFixed from) (ITFixed to)) [x]
555 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "Z" from to x
556doOp v (LTrunc ITNative (ITFixed to)) [x]
557 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
558doOp v (LTrunc ITChar (ITFixed to)) [x]
559 = doOp v (LTrunc ITNative (ITFixed to)) [x]
560doOp v (LTrunc (ITFixed from) ITNative) [x]
561 = v ++ "MKINT((i_int)" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
562doOp v (LTrunc (ITFixed from) ITChar) [x]
563 = doOp v (LTrunc (ITFixed from) ITNative) [x]
564doOp v (LTrunc ITBig (ITFixed IT64)) [x]
565 = v ++ "idris_b64const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : idris_truncBigB64(GETMPZ(" ++ creg x ++ ")))"
566doOp v (LTrunc ITBig (ITFixed to)) [x]
567 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : mpz_get_ui(GETMPZ(" ++ creg x ++ ")))"
568doOp v (LTrunc (ITFixed from) (ITFixed to)) [x]
569 | nativeTyWidth from > nativeTyWidth to = bitCoerce v "T" from to x
571doOp v LFExp [x] = v ++ flUnOp "exp" (creg x)
572doOp v LFLog [x] = v ++ flUnOp "log" (creg x)
573doOp v LFSin [x] = v ++ flUnOp "sin" (creg x)
574doOp v LFCos [x] = v ++ flUnOp "cos" (creg x)
575doOp v LFTan [x] = v ++ flUnOp "tan" (creg x)
576doOp v LFASin [x] = v ++ flUnOp "asin" (creg x)
577doOp v LFACos [x] = v ++ flUnOp "acos" (creg x)
578doOp v LFATan [x] = v ++ flUnOp "atan" (creg x)
579doOp v LFSqrt [x] = v ++ flUnOp "sqrt" (creg x)
580doOp v LFFloor [x] = v ++ flUnOp "floor" (creg x)
581doOp v LFCeil [x] = v ++ flUnOp "ceil" (creg x)
582doOp v LFNegate [x] = v ++ "MKFLOAT(vm, -GETFLOAT(" ++ (creg x) ++ "))"
584-- String functions which don't need to know we're UTF8
585doOp v LStrConcat [l,r] = v ++ "idris_concat(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
586doOp v LStrLt [l,r] = v ++ "idris_strlt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
587doOp v LStrEq [l,r] = v ++ "idris_streq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
589doOp v LReadStr [_] = v ++ "idris_readStr(vm, stdin)"
590doOp v LWriteStr [_,s]
591 = v ++ "MKINT((i_int)(idris_writeStr(stdout"
592 ++ ",GETSTR("
593 ++ creg s ++ "))))"
596-- String functions which need to know we're UTF8
597doOp v LStrHead [x] = v ++ "idris_strHead(vm, " ++ creg x ++ ")"
598doOp v LStrTail [x] = v ++ "idris_strTail(vm, " ++ creg x ++ ")"
599doOp v LStrCons [x, y] = v ++ "idris_strCons(vm, " ++ creg x ++ "," ++ creg y ++ ")"
600doOp v LStrIndex [x, y] = v ++ "idris_strIndex(vm, " ++ creg x ++ "," ++ creg y ++ ")"
601doOp v LStrRev [x] = v ++ "idris_strRev(vm, " ++ creg x ++ ")"
602doOp v LStrLen [x] = v ++ "idris_strlen(vm, " ++ creg x ++ ")"
603doOp v LStrSubstr [x,y,z] = v ++ "idris_substr(vm, " ++ creg x ++ "," ++ creg y ++ "," ++ creg z ++ ")"
605doOp v LFork [x] = v ++ "MKPTR(vm, vmThread(vm, " ++ cname (sMN 0 "EVAL") ++ ", " ++ creg x ++ "))"
606doOp v LPar [x] = v ++ creg x -- "MKPTR(vm, vmThread(vm, " ++ cname (MN 0 "EVAL") ++ ", " ++ creg x ++ "))"
607doOp v (LChInt ITNative) args = v ++ creg (last args)
608doOp v (LChInt ITChar) args = doOp v (LChInt ITNative) args
609doOp v (LIntCh ITNative) args = v ++ creg (last args)
610doOp v (LIntCh ITChar) args = doOp v (LIntCh ITNative) args
612doOp v LSystemInfo [x] = v ++ "idris_systemInfo(vm, " ++ creg x ++ ")"
613doOp v LNoOp args = v ++ creg (last args)
615-- Pointer primitives (declared as %extern in Builtins.idr)
616doOp v (LExternal rf) [_,x]
617 | rf == sUN "prim__readFile"
618 = v ++ "idris_readStr(vm, GETPTR(" ++ creg x ++ "))"
619doOp v (LExternal wf) [_,x,s]
620 | wf == sUN "prim__writeFile"
621 = v ++ "MKINT((i_int)(idris_writeStr(GETPTR(" ++ creg x
622 ++ "),GETSTR("
623 ++ creg s ++ "))))"
624doOp v (LExternal vm) [] | vm == sUN "prim__vm" = v ++ "MKPTR(vm, vm)"
625doOp v (LExternal si) [] | si == sUN "prim__stdin" = v ++ "MKPTR(vm, stdin)"
626doOp v (LExternal so) [] | so == sUN "prim__stdout" = v ++ "MKPTR(vm, stdout)"
627doOp v (LExternal se) [] | se == sUN "prim__stderr" = v ++ "MKPTR(vm, stderr)"
629doOp v (LExternal nul) [] | nul == sUN "prim__null" = v ++ "MKPTR(vm, NULL)"
630doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqPtr"
631 = v ++ "MKINT((i_int)(GETPTR(" ++ creg x ++ ") == GETPTR(" ++ creg y ++ ")))"
632doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqManagedPtr"
633 = v ++ "MKINT((i_int)(GETMPTR(" ++ creg x ++ ") == GETMPTR(" ++ creg y ++ ")))"
634doOp v (LExternal rp) [p, i] | rp == sUN "prim__registerPtr"
635 = v ++ "MKMPTR(vm, GETPTR(" ++ creg p ++ "), GETINT(" ++ creg i ++ "))"
636doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek8"
637 = v ++ "idris_peekB8(vm," ++ creg p ++ "," ++ creg o ++")"
638doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke8"
639 = v ++ "idris_pokeB8(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
640doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek16"
641 = v ++ "idris_peekB16(vm," ++ creg p ++ "," ++ creg o ++")"
642doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke16"
643 = v ++ "idris_pokeB16(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
644doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek32"
645 = v ++ "idris_peekB32(vm," ++ creg p ++ "," ++ creg o ++")"
646doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke32"
647 = v ++ "idris_pokeB32(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
648doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek64"
649 = v ++ "idris_peekB64(vm," ++ creg p ++ "," ++ creg o ++")"
650doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke64"
651 = v ++ "idris_pokeB64(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
652doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekPtr"
653 = v ++ "idris_peekPtr(vm," ++ creg p ++ "," ++ creg o ++")"
654doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokePtr"
655 = v ++ "idris_pokePtr(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
656doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokeDouble"
657 = v ++ "idris_pokeDouble(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
658doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekDouble"
659 = v ++ "idris_peekDouble(vm," ++ creg p ++ "," ++ creg o ++")"
660doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokeSingle"
661 = v ++ "idris_pokeSingle(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
662doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekSingle"
663 = v ++ "idris_peekSingle(vm," ++ creg p ++ "," ++ creg o ++")"
664doOp v (LExternal pk) [] | pk == sUN "prim__sizeofPtr"
665 = v ++ "MKINT(sizeof(void*))"
666doOp v (LExternal mpt) [p] | mpt == sUN "prim__asPtr" = v ++ "MKPTR(vm, GETMPTR("++ creg p ++"))"
667doOp _ op args = error $ "doOp not implemented (" ++ show (op, args) ++ ")"
670flUnOp :: String -> String -> String
671flUnOp name val = "MKFLOAT(vm, " ++ name ++ "(GETFLOAT(" ++ val ++ ")))"
673-------------------- Interface file generation
675-- First, the wrappers in the C file
677ifaceC :: Export -> String
678ifaceC (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
679ifaceC (ExportFun n cn ret args)
680 = ctype ret ++ " " ++ cdesc cn ++
681 "(VM* vm" ++ showArgs (zip argNames args) ++ ") {\n"
682 ++ mkBody n (zip argNames args) ret ++ "}\n\n"
683 where showArgs [] = ""
684 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
685 showArgs ts
687 argNames = zipWith (++) (repeat "arg") (map show [0..])
689mkBody n as t = indent 1 ++ "INITFRAME;\n" ++
690 indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
691 push 0 as ++ call n ++ retval t
692 where push i [] = ""
693 push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
694 ("TOP(" ++ show i ++ ") = ") n
695 ++ ";\n" ++ push (i + 1) ts
697 call _ = indent 1 ++ "STOREOLD;\n" ++
698 indent 1 ++ "BASETOP(0);\n" ++
699 indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
700 indent 1 ++ "CALL(" ++ cname n ++ ");\n"
702 retval (FIO t)
703 = indent 1 ++ "TOP(0) = NULL;\n" ++
704 indent 1 ++ "TOP(1) = NULL;\n" ++
705 indent 1 ++ "TOP(2) = RVAL;\n" ++
706 indent 1 ++ "STOREOLD;\n" ++
707 indent 1 ++ "BASETOP(0);\n" ++
708 indent 1 ++ "ADDTOP(3);\n" ++
709 indent 1 ++ "CALL(" ++ cname (sUN "call__IO") ++ ");\n" ++
710 retval t
711 retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
713ctype (FCon c)
714 | c == sUN "C_Str" = "char*"
715 | c == sUN "C_Float" = "float"
716 | c == sUN "C_Ptr" = "void*"
717 | c == sUN "C_MPtr" = "void*"
718 | c == sUN "C_Unit" = "void"
719ctype (FApp c [_,ity])
720 | c == sUN "C_IntT" = carith ity
721ctype (FApp c [_])
722 | c == sUN "C_Any" = "VAL"
723ctype (FStr s) = s
724ctype FUnknown = "void*"
725ctype (FIO t) = ctype t
726ctype t = error "Can't happen: Not a valid interface type " ++ show t
728carith (FCon i)
729 | i == sUN "C_IntChar" = "char"
730 | i == sUN "C_IntNative" = "int"
731carith t = error "Can't happen: Not an exportable arithmetic type"
733cdesc (FStr s) = s
734cdesc s = error "Can't happen: Not a valid C name"
736-- Then, the header files
738codegenH :: [ExportIFace] -> IO ()
739codegenH es = mapM_ writeIFace es
741writeIFace :: ExportIFace -> IO ()
742writeIFace (Export ffic hdr exps)
743 | ffic == sNS (sUN "FFI_C") ["FFI_C"]
744 = do let hfile = "#ifndef " ++ hdr_guard hdr ++ "\n" ++
745 "#define " ++ hdr_guard hdr ++ "\n\n" ++
746 "#include <idris_rts.h>\n\n" ++
747 concatMap hdr_export exps ++ "\n" ++
748 "#endif\n\n"
749 writeFile hdr hfile
750 | otherwise = return ()
752hdr_guard x = "__" ++ map hchar x
753 where hchar x | isAlphaNum x = toUpper x
754 hchar _ = '_'
756hdr_export :: Export -> String
757hdr_export (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
758hdr_export (ExportFun n cn ret args)
759 = ctype ret ++ " " ++ cdesc cn ++
760 "(VM* vm" ++ showArgs (zip argNames args) ++ ");\n"
761 where showArgs [] = ""
762 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
763 showArgs ts
765 argNames = zipWith (++) (repeat "arg") (map show [0..])
767------------------ Callback wrapper generation ----------------
768-- Generate callback wrappers and a function to select the
769-- correct wrapper function to pass.
770-- TODO: This is limited to functions that are specified in
771-- the foreign call. Otherwise we would have to generate wrappers for all
772-- functions with correct arity or do flow analysis
773-- to find all possible inputs to the foreign call.
774genWrappers :: [(Name, [BC])] -> String
775genWrappers bcs = let
776 tags = nubBy (\x y -> snd x == snd y) $ concatMap (getCallback . snd) bcs
777 in
778 case tags of
779 [] -> ""
780 t -> concatMap genWrapper t ++ genDispatcher t
782genDispatcher :: [(FDesc, Int)] -> String
783genDispatcher tags = "void* _idris_get_wrapper(VAL con)\n" ++
784 "{\n" ++
785 indent 1 ++ "switch(TAG(con)) {\n" ++
786 concatMap makeSwitch tags ++
787 indent 1 ++ "}\n" ++
788 indent 1 ++ "fprintf(stderr, \"No wrapper for callback\");\n" ++
789 indent 1 ++ "exit(-1);\n" ++
790 "}\n\n"
791 where
792 makeSwitch (_, tag) =
793 indent 1 ++ "case " ++ show tag ++ ":\n" ++
794 indent 2 ++ "return (void*) &" ++ wrapperName tag ++ ";\n"
796genWrapper :: (FDesc, Int) -> String
797genWrapper (desc, tag) | (toFType desc) == FFunctionIO =
798 error $ "Cannot create C callbacks for IO functions, wrap them with unsafePerformIO.\n"
799genWrapper (desc, tag) = ret ++ " " ++ wrapperName tag ++ "(" ++
800 renderArgs argList ++")\n" ++
801 "{\n" ++
802 (if ret /= "void" then indent 1 ++ ret ++ " ret;\n" else "") ++
803 indent 1 ++ "VM* vm = get_vm();\n" ++
804 indent 1 ++ "if (vm == NULL) {\n" ++
805 indent 2 ++ "fprintf(stderr, \"No vm available in callback.\");\n" ++
806 indent 2 ++ "exit(-1);\n" ++
807 indent 1 ++ "}\n" ++
808 indent 1 ++ "INITFRAME;\n" ++
809 indent 1 ++ "RESERVE(" ++ show (len + 1) ++ ");\n" ++
810 indent 1 ++ "allocCon(REG1, vm, " ++ show tag ++ ",0 , 0);\n" ++
811 indent 1 ++ "TOP(0) = REG1;\n" ++
813 push 1 argList ++
814 indent 1 ++ "STOREOLD;\n" ++
815 indent 1 ++ "BASETOP(0);\n" ++
816 indent 1 ++ "ADDTOP(" ++ show (len + 1) ++ ");\n" ++
817 indent 1 ++ "CALL(_idris__123_APPLY0_125_);\n" ++
818 if ret /= "void"
819 then indent 1 ++ "ret = " ++ irts_c (toFType ft) "RVAL" ++ ";\n"
820 ++ indent 1 ++ "return ret;\n}\n\n"
821 else "}\n\n"
822 where
823 (ret, ft) = rty desc
824 argList = zip (args desc) [0..]
825 len = length argList
826 renderArgs [] = "void"
827 renderArgs [((s, _), n)] = s ++ " a" ++ (show n)
828 renderArgs (((s, _), n):xs) = s ++ " a" ++ (show n) ++ ", " ++
829 renderArgs xs
830 rty (FApp c [_,ty])
831 | c == sUN "C_FnBase" = (ctype ty, ty)
832 | c == sUN "C_FnIO" = (ctype ty, ty)
833 | c == sUN "C_FnT" = rty ty
834 rty (FApp c [_,_,ty,fn])
835 | c == sUN "C_Fn" = rty fn
836 rty x = ("", x)
837 args (FApp c [_,ty])
838 | c == sUN "C_FnBase" = []
839 | c == sUN "C_FnIO" = []
840 | c == sUN "C_FnT" = args ty
841 args (FApp c [_,_,ty,fn])
842 | toFType ty == FUnit = []
843 | c == sUN "C_Fn" = (ctype ty, ty) : args fn
844 args _ = []
845 push i [] = ""
846 push i (((c, t), n) : ts) = indent 1 ++ c_irts (toFType t)
847 ("TOP(" ++ show i ++ ") = ") ("a" ++ show n)
848 ++ ";\n" ++ push (i + 1) ts
850wrapperName :: Int -> String
851wrapperName tag = "_idris_wrapper_" ++ show tag
853getCallback :: [BC] -> [(FDesc, Int)]
854getCallback bc = getCallback' (reverse bc)
855 where
856 getCallback' (x:xs) = case hasCallback x of
857 [] -> getCallback' xs
858 cbs -> case findCons cbs xs of
859 [] -> error "Idris function couldn't be wrapped."
860 x -> x
861 getCallback' [] = []
862 findCons (c:cs) xs = findCon c xs ++ findCons cs xs
863 findCons [] _ = []
864 findCon c ((MKCON l loc tag args):xs) | snd c == l = [(fst c, tag)]
865 findCon c (_:xs) = findCon c xs
866 findCon c [] = []
868hasCallback :: BC -> [(FDesc, Reg)]
869hasCallback (FOREIGNCALL l rty (FStr fn) args) = filter isFn args
870 where
871 isFn (desc,_) = case toFType desc of
872 FFunction -> True
873 FFunctionIO -> True
874 _ -> False
875hasCallback _ = []