Split up phase 2 into multiple modules

This commit is contained in:
Joscha 2020-04-05 09:51:24 +00:00
parent d82ce69b1b
commit 8d0e70cf5d
5 changed files with 503 additions and 436 deletions

View file

@ -0,0 +1,138 @@
{-# LANGUAGE DataKinds #-}
module Mima.Asm.Phase2.Subphase1
( subphase1
) where
import Control.Monad
import Control.Monad.Trans.Class
import Control.Monad.Trans.State
import Data.Foldable
import qualified Data.Map.Strict as Map
import qualified Data.Text as T
import qualified Mima.Asm.Phase1 as P1
import Mima.Asm.Phase2.Types
import Mima.Asm.Phase2.Util
import Mima.Asm.Types
import Mima.Asm.Weed
{- Converting phase 1 types to phase 2 types -}
p1ToP2Name :: P1.Name s -> Name s
p1ToP2Name (P1.Name s text) = Name s text
p1ToP2JsonValue :: P1.JsonValue s -> JsonValue s
p1ToP2JsonValue (P1.JsonValue s value) = JsonValue s value
p1ToP2Address :: P1.Address s -> WeedS1 s (OrgAddress s)
p1ToP2Address (P1.AddressAbsolute s addr) = lift $ OrgAddrAbsolute s <$> intToBounded s addr
p1ToP2Address (P1.AddressRelative s offset) = pure $ OrgAddrRelative s offset
p1ToP2Location :: P1.Location s -> WeedS1 s (Location1 s)
p1ToP2Location (P1.LocationAddress (P1.AddressAbsolute s addr)) =
lift $ Loc1Absolute s <$> intToBounded s addr
p1ToP2Location (P1.LocationAddress (P1.AddressRelative s offset)) =
pure $ Loc1Relative s offset
p1ToP2Location (P1.LocationLabel name) = pure $ Loc1Label $ p1ToP2Name name
p1ToP2Location (P1.LocationLabelRel s name s' offset) =
pure $ Loc1LabelRel s (p1ToP2Name name) s' offset
p1ToP2Instruction :: P1.Instruction s -> WeedS1 s (Instruction 'S1 s)
p1ToP2Instruction (P1.SmallInstruction _ (P1.SmallOpcode _ so) loc) =
SmallInstruction so <$> p1ToP2Location loc
p1ToP2Instruction (P1.LargeInstruction _ (P1.LargeOpcode _ lo) maybeSv) = do
val <- case maybeSv of
Nothing -> pure Nothing
Just (P1.SmallValue s v) -> lift $ Just <$> intToBounded s v
pure $ LargeInstruction lo val
p1ToP2Word :: P1.MimaWord s -> WeedS1 s (MimaWord 'S1 s)
p1ToP2Word (P1.WordRaw s w) = lift $ WordRaw <$> intToBounded s w
p1ToP2Word (P1.WordLocation loc) = WordLocation <$> p1ToP2Location loc
p1ToP2RegDir :: P1.RegisterDirective s -> WeedS1 s (RegisterDirective 'S1 s)
p1ToP2RegDir (P1.RegIar s _ loc) = RegIar s <$> p1ToP2Location loc
p1ToP2RegDir (P1.RegAcc s _ word) = RegAcc s <$> p1ToP2Word word
p1ToP2RegDir (P1.RegRa s _ loc) = RegRa s <$> p1ToP2Location loc
p1ToP2RegDir (P1.RegSp s _ loc) = RegSp s <$> p1ToP2Location loc
p1ToP2RegDir (P1.RegFp s _ loc) = RegFp s <$> p1ToP2Location loc
{- Subphase 1 -}
data SingleMeta s = SingleMeta s (P1.Name s) (P1.JsonValue s)
deriving (Show)
instance Onion SingleMeta where
peel (SingleMeta s _ _) = s
data StateS1 s = StateS1
{ s1Metas :: Map.Map T.Text (SingleMeta s)
, s1Tokens :: [AsmToken 'S1 s]
} deriving (Show)
type WeedS1 s = StateT (StateS1 s) (Weed (WeedError s))
addMeta :: s -> P1.Name s -> P1.JsonValue s -> WeedS1 s ()
addMeta s name@(P1.Name namePos nameText) value = do
s1 <- get
when (nameText `Map.member` s1Metas s1) $
lift $ harmless $ errorWith namePos "duplicate .meta names"
let meta = SingleMeta s name value
put s1{s1Metas = Map.insert nameText meta $ s1Metas s1}
takeMetas :: WeedS1 s [SingleMeta s]
takeMetas = do
s <- get
put s{s1Metas = Map.empty}
pure $ Map.elems $ s1Metas s
withMetas :: WeedS1 s () -> WeedS1 s ()
withMetas f = do
metas <- takeMetas
for_ (reverse metas) $ \(SingleMeta s name value) ->
addToken $ TokenMeta s () $
MetaStart s (p1ToP2Name name) (p1ToP2JsonValue value)
f
for_ metas $ \(SingleMeta s name _) ->
addToken $ TokenMeta s () $ MetaStop s (p1ToP2Name name)
addToken :: AsmToken 'S1 s -> WeedS1 s ()
addToken t = modify $ \s -> s{s1Tokens = t : s1Tokens s}
addP1Token :: P1.AsmToken s -> WeedS1 s ()
addP1Token (P1.TokenLabel name) =
addToken $ TokenLabel (peel name) () $ p1ToP2Name name
addP1Token (P1.TokenInstruction instr) = do
i <- p1ToP2Instruction instr
withMetas $ addToken $ TokenInstr (peel instr) () i
addP1Token (P1.TokenDirective (P1.Reg s _ regDir)) = do
r <- p1ToP2RegDir regDir
addToken $ TokenReg s () r
addP1Token (P1.TokenDirective (P1.Org s _ addr)) = do
withMetas $ pure ()
a <- p1ToP2Address addr
addToken $ TokenOrg s a
addP1Token (P1.TokenDirective (P1.Lit s _ word)) = do
w <- p1ToP2Word word
withMetas $ addToken $ TokenLit s () w
addP1Token (P1.TokenDirective (P1.Arr s _ ws)) =
withMetas $ for_ ws $ \word -> do
w <- p1ToP2Word word
addToken $ TokenLit s () w
addP1Token (P1.TokenDirective (P1.Meta s _ name value)) =
addMeta s name value
addP1Token (P1.TokenDirective (P1.MetaStart s _ name value)) =
addToken $ TokenMeta s () $
MetaStart s (p1ToP2Name name) (p1ToP2JsonValue value)
addP1Token (P1.TokenDirective (P1.MetaStop s _ name)) =
addToken $ TokenMeta s () $ MetaStop s (p1ToP2Name name)
addP1Token P1.TokenComment{} = pure ()
subphase1 :: P1.Phase1 s -> Weed (WeedError s) (Phase2 'S1 s)
subphase1 ts = do
let initialS = StateS1 Map.empty []
s <- flip execStateT initialS $ do
traverse_ addP1Token ts
withMetas $ pure ()
pure $ reverse $ s1Tokens s