diff --git a/fco2/Errors.hs b/fco2/Errors.hs index 67dc0e3..77327bc 100644 --- a/fco2/Errors.hs +++ b/fco2/Errors.hs @@ -4,12 +4,24 @@ module Errors where import qualified AST as A import Metadata -die :: String -> a -die s = error $ "\n\nError:\n" ++ s +-- | Class of monads that can fail. +class Monad m => Die m where + -- | Fail, giving an error message. + die :: String -> m a + -- | Fail, giving a position and an error message. + dieP :: Die m => Meta -> String -> m a + dieP m s = die $ show m ++ ": " ++ s + +-- | Wrapper around error that gives nicer formatting. +dieIO :: Monad m => String -> m a +dieIO s = error $ "\n\nError: " ++ s ++ "\n" + +-- | Fail after an internal error. dieInternal :: Monad m => String -> m a -dieInternal s = die $ "Internal error: " ++ s - -dieP :: Monad m => Meta -> String -> m a -dieP m s = die $ show m ++ ": " ++ s +dieInternal s = dieIO $ "Internal error: " ++ s +-- | Extract a value from a Maybe type, dying with the given error if it's Nothing. +checkJust :: Die m => String -> Maybe t -> m t +checkJust _ (Just v) = return v +checkJust err _ = die err diff --git a/fco2/GenerateC.hs b/fco2/GenerateC.hs index ad99778..c3a966e 100644 --- a/fco2/GenerateC.hs +++ b/fco2/GenerateC.hs @@ -17,7 +17,10 @@ import TLP import Types --{{{ monad definition -type CGen a = WriterT [String] (ErrorT String (StateT ParseState IO)) a +type CGen = WriterT [String] (ErrorT String (StateT ParseState IO)) + +instance Die CGen where + die = throwError --}}} --{{{ top-level @@ -25,7 +28,7 @@ generateC :: ParseState -> A.Process -> IO String generateC st ast = do v <- evalStateT (runErrorT (runWriterT (genTopLevel ast))) st case v of - Left e -> die e + Left e -> dieIO e Right (_, ss) -> return $ concat ss genTLPChannel :: TLPChannel -> CGen () @@ -53,11 +56,6 @@ missing s = tell ["\n#error Unimplemented: ", s, "\n"] genComma :: CGen () genComma = tell [", "] -withPS :: (ParseState -> a) -> CGen a -withPS f - = do st <- get - return $ f st - checkJust :: MonadError String m => Maybe t -> m t checkJust (Just v) = return v checkJust Nothing = throwError "checkJust failed" @@ -66,8 +64,7 @@ type SubscripterFunction = A.Variable -> A.Variable overArray :: A.Variable -> (SubscripterFunction -> Maybe (CGen ())) -> CGen () overArray var func - = do ps <- get - let A.Array ds _ = fromJust $ typeOfVariable ps var + = do A.Array ds _ <- typeOfVariable var let m = emptyMeta specs <- sequence [makeNonceVariable "i" m A.Int A.VariableName A.Original | _ <- ds] let indices = [A.Variable m n | A.Specification _ n _ <- specs] @@ -100,8 +97,7 @@ data InputType = ITTimerRead | ITTimerAfter | ITOther inputType :: A.Variable -> A.InputMode -> CGen InputType inputType c im - = do ps <- get - t <- checkJust $ typeOfVariable ps c + = do t <- typeOfVariable c return $ case t of A.Timer -> case im of @@ -187,8 +183,7 @@ genConversion m A.DefaultConversion t e = do tell ["(("] genType t tell [") "] - ps <- get - let origT = fromJust $ typeOfExpression ps e + origT <- typeOfExpression e if isSafeConversion origT t then genExpression e else do genTypeSymbol "range_check" origT @@ -287,9 +282,8 @@ the above table this isn't too horrible... -} genVariable :: A.Variable -> CGen () genVariable v - = do ps <- get - am <- checkJust $ abbrevModeOfVariable ps v - t <- checkJust $ typeOfVariable ps v + = do am <- abbrevModeOfVariable v + t <- typeOfVariable v let isSub = case v of A.Variable _ _ -> False A.SubscriptedVariable _ _ _ -> True @@ -334,8 +328,7 @@ genVariable v genArraySubscript :: A.Variable -> [A.Expression] -> CGen () genArraySubscript v es - = do ps <- get - t <- checkJust $ typeOfVariable ps v + = do t <- typeOfVariable v let numDims = case t of A.Array ds _ -> length ds tell ["["] sequence_ $ intersperse (tell [" + "]) $ genPlainSub v es [0..(numDims - 1)] @@ -416,8 +409,7 @@ genSimpleDyadic s e f genFuncDyadic :: Meta -> String -> A.Expression -> A.Expression -> CGen () genFuncDyadic m s e f - = do ps <- get - let t = fromJust $ typeOfExpression ps e + = do t <- typeOfExpression e genTypeSymbol s t tell [" ("] genExpression e @@ -454,21 +446,19 @@ genDyadic m A.After e f = genFuncDyadic m "after" e f genInputItem :: A.Variable -> A.InputItem -> CGen () genInputItem c (A.InCounted m cv av) = do genInputItem c (A.InVariable m cv) - ps <- get - t <- checkJust $ typeOfVariable ps av + t <- typeOfVariable av tell ["ChanIn ("] genVariable c tell [", "] fst $ abbrevVariable A.Abbrev t av tell [", "] - let subT = fromJust $ subscriptType ps (A.Subscript m $ makeConstant m 0) t + subT <- subscriptType (A.Subscript m $ makeConstant m 0) t genVariable cv tell [" * "] genBytesInType subT tell [");\n"] genInputItem c (A.InVariable m v) - = do ps <- get - t <- checkJust $ typeOfVariable ps v + = do t <- typeOfVariable v let rhs = fst $ abbrevVariable A.Abbrev t v case t of A.Int -> @@ -489,8 +479,7 @@ genInputItem c (A.InVariable m v) genOutputItem :: A.Variable -> A.OutputItem -> CGen () genOutputItem c (A.OutCounted m ce ae) = do genOutputItem c (A.OutExpression m ce) - ps <- get - t <- checkJust $ typeOfExpression ps ae + t <- typeOfExpression ae case ae of A.ExprVariable m v -> do tell ["ChanOut ("] @@ -498,14 +487,13 @@ genOutputItem c (A.OutCounted m ce ae) tell [", "] fst $ abbrevVariable A.Abbrev t v tell [", "] - let subT = fromJust $ subscriptType ps (A.Subscript m $ makeConstant m 0) t + subT <- subscriptType (A.Subscript m $ makeConstant m 0) t genExpression ce tell [" * "] genBytesInType subT tell [");\n"] genOutputItem c (A.OutExpression m e) - = do ps <- get - t <- checkJust $ typeOfExpression ps e + = do t <- typeOfExpression e case (t, e) of (A.Int, _) -> do tell ["ChanOutInt ("] @@ -935,8 +923,7 @@ genAssign [v] el = case el of A.FunctionCallList m n es -> missing "function call" A.ExpressionList m [e] -> - do ps <- get - let t = fromJust $ typeOfVariable ps v + do t <- typeOfVariable v doAssign t v e where doAssign :: A.Type -> A.Variable -> A.Expression -> CGen () @@ -954,8 +941,7 @@ genAssign [v] el --{{{ input genInput :: A.Variable -> A.InputMode -> CGen () genInput c im - = do ps <- get - t <- checkJust $ typeOfVariable ps c + = do t <- typeOfVariable c case t of A.Timer -> case im of A.InputSimple m [A.InVariable m' v] -> genTimerRead c v @@ -967,8 +953,7 @@ genInput c im genInputCase :: Meta -> A.Variable -> A.Structured -> CGen () genInputCase m c s - = do ps <- get - t <- checkJust $ typeOfVariable ps c + = do t <- typeOfVariable c let proto = case t of A.Chan (A.UserProtocol n) -> n tag <- makeNonce "case_tag" genName proto @@ -1023,8 +1008,7 @@ genOutput c ois = sequence_ $ map (genOutputItem c) ois genOutputCase :: A.Variable -> A.Name -> [A.OutputItem] -> CGen () genOutputCase c tag ois - = do ps <- get - t <- checkJust $ typeOfVariable ps c + = do t <- typeOfVariable c let proto = case t of A.Chan (A.UserProtocol n) -> n tell ["ChanOutInt ("] genVariable c diff --git a/fco2/Makefile b/fco2/Makefile index ba9605f..e6cbe88 100644 --- a/fco2/Makefile +++ b/fco2/Makefile @@ -22,7 +22,7 @@ sources = \ Utils.hs $(targets): $(sources) - ghc -fglasgow-exts -o fco --make Main + ghc -fglasgow-exts -fallow-undecidable-instances -o fco --make Main CFLAGS = -g -std=gnu99 -Wall `kroc --cflags` `kroc --ccincpath` diff --git a/fco2/Parse.hs b/fco2/Parse.hs index a461824..c99f7d2 100644 --- a/fco2/Parse.hs +++ b/fco2/Parse.hs @@ -1,7 +1,9 @@ -- | Parse occam code into an AST. module Parse where -import Control.Monad.State (StateT, execStateT, liftIO, modify, get) +import Control.Monad (liftM) +import Control.Monad.Error (runErrorT) +import Control.Monad.State (MonadState, StateT, execStateT, liftIO, modify, get, put) import Data.List import Data.Maybe import qualified IO @@ -24,6 +26,16 @@ import Utils --{{{ setup stuff for Parsec type OccParser = GenParser Char ParseState +-- | Make MonadState functions work in the parser monad. +-- This came from http://hackage.haskell.org/trac/ghc/ticket/1274 -- which means +-- it'll probably be in a future GHC release anyway. +instance MonadState st (GenParser tok st) where + get = getState + put = setState + +instance Die (GenParser tok st) where + die = fail + occamStyle = emptyDef { P.commentLine = "--" @@ -271,7 +283,7 @@ maybeSubscripted prodName inner subscripter typer postSubscripts :: A.Type -> OccParser [A.Subscript] postSubscripts t = (do sub <- postSubscript t - t' <- pSubscriptType sub t + t' <- subscriptType sub t rest <- postSubscripts t' return $ sub : rest) <|> return [] @@ -368,27 +380,6 @@ matchType et rt _ -> if rt == et then return () else bad where bad = fail $ "type mismatch (got " ++ show rt ++ "; expected " ++ show et ++ ")" - -checkMaybe :: String -> Maybe a -> OccParser a -checkMaybe msg op - = case op of - Just t -> return t - Nothing -> fail msg - -pTypeOf :: (ParseState -> a -> Maybe b) -> a -> OccParser b -pTypeOf f item - = do st <- getState - checkMaybe "cannot compute type" $ f st item - -pTypeOfVariable = pTypeOf typeOfVariable -pTypeOfLiteral = pTypeOf typeOfLiteral -pTypeOfExpression = pTypeOf typeOfExpression -pSpecTypeOfName = pTypeOf specTypeOfName - -pSubscriptType :: A.Subscript -> A.Type -> OccParser A.Type -pSubscriptType sub t - = do st <- getState - checkMaybe "cannot subscript type" $ subscriptType st sub t --}}} --{{{ name scoping @@ -415,10 +406,11 @@ scopeIn n@(A.Name m nt s) t am A.ndType = t, A.ndAbbrevMode = am } - setState $ psDefineName n' nd $ st { - psNameCounter = (psNameCounter st) + 1, - psLocalNames = (s, n') : (psLocalNames st) - } + defineName n' nd + modify $ (\st -> st { + psNameCounter = (psNameCounter st) + 1, + psLocalNames = (s, n') : (psLocalNames st) + }) return n' scopeOut :: A.Name -> OccParser () @@ -602,7 +594,7 @@ byte -- i.e. array literal table :: OccParser A.Literal table - = maybeSubscripted "table" table' A.SubscriptedLiteral pTypeOfLiteral + = maybeSubscripted "table" table' A.SubscriptedLiteral typeOfLiteral table' :: OccParser A.Literal table' @@ -611,11 +603,10 @@ table' <|> try (do { m <- md; (s, dim) <- stringLiteral; return $ A.Literal m (A.Array [dim] A.Byte) s }) <|> do m <- md es <- tryXVX sLeft (sepBy1 expression sComma) sRight - ps <- getState - ets <- mapM (\e -> checkMaybe "can't type expression" $ typeOfExpression ps e) es + ets <- mapM typeOfExpression es t <- listType m ets return $ A.Literal m t (A.ArrayLiteral m es) - <|> maybeSliced table A.SubscriptedLiteral pTypeOfLiteral + <|> maybeSliced table A.SubscriptedLiteral typeOfLiteral "table'" stringLiteral :: OccParser (A.LiteralRepr, A.Dimension) @@ -638,7 +629,7 @@ character --{{{ expressions functionNameSingle :: OccParser A.Name = do n <- functionName - rts <- (pTypeOf returnTypesOfFunction) n + rts <- returnTypesOfFunction n case rts of [_] -> return n _ -> pzero @@ -646,7 +637,7 @@ functionNameSingle :: OccParser A.Name functionNameMulti :: OccParser A.Name = do n <- functionName - rts <- (pTypeOf returnTypesOfFunction) n + rts <- returnTypesOfFunction n case rts of [_] -> pzero _ -> return n @@ -684,7 +675,7 @@ sizeExpr exprOfType :: A.Type -> OccParser A.Expression exprOfType wantT = do e <- expression - t <- pTypeOfExpression e + t <- typeOfExpression e matchType wantT t return e @@ -752,7 +743,7 @@ conversionMode --{{{ operands operand :: OccParser A.Expression operand - = maybeSubscripted "operand" operand' A.SubscriptedExpr pTypeOfExpression + = maybeSubscripted "operand" operand' A.SubscriptedExpr typeOfExpression operand' :: OccParser A.Expression operand' @@ -762,7 +753,7 @@ operand' operandNotTable :: OccParser A.Expression operandNotTable - = maybeSubscripted "operandNotTable" operandNotTable' A.SubscriptedExpr pTypeOfExpression + = maybeSubscripted "operandNotTable" operandNotTable' A.SubscriptedExpr typeOfExpression operandNotTable' :: OccParser A.Expression operandNotTable' @@ -779,45 +770,45 @@ operandNotTable' --{{{ variables, channels, timers, ports variable :: OccParser A.Variable variable - = maybeSubscripted "variable" variable' A.SubscriptedVariable pTypeOfVariable + = maybeSubscripted "variable" variable' A.SubscriptedVariable typeOfVariable variable' :: OccParser A.Variable variable' = try (do { m <- md; n <- variableName; return $ A.Variable m n }) - <|> try (maybeSliced variable A.SubscriptedVariable pTypeOfVariable) + <|> try (maybeSliced variable A.SubscriptedVariable typeOfVariable) "variable'" channel :: OccParser A.Variable channel - = maybeSubscripted "channel" channel' A.SubscriptedVariable pTypeOfVariable + = maybeSubscripted "channel" channel' A.SubscriptedVariable typeOfVariable "channel" channel' :: OccParser A.Variable channel' = try (do { m <- md; n <- channelName; return $ A.Variable m n }) - <|> try (maybeSliced channel A.SubscriptedVariable pTypeOfVariable) + <|> try (maybeSliced channel A.SubscriptedVariable typeOfVariable) "channel'" timer :: OccParser A.Variable timer - = maybeSubscripted "timer" timer' A.SubscriptedVariable pTypeOfVariable + = maybeSubscripted "timer" timer' A.SubscriptedVariable typeOfVariable "timer" timer' :: OccParser A.Variable timer' = try (do { m <- md; n <- timerName; return $ A.Variable m n }) - <|> try (maybeSliced timer A.SubscriptedVariable pTypeOfVariable) + <|> try (maybeSliced timer A.SubscriptedVariable typeOfVariable) "timer'" port :: OccParser A.Variable port - = maybeSubscripted "port" port' A.SubscriptedVariable pTypeOfVariable + = maybeSubscripted "port" port' A.SubscriptedVariable typeOfVariable "port" port' :: OccParser A.Variable port' = try (do { m <- md; n <- portName; return $ A.Variable m n }) - <|> try (maybeSliced port A.SubscriptedVariable pTypeOfVariable) + <|> try (maybeSliced port A.SubscriptedVariable typeOfVariable) "port'" --}}} --{{{ protocols @@ -880,25 +871,25 @@ declaration abbreviation :: OccParser A.Specification abbreviation = do m <- md - (do { (n, v) <- tryVXV newVariableName sIS variable; sColon; eol; t <- pTypeOfVariable v; return $ A.Specification m n $ A.Is m A.Abbrev t v } - <|> do { (s, n, v) <- try (do { s <- specifier; n <- newVariableName; sIS; v <- variable; return (s, n, v) }); sColon; eol; t <- pTypeOfVariable v; matchType s t; return $ A.Specification m n $ A.Is m A.Abbrev s v } + (do { (n, v) <- tryVXV newVariableName sIS variable; sColon; eol; t <- typeOfVariable v; return $ A.Specification m n $ A.Is m A.Abbrev t v } + <|> do { (s, n, v) <- try (do { s <- specifier; n <- newVariableName; sIS; v <- variable; return (s, n, v) }); sColon; eol; t <- typeOfVariable v; matchType s t; return $ A.Specification m n $ A.Is m A.Abbrev s v } <|> valIsAbbrev - <|> try (do { n <- newChannelName; sIS; c <- channel; sColon; eol; t <- pTypeOfVariable c; return $ A.Specification m n $ A.Is m A.Abbrev t c }) - <|> try (do { n <- newTimerName; sIS; c <- timer; sColon; eol; t <- pTypeOfVariable c; return $ A.Specification m n $ A.Is m A.Abbrev t c }) - <|> try (do { n <- newPortName; sIS; c <- port; sColon; eol; t <- pTypeOfVariable c; return $ A.Specification m n $ A.Is m A.Abbrev t c }) - <|> try (do { s <- specifier; n <- newChannelName; sIS; c <- channel; sColon; eol; t <- pTypeOfVariable c; matchType s t; return $ A.Specification m n $ A.Is m A.Abbrev s c }) - <|> try (do { s <- specifier; n <- newTimerName; sIS; c <- timer; sColon; eol; t <- pTypeOfVariable c; matchType s t; return $ A.Specification m n $ A.Is m A.Abbrev s c }) - <|> try (do { s <- specifier; n <- newPortName; sIS; c <- port; sColon; eol; t <- pTypeOfVariable c; matchType s t; return $ A.Specification m n $ A.Is m A.Abbrev s c }) - <|> try (do { n <- newChannelName; sIS; sLeft; cs <- sepBy1 channel sComma; sRight; sColon; eol; ts <- mapM pTypeOfVariable cs; t <- listType m ts; return $ A.Specification m n $ A.IsChannelArray m t cs }) - <|> try (do { s <- specifier; n <- newChannelName; sIS; sLeft; cs <- sepBy1 channel sComma; sRight; sColon; eol; ts <- mapM pTypeOfVariable cs; t <- listType m ts; matchType s t; return $ A.Specification m n $ A.IsChannelArray m s cs })) + <|> try (do { n <- newChannelName; sIS; c <- channel; sColon; eol; t <- typeOfVariable c; return $ A.Specification m n $ A.Is m A.Abbrev t c }) + <|> try (do { n <- newTimerName; sIS; c <- timer; sColon; eol; t <- typeOfVariable c; return $ A.Specification m n $ A.Is m A.Abbrev t c }) + <|> try (do { n <- newPortName; sIS; c <- port; sColon; eol; t <- typeOfVariable c; return $ A.Specification m n $ A.Is m A.Abbrev t c }) + <|> try (do { s <- specifier; n <- newChannelName; sIS; c <- channel; sColon; eol; t <- typeOfVariable c; matchType s t; return $ A.Specification m n $ A.Is m A.Abbrev s c }) + <|> try (do { s <- specifier; n <- newTimerName; sIS; c <- timer; sColon; eol; t <- typeOfVariable c; matchType s t; return $ A.Specification m n $ A.Is m A.Abbrev s c }) + <|> try (do { s <- specifier; n <- newPortName; sIS; c <- port; sColon; eol; t <- typeOfVariable c; matchType s t; return $ A.Specification m n $ A.Is m A.Abbrev s c }) + <|> try (do { n <- newChannelName; sIS; sLeft; cs <- sepBy1 channel sComma; sRight; sColon; eol; ts <- mapM typeOfVariable cs; t <- listType m ts; return $ A.Specification m n $ A.IsChannelArray m t cs }) + <|> try (do { s <- specifier; n <- newChannelName; sIS; sLeft; cs <- sepBy1 channel sComma; sRight; sColon; eol; ts <- mapM typeOfVariable cs; t <- listType m ts; matchType s t; return $ A.Specification m n $ A.IsChannelArray m s cs })) "abbreviation" valIsAbbrev :: OccParser A.Specification valIsAbbrev = do m <- md sVAL - (n, t, e) <- do { (n, e) <- tryVXV newVariableName sIS expression; sColon; eol; t <- pTypeOfExpression e; return (n, t, e) } - <|> do { s <- specifier; n <- newVariableName; sIS; e <- expression; sColon; eol; t <- pTypeOfExpression e; matchType s t; return (n, t, e) } + (n, t, e) <- do { (n, e) <- tryVXV newVariableName sIS expression; sColon; eol; t <- typeOfExpression e; return (n, t, e) } + <|> do { s <- specifier; n <- newVariableName; sIS; e <- expression; sColon; eol; t <- typeOfExpression e; matchType s t; return (n, t, e) } return $ A.Specification m n $ A.IsExpr m A.ValAbbrev t e "VAL IS abbreviation" @@ -1097,10 +1088,7 @@ channelOutput c <- tryVX channel sBang -- This is an ambiguity in the occam grammar; you can't tell in "a ! b" -- whether b is a variable or a tag, without knowing the type of a. - st <- getState - isCase <- case typeOfVariable st c of - Just t -> return $ isCaseProtocolType st t - Nothing -> fail $ "cannot figure out the type of " ++ show c + isCase <- typeOfVariable c >>= isCaseProtocolType if isCase then (try (do { t <- tagName; sSemi; os <- sepBy1 outputItem sSemi; eol; return $ A.OutputCase m c t os }) @@ -1303,7 +1291,7 @@ procInstance :: OccParser A.Process procInstance = do m <- md n <- tryVX procName sLeftR - st <- pSpecTypeOfName n + st <- specTypeOfName n let fs = case st of A.Proc _ fs _ -> fs as <- actuals fs sRightR @@ -1317,10 +1305,10 @@ actuals fs = intersperseP (map actual fs) sComma actual :: A.Formal -> OccParser A.Actual actual (A.Formal am t n) = do case am of - A.ValAbbrev -> do { e <- expression; et <- pTypeOfExpression e; matchType t et; return $ A.ActualExpression t e } "actual expression for " ++ an + A.ValAbbrev -> do { e <- expression; et <- typeOfExpression e; matchType t et; return $ A.ActualExpression t e } "actual expression for " ++ an _ -> if isChannelType t - then do { c <- channel; ct <- pTypeOfVariable c; matchType t ct; return $ A.ActualVariable am t c } "actual channel for " ++ an - else do { v <- variable; vt <- pTypeOfVariable v; matchType t vt; return $ A.ActualVariable am t v } "actual variable for " ++ an + then do { c <- channel; ct <- typeOfVariable c; matchType t ct; return $ A.ActualVariable am t c } "actual channel for " ++ an + else do { v <- variable; vt <- typeOfVariable v; matchType t vt; return $ A.ActualVariable am t v } "actual variable for " ++ an where an = A.nameName n --}}} @@ -1417,16 +1405,14 @@ mangleModName mod then mod else mod ++ ".occ" -type LoaderM a = StateT ParseState IO a - -- | Load all the source files necessary for a program. -- We have to do this now, before entering the parser, because the parser -- doesn't run in the IO monad. If there were a monad transformer version of -- Parsec then we could just open files as we need them. loadSource :: String -> ParseState -> IO ParseState -loadSource file ps = execStateT (load file file) ps +loadSource file ps = execStateT (runErrorT (load file file)) ps where - load :: String -> String -> LoaderM () + load :: String -> String -> PassM () load file realName = do ps <- get case lookup file (psSourceFiles ps) of @@ -1453,7 +1439,7 @@ parseFile file ps = do let source = fromJust $ lookup file (psSourceFiles ps) let ps' = ps { psLoadedFiles = file : psLoadedFiles ps } case runParser sourceFile ps' file source of - Left err -> die $ "Parse error: " ++ show err + Left err -> dieIO $ "Parse error: " ++ show err Right (p, ps'') -> return (replaceMain p, ps'') where replaceMain :: A.Process -> A.Process -> A.Process diff --git a/fco2/ParseState.hs b/fco2/ParseState.hs index 4c47a14..5e07677 100644 --- a/fco2/ParseState.hs +++ b/fco2/ParseState.hs @@ -5,6 +5,7 @@ import Data.Generics import Control.Monad.State import qualified AST as A +import Errors import Metadata data Flag = ParseOnly | Verbose | Debug @@ -56,16 +57,28 @@ emptyState = ParseState { psAdditionalArgs = [] } +-- | Class of monads which keep a ParseState. +-- (This is just shorthand for the equivalent MonadState constraint.) +class MonadState ParseState m => PSM m +instance MonadState ParseState m => PSM m + -- | Add the definition of a name. -psDefineName :: A.Name -> A.NameDef -> ParseState -> ParseState -psDefineName n nd ps = ps { psNames = (A.nameName n, nd) : psNames ps } +defineName :: PSM m => A.Name -> A.NameDef -> m () +defineName n nd = modify $ (\ps -> ps { psNames = (A.nameName n, nd) : psNames ps }) -- | Find the definition of a name. psLookupName :: ParseState -> A.Name -> Maybe A.NameDef psLookupName ps n = lookup (A.nameName n) (psNames ps) +lookupName :: (PSM m, Die m) => A.Name -> m A.NameDef +lookupName n + = do ps <- get + case lookup (A.nameName n) (psNames ps) of + Just nd -> return nd + Nothing -> die $ "cannot find name " ++ A.nameName n + -- | Generate a throwaway unique name. -makeNonce :: MonadState ParseState m => String -> m String +makeNonce :: PSM m => String -> m String makeNonce s = do ps <- get let i = psNonceCounter ps @@ -73,13 +86,13 @@ makeNonce s return $ s ++ "_n" ++ show i -- | Add a pulled item to the collection. -addPulled :: MonadState ParseState m => (A.Process -> A.Process) -> m () +addPulled :: PSM m => (A.Process -> A.Process) -> m () addPulled item = do ps <- get put $ ps { psPulledItems = item : psPulledItems ps } -- | Apply pulled items to a Process. -applyPulled :: MonadState ParseState m => A.Process -> m A.Process +applyPulled :: PSM m => A.Process -> m A.Process applyPulled ast = do ps <- get let ast' = foldl (\p f -> f p) ast (psPulledItems ps) @@ -87,7 +100,7 @@ applyPulled ast return ast' -- | Generate and define a nonce specification. -defineNonce :: MonadState ParseState m => Meta -> String -> A.SpecType -> A.NameType -> A.AbbrevMode -> m A.Specification +defineNonce :: PSM m => Meta -> String -> A.SpecType -> A.NameType -> A.AbbrevMode -> m A.Specification defineNonce m s st nt am = do ns <- makeNonce s let n = A.Name m A.ProcName ns @@ -99,33 +112,34 @@ defineNonce m s st nt am A.ndType = st, A.ndAbbrevMode = am } - modify $ psDefineName n nd + defineName n nd return $ A.Specification m n st -- | Generate and define a no-arg wrapper PROC around a process. -makeNonceProc :: MonadState ParseState m => Meta -> A.Process -> m A.Specification +makeNonceProc :: PSM m => Meta -> A.Process -> m A.Specification makeNonceProc m p = defineNonce m "wrapper_proc" (A.Proc m [] p) A.ProcName A.Abbrev -- | Generate and define a variable abbreviation. -makeNonceIs :: MonadState ParseState m => String -> Meta -> A.Type -> A.AbbrevMode -> A.Variable -> m A.Specification +makeNonceIs :: PSM m => String -> Meta -> A.Type -> A.AbbrevMode -> A.Variable -> m A.Specification makeNonceIs s m t am v = defineNonce m s (A.Is m am t v) A.VariableName am -- | Generate and define an expression abbreviation. -makeNonceIsExpr :: MonadState ParseState m => String -> Meta -> A.Type -> A.Expression -> m A.Specification +makeNonceIsExpr :: PSM m => String -> Meta -> A.Type -> A.Expression -> m A.Specification makeNonceIsExpr s m t e = defineNonce m s (A.IsExpr m A.ValAbbrev t e) A.VariableName A.ValAbbrev -- | Generate and define a variable. -makeNonceVariable :: MonadState ParseState m => String -> Meta -> A.Type -> A.NameType -> A.AbbrevMode -> m A.Specification +makeNonceVariable :: PSM m => String -> Meta -> A.Type -> A.NameType -> A.AbbrevMode -> m A.Specification makeNonceVariable s m t nt am = defineNonce m s (A.Declaration m t) nt am -- | Is a name on the list of constants? -isConstantName :: ParseState -> A.Name -> Bool -isConstantName ps n - = case lookup (A.nameName n) (psConstants ps) of - Just _ -> True - Nothing -> False +isConstantName :: PSM m => A.Name -> m Bool +isConstantName n + = do ps <- get + case lookup (A.nameName n) (psConstants ps) of + Just _ -> return True + Nothing -> return False diff --git a/fco2/Pass.hs b/fco2/Pass.hs index 2864f61..80c5a1c 100644 --- a/fco2/Pass.hs +++ b/fco2/Pass.hs @@ -6,16 +6,28 @@ import Control.Monad.State import System.IO import qualified AST as A +import Errors import ParseState import PrettyShow -type PassM a = StateT ParseState IO a +-- | The monad in which AST-mangling passes operate. +type PassM = ErrorT String (StateT ParseState IO) +instance Die PassM where + die = throwError + +-- | The type of an AST-mangling pass. type Pass = A.Process -> PassM A.Process +-- | Run a pass, dying with the appropriate error if it fails. runPass :: Pass -> A.Process -> ParseState -> IO (A.Process, ParseState) -runPass pass ast st = runStateT (pass ast) st +runPass pass ast st + = do (v, ps) <- runStateT (runErrorT (pass ast)) st + case v of + Left e -> dieIO e + Right r -> return (r, ps) +-- | Compose a list of passes into a single pass. runPasses :: [(String, Pass)] -> A.Process -> PassM A.Process runPasses [] ast = return ast runPasses ((s, p):ps) ast @@ -26,22 +38,33 @@ runPasses ((s, p):ps) ast debug $ "}}}" runPasses ps ast' +-- | Print a progress message if appropriate. progress :: String -> PassM () progress s = do ps <- get liftIO $ progressIO ps s +-- | Print a progress message if appropriate (in the IO monad). progressIO :: ParseState -> String -> IO () progressIO ps s = when (Verbose `elem` psFlags ps) $ hPutStrLn stderr s +-- | Print a debugging message if appropriate. debug :: String -> PassM () debug s = do ps <- get liftIO $ debugIO ps s +-- | Print a debugging message if appropriate (in the IO monad). debugIO :: ParseState -> String -> IO () debugIO ps s = when (Debug `elem` psFlags ps) $ hPutStrLn stderr s +-- | Dump the AST and parse state if appropriate. +debugAST :: A.Process -> PassM () +debugAST p + = do ps <- get + liftIO $ debugASTIO ps p + +-- | Dump the AST and parse state if appropriate (in the IO monad). debugASTIO :: ParseState -> A.Process -> IO () debugASTIO ps p = do debugIO ps $ "{{{ AST" @@ -51,8 +74,3 @@ debugASTIO ps p debugIO ps $ pshow ps debugIO ps $ "}}}" -debugAST :: A.Process -> PassM () -debugAST p - = do ps <- get - liftIO $ debugASTIO ps p - diff --git a/fco2/SimplifyExprs.hs b/fco2/SimplifyExprs.hs index 0bd0a31..4f1f346 100644 --- a/fco2/SimplifyExprs.hs +++ b/fco2/SimplifyExprs.hs @@ -46,7 +46,7 @@ functionsToProcs = doGeneric `extM` doSpecification A.ndType = st, A.ndAbbrevMode = A.Original } - modify $ psDefineName n nd + defineName n nd doGeneric spec doSpecification s = doGeneric s @@ -89,8 +89,7 @@ pullUp = doGeneric `extM` doProcess `extM` doSpecification `extM` doExpression ` doExpression :: A.Expression -> PassM A.Expression doExpression e = do e' <- doExpressionFunc e - ps <- get - let t = fromJust $ typeOfExpression ps e' + t <- typeOfExpression e' case t of A.Array _ _ -> case e' of @@ -109,13 +108,11 @@ pullUp = doGeneric `extM` doProcess `extM` doSpecification `extM` doExpression ` doVariable :: A.Variable -> PassM A.Variable doVariable v@(A.SubscriptedVariable m _ _) = do v' <- doGeneric v - ps <- get - let t = fromJust $ typeOfVariable ps v' + t <- typeOfVariable v' case t of A.Array _ _ -> - do let am = case fromJust $ abbrevModeOfVariable ps v' of - A.Original -> A.Abbrev - t -> t + do origAM <- abbrevModeOfVariable v' + let am = makeAbbrevAM origAM spec@(A.Specification _ n _) <- makeNonceIs "array_slice" m t am v' addPulled $ A.ProcSpec m spec return $ A.Variable m n @@ -126,9 +123,9 @@ pullUp = doGeneric `extM` doProcess `extM` doSpecification `extM` doExpression ` convertFuncCall :: Meta -> A.Name -> [A.Expression] -> PassM [A.Variable] convertFuncCall m n es = do es' <- pullUp es - ps <- get - let ets = [fromJust $ typeOfExpression ps e | e <- es'] + ets <- sequence [typeOfExpression e | e <- es'] + ps <- get let rts = fromJust $ lookup (A.nameName n) (psFunctionReturns ps) specs <- sequence [makeNonceVariable "return_actual" m t A.VariableName A.Original | t <- rts] sequence_ [addPulled $ A.ProcSpec m spec | spec <- specs] diff --git a/fco2/SimplifyProcs.hs b/fco2/SimplifyProcs.hs index 214d624..b9d2a83 100644 --- a/fco2/SimplifyProcs.hs +++ b/fco2/SimplifyProcs.hs @@ -50,8 +50,7 @@ removeParAssign = doGeneric `extM` doProcess doProcess :: A.Process -> PassM A.Process doProcess (A.Assign m vs@(_:_:_) (A.ExpressionList _ es)) - = do ps <- get - let ts = [fromJust $ typeOfVariable ps v | v <- vs] + = do ts <- mapM typeOfVariable vs specs <- sequence [makeNonceVariable "assign_temp" m t A.VariableName A.Original | t <- ts] let temps = [A.Variable m n | A.Specification _ n _ <- specs] let first = [A.Assign m [v] (A.ExpressionList m [e]) | (v, e) <- zip temps es] diff --git a/fco2/TLP.hs b/fco2/TLP.hs index 431faa1..649f082 100644 --- a/fco2/TLP.hs +++ b/fco2/TLP.hs @@ -8,6 +8,7 @@ import Data.List import Data.Maybe import qualified AST as A +import Errors import Metadata import ParseState import Types @@ -17,26 +18,27 @@ data TLPChannel = TLPIn | TLPOut | TLPError -- | Get the name of the TLP and the channels it uses. -- Fail if the process isn't using a valid interface. -tlpInterface :: (MonadState ParseState m, MonadError String m) => m (A.Name, [TLPChannel]) +tlpInterface :: (PSM m, Die m) => m (A.Name, [TLPChannel]) tlpInterface = do ps <- get let mainName = snd $ head $ psMainLocals ps - formals <- case fromJust $ specTypeOfName ps mainName of + st <- specTypeOfName mainName + formals <- case st of A.Proc _ fs _ -> return fs - _ -> throwError "Last definition is not a PROC" + _ -> die "Last definition is not a PROC" chans <- mapM tlpChannel formals - when ((nub chans) /= chans) $ throwError "Channels used more than once in TLP" + when ((nub chans) /= chans) $ die "Channels used more than once in TLP" return (mainName, chans) where - tlpChannel :: (MonadState ParseState m, MonadError String m) => A.Formal -> m TLPChannel + tlpChannel :: (PSM m, Die m) => A.Formal -> m TLPChannel tlpChannel (A.Formal _ (A.Chan A.Byte) n) - = do ps <- get - let origN = A.ndOrigName $ fromJust $ psLookupName ps n + = do def <- lookupName n + let origN = A.ndOrigName def case lookup origN tlpChanNames of Just c -> return c - _ -> throwError $ "TLP formal " ++ show n ++ " has unrecognised name" + _ -> die $ "TLP formal " ++ show n ++ " has unrecognised name" tlpChannel (A.Formal _ _ n) - = throwError $ "TLP formal " ++ show n ++ " has unrecognised type" + = die $ "TLP formal " ++ show n ++ " has unrecognised type" tlpChanNames :: [(String, TLPChannel)] tlpChanNames diff --git a/fco2/TODO b/fco2/TODO index b016711..e233890 100644 --- a/fco2/TODO +++ b/fco2/TODO @@ -19,14 +19,6 @@ nothing to do with parsing. Types needs cleaning up and Haddocking. -Types should provide versions of the functions that work in a state monad. -If we can make them work in the parser monad (by providing an instance of -MonadState for it?), that'd be even better. - See: http://hackage.haskell.org/trac/ghc/ticket/1274 - -Errors is nearly useless, because none of our monads really fail in sensible -ways. - ## Driver Add an option for whether to compile out overflow/bounds checks. diff --git a/fco2/Types.hs b/fco2/Types.hs index 89f5b38..c28107f 100644 --- a/fco2/Types.hs +++ b/fco2/Types.hs @@ -4,62 +4,62 @@ module Types where -- FIXME: This module is a mess -- sort it and document the functions. import Control.Monad +import Control.Monad.State import Data.Generics import Data.Maybe import qualified AST as A +import Errors import ParseState import Metadata -perhaps :: Maybe a -> (a -> b) -> Maybe b -perhaps m f = m >>= (Just . f) +specTypeOfName :: (PSM m, Die m) => A.Name -> m A.SpecType +specTypeOfName n + = liftM A.ndType (lookupName n) -specTypeOfName :: ParseState -> A.Name -> Maybe A.SpecType -specTypeOfName ps n - = (psLookupName ps n) `perhaps` A.ndType +abbrevModeOfName :: (PSM m, Die m) => A.Name -> m A.AbbrevMode +abbrevModeOfName n + = liftM A.ndAbbrevMode (lookupName n) -abbrevModeOfName :: ParseState -> A.Name -> Maybe A.AbbrevMode -abbrevModeOfName ps n - = (psLookupName ps n) `perhaps` A.ndAbbrevMode - -typeOfName :: ParseState -> A.Name -> Maybe A.Type -typeOfName ps n - = case specTypeOfName ps n of - Just (A.Declaration m t) -> Just t - Just (A.Is m am t v) -> typeOfVariable ps v - Just (A.IsExpr m am t e) -> typeOfExpression ps e - Just (A.IsChannelArray m t (c:_)) -> typeOfVariable ps c `perhaps` A.Array [A.UnknownDimension] - Just (A.Retypes m am t v) -> Just t - Just (A.RetypesExpr m am t e) -> Just t - _ -> Nothing +typeOfName :: (PSM m, Die m) => A.Name -> m A.Type +typeOfName n + = do st <- specTypeOfName n + case st of + A.Declaration _ t -> return t + A.Is _ _ _ v -> typeOfVariable v + A.IsExpr _ _ _ e -> typeOfExpression e + A.IsChannelArray _ _ (c:_) -> liftM (A.Array [A.UnknownDimension]) $ typeOfVariable c + A.Retypes _ _ t _ -> return t + A.RetypesExpr _ _ t _ -> return t + _ -> die $ "cannot type name " ++ show st --{{{ identifying types -typeOfRecordField :: ParseState -> A.Type -> A.Name -> Maybe A.Type -typeOfRecordField ps (A.UserDataType rec) field - = do st <- specTypeOfName ps rec +typeOfRecordField :: (PSM m, Die m) => A.Type -> A.Name -> m A.Type +typeOfRecordField (A.UserDataType rec) field + = do st <- specTypeOfName rec case st of - A.DataTypeRecord _ _ fs -> lookup field fs - _ -> Nothing -typeOfRecordField _ _ _ = Nothing + A.DataTypeRecord _ _ fs -> checkJust "unknown record field" $ lookup field fs + _ -> die "not record type" +typeOfRecordField _ _ = die "not record type" -subscriptType :: ParseState -> A.Subscript -> A.Type -> Maybe A.Type -subscriptType _ (A.SubscriptFromFor _ _ _) t = Just t -subscriptType _ (A.SubscriptFrom _ _) t = Just t -subscriptType _ (A.SubscriptFor _ _) t = Just t -subscriptType ps (A.SubscriptField _ tag) t = typeOfRecordField ps t tag -subscriptType _ (A.Subscript _ _) (A.Array [_] t) = Just t -subscriptType _ (A.Subscript _ _) (A.Array (_:ds) t) = Just $ A.Array ds t -subscriptType _ _ _ = Nothing +subscriptType :: (PSM m, Die m) => A.Subscript -> A.Type -> m A.Type +subscriptType (A.SubscriptFromFor _ _ _) t = return t +subscriptType (A.SubscriptFrom _ _) t = return t +subscriptType (A.SubscriptFor _ _) t = return t +subscriptType (A.SubscriptField _ tag) t = typeOfRecordField t tag +subscriptType (A.Subscript _ _) (A.Array [_] t) = return t +subscriptType (A.Subscript _ _) (A.Array (_:ds) t) = return $ A.Array ds t +subscriptType _ _ = die "unsubscriptable type" -typeOfVariable :: ParseState -> A.Variable -> Maybe A.Type -typeOfVariable ps (A.Variable m n) = typeOfName ps n -typeOfVariable ps (A.SubscriptedVariable m s v) - = typeOfVariable ps v >>= subscriptType ps s +typeOfVariable :: (PSM m, Die m) => A.Variable -> m A.Type +typeOfVariable (A.Variable m n) = typeOfName n +typeOfVariable (A.SubscriptedVariable m s v) + = typeOfVariable v >>= subscriptType s -abbrevModeOfVariable :: ParseState -> A.Variable -> Maybe A.AbbrevMode -abbrevModeOfVariable ps (A.Variable _ n) = abbrevModeOfName ps n -abbrevModeOfVariable ps (A.SubscriptedVariable _ sub v) - = do am <- abbrevModeOfVariable ps v +abbrevModeOfVariable :: (PSM m, Die m) => A.Variable -> m A.AbbrevMode +abbrevModeOfVariable (A.Variable _ n) = abbrevModeOfName n +abbrevModeOfVariable (A.SubscriptedVariable _ sub v) + = do am <- abbrevModeOfVariable v return $ case (am, sub) of (A.ValAbbrev, A.Subscript _ _) -> A.ValAbbrev (_, A.Subscript _ _) -> A.Original @@ -77,51 +77,53 @@ dyadicIsBoolean A.MoreEq = True dyadicIsBoolean A.After = True dyadicIsBoolean _ = False -typeOfExpression :: ParseState -> A.Expression -> Maybe A.Type -typeOfExpression ps e +typeOfExpression :: (PSM m, Die m) => A.Expression -> m A.Type +typeOfExpression e = case e of - A.Monadic m op e -> typeOfExpression ps e + A.Monadic m op e -> typeOfExpression e A.Dyadic m op e f -> - if dyadicIsBoolean op then Just A.Bool else typeOfExpression ps e - A.MostPos m t -> Just t - A.MostNeg m t -> Just t - A.SizeType m t -> Just A.Int - A.SizeExpr m t -> Just A.Int - A.SizeVariable m t -> Just A.Int - A.Conversion m cm t e -> Just t - A.ExprVariable m v -> typeOfVariable ps v - A.ExprLiteral m l -> typeOfLiteral ps l - A.True m -> Just A.Bool - A.False m -> Just A.Bool - A.FunctionCall m n es -> - case returnTypesOfFunction ps n of - Just [t] -> Just t - _ -> Nothing + if dyadicIsBoolean op then return A.Bool else typeOfExpression e + A.MostPos m t -> return t + A.MostNeg m t -> return t + A.SizeType m t -> return A.Int + A.SizeExpr m t -> return A.Int + A.SizeVariable m t -> return A.Int + A.Conversion m cm t e -> return t + A.ExprVariable m v -> typeOfVariable v + A.ExprLiteral m l -> typeOfLiteral l + A.True m -> return A.Bool + A.False m -> return A.Bool + A.FunctionCall m n es -> liftM head $ returnTypesOfFunction n A.SubscriptedExpr m s e -> - typeOfExpression ps e >>= subscriptType ps s - A.BytesInExpr m e -> Just A.Int - A.BytesInType m t -> Just A.Int - A.OffsetOf m t n -> Just A.Int + typeOfExpression e >>= subscriptType s + A.BytesInExpr m e -> return A.Int + A.BytesInType m t -> return A.Int + A.OffsetOf m t n -> return A.Int -typeOfLiteral :: ParseState -> A.Literal -> Maybe A.Type -typeOfLiteral ps (A.Literal m t lr) = Just t -typeOfLiteral ps (A.SubscriptedLiteral m s l) - = typeOfLiteral ps l >>= subscriptType ps s +typeOfLiteral :: (PSM m, Die m) => A.Literal -> m A.Type +typeOfLiteral (A.Literal m t lr) = return t +typeOfLiteral (A.SubscriptedLiteral m s l) + = typeOfLiteral l >>= subscriptType s --}}} -returnTypesOfFunction :: ParseState -> A.Name -> Maybe [A.Type] -returnTypesOfFunction ps n - = case specTypeOfName ps n of - Just (A.Function m rs fs vp) -> Just rs - -- If it's not defined as a function, it might have been converted to a proc. - _ -> lookup (A.nameName n) (psFunctionReturns ps) +returnTypesOfFunction :: (PSM m, Die m) => A.Name -> m [A.Type] +returnTypesOfFunction n + = do st <- specTypeOfName n + case st of + A.Function m rs fs vp -> return rs + -- If it's not defined as a function, it might have been converted to a proc. + _ -> + do ps <- get + checkJust "not defined as a function" $ + lookup (A.nameName n) (psFunctionReturns ps) -isCaseProtocolType :: ParseState -> A.Type -> Bool -isCaseProtocolType ps (A.Chan (A.UserProtocol pr)) - = case specTypeOfName ps pr of - Just (A.ProtocolCase _ _) -> True - _ -> False -isCaseProtocolType ps _ = False +isCaseProtocolType :: (PSM m, Die m) => A.Type -> m Bool +isCaseProtocolType (A.Chan (A.UserProtocol pr)) + = do st <- specTypeOfName pr + case st of + A.ProtocolCase _ _ -> return True + _ -> return False +isCaseProtocolType _ = return False abbrevModeOfSpec :: A.SpecType -> A.AbbrevMode abbrevModeOfSpec s @@ -148,6 +150,12 @@ stripArrayType :: A.Type -> A.Type stripArrayType (A.Array _ t) = stripArrayType t stripArrayType t = t +-- | Given the abbreviation mode of something, return what the abbreviation +-- mode of something that abbreviated it would be. +makeAbbrevAM :: A.AbbrevMode -> A.AbbrevMode +makeAbbrevAM A.Original = A.Abbrev +makeAbbrevAM am = am + -- | Generate a constant expression from an integer -- for array sizes and the like. makeConstant :: Meta -> Int -> A.Expression makeConstant m n = A.ExprLiteral m $ A.Literal m A.Int $ A.IntLiteral m (show n) diff --git a/fco2/Unnest.hs b/fco2/Unnest.hs index 25bba9c..96e77a1 100644 --- a/fco2/Unnest.hs +++ b/fco2/Unnest.hs @@ -89,37 +89,34 @@ removeFreeNames = doGeneric `extM` doSpecification `extM` doProcess doSpecification spec = case spec of A.Specification m n st@(A.Proc _ fs p) -> do - ps <- get -- Figure out the free names. We only want to do this for channels -- and variables, and we don't want to do it for constants because -- they'll get pulled to the top level anyway. - let allFreeNames = Map.elems $ freeNamesIn st - let freeNames = [n | n <- allFreeNames, - case A.nameType n of - A.ChannelName -> True - A.VariableName -> True - _ -> False, - not $ isConstantName ps n] - let types = [fromJust $ typeOfName ps n | n <- freeNames] - let ams = [case fromJust $ abbrevModeOfName ps n of - A.Original -> A.Abbrev - t -> t - | n <- freeNames] + let freeNames' = Map.elems $ freeNamesIn st + let freeNames'' = [n | n <- freeNames', + case A.nameType n of + A.ChannelName -> True + A.VariableName -> True + _ -> False] + freeNames <- filterM isConstantName freeNames'' + types <- mapM typeOfName freeNames + origAMs <- mapM abbrevModeOfName freeNames + let ams = map makeAbbrevAM origAMs -- Generate and define new names to replace them with newNamesS <- sequence [makeNonce (A.nameName n) | n <- freeNames] let newNames = [on { A.nameName = nn } | (on, nn) <- zip freeNames newNamesS] - sequence_ [let ond = fromJust $ psLookupName ps on - in modify $ psDefineName nn (ond { A.ndName = A.nameName nn, - A.ndAbbrevMode = am }) - | (on, nn, am) <- zip3 freeNames newNames ams] + onds <- mapM lookupName freeNames + sequence_ [defineName nn (ond { A.ndName = A.nameName nn, + A.ndAbbrevMode = am }) + | (ond, nn, am) <- zip3 onds newNames ams] -- Add formals for each of the free names let newFs = [A.Formal am t n | (am, t, n) <- zip3 ams types newNames] p' <- removeFreeNames $ replaceNames (zip freeNames newNames) p let st' = A.Proc m (fs ++ newFs) p' let spec' = A.Specification m n st' -- Update the definition of the proc - let nameDef = fromJust $ psLookupName ps n - modify $ psDefineName n (nameDef { A.ndType = st' }) + nameDef <- lookupName n + defineName n (nameDef { A.ndType = st' }) -- Note that we should add extra arguments to calls of this proc -- when we find them let newAs = [case am of @@ -155,20 +152,20 @@ removeNesting p doSpecification :: A.Specification -> PassM A.Specification doSpecification spec@(A.Specification m n st) - = do ps <- get - if isConstantName ps n || canPull ps st then + = do isConst <- isConstantName n + if isConst || canPull st then do spec' <- doGeneric spec addPulled $ A.ProcSpec m spec' return A.NoSpecification else doGeneric spec - canPull :: ParseState -> A.SpecType -> Bool - canPull _ (A.Proc _ _ _) = True - canPull _ (A.DataType _ _) = True - canPull _ (A.DataTypeRecord _ _ _) = True - canPull _ (A.Protocol _ _) = True - canPull _ (A.ProtocolCase _ _) = True - canPull _ _ = False + canPull :: A.SpecType -> Bool + canPull (A.Proc _ _ _) = True + canPull (A.DataType _ _) = True + canPull (A.DataTypeRecord _ _ _) = True + canPull (A.Protocol _ _) = True + canPull (A.ProtocolCase _ _) = True + canPull _ = False -- | Remove specifications that have been turned into NoSpecifications. removeNoSpecs :: Data t => t -> PassM t