soyuz-0.0.0: DCPU16/Assembly/Printer.hs
-- | DCPU-16 pretty-printing.
--
-- Meant for printing disassembly, debugger data, and other machine output.
--
-- Focus is on consistency and predictability, not special snowflake
-- indentation or ASCII art.
--
-- Should be compatible with other people's stuff, with two caveats:
--
-- * I saw a screenshot that used () for indirect rather than [].
--
-- * Output is lower case.
module DCPU16.Assembly.Printer
( pprint
) where
import DCPU16.Instructions
import Text.PrettyPrint
import Data.Char (toLower)
import Data.ByteString.Char8 (unpack)
import Text.Printf
import Data.Word (Word16)
import Data.Vector (Vector)
import qualified Data.Vector as V
-- | Nicely formatted ASCII output.
pprint :: Vector Instruction -> String
pprint = render . V.foldl pI empty
pI :: Doc -> Instruction -> Doc
pI acc (Comment solo xs)
| not solo = acc $$ nest 40 (semi <> text xs)
| otherwise = acc $+$ semi <> text xs
pI acc (Label s) = acc $$ colon <> text (unpack s)
pI acc (Data x) = acc $$ nest 16 (text "dat" <+> pW x)
pI acc (Basic op a b) = acc $$ nest 16 (pBO op <+> pO a <> comma <+> pO b)
pI acc (NonBasic op a)= acc $$ nest 16 (pNBO op <+> pO a)
pW (Const x) | x<0xa = text . show $ x
| otherwise = pHex "0x%x" x
pW (LabelAddr s) = text . unpack $ s
pBO :: BasicOp -> Doc
pBO = text . map toLower . show
pNBO :: NonBasicOp -> Doc
pNBO JSR = text "jsr"
pNBO (Reserved code) = pHex "; RESERVED INSTRUCTION: 0x%x" code
pO :: Operand -> Doc
pO (Direct r) = pReg r
pO (Indirect r) = brackets $ pReg r
pO (Offset off r) = brackets $ pW off <> char '+' <> pReg r
pO (IndirectLiteral w) = brackets $ pW w
pO (DirectLiteral w) = pW w
pO (ShortLiteral w) = pW w
pO o = text . map toLower . show $ o
pHex :: String -> Word16 -> Doc
pHex fmt w = text (printf fmt w)
pReg = text . map toLower . show