aboutsummaryrefslogtreecommitdiff
path: root/src/Language/SimpleShell/Parser/Function.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Language/SimpleShell/Parser/Function.hs')
-rw-r--r--src/Language/SimpleShell/Parser/Function.hs40
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_