Make all the Types functions monadic; make Errors useful

This commit is contained in:
Adam Sampson 2007-04-24 21:49:03 +00:00
parent 7d2013d3f1
commit 2383345f88
12 changed files with 282 additions and 273 deletions

View File

@ -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

View File

@ -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

View File

@ -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`

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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]

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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