aboutsummaryrefslogtreecommitdiff
path: root/src/Language/SimpleShell/Parser/Module.hs
blob: 8918f860bc55b17cf7b102340d9ec8a86a46a654 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
module Language.SimpleShell.Parser.Module
  ( moduleP0
  , modulePF
  )
where


import Language.SimpleShell.AST.Module (Module(..), ModuleElement(..))
import Language.SimpleShell.AST.Name (FunName, ProcedureName)
import Language.SimpleShell.AST.SimpleType (FunSig, ProcedureSig)
import Language.SimpleShell.Parser.Common.Root (RootParser)
import Language.SimpleShell.Parser.Function (functionP0, functionP)

import Control.Monad (void)
import Control.Monad.Reader (ReaderT, runReaderT, withReaderT)
import Control.Monad.State (StateT, execStateT, gets, modify)
import Control.Monad.Trans.Class (lift)
import Data.Map (Map)
import qualified Data.Map as Map (empty, lookup, insert)
import Data.Text (unpack)
import Text.Megaparsec (many)


type ModuleParser0 = StateT ModuleContext RootParser
type ModuleParser = ReaderT ModuleContext RootParser

moduleP0 :: RootParser ModuleContext
moduleP0 = execStateT moduleMP0 initModuleContext

modulePF :: ModuleContext -> RootParser Module
modulePF = runReaderT moduleMP


data ModuleContext
  = ModuleContext
      { ctxFuns       :: Map FunName       FunSig
      , ctxProcedures :: Map ProcedureName ProcedureSig
      }
  deriving (Show)

initModuleContext :: ModuleContext
initModuleContext = ModuleContext Map.empty Map.empty


addFun :: FunName -> FunSig -> ModuleParser0 ()
addFun fname sig = do
  funs <- gets ctxFuns
  case Map.lookup fname funs of
    Just _  -> fail $ "Function `" ++ unpack fname ++ "` already defined."
    Nothing -> modify (\ctx -> ctx { ctxFuns = Map.insert fname sig funs })


moduleMP0 :: ModuleParser0 ()
moduleMP0 = void $ many (lift functionP0 >>= uncurry addFun)


moduleMP :: ModuleParser Module
moduleMP = Module <$> many elementP
  where
    elementP :: ModuleParser ModuleElement
    elementP = FunctionElement <$> withReaderT ctxFuns functionP