module Micro.Asm.Sdcc where import qualified Micro.Ast as A toIdent :: A.Ident -> String toIdent id = "_" ++ id toLabel :: A.Ident -> Bool -> String toLabel id False = toIdent id ++ "::" toLabel id True = toIdent id ++ ":" toData :: A.Type -> String toData (A.Type t) | t == "bool" || t == "u8" || t == "s8" = ".ds 1" | t == "u16" || t == "s16" = ".ds 2" | otherwise = ".ds 2" toData (A.FuncType _ _) = ".ds 2" toInit :: A.Type -> A.Expr -> String toInit (A.Type t) (A.Num v _) | t == "bool" || t == "u8" || t == "s8" = ".db " ++ show v | t == "u16" || t == "s16" = ".dw " ++ show v | otherwise = ".dw " ++ show v toInit _ v = ".dw " ++ show v header :: String -> [String] header version = [";", "; File created by Micro v" ++ version ++ " (SDCC)", ";"] module' :: String -> String module' name = "\t.module " ++ name optsdcc :: String optsdcc = "\t.optsdcc -mz80" area :: String -> String area name = "\n\t.area " ++ name globl :: String -> String globl id = "\t.globl " ++ id code :: [String] code = [area "_CODE"] data Output = Output { oPre :: [String], oInit :: [String], oData :: [String], oCode :: [String] } emit :: A.Expr -> Output emit x = case x of (A.Module name _) -> o {oPre = [module' name, optsdcc, ""]} (A.Func ident params ret body priv anon pos) -> do let out = map emit body let code = concat (map oCode out) o { oPre = if priv then [] else [globl $ toIdent ident], oCode = [toLabel ident priv] ++ code ++ (if last code /= "\tret" then ["\tret"] else []) } (A.Var id typ val priv False _) -> o { oPre = if priv then [] else [globl $ toIdent id], oData = [toLabel id priv, "\t" ++ toData typ], oInit = ["__xinit" ++ toLabel id True, "\t" ++ toInit typ val] } (A.Call (A.Variable id _) _ _) -> o {oCode = ["\tcall " ++ toIdent id]} (A.Return (Just value) _) -> o {oCode = ["\tld hl, ???", "\tret"]} (A.Return Nothing _) -> o {oCode = ["\tret"]} _ -> o where o = Output [] [] [] [] generate :: String -> [A.Expr] -> String generate version ast = do out <- pure $ map emit ast pre <- pure $ concat $ map oPre out dat <- pure $ ["\n\t.area _DATA", "\t.area _INITIALIZED"] ++ concat (map oData out) code <- pure $ ["\n\t.area _CODE"] ++ concat (map oCode out) init <- pure $ ["\n\t.area _INITIALIZER"] ++ concat (map oInit out) ++ ["\n\t.area _GSINIT", "\t.area _GSFINAL"] unlines $ header version ++ pre ++ dat ++ code ++ init