@@ -24,15 +24,19 @@ import Control.Monad
2424import Debug.Trace
2525
2626codegenC :: CodeGenerator
27−codegenC ci = 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− (debugLevel ci)
27+codegenC 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)
3640
3741 where mkLib l = "-l" ++ l
3842 incdir i = "-I" ++ i
@@ -44,17 +48,20 @@ codegenC' :: [(Name, SDecl)] ->
4448 [String] -> -- extra object files
4549 [String] -> -- extra compiler flags (libraries)
4650 [String] -> -- extra compiler flags (anything)
51+ [ExportIFace] ->
52+ Bool -> -- interfaces too (so make a .o instead)
4753 DbgLevel ->
4854 IO ()
49−codegenC' defs out exec incs objs libs flags dbg
55+codegenC' defs out exec incs objs libs flags exports iface dbg
5056 = do -- print defs
5157 let bc = map toBC defs
5258 let h = concatMap toDecl (map fst bc)
5359 let cc = concatMap (uncurry toC) bc
60+ let hi = concatMap ifaceC (concatMap getExp exports)
5461 d <- getDataDir
5562 mprog <- readFile (d </> "rts" </> "idris_main" <.> "c")
5663 let cout = headers incs ++ debug dbg ++ h ++ cc ++
57− (if (exec == Executable) then mprog else "")
64+ (if (exec == Executable) then mprog else hi)
5865 case exec of
5966 MavenProject -> putStrLn ("FAILURE: output type not supported")
6067 Raw -> writeFile out cout
@@ -67,21 +74,23 @@ codegenC' defs out exec incs objs libs flags dbg
6774 libFlags <- getLibFlags
6875 incFlags <- getIncFlags
6976 let args = [gccDbg dbg] ++
70− gccFlags ++
77+ gccFlags iface ++
7178 -- # Any flags defined here which alter the RTS API must also be added to config.mk
7279 ["-DHAS_PTHREAD", "-DIDRIS_ENABLE_STATS", "-msse2",
7380 "-I."] ++ objs ++ ["-x", "c"] ++
7481 (if (exec == Executable) then [] else ["-c"]) ++
7582 [tmpn] ++
76− concatMap words libFlags ++
83+ (if not iface then concatMap words libFlags else []) ++
7784 concatMap words incFlags ++
78− concatMap words libs ++
85+ (if not iface then concatMap words libs else []) ++
7986 concatMap words flags ++
8087 ["-o", out]
81−-- putStrLn gcc
88+-- putStrLn (show args)
8289 exit <- rawSystem comp args
8390 when (exit /= ExitSuccess) $
8491 putStrLn ("FAILURE: " ++ show comp ++ " " ++ show args)
92+ where
93+ getExp (Export _ _ exp) = exp
8594
8695headers xs =
8796 concatMap
@@ -93,7 +102,8 @@ debug _ = ""
93102
94103-- We're using signed integers now. Make sure we get consistent semantics
95104-- out of them from gcc. See e.g. http://thiemonagel.de/2010/01/signed-integer-overflow/
96−gccFlags = ["-fwrapv", "-fno-strict-overflow"]
105+gccFlags i = if i then ["-fwrapv"]
106+ else ["-fwrapv", "-fno-strict-overflow"]
97107
98108gccDbg DEBUG = "-g"
99109gccDbg TRACE = "-O2"
@@ -311,7 +321,7 @@ toFType (FApp c [_,ity])
311321 | c == sUN "C_IntT" = FArith (toAType ity)
312322toFType (FApp c [_])
313323 | c == sUN "C_Any" = FAny
314−toFType t = error (show t ++ " not defined in toFType")
324+toFType t = FAny
315325
316326c_irts (FArith (ATInt ITNative)) l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
317327c_irts (FArith (ATInt ITChar)) l x = c_irts (FArith (ATInt ITNative)) l x
@@ -561,3 +571,91 @@ doOp _ op args = error "doOp of (" ++ show op ++ ") not implemented, arguments (
561571
562572flUnOp :: String -> String -> String
563573flUnOp name val = "MKFLOAT(vm, " ++ name ++ "(GETFLOAT(" ++ val ++ ")))"
574+
575+-------------------- Interface file generation
576+
577+-- First, the wrappers in the C file
578+
579+ifaceC :: Export -> String
580+ifaceC (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
581+ifaceC (ExportFun n cn ret args)
582+ = ctype ret ++ " " ++ cdesc cn ++
583+ "(VM* vm" ++ showArgs (zip argNames args) ++ ") {\n"
584+ ++ mkBody n (zip argNames args) ret ++ "}\n\n"
585+ where showArgs [] = ""
586+ showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
587+ showArgs ts
588+
589+ argNames = zipWith (++) (repeat "arg") (map show [0..])
590+
591+mkBody n as t = indent 1 ++ "INITFRAME;\n" ++
592+ indent 1 ++ "RESERVE(" ++ show (length as) ++ ");\n" ++
593+ push 0 as ++ call n ++ retval t
594+ where push i [] = ""
595+ push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
596+ ("TOP(" ++ show i ++ ") = ") n
597+ ++ ";\n" ++ push (i + 1) ts
598+
599+ call _ = indent 1 ++ "STOREOLD;\n" ++
600+ indent 1 ++ "BASETOP(0);\n" ++
601+ indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
602+ indent 1 ++ "CALL(" ++ cname n ++ ");\n"
603+
604+ retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
605+
606+ctype (FCon c)
607+ | c == sUN "C_Str" = "char*"
608+ | c == sUN "C_Float" = "float"
609+ | c == sUN "C_Ptr" = "void*"
610+ | c == sUN "C_MPtr" = "void*"
611+ | c == sUN "C_Unit" = "void"
612+ctype (FApp c [_,ity])
613+ | c == sUN "C_IntT" = carith ity
614+ctype (FApp c [_])
615+ | c == sUN "C_Any" = "VAL"
616+ctype (FStr s) = s
617+ctype FUnknown = "void*"
618+ctype FWorld = "void*"
619+ctype t = error "Can't happen: Not a valid interface type " ++ show t
620+
621+carith (FCon i)
622+ | i == sUN "C_IntChar" = "char"
623+ | i == sUN "C_IntNative" = "int"
624+carith t = error "Can't happen: Not an exportable arithmetic type"
625+
626+cdesc (FStr s) = s
627+cdesc s = error "Can't happen: Not a valid C name"
628+
629+-- Then, the header files
630+
631+codegenH :: [ExportIFace] -> IO ()
632+codegenH es = mapM_ writeIFace es
633+
634+writeIFace :: ExportIFace -> IO ()
635+writeIFace (Export ffic hdr exps)
636+ | ffic == sUN "FFI_C"
637+ = do let hfile = "#ifndef " ++ hdr_guard hdr ++ "\n" ++
638+ "#define " ++ hdr_guard hdr ++ "\n\n" ++
639+ "#include <idris_rts.h>\n\n" ++
640+ concatMap hdr_export exps ++ "\n" ++
641+ "#endif\n\n"
642+ writeFile hdr hfile
643+ | otherwise = return ()
644+
645+hdr_guard x = "__" ++ map hchar x
646+ where hchar x | isAlphaNum x = toUpper x
647+ hchar _ = '_'
648+
649+hdr_export :: Export -> String
650+hdr_export (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
651+hdr_export (ExportFun n cn ret args)
652+ = ctype ret ++ " " ++ cdesc cn ++
653+ "(VM* vm" ++ showArgs (zip argNames args) ++ ");\n"
654+ where showArgs [] = ""
655+ showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
656+ showArgs ts
657+
658+ argNames = zipWith (++) (repeat "arg") (map show [0..])
659+
660+
661+