diff options
Diffstat (limited to 'src/Language/SimpleShell/Parser/Function.hs')
-rw-r--r-- | src/Language/SimpleShell/Parser/Function.hs | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/src/Language/SimpleShell/Parser/Function.hs b/src/Language/SimpleShell/Parser/Function.hs index be3f424..5bc2007 100644 --- a/src/Language/SimpleShell/Parser/Function.hs +++ b/src/Language/SimpleShell/Parser/Function.hs @@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE FlexibleContexts #-} module Language.SimpleShell.Parser.Function ( functionP @@ -14,7 +15,7 @@ import Language.SimpleShell.AST.SimpleType (SimpleType, FunSig, Typed) import Language.SimpleShell.Parser.Common.Lexeme (symbol) import Language.SimpleShell.Parser.Common.Root (RootParser) import Language.SimpleShell.Parser.Expr - ( runExprParser + ( ExprContext(ExprContext) , strongTermP , strongTermP0_ ) @@ -22,10 +23,22 @@ import Language.SimpleShell.Parser.Name (nameP, keyword) import Language.SimpleShell.Parser.SimpleType (simpleTypeP, forceType) import Control.Applicative ((<|>)) -import Text.Megaparsec (sepBy) +import Control.Monad (guard) +import Control.Monad.Reader (ReaderT, withReaderT) +import Data.List (nub) +import Data.Map (Map) +import qualified Data.Map as Map (fromList) +import Data.Text (Text) +import Data.Tuple (swap) +import Text.Megaparsec (MonadParsec, sepBy) -functionPrefixP :: RootParser (SimpleType, FunName, [Typed VarName]) +type FunctionParser0 = RootParser +type FunctionParser = ReaderT (Map FunName FunSig) RootParser + + +functionPrefixP + :: (MonadParsec e Text m) => m (SimpleType, FunName, [Typed VarName]) functionPrefixP = do keyword "function" t' <- simpleTypeP @@ -34,15 +47,16 @@ functionPrefixP = do symbol "=" return (t', fname, params) -functionP :: RootParser Function +functionP :: FunctionParser Function functionP = do (t', fname, params) <- functionPrefixP let vars = map snd params + checkNoDupVarNames vars body <- forceType t' (bodyP params) <|> fail "Function return type mismatch." return $ Function fname vars body -- | First-pass function parser. -functionP0 :: RootParser (FunName, FunSig) +functionP0 :: FunctionParser0 (FunName, FunSig) functionP0 = do (t', fname, params) <- functionPrefixP let ts = map fst params @@ -50,11 +64,19 @@ functionP0 = do return (fname, (t', ts)) -paramP :: RootParser (Typed VarName) +checkNoDupVarNames :: [VarName] -> FunctionParser () +checkNoDupVarNames vars = + guard (length (nub vars) == length vars) -- TODO: inefficient + <|> fail "Duplicate variable name." + + +paramP :: (MonadParsec e Text m) => m (Typed VarName) paramP = (,) <$> simpleTypeP <*> nameP -bodyP :: [Typed VarName] -> RootParser (Typed Expr) -bodyP params = runExprParser params strongTermP +bodyP :: [Typed VarName] -> FunctionParser (Typed Expr) +bodyP params = withReaderT f strongTermP + where + f funs = ExprContext funs (Map.fromList $ map swap params) -bodyP_ :: RootParser () +bodyP_ :: FunctionParser0 () bodyP_ = strongTermP0_ |