module Flite.Parsec.Parse where import Flite.Syntax import Flite.Pretty import Control.Applicative import Control.Monad import Data.Char import Text.ParserCombinators.Parsec hiding (many, option, (<|>)) import Text.ParserCombinators.Parsec.Language import qualified Text.ParserCombinators.Parsec.Token as T flite = T.makeTokenParser $ emptyDef { commentLine = "--" , nestedComments = False , identStart = letter , identLetter = alphaNum , opStart = opLetter haskellStyle , opLetter = oneOf "<=>-+/" , reservedNames = ["case", "of", "let", "in", "if", "then", "else"] , caseSensitive = True } identifier = T.identifier flite reservedOp = T.reservedOp flite reserved = T.reserved flite natural = T.natural flite parens = T.parens flite semi = T.semi flite braces = T.braces flite symbol = T.symbol flite operator = T.operator flite charLiteral = T.charLiteral flite stringLiteral = T.stringLiteral flite instance Applicative (GenParser s a) where pure = return (<*>) = ap instance Alternative (GenParser s a) where empty = mzero (<|>) = mplus prog :: Parser Prog prog = block defn block :: Parser a -> Parser [a] block p = braces (p `sepEndBy` semi) "block" primitives = ["(+)", "(-)", "(==)", "(/=)", "(<=)", "emit", "emitInt"] prim :: Parser Id prim = try $ do v <- identifier <|> pure (++) <*> symbol "(" <*> (pure (++) <*> operator <*> symbol ")") if v `elem` primitives then return v else unexpected (show v) "primitive" var :: Parser Id var = try $ do v <- identifier if isLower (head v) then return v else unexpected ("constructor " ++ show v) "variable" con :: Parser Id con = try $ do c <- identifier if isUpper (head c) then return c else unexpected ("variable " ++ show c) "constructor" defn :: Parser Decl defn = pure Func <*> var <*> many pat <*> (reservedOp "=" *> expr) "definition" pat :: Parser Exp pat = pure Var <*> var <|> pure App <*> (pure Con <*> con) <*> pure [] <|> parens pat' "pattern" pat' :: Parser Exp pat' = pure Var <*> var <|> pure App <*> (pure Con <*> con) <*> many pat expr :: Parser Exp expr = pure App <*> expr' <*> many expr' expr' :: Parser Exp expr' = pure Case <*> (reserved "case" *> expr) <*> (reserved "of" *> block alt) <|> pure Let <*> (reserved "let" *> block bind) <*> (reserved "in" *> expr) <|> pure ifthenelse <*> (reserved "if" *> expr) <*> (reserved "then" *> expr) <*> (reserved "else" *> expr) <|> pure Fun <*> prim <|> pure Var <*> var <|> pure Con <*> con <|> pure Int <*> (pure fromInteger <*> natural) <|> pure (Int . ord) <*> charLiteral <|> pure stringExp <*> stringLiteral <|> parens expr ifthenelse :: Exp -> Exp -> Exp -> Exp ifthenelse x y z = Case x [(App (Con "True") [], y), (App (Con "False") [], z)] stringExp :: String -> Exp stringExp [] = App (Con "Nil") [] stringExp (x:xs) = App (Con "Cons") [Int . ord $ x, stringExp xs] alt :: Parser Alt alt = pure (,) <*> pat' <*> (reservedOp "->" *> expr) bind :: Parser Binding bind = pure (,) <*> var <*> (reservedOp "=" *> expr) parseProgFile :: SourceName -> IO Prog parseProgFile f = parseFromFile prog f >>= \result -> case result of Left e -> error . show $ e Right p -> return p