pisigma-0.1.0.3: src/Language/PiSigma/Parser.hs
module Language.PiSigma.Parser
( parse
, sPhrase
, sProg
, s2Terms
, sTerm )
where
import Prelude hiding (pi)
import Control.Monad
import Control.Applicative hiding ((<|>), many)
import Data.List
import Text.Parsec.Combinator
import Text.Parsec.Error
( ParseError )
import Text.Parsec.Pos
( SourceName )
import Text.Parsec.Prim
hiding
( label
, parse
, token )
import qualified Text.ParserCombinators.Parsec
as Parsec
( parse )
import Text.ParserCombinators.Parsec.Char
( string )
import Language.PiSigma.Lexer
import Language.PiSigma.Syntax hiding (label)
import qualified Language.PiSigma.Util.String.Internal
as Internal
import qualified Language.PiSigma.Util.String.Parser
as Parser
sLabel :: Parser Name
sLabel = Internal.fromString <$> (string "'" *> identifier)
sName :: Parser Name
sName = Internal.fromString <$> identifier
-- * Terms
sTerm5 :: Parser Term
sTerm5 = choice
[ Type <$> locReserved "Type"
, Enum <$> location
<*> braces (many sName)
<?> "enumeration"
, Case <$> locReserved "case"
<*> sTerm
<* reserved "of"
<*> braces (sBranch `sepBy` locReservedOp "|")
, Label <$> location
<*> sLabel
<?> "label"
, Box <$> location
<*> boxed sTerm
<?> "box"
, Lift <$> tokLift
<*> sTerm5
<?> "'^'"
, Var <$> location <*> sName
, parens sTerm
]
where
boxed p = choice [ brackets p
, reservedOp "♯" *> p
]
sTerm4 :: Parser Term
sTerm4 = choice
[ try $ (uncurry . Pair) <$> location
<*> parens ((,) <$> sTerm <* comma <*> sTerm)
, sTerm5
]
sTerm3 :: Parser Term
sTerm3 = choice
[ try (parens (sigmas <$> many1 ((,) <$> location <*> sName) <* reservedOp ":" <*> sTerm) <* reservedOp "*") <*> sTerm2
, Force <$> tokForce <*> sTerm4
, foldl1 App <$> many1 sTerm4
]
sTerm2 :: Parser Term
sTerm2 = foldr1 (-*-) <$> sTerm3 `sepBy1` reservedOp "*"
-- TODO: make more beautiful or renumber
sTerm1b :: Parser Term
sTerm1b = choice
[ try (parens (pis <$> many1 ((,) <$> location <*> sName) <* reservedOp ":" <*> sTerm) <* tokArr) <*> sTerm
, sTerm2
]
sTerm1 :: Parser Term
sTerm1 = foldr1 (->-) <$> sTerm1b `sepBy1` tokArr
sTerm :: Parser Term
sTerm = choice
[ lam <$ tokLam
<*> many ((,) <$> location <*> sName)
<* tokArr
<*> sTerm
, split <$> locReserved "split"
<*> sTerm
<* reserved "with"
<*> parens ((,) <$> sName
<* comma
<*> sName)
<* tokArr
<*> sTerm
, Let <$> locReserved "let"
<*> sProg
<* reserved "in"
<*> sTerm
, sTerm1
]
sProg :: Parser Prog
sProg = concat <$> (sEntry `sepEndBy` semi)
sEntry :: Parser [Entry]
sEntry =
do
l <- location
n <- sName
b <- choice [ True <$ reservedOp ":"
, False <$ reservedOp "="
]
t <- sTerm
if b
then do
d <- option Nothing (Just <$ reservedOp "=" <*> sTerm)
case d of
Nothing -> return [Decl l n t]
Just t' -> return [Decl l n t, Defn l n t']
else return [Defn l n t]
sBranch :: Parser (Label,Term)
sBranch = (,) <$> sName <* tokArr <*> sTerm
sPhrase :: Parser Phrase
sPhrase = choice
[ try $ Prog <$> sProg <* eof
, Term <$> sTerm <* eof
]
s2Terms :: Parser (Term, Term)
s2Terms = (,) <$> sTerm5 <*> sTerm5
parse :: Parser a -> SourceName -> Parser.String -> Either ParseError a
parse p = Parsec.parse (whiteSpace *> p <* eof)