X-Git-Url: http://git.tomasm.cz/fp.git/blobdiff_plain/880eb9d73e5ea9239698d8f6d294032b6e339310..HEAD:/src/HM/Parser.hs diff --git a/src/HM/Parser.hs b/src/HM/Parser.hs index f02a7cc..8b5575d 100644 --- a/src/HM/Parser.hs +++ b/src/HM/Parser.hs @@ -11,9 +11,10 @@ -- -- Parser for Hindley-Milner terms and types. -module HM.Parser +module HM.Parser ( tRead - , parseTerm + , parseTypedTerm + , parseVar ) where import Data.Char (isAsciiLower, isAsciiUpper) @@ -23,6 +24,16 @@ import Control.Applicative import HM.Term +-- $setup +-- >>> import Test.QuickCheck +-- >>> import Test.HM.Term + +-- | +-- >>> print $ Lam "x" (Var "x") +-- (λx.x) + + + braced :: String -> String braced t = "(" ++ t ++ ")" @@ -33,10 +44,14 @@ instance Show Term where show (App a (NTTerm (App b c))) = show a ++ " " ++ braced ( show (App b c)) show (App t r) = show t ++ " " ++ show r show (Let x e1 e2) = braced $ "LET " ++ x ++ " = " ++ show e1 ++ " IN " ++ show e2 + show (Lit (LInt x)) = show x + show (Lit (LBool x)) = show x + show (Lit (LFunc x)) = show x instance Show TypedTerm where show (NTTerm t) = show t - show (TTerm t tp) = braced $ show t ++ " :: " ++ show tp + show (TTerm (Var x) tp) = x ++ " :: " ++ show tp + show (TTerm t tp) = braced (show t) ++ " :: " ++ show tp instance Show Type where show (Primitive t) = t @@ -54,77 +69,78 @@ tRead s = case parseOnly (parseTypedTerm <* endOfInput) (T.pack s) of parseTerm :: Parser Term parseTerm = parseLet <|> + parseLambda <|> parseApp <|> - parseVar <|> - parseLambda + parseBraces parseTerm <|> + parseLit <|> + parseVar -parseTermNA :: Parser Term -parseTermNA = parseLet <|> +parseTermNoApp :: Parser Term +parseTermNoApp = parseBraces parseTerm <|> + parseLet <|> parseVar <|> + parseLit <|> parseLambda -parseTypeAndTermNA :: Parser TypedTerm -parseTypeAndTermNA = do - term <- parseTermNA +parseTypeAndTerm :: Parser Term -> Parser TypedTerm +parseTypeAndTerm p = do + term <- p string " :: " tp <- parseTypeScheme return $! TTerm term tp -parseTypeAndTerm :: Parser TypedTerm -parseTypeAndTerm = do - term <- parseTerm - string " :: " - tp <- parseTypeScheme - return $! TTerm term tp -parseTypedTermNA :: Parser TypedTerm -parseTypedTermNA = parseBraces <|> - parseTypeAndTermNA <|> - (NTTerm <$> parseTerm) +parseTypedTermNoApp :: Parser TypedTerm +parseTypedTermNoApp = parseBraces parseTypedTerm <|> + parseTypeAndTerm parseTermNoApp <|> + (NTTerm <$> parseTermNoApp) parseTypedTerm :: Parser TypedTerm -parseTypedTerm = parseBraces <|> - parseTypeAndTerm <|> - (NTTerm <$> parseTerm) +parseTypedTerm = parseTypeAndTerm parseTerm <|> + (NTTerm <$> parseTerm) <|> + parseBraces parseTypedTerm parseType :: Parser Type -parseType = parsePrimitive <|> - parseTypeVar <|> - parseTypeFunction +parseType = parseType <|> + parseTypeFunction <|> + parsePrimitive <|> + parseTypeVar parsePrimitive :: Parser Type parsePrimitive = do - x <- many1 $ satisfy isAsciiUpper - return $! Primitive x + x <- satisfy isAsciiUpper + xs <- many letter + return $! Primitive (x:xs) parseTypeVar :: Parser Type parseTypeVar = do - x <- many1 $ satisfy isAsciiLower + x <- many1 $ satisfy isAsciiLower return $! TypeVar x parseTypeFunction :: Parser Type parseTypeFunction = do - a <- parseType + a <- parseBraces parseType <|> parsePrimitive <|> parseTypeVar string " -> " b <- parseType return $! TypeFunction a b parseTypeScheme :: Parser TypeScheme -parseTypeScheme = parseForAll <|> +parseTypeScheme = parseBraces parseTypeScheme <|> + parseForAll <|> (TScheme <$> parseType) parseForAll :: Parser TypeScheme parseForAll = do string "FORALL " (TypeVar x) <- parseTypeVar - string "." + string ": " t <- parseTypeScheme return $! TSForAll x t -parseBraces :: Parser TypedTerm -parseBraces = do +parseBraces :: Parser a -> Parser a +parseBraces p = do char '(' - t <- parseTypedTerm + t <- p char ')' return t @@ -143,6 +159,25 @@ parseVar = do x <- many1 $ satisfy isAsciiLower return $! Var x +parseLit :: Parser Term +parseLit = do + x <- parseLInt <|> parseLBool <|> parseLFun + return $! Lit x + +parseLFun :: Parser Literal +parseLFun = + (string "If" >> return (LFunc If)) + +parseLBool :: Parser Literal +parseLBool = + (string "True" >> return (LBool True)) <|> + (string "False" >> return (LBool False)) + +parseLInt :: Parser Literal +parseLInt = do + x <- decimal + return $! LInt x + parseLambda :: Parser Term parseLambda = do char '\\' <|> char 'λ' <|> char 'L' @@ -154,18 +189,18 @@ parseLambda = do parseApp :: Parser Term parseApp = do - aps <- sepBy1 parseTypedTermNA (char ' ') - return $! createApp aps + aps <- sepBy1 parseTypedTermNoApp (char ' ') + createApp aps createLambda :: [Term] -> TypedTerm -> TypedTerm createLambda (Var x : vs) t = NTTerm . Lam x $ createLambda vs t createLambda [] t = t createLambda _ _ = error "createLambda failed" -createApp :: [TypedTerm] -> Term -createApp [t,ts] = App t ts +createApp :: [TypedTerm] -> Parser Term +createApp [t,ts] = return $ App t ts createApp (t:ts:tss) = createApp (NTTerm (App t ts) : tss) -createApp [] = error "empty createApp" +createApp _ = fail "not App" -- |