{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards #-}
module Parse where
import qualified Text.Parsec as P
import qualified Text.Parsec.Token as PT
import Text.Parsec.Language
import Text.Parsec.Expr
import Text.Parsec ((<?>))
import Control.Applicative
import Control.Monad.Identity (Identity)
import Syntax
type Parser = P.Parsec String ()
-- | parse olala, calls 'prog'
parse :: Parser a -> P.SourceName -> String -> Either P.ParseError a
parse = P.parse
-- Parser
prog :: Parser Transformation
prog = do
P.string "transform"
whiteSpace
(x, tau1) <- parens $ do x <- identifier
colon
tau1 <- recsig
return (x, tau1)
tau2 <- colon *> recsig
body <- braces expr
return $ TRANS x tau1 tau2 body
expr :: Parser Expression
expr = buildExpressionParser table term
<?> "expression"
term :: Parser Expression
term = P.try (LIT <$> value)
<|> P.try (MUTATE <$> identifier
<*> brackets identifier
<*> (P.string ":=" *> expr))
<|> REC <$> (braces . commaSep) (do l <- identifier
whiteSpace
P.char '='
whiteSpace
e <- expr
return (l, e))
<|> P.try (ASSIGN <$> (identifier <* P.string ":=") <*> expr)
<|> P.try (OP <$> opr <*> (parens . commaSep) expr)
<|> VAR <$> identifier
<|> parens expr
<?> "expression-term"
value :: Parser Value
value = NUM <$> float
<|> CAT <$> stringLiteral
<|> MAP <$> (braces . commaSep) (do l <- identifier
whiteSpace
P.char '='
whiteSpace
v <- value
return (l, v))
<?> "value"
opr :: Parser OPR
opr = SUM <$ P.char '+'
<|> CONCAT <$ P.char '*'
<?> "operator"
table :: OperatorTable String u Identity Expression
table = [ [Postfix (do {f <- brackets identifier; return (\e -> PROJ e f)})]
, [binary semi SEQ AssocRight] ]
binary :: P.ParsecT s u m a1 -> (a -> a -> a) -> Assoc -> Operator s u m a
binary op fun asc = Infix (do{ op ; return fun }) asc
postfix :: P.ParsecT s u m a1 -> (a -> a) -> Operator s u m a
postfix op fun = Postfix (do{ op; return fun })
recsig :: Parser Sig
recsig = Sig <$> (braces . commaSep $ do l <- identifier
colon
sig <- tysig
return (l, sig))
tysig :: Parser Descriptor
tysig = (uncurry INTERVAL) <$> (P.char 'N' *> brackets (do lb <- float
comma
ub <- float
return (lb, ub)))
<|> SET <$> (P.char 'C' *> (brackets . commaSep) stringLiteral)
<?> "type signature"
-- Lexer
transformeRDef :: LanguageDef st
transformeRDef = emptyDef { PT.commentLine = "#"}
PT.TokenParser {..} = PT.makeTokenParser transformeRDef