> module Epic.CodegenC where > import Control.Monad.State > import Epic.Language > import Epic.Bytecode > import Debug.Trace > codegenC :: Context -> [Decl] -> String > codegenC ctxt decs = > fileHeader ++ > headers decs ++ "\n" ++ > wrappers decs ++ > workers ctxt decs > -- ++ mainDriver > writeIFace :: [Decl] -> String > writeIFace [] = "" > writeIFace ((Decl name ret (Bind args _ _)):xs) = > "extern " ++ showC name ++ " ("++ showextargs (args) ++ ")" ++ > " -> " ++ show ret ++ "\n" ++ writeIFace xs > writeIFace (_:xs) = writeIFace xs > showextargs [] = "" > showextargs [(n,ty)] = showC n ++ ":" ++ show ty > showextargs ((n,ty):xs) = showC n ++ ":" ++ show ty ++ ", " ++ > showextargs xs > fileHeader = "#include \"closure.h\"\n" ++ > "#include \"stdfuns.h\"\n" ++ > "#include \n\n" > mainDriver = "int main(int argc, char*[] argv) {\nGC_init();\ninit_evm();\n_do__U_main(); return 0; }\n" > showarg _ i = "void* " ++ loc i > showargs [] i= "" > showargs [x] i = showarg x i > showargs (x:xs) i = showarg x i ++ ", " ++ showargs xs (i+1) > headers [] = "" > headers ((Decl fname ret (Bind args _ _)):xs) = > "void* " ++ thunk fname ++ "(void** block);\n" ++ > "void* " ++ quickcall fname ++ "(" ++ showargs args 0 ++ ");\n" ++ > headers xs > headers ((Extern fname ret tys):xs) = > "void* " ++ thunk fname ++ "(void** block);\n" ++ > "void* " ++ quickcall fname ++ "(" ++ showargs (zip (names 0) tys) 0 ++ ");\n" ++ > headers xs > where names i = (MN "arg" i):(names (i+1)) > headers ((Include h):xs) = "#include <"++h++">\n" ++ headers xs > headers (_:xs) = headers xs > wrappers [] = "" > wrappers ((Decl fname ret (Bind args _ _)):xs) = > "void* " ++ thunk fname ++ "(void** block) {\n return " ++ > quickcall fname ++ "(" ++ > wrapperArgs (length args) ++ ");\n}\n\n" ++ > wrappers xs > wrappers (_:xs) = wrappers xs > wrapperArgs 0 = "" > wrapperArgs 1 = "block[0]" > wrapperArgs x = wrapperArgs (x-1) ++ ", block[" ++ show (x-1) ++ "]" > workers _ [] = "" > workers ctxt ((Decl fname ret func@(Bind args locals defn)):xs) = > -- trace (show fname ++ ": " ++ show defn) $ > "void* " ++ quickcall fname ++ "(" ++ showargs args 0 ++ ") {\n" ++ > compileBody (compile ctxt fname func) ++ "\n}\n\n" ++ > workers ctxt xs > workers ctxt (_:xs) = workers ctxt xs > tmp v = "tmp" ++ show v > loc v = "var" ++ show v > quickcall fn = "_do_" ++ showC fn > thunk fn = "_wrap_" ++ showC fn > compileBody :: FunCode -> String > compileBody (Code args bytecode) = > let (code, b) = runState (cgs bytecode) 0 in > if (b>0) then "void** block;\n" ++ code else code -- = EMALLOC("++show b++"*sizeof(void*));\n"++code else code > where > sizeneeded x = do > max <- get > if (x>max) then put x else return () > cgs [] = return "" > cgs (x:xs) = do xc <- cg x > xsc <- cgs xs > return $ xc ++ "\n" ++ xsc > cg (CALL t fn args) = return $ tmp t ++ " = " ++ quickcall fn ++ > targs "(" args ++ ");" > cg (TAILCALL t fn args) = return $ "return " ++ quickcall fn ++ > targs "(" args ++ ");" > cg (THUNK t ar fn []) = do > return $ tmp t ++ > " = (void*)CLOSURE(" ++ thunk fn ++ ", " ++ > show ar ++ ", 0, 0);" > cg (THUNK t ar fn args) = do > sizeneeded (length args) > return $ argblock "block" args ++ tmp t ++ > " = (void*)CLOSURE(" ++ thunk fn ++ ", " ++ > show ar ++ "," ++ show (length args) ++ > ", block);" > cg (ADDARGS t th args) = do sizeneeded (length args) > return $ closureApply t th args > cg (FOREIGN ty t fn args) = return $ > castFrom t ty > (fn ++ "(" ++ foreignArgs args ++ ")") > ++ ";" > cg (VAR t l) = return $ tmp t ++ " = " ++ loc l ++ ";" > cg (ASSIGN l t) = return $ loc l ++ " = " ++ tmp t ++ ";" > cg (CON t tag args) = do sizeneeded (length args) > return $ constructor t tag args > cg (UNIT t) = return $ tmp t ++ " = MKUNIT;" > cg (INT t i) = return $ "ASSIGNINT("++tmp t ++ ", " ++show i++");" > cg (BIGINT t i) = return $ tmp t ++ " = NEWBIGINT(\"" ++show i++"\");" > cg (FLOAT t i) = return $ tmp t ++ " = MKFLOAT("++show i++");" > cg (BIGFLOAT t i) = return $ tmp t ++ " = NEWBIGFLOAT(\""++show i++"\");" > cg (STRING t s) = return $ tmp t ++ " = MKSTR("++show s++");" > cg (PROJ t1 t2 i) = return $ tmp t1 ++ " = PROJECT((Closure*)"++tmp t2++", "++show i++");" > cg (PROJVAR l t i) = return $ loc l ++ " = PROJECT((Closure*)"++tmp t++", "++show i++");" > cg (OP t op l r) = return $ doOp t op l r > cg (LOCALS n) = return $ declare "void* " loc (length args) n > cg (TMPS n) = return $ declare "void* " tmp 0 n > cg (CASE v alts def) = do > altscode <- cgalts alts def 0 > return $ "assert(ISCON("++tmp v++"));\n" ++ > "switch(TAG(" ++ tmp v ++")) {\n" ++ > altscode > ++ "}" > cg (IF v t e) = do > tcode <- cgs t > ecode <- cgs e > return $ "assert(ISINT("++tmp v++"));\n" ++ > "if (GETINT("++tmp v++")) {\n" ++ tcode ++ "} else {\n" ++ > ecode ++ "}" > cg (EVAL v) = return $ tmp v ++ "=(void*)EVAL((VAL)"++tmp v++");" > cg (RETURN t) = return $ "return "++tmp t++";" > cg DRETURN = return $ "return NULL;" > cg (ERROR s) = return $ "ERROR("++show s++");" > cg (TRACE s args) = return $ "TRACE {\n\tprintf(\"%s\\n\", " ++ show s ++ ");\n" ++ > concat (map dumpClosure args) ++ " }" > where dumpClosure i > = "\tdumpClosure(" ++ loc i ++ "); printf(\"--\\n\");\n" > -- cg x = return $ "NOP; // not done " ++ show x > cgalts [] def _ = > case def of > Nothing -> return $ "" > (Just bc) -> do bcode <- cgs bc > return $ "default:\n" ++ bcode ++ "break;\n" > cgalts ((t,bc):alts) def tag > = do bcode <- cgs bc > altscode <- cgalts alts def (tag+1) > return $ "case "++ show t ++":\n" ++ > bcode ++ "break;\n" ++ altscode > targs st [] = st > targs st [x] = st ++ tmp x > targs st (x:xs) = st ++ tmp x ++ targs ", " xs > argblock name [] = name ++ " = 0;\n" > argblock name args = name ++ " = EMALLOC(sizeof(void*)*" ++ show (length args) ++ ");\n" ++ > ab name args 0 > ab nm [] i = "" > ab nm (x:xs) i = nm ++ "[" ++ show i ++ "] = " ++ tmp x ++";\n" ++ > ab nm xs (i+1) > constructor t tag [] > = tmp t ++ " = CONSTRUCTOR(" ++ > show tag ++ ", 0, 0);" > constructor t tag args > | length args < 3 && length args > 0 > = tmp t ++ " = CONSTRUCTOR" ++ show (length args) ++ "(" ++ > show tag ++ targs ", " args ++ ");" > constructor t tag args = argblock "block" args ++ tmp t ++ > " = (void*)CONSTRUCTOR(" ++ > show tag ++ ", " ++ > show (length args) ++ > ", block);" > closureApply t th [] > = tmp t ++ " = CLOSURE_APPLY((VAL)" ++ > tmp th ++ ", 0, 0);" > closureApply t th args > | length args < 3 && length args > 0 > = tmp t ++ " = CLOSURE_APPLY" ++ show (length args) ++ "((VAL)" ++ > tmp th ++ targs ", " args ++ ");" > closureApply t th args = argblock "block" args ++ tmp t ++ > " = CLOSURE_APPLY((VAL)" ++ > tmp th ++ ", " ++ > show (length args) ++ > ", block);" > declare decl fn start end > | start == end = "" > | otherwise = decl ++ fn start ++";\n" ++ > declare decl fn (start+1) end > foreignArgs [] = "" > foreignArgs [x] = foreignArg x > foreignArgs (x:xs) = foreignArg x ++ ", " ++ foreignArgs xs > castFrom t TyUnit x = tmp t ++ " = NULL; " ++ x > castFrom t TyString rest = tmp t ++ " = MKSTR((char*)(" ++ rest ++ "))" > castFrom t TyPtr rest = tmp t ++ " = MKPTR(" ++ rest ++ ")" > castFrom t TyInt rest = tmp t ++ " = MKINT((int)(" ++ rest ++ "))" > castFrom t TyBigInt rest = tmp t ++ " = MKBIGINT((mpz_t*)(" ++ rest ++ "))" > castFrom t _ rest = tmp t ++ " = (void*)(" ++ rest ++ ")" > foreignArg (t, TyInt) = "GETINT("++ tmp t ++")" > foreignArg (t, TyBigInt) = "*(GETBIGINT("++ tmp t ++"))" > foreignArg (t, TyString) = "GETSTR("++ tmp t ++")" > foreignArg (t, TyPtr) = "GETPTR("++ tmp t ++")" > foreignArg (t, _) = tmp t > doOp t Plus l r = tmp t ++ " = INTOP(+,"++tmp l ++ ", "++tmp r++");" > doOp t Minus l r = tmp t ++ " = INTOP(-,"++tmp l ++ ", "++tmp r++");" > doOp t Times l r = tmp t ++ " = INTOP(*,"++tmp l ++ ", "++tmp r++");" > doOp t Divide l r = tmp t ++ " = INTOP(/,"++tmp l ++ ", "++tmp r++");" > doOp t OpEQ l r = tmp t ++ " = INTOP(==,"++tmp l ++ ", "++tmp r++");" > doOp t OpGT l r = tmp t ++ " = INTOP(>,"++tmp l ++ ", "++tmp r++");" > doOp t OpLT l r = tmp t ++ " = INTOP(<,"++tmp l ++ ", "++tmp r++");" > doOp t OpGE l r = tmp t ++ " = INTOP(>=,"++tmp l ++ ", "++tmp r++");" > doOp t OpLE l r = tmp t ++ " = INTOP(<=,"++tmp l ++ ", "++tmp r++");"