163 lines
5.0 KiB
Haskell
163 lines
5.0 KiB
Haskell
-- | Compiler state.
|
|
module ParseState where
|
|
|
|
import Data.Generics
|
|
import Control.Monad.State
|
|
|
|
import qualified AST as A
|
|
import Errors
|
|
import Metadata
|
|
|
|
-- | State necessary for compilation.
|
|
data ParseState = ParseState {
|
|
-- Set by Main (from command-line options)
|
|
psVerboseLevel :: Int,
|
|
psParseOnly :: Bool,
|
|
psOutputFile :: String,
|
|
|
|
-- Set by preprocessor
|
|
psSourceFiles :: [(String, String)],
|
|
psIndentLinesIn :: [String],
|
|
psIndentLinesOut :: [String],
|
|
|
|
-- Set by Parse
|
|
psLocalNames :: [(String, A.Name)],
|
|
psMainLocals :: [(String, A.Name)],
|
|
psNames :: [(String, A.NameDef)],
|
|
psNameCounter :: Int,
|
|
psTypeContext :: [Maybe A.Type],
|
|
psLoadedFiles :: [String],
|
|
psWarnings :: [String],
|
|
|
|
-- Set by passes
|
|
psNonceCounter :: Int,
|
|
psFunctionReturns :: [(String, [A.Type])],
|
|
psPulledItems :: [A.Structured -> A.Structured],
|
|
psAdditionalArgs :: [(String, [A.Actual])]
|
|
}
|
|
deriving (Show, Data, Typeable)
|
|
|
|
instance Show (A.Structured -> A.Structured) where
|
|
show p = "(function on Structured)"
|
|
|
|
emptyState :: ParseState
|
|
emptyState = ParseState {
|
|
psVerboseLevel = 0,
|
|
psParseOnly = False,
|
|
psOutputFile = "-",
|
|
|
|
psSourceFiles = [],
|
|
psIndentLinesIn = [],
|
|
psIndentLinesOut = [],
|
|
|
|
psLocalNames = [],
|
|
psMainLocals = [],
|
|
psNames = [],
|
|
psNameCounter = 0,
|
|
psTypeContext = [],
|
|
psLoadedFiles = [],
|
|
psWarnings = [],
|
|
|
|
psNonceCounter = 0,
|
|
psFunctionReturns = [],
|
|
psPulledItems = [],
|
|
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.
|
|
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.
|
|
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
|
|
|
|
-- | Add a warning.
|
|
addWarning :: PSM m => Meta -> String -> m ()
|
|
addWarning m s = modify (\ps -> ps { psWarnings = msg : psWarnings ps })
|
|
where msg = "Warning: " ++ show m ++ ": " ++ s
|
|
|
|
-- | Generate a throwaway unique name.
|
|
makeNonce :: PSM m => String -> m String
|
|
makeNonce s
|
|
= do ps <- get
|
|
let i = psNonceCounter ps
|
|
put ps { psNonceCounter = i + 1 }
|
|
return $ s ++ "_n" ++ show i
|
|
|
|
-- | Add a pulled item to the collection.
|
|
addPulled :: PSM m => (A.Structured -> A.Structured) -> m ()
|
|
addPulled item = modify (\ps -> ps { psPulledItems = item : psPulledItems ps })
|
|
|
|
-- | Apply pulled items to a Structured.
|
|
applyPulled :: PSM m => A.Structured -> m A.Structured
|
|
applyPulled ast
|
|
= do ps <- get
|
|
let ast' = foldl (\p f -> f p) ast (psPulledItems ps)
|
|
put $ ps { psPulledItems = [] }
|
|
return ast'
|
|
|
|
-- | Enter a type context.
|
|
pushTypeContext :: PSM m => Maybe A.Type -> m ()
|
|
pushTypeContext t
|
|
= modify (\ps -> ps { psTypeContext = t : psTypeContext ps })
|
|
|
|
-- | Leave a type context.
|
|
popTypeContext :: PSM m => m ()
|
|
popTypeContext
|
|
= modify (\ps -> ps { psTypeContext = tail $ psTypeContext ps })
|
|
|
|
-- | Get the current type context (or the given default value if there isn't one).
|
|
getTypeContext :: PSM m => A.Type -> m A.Type
|
|
getTypeContext def
|
|
= do ps <- get
|
|
case psTypeContext ps of
|
|
(Just c):_ -> return c
|
|
_ -> return def
|
|
|
|
-- | Generate and define a nonce 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
|
|
let nd = A.NameDef {
|
|
A.ndMeta = m,
|
|
A.ndName = ns,
|
|
A.ndOrigName = ns,
|
|
A.ndNameType = nt,
|
|
A.ndType = st,
|
|
A.ndAbbrevMode = am
|
|
}
|
|
defineName n nd
|
|
return $ A.Specification m n st
|
|
|
|
-- | Generate and define a no-arg wrapper PROC around a process.
|
|
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 :: 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 :: 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 :: 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
|
|
|