Fix flag parsing and weeding

This commit is contained in:
Joscha 2019-11-25 14:16:05 +00:00
parent e5728a0fb4
commit 745c201d00
5 changed files with 37 additions and 17 deletions

View file

@ -1,7 +1,8 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module Mima.Format.FlagFile module Mima.Format.FlagFile
( formatFlagFile ( formatFlagSet
, formatFlagFile
) where ) where
import qualified Data.Map as Map import qualified Data.Map as Map
@ -15,8 +16,8 @@ import Mima.Word
fAddress :: MimaAddress -> T.Text fAddress :: MimaAddress -> T.Text
fAddress = fixWidthHex 5 . toHex fAddress = fixWidthHex 5 . toHex
fFlagSet :: Set.Set Char -> T.Text formatFlagSet :: Set.Set Char -> T.Text
fFlagSet = T.pack . Set.toAscList formatFlagSet = T.pack . Set.toAscList
fRange :: AddressRange -> T.Text fRange :: AddressRange -> T.Text
fRange r fRange r
@ -27,7 +28,7 @@ fRange r
upper = upperAddress r upper = upperAddress r
fLine :: (AddressRange, Set.Set Char) -> T.Text fLine :: (AddressRange, Set.Set Char) -> T.Text
fLine (r, s) = fRange r <> ": " <> fFlagSet s <> "\n" fLine (r, s) = fRange r <> ": " <> formatFlagSet s <> "\n"
formatFlagFile :: RawFlags -> T.Text formatFlagFile :: RawFlags -> T.Text
formatFlagFile = mconcat . map fLine . Map.assocs formatFlagFile = mconcat . map fLine . Map.assocs

View file

@ -8,6 +8,7 @@ module Mima.Parse.Assembly.Directive
import qualified Data.Set as Set import qualified Data.Set as Set
import Text.Megaparsec import Text.Megaparsec
import qualified Text.Megaparsec.Char as C
import Mima.Parse.Assembly.Common import Mima.Parse.Assembly.Common
import Mima.Parse.Assembly.Lexeme import Mima.Parse.Assembly.Lexeme
@ -40,7 +41,7 @@ lSetRegister =
<|> SetSP <$> sepBySpace "sp" address <|> SetSP <$> sepBySpace "sp" address
<|> SetFP <$> sepBySpace "fp" address <|> SetFP <$> sepBySpace "fp" address
where where
sepBySpace name parser = symbol' name *> lSpace *> lexeme parser sepBySpace name parser = C.string' name *> lSpace *> lexeme parser
lWordArray :: Parser [MimaWord] lWordArray :: Parser [MimaWord]
lWordArray = open *> (word `sepBy` comma) <* close lWordArray = open *> (word `sepBy` comma) <* close
@ -58,8 +59,8 @@ lDirective = label "assembler directive" $
<|> DOrg <$> directive ".org" (lexeme largeValue) <|> DOrg <$> directive ".org" (lexeme largeValue)
<|> DLit <$> directive ".lit" (lexeme word) <|> DLit <$> directive ".lit" (lexeme word)
<|> DArr <$> directive ".arr" lWordArray <|> DArr <$> directive ".arr" lWordArray
<|> DFlag <$> directive ".flag" lFlags
<|> DFlagOn <$> directive ".flagon" lFlags <|> DFlagOn <$> directive ".flagon" lFlags
<|> DFlagOff <$> directive ".flagoff" lFlags <|> DFlagOff <$> directive ".flagoff" lFlags
<|> DFlag <$> directive ".flag" lFlags
where where
directive name parser = symbol name *> lSpace *> parser directive name parser = C.string name *> lSpace *> parser

View file

@ -31,7 +31,7 @@ symbol' :: T.Text -> Parser T.Text
symbol' = L.symbol' space symbol' = L.symbol' space
lSpace :: Parser () lSpace :: Parser ()
lSpace = lexeme space lSpace = () <$ lexeme whitespace
lNewline :: Parser () lNewline :: Parser ()
lNewline = void $ lexeme C.newline lNewline = void $ lexeme C.newline

View file

@ -9,8 +9,10 @@ import Control.Monad.Trans.Class
import Control.Monad.Trans.State import Control.Monad.Trans.State
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.Text as T
import Mima.Flag import Mima.Flag
import Mima.Format.FlagFile
import Mima.Label import Mima.Label
import Mima.Parse.Assembly.Common import Mima.Parse.Assembly.Common
import Mima.Parse.Assembly.Directive import Mima.Parse.Assembly.Directive
@ -23,8 +25,8 @@ import Mima.Word
data WeedState = WeedState data WeedState = WeedState
{ wsAt :: MimaAddress { wsAt :: MimaAddress
, wsOccupied :: Bool , wsOccupied :: Bool
, wsLastFlagsAt :: MimaAddress , wsLastFlagsAt :: MimaAddress -- The address of the last flags change
, wsOpenFlags :: Set.Set Char , wsOpenFlags :: Set.Set Char -- Which flags are currently active
, wsResult :: WeedResult Address , wsResult :: WeedResult Address
} deriving (Show) } deriving (Show)
@ -124,7 +126,7 @@ turnFlagsOn :: WithOffset a -> Set.Set Char -> SWeed ()
turnFlagsOn thing flags = do turnFlagsOn thing flags = do
WeedState{..} <- get WeedState{..} <- get
let newFlags = Set.union wsOpenFlags flags let newFlags = Set.union wsOpenFlags flags
when (flags == newFlags) $ when (wsOpenFlags == newFlags) $
lift $ harmless $ errorAt thing "All flags already active at this address" lift $ harmless $ errorAt thing "All flags already active at this address"
pushFlags newFlags pushFlags newFlags
@ -132,7 +134,7 @@ turnFlagsOff :: WithOffset a -> Set.Set Char -> SWeed ()
turnFlagsOff thing flags = do turnFlagsOff thing flags = do
WeedState{..} <- get WeedState{..} <- get
let newFlags = wsOpenFlags Set.\\ flags let newFlags = wsOpenFlags Set.\\ flags
when (flags == newFlags) $ when (wsOpenFlags == newFlags) $
lift $ harmless $ errorAt thing "All flags already inactive at this address" lift $ harmless $ errorAt thing "All flags already inactive at this address"
pushFlags newFlags pushFlags newFlags
@ -160,4 +162,16 @@ weedStep thing =
SLabel l -> addLabel thing l SLabel l -> addLabel thing l
weedStatements :: [WithOffset (Statement Address)] -> Weed WeedError (WeedResult Address) weedStatements :: [WithOffset (Statement Address)] -> Weed WeedError (WeedResult Address)
weedStatements statements = wsResult <$> execStateT (mapM_ weedStep statements) initialState weedStatements statements = do
result <- execStateT (mapM_ weedStep statements) initialState
when (not $ Set.null $ wsOpenFlags result)
$ harmless
$ errorAt' (lastOffset statements)
$ "Flags were never closed: " ++ T.unpack (formatFlagSet (wsOpenFlags result))
pure $ wsResult result
where
-- Quick and dirty solution, plus I'm too lazy to see if the prelude has a
-- safe head
lastOffset [] = 0
lastOffset [s] = woOffset s
lastOffset (_:s) = lastOffset s

View file

@ -14,6 +14,7 @@ module Mima.Parse.Weed
, withOffset , withOffset
, errorAt , errorAt
, errorAt' , errorAt'
, errorsAt'
, runWeedBundle , runWeedBundle
) where ) where
@ -93,10 +94,13 @@ withOffset :: Parser a -> Parser (WithOffset a)
withOffset p = WithOffset <$> getOffset <*> p withOffset p = WithOffset <$> getOffset <*> p
errorAt :: WithOffset a -> String -> WeedError errorAt :: WithOffset a -> String -> WeedError
errorAt wo errorMsg = errorAt' wo [errorMsg] errorAt wo errorMsg = errorAt' (woOffset wo) errorMsg
errorAt' :: WithOffset a -> [String] -> WeedError errorAt' :: Int -> String -> WeedError
errorAt' wo = FancyError (woOffset wo) . Set.fromList . map ErrorFail errorAt' o errorMsg = errorsAt' o [errorMsg]
errorsAt' :: Int -> [String] -> WeedError
errorsAt' o = FancyError o . Set.fromList . map ErrorFail
runWeedBundle :: FilePath -> T.Text -> Weed WeedError a -> Either WeedErrorBundle a runWeedBundle :: FilePath -> T.Text -> Weed WeedError a -> Either WeedErrorBundle a
runWeedBundle filename input w = case runWeed w of runWeedBundle filename input w = case runWeed w of