TParse provides functions for parsing type expressions. Although LIPL does not allow type annotations, using type parsing functions, one can write type expressions like:
a -> b instead of TApp (TApp (TConst "->") TVar "a") (TVar "b")
> module TParse where
>
> import qualified Text.ParserCombinators.Parsec as P
> import qualified Text.ParserCombinators.Parsec.Token as P
> import qualified Text.ParserCombinators.Parsec.Expr as P
> import qualified Text.ParserCombinators.Parsec.Language as P
> import Text.ParserCombinators.Parsec ((<|>), (<?>))
>
> import ParseUtils hiding (lexer)
> import Type
>
> tParse texpr = case P.parse parseExpr "type expression" texpr of
> Right t -> t
> Left err -> error (show err ++ ": type expression parse error")
tParse parses a type expression to Type. In case of error, exception is raised (program quits).
> lexer = P.makeTokenParser (P.haskellStyle {
> P.reservedOpNames = ["->"]
> })
>
> parens = P.parens lexer
> reservedOp = P.reservedOp lexer
> lexeme = P.lexeme lexer
> term = lexeme parseType <|> parens expr <?> "term"
parens takes a parser and creates a parser that parses what the given parser parses enclosed in parenthesis:
parens p ==> parses ( what p parses )
reservedOp takes a String and creates a parser that accepts input that is same as the given String. The given String can be the reserved operator (->).
lexeme takes a parser and creates a parser that accepts what the given parser accepts and skips whitespaces after parsing.
term parses what parseType parses or parenthesized expr.
> expr = P.buildExpressionParser table term <?> "expr"
>
> table = [
> [P.Infix (do
> reservedOp "->"
> return fn
> <?> "operator") P.AssocRight]]
expr parses terms connected with ->:
term1 -> term2 -> term3 ...
> parseExpr = do
> t <- expr
> P.eof
> return t <?> "Expression"
parseExpr parses a type expression.
Below parsers are straight forward:
> parseTVar = do
> x <- P.letter
> xs <- P.many P.alphaNum
> return (TVar (x:xs)) <?> "Variable"
>
> parseFunc = do
> t1 <- parseType
> P.spaces
> P.string "->"
> P.spaces
> t2 <- parseType
> return (t1 `fn` t2) <?> "Function"
>
> parseInt = do
> P.string "Int"
> return tInt <?> "Int"
>
> parseFloat = do
> P.string "Float"
> return tFloat <?> "Float"
>
> parseBool = do
> P.string "Bool"
> return tBool <?> "Bool"
>
> parseChar = do
> P.string "Char" <?> "Char"
> return tChar
>
> parseStr = do
> P.string "Str" <?> "Str"
> return $ list tChar
>
> parseList = do
> lbracket
> t <- term
> rbracket
> return (list t) <?> "List"
>
> parseUnit = do
> lparen
> rparen
> return tUnit <?> "Unit"
>
> parsePair = do
> lparen
> t1 <- parseType
> comma
> t2 <- parseType
> rparen
> return (pair t1 t2) <?> "Pair"
>
> parseType = do
> P.try parseList
> <|> P.try parseInt
> <|> P.try parseFloat
> <|> P.try parseBool
> <|> P.try parseChar
> <|> P.try parseStr
> <|> P.try parsePair
> <|> P.try parseUnit
> <|> P.try parseTVar
parseType parses any valid Type:
Int, Bool, [((Int -> a) -> b -> Char)], [Char] -> a, ...
Note that parenthesis are needed in [(a -> b)] because parseList expects a term inside [ ]. [a -> b] won't get parsed.