on ec97cac help sign in
Idris-dev/src/IRTS/CodegenC.hs
877 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"
667 = v ++ "MKPTR(vm, GETMPTR("++ creg p ++"))"
668doOp v (LExternal offs) [p, n] | offs == sUN "prim__ptrOffset"
669 = v ++ "MKPTR(vm, GETPTR(" ++ creg p ++ ") + GETINT(" ++ creg n ++ "))"
670doOp _ op args = error $ "doOp not implemented (" ++ show (op, args) ++ ")"
673flUnOp :: String -> String -> String
674flUnOp name val = "MKFLOAT(vm, " ++ name ++ "(GETFLOAT(" ++ val ++ ")))"
676-------------------- Interface file generation
678-- First, the wrappers in the C file
680ifaceC :: Export -> String
681ifaceC (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
682ifaceC (ExportFun n cn ret args)
683 = ctype ret ++ " " ++ cdesc cn ++
684 "(VM* vm" ++ showArgs (zip argNames args) ++ ") {\n"
685 ++ mkBody n (zip argNames args) ret ++ "}\n\n"
686 where showArgs [] = ""
687 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
688 showArgs ts
690 argNames = zipWith (++) (repeat "arg") (map show [0..])
692mkBody n as t = indent 1 ++ "INITFRAME;\n" ++
693 indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
694 push 0 as ++ call n ++ retval t
695 where push i [] = ""
696 push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
697 ("TOP(" ++ show i ++ ") = ") n
698 ++ ";\n" ++ push (i + 1) ts
700 call _ = indent 1 ++ "STOREOLD;\n" ++
701 indent 1 ++ "BASETOP(0);\n" ++
702 indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
703 indent 1 ++ "CALL(" ++ cname n ++ ");\n"
705 retval (FIO t)
706 = indent 1 ++ "TOP(0) = NULL;\n" ++
707 indent 1 ++ "TOP(1) = NULL;\n" ++
708 indent 1 ++ "TOP(2) = RVAL;\n" ++
709 indent 1 ++ "STOREOLD;\n" ++
710 indent 1 ++ "BASETOP(0);\n" ++
711 indent 1 ++ "ADDTOP(3);\n" ++
712 indent 1 ++ "CALL(" ++ cname (sUN "call__IO") ++ ");\n" ++
713 retval t
714 retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
716ctype (FCon c)
717 | c == sUN "C_Str" = "char*"
718 | c == sUN "C_Float" = "float"
719 | c == sUN "C_Ptr" = "void*"
720 | c == sUN "C_MPtr" = "void*"
721 | c == sUN "C_Unit" = "void"
722ctype (FApp c [_,ity])
723 | c == sUN "C_IntT" = carith ity
724ctype (FApp c [_])
725 | c == sUN "C_Any" = "VAL"
726ctype (FStr s) = s
727ctype FUnknown = "void*"
728ctype (FIO t) = ctype t
729ctype t = error "Can't happen: Not a valid interface type " ++ show t
731carith (FCon i)
732 | i == sUN "C_IntChar" = "char"
733 | i == sUN "C_IntNative" = "int"
734carith t = error "Can't happen: Not an exportable arithmetic type"
736cdesc (FStr s) = s
737cdesc s = error "Can't happen: Not a valid C name"
739-- Then, the header files
741codegenH :: [ExportIFace] -> IO ()
742codegenH es = mapM_ writeIFace es
744writeIFace :: ExportIFace -> IO ()
745writeIFace (Export ffic hdr exps)
746 | ffic == sNS (sUN "FFI_C") ["FFI_C"]
747 = do let hfile = "#ifndef " ++ hdr_guard hdr ++ "\n" ++
748 "#define " ++ hdr_guard hdr ++ "\n\n" ++
749 "#include <idris_rts.h>\n\n" ++
750 concatMap hdr_export exps ++ "\n" ++
751 "#endif\n\n"
752 writeFile hdr hfile
753 | otherwise = return ()
755hdr_guard x = "__" ++ map hchar x
756 where hchar x | isAlphaNum x = toUpper x
757 hchar _ = '_'
759hdr_export :: Export -> String
760hdr_export (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
761hdr_export (ExportFun n cn ret args)
762 = ctype ret ++ " " ++ cdesc cn ++
763 "(VM* vm" ++ showArgs (zip argNames args) ++ ");\n"
764 where showArgs [] = ""
765 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
766 showArgs ts
768 argNames = zipWith (++) (repeat "arg") (map show [0..])
770------------------ Callback wrapper generation ----------------
771-- Generate callback wrappers and a function to select the
772-- correct wrapper function to pass.
773-- TODO: This is limited to functions that are specified in
774-- the foreign call. Otherwise we would have to generate wrappers for all
775-- functions with correct arity or do flow analysis
776-- to find all possible inputs to the foreign call.
777genWrappers :: [(Name, [BC])] -> String
778genWrappers bcs = let
779 tags = nubBy (\x y -> snd x == snd y) $ concatMap (getCallback . snd) bcs
780 in
781 case tags of
782 [] -> ""
783 t -> concatMap genWrapper t ++ genDispatcher t
785genDispatcher :: [(FDesc, Int)] -> String
786genDispatcher tags = "void* _idris_get_wrapper(VAL con)\n" ++
787 "{\n" ++
788 indent 1 ++ "switch(TAG(con)) {\n" ++
789 concatMap makeSwitch tags ++
790 indent 1 ++ "}\n" ++
791 indent 1 ++ "fprintf(stderr, \"No wrapper for callback\");\n" ++
792 indent 1 ++ "exit(-1);\n" ++
793 "}\n\n"
794 where
795 makeSwitch (_, tag) =
796 indent 1 ++ "case " ++ show tag ++ ":\n" ++
797 indent 2 ++ "return (void*) &" ++ wrapperName tag ++ ";\n"
799genWrapper :: (FDesc, Int) -> String
800genWrapper (desc, tag) | (toFType desc) == FFunctionIO =
801 error $ "Cannot create C callbacks for IO functions, wrap them with unsafePerformIO.\n"
802genWrapper (desc, tag) = ret ++ " " ++ wrapperName tag ++ "(" ++
803 renderArgs argList ++")\n" ++
804 "{\n" ++
805 (if ret /= "void" then indent 1 ++ ret ++ " ret;\n" else "") ++
806 indent 1 ++ "VM* vm = get_vm();\n" ++
807 indent 1 ++ "if (vm == NULL) {\n" ++
808 indent 2 ++ "vm = idris_vm();\n" ++
809 indent 1 ++ "}\n" ++
810 indent 1 ++ "INITFRAME;\n" ++
811 indent 1 ++ "RESERVE(" ++ show (len + 1) ++ ");\n" ++
812 indent 1 ++ "allocCon(REG1, vm, " ++ show tag ++ ",0 , 0);\n" ++
813 indent 1 ++ "TOP(0) = REG1;\n" ++
815 push 1 argList ++
816 indent 1 ++ "STOREOLD;\n" ++
817 indent 1 ++ "BASETOP(0);\n" ++
818 indent 1 ++ "ADDTOP(" ++ show (len + 1) ++ ");\n" ++
819 indent 1 ++ "CALL(_idris__123_APPLY0_125_);\n" ++
820 if ret /= "void"
821 then indent 1 ++ "ret = " ++ irts_c (toFType ft) "RVAL" ++ ";\n"
822 ++ indent 1 ++ "return ret;\n}\n\n"
823 else "}\n\n"
824 where
825 (ret, ft) = rty desc
826 argList = zip (args desc) [0..]
827 len = length argList
828 renderArgs [] = "void"
829 renderArgs [((s, _), n)] = s ++ " a" ++ (show n)
830 renderArgs (((s, _), n):xs) = s ++ " a" ++ (show n) ++ ", " ++
831 renderArgs xs
832 rty (FApp c [_,ty])
833 | c == sUN "C_FnBase" = (ctype ty, ty)
834 | c == sUN "C_FnIO" = (ctype ty, ty)
835 | c == sUN "C_FnT" = rty ty
836 rty (FApp c [_,_,ty,fn])
837 | c == sUN "C_Fn" = rty fn
838 rty x = ("", x)
839 args (FApp c [_,ty])
840 | c == sUN "C_FnBase" = []
841 | c == sUN "C_FnIO" = []
842 | c == sUN "C_FnT" = args ty
843 args (FApp c [_,_,ty,fn])
844 | toFType ty == FUnit = []
845 | c == sUN "C_Fn" = (ctype ty, ty) : args fn
846 args _ = []
847 push i [] = ""
848 push i (((c, t), n) : ts) = indent 1 ++ c_irts (toFType t)
849 ("TOP(" ++ show i ++ ") = ") ("a" ++ show n)
850 ++ ";\n" ++ push (i + 1) ts
852wrapperName :: Int -> String
853wrapperName tag = "_idris_wrapper_" ++ show tag
855getCallback :: [BC] -> [(FDesc, Int)]
856getCallback bc = getCallback' (reverse bc)
857 where
858 getCallback' (x:xs) = case hasCallback x of
859 [] -> getCallback' xs
860 cbs -> case findCons cbs xs of
861 [] -> error "Idris function couldn't be wrapped."
862 x -> x
863 getCallback' [] = []
864 findCons (c:cs) xs = findCon c xs ++ findCons cs xs
865 findCons [] _ = []
866 findCon c ((MKCON l loc tag args):xs) | snd c == l = [(fst c, tag)]
867 findCon c (_:xs) = findCon c xs
868 findCon c [] = []
870hasCallback :: BC -> [(FDesc, Reg)]
871hasCallback (FOREIGNCALL l rty (FStr fn) args) = filter isFn args
872 where
873 isFn (desc,_) = case toFType desc of
874 FFunction -> True
875 FFunctionIO -> True
876 _ -> False
877hasCallback _ = []