module Typed.Parser (
parseProgram, parseContext
) where
import Typed.Term ( Term(..), Program, natFromInt )
import Typed.Type ( Type(..), Context, context )
import Sidekick ( functionize )
import Control.Monad ( MonadPlus(..), ap, liftM )
import Control.Applicative
import Text.ParserCombinators.Parsec hiding ( many, optional, (<|>) )
import Text.ParserCombinators.Parsec.Error
import Text.ParserCombinators.Parsec.Language
import Text.ParserCombinators.Parsec.Token
instance Applicative (GenParser s a) where
pure = return
(<*>) = ap
instance Alternative (GenParser s a) where
empty = mzero
(<|>) = mplus
parseProgram :: String -> Program
parseProgram input = case (parse parseprogram "(program parser)" input) of
Left e -> (error . show) e
Right ts -> ts
parseContext :: String -> Context
parseContext input = case (parse parsecontexts "(context parser)" input) of
Left e -> (error . show) e
Right ctxs -> (functionize . concat) ctxs
typesLang = LanguageDef
{ commentStart = "[:"
, commentEnd = ":]"
, commentLine = "%"
, nestedComments = True
, identStart = upper
, identLetter = alphaNum <|> char '_' <|> (char '\'' <* notFollowedBy alphaNum)
, opStart = fail "operators not supported"
, opLetter = fail "operators not supported"
, reservedNames = [ "Unit"
, "Bool"
, "Nat"
, "Wrong"
]
, reservedOpNames = ["->"]
, caseSensitive = True
}
types = makeTokenParser typesLang
termsLang = LanguageDef
{ commentStart = "[:"
, commentEnd = ":]"
, commentLine = "%"
, nestedComments = True
, identStart = lower
, identLetter = alphaNum <|> char '_' <|> (char '\'' <* notFollowedBy alphaNum)
, opStart = fail "operators not supported"
, opLetter = fail "operators not supported"
, reservedNames = [ "unit"
, "true"
, "false"
, "if"
, "then"
, "else"
, "zero"
, "succ"
, "pred"
, "iszero"
, "lambda"
, "wrong"
]
, reservedOpNames = []
, caseSensitive = True
}
terms = makeTokenParser termsLang
parseprogram = manyTill parsestatement eof
parsestatement = parseterm <* (semi terms)
parsetype = chainr1 parsenoarrow $ reservedOp types "->" >> return TpArrow
parseterm = chainl1 parsenoapp $ return TmApp
parsecontexts = manyTill parsetypings eof
parsetypings = do xs <- sepBy (identifier terms) (comma terms)
symbol types "::"
p <- (parsetype <* symbol types ";")
return $ context xs p
parsenoarrow = parsetpunit
<|> parsetpbool
<|> parsetpnat
<|> parsetpcustom
<|> parens types parsetype
parsetpunit = parse0ary types "Unit" TpUnit
parsetpbool = parse0ary types "Bool" TpBool
parsetpnat = parse0ary types "Nat" TpNat
parsetpcustom = do name <- identifier types
return $ TpCustom name
parsenoapp = parseunitval
<|> parseboolval
<|> parsenatval
<|> parseabsval
<|> parsesucc
<|> parsepred
<|> parseiszero
<|> parsevar
<|> parseif
<|> parens terms parseterm
parseunitval = parseunit <?> "unit"
parseboolval = parsetrue <|> parsefalse <?> "boolean"
parsenatval = parsezero <|> parsenumber <?> "natural"
parseabsval = parseabs
parseunit = parse0ary terms "unit" TmUnit
parsetrue = parse0ary terms "true" TmTrue
parsefalse = parse0ary terms "false" TmFalse
parsezero = parse0ary terms "zero" TmZero
parsesucc = parse1ary terms "succ" TmSucc
parsepred = parse1ary terms "pred" TmPred
parseiszero = parse1ary terms "iszero" TmIsZero
parsenumber = liftM natFromInt (natural terms) <?> "number constant"
parsevar = do name <- identifier terms
return $ TmVar name
parseif = do reserved terms "if"
t <- parseterm
reserved terms "then"
t1 <- parseterm
reserved terms "else"
liftM (TmIf t t1) parseterm
parseabs = do symbol terms "\\"
x <- identifier terms
colon terms
p <- parsetype
dot terms
t <- parseterm
return $ TmAbs (x,p) t
parse0ary tkp name cons = reserved tkp name >> return cons
parse1ary tkp name cons = reserved tkp name >> liftM cons parseterm