{-# LANGUAGE PatternGuards, ScopedTypeVariables, TypeFamilies, TypeSynonymInstances #-} -- | Parser module Parser ( -- * The parsing monad P, parse, -- ** Quasiquote parsing parseQuasi, -- ** REPL command parsing parseGetInfo, parseInteractive, -- ** Parsers parseProg, parseRepl, parseDecls, parseDecl, parseModExp, parseTyDec, parseAbsTy, parseType, parseTyPat, parseQExp, parseExpr, parsePatt, parseCaseAlt, parseBinding, parseSigExp, parseSigItem, -- * Convenience parsers (quick and dirty) pp, pds, pd, pme, ptd, pt, ptp, pqe, pe, px ) where import Util import Paths import Prec import Syntax import Sigma import Lexer import qualified Data.Map as M import qualified Language.Haskell.TH as TH import Text.ParserCombinators.Parsec hiding (parse) import System.IO.Unsafe (unsafePerformIO) data St = St { stSigma :: Bool, stAnti :: Bool } -- | A 'Parsec' character parser, with abstract state type P a = CharParser St a state0 :: St state0 = St { stSigma = False, stAnti = False } -- | Run a parser, given the source file name, on a given string parse :: P a -> SourceName -> String -> Either ParseError a parse p = runParser p state0 -- | Run a parser on the given string in quasiquote mode parseQuasi :: String -> (Maybe Char -> Maybe TH.Name -> P a) -> TH.Q a parseQuasi str p = do setter <- TH.location >>! mkSetter let parser = do setter iflag <- optionMaybe (char '+') lflag <- choice [ do char '@' choice [ char '=' >> identp_no_ws >>! Just, char '!' >> return Nothing ], char '!' >> return Nothing, return (Just "_loc") ] p iflag (fmap TH.mkName lflag) case runParser parser state0 { stAnti = True } "" str of Left e -> fail (show e) Right a -> return a where mkSetter = setPosition . toSourcePos . fromTHLoc parseGetInfo :: String -> Maybe [Ident Raw] parseGetInfo = (const Nothing ||| Just) . runParser parser state0 "-" where parser = finish $ sharpInfo *> many1 (identp <|> fmap Var <$> qlidnatp <|> J [] . Var . Syntax.lid <$> (operator <|> semis)) parseInteractive :: Id i => Int -> String -> Either ParseError [Decl i] parseInteractive line src = parse p "-" src where p = do pos <- getPosition setPosition (pos `setSourceLine` line) optional whiteSpace r <- replp eof return r withSigma :: Bool -> P a -> P a withSigma = mapSigma . const mapSigma :: (Bool -> Bool) -> P a -> P a mapSigma f p = do st <- getState setState st { stSigma = f (stSigma st) } r <- p setState st return r getSigma :: P Bool getSigma = stSigma `fmap` getState curLoc :: P Loc curLoc = getPosition >>! fromSourcePos addLoc :: Relocatable a => P a -> P a addLoc p = do before <- getPosition a <- p after <- getPosition return (a <<@ fromSourcePosSpan before after) class Nameable a where (@@) :: String -> a -> a infixr 0 @@ instance Relocatable a => Nameable (P a) where s @@ p = addLoc p s instance Nameable r => Nameable (a -> r) where s @@ p = \x -> s @@ p x punit :: P () punit = pure () delimList :: P pre -> (P [a] -> P [a]) -> P sep -> P a -> P [a] delimList before around delim each = choice [ before >> choice [ around (each `sepBy` delim), each >>! \x -> [x] ], return [] ] chainl1last :: P a -> P (a -> a -> a) -> P a -> P a chainl1last each sep final = start where start = each >>= loop loop a = option a $ do build <- sep choice [ each >>= loop . build a, final >>= return . build a ] chainr1last :: P a -> P (a -> a -> a) -> P a -> P a chainr1last each sep final = start where start = do a <- each builder <- loop return (builder a) loop = option id $ do build <- sep choice [ do b <- each builder <- loop return (\a -> a `build` builder b), do b <- final return (\a -> a `build` b) ] foldlp :: (a -> b -> a) -> P a -> P b -> P a foldlp make start follow = foldl make <$> start <*> many follow -- Antiquote antip :: AntiDict -> P Anti antip dict = antilabels . lexeme . try $ do char '$' "" (s1, s2) <- (,) <$> option "" (try (option "" identp_no_ws <* char ':')) <*> identp_no_ws assertAnti case M.lookup s1 dict of Just _ -> return (Anti s1 s2) Nothing -> unexpected $ "antiquote tag: `" ++ s1 ++ "'" where antilabels p = do st <- getState if (stAnti st) then labels p [ "antiquote `" ++ key ++ "'" | key <- M.keys dict, key /= "" ] else p identp_no_ws :: P String identp_no_ws = do c <- lower <|> char '_' cs <- many (alphaNum <|> oneOf "_'") return (c:cs) -- Fail if we should not recognize antiquotes assertAnti :: P () assertAnti = do st <- getState unless (stAnti st) (unexpected "antiquote") -- | Parse an antiquote and inject into syntax antiblep :: forall a. Antible a => P a antiblep = antip (dictOf (undefined::a)) >>! injAnti antioptp :: Antible a => P a -> P (Maybe a) antioptp = antioptaroundp id antioptaroundp :: Antible a => (P (Maybe a) -> P (Maybe a)) -> P a -> P (Maybe a) antioptaroundp wrap p = wrap present <|> pure Nothing where present = antiblep <|> Just <$> antiblep <|> Just <$> p antilist1p :: Antible a => P b -> P a -> P [a] antilist1p sep p = antiblep <|> sepBy1 (antiblep <|> p) sep -- Just uppercase identifiers uidp :: Id i => P (Uid i) uidp = Syntax.uid <$> Lexer.uid <|> antiblep "uppercase identifier" -- Just lowercase identifiers lidp :: Id i => P (Lid i) lidp = Syntax.lid <$> Lexer.lid <|> antiblep "lowercase identifier" -- Lowercase identifiers or naturals -- - tycon declarations lidnatp :: Id i => P (Lid i) lidnatp = Syntax.lid <$> (Lexer.lid <|> show <$> natural) <|> operatorp <|> Syntax.lid <$> try (parens semis) <|> antiblep "type name" -- Just operators operatorp :: Id i => P (Lid i) operatorp = try (parens operator) >>! Syntax.lid "operator name" -- Add a path before something pathp :: Id i => P ([Uid i] -> b) -> P b pathp p = try $ do path <- many $ try $ uidp <* dot make <- p return (make path) -- Qualified uppercase identifiers: -- - module names occurences -- - datacons in patterns (though path is ignored) quidp :: Id i => P (QUid i) quidp = pathp (uidp >>! flip J) <|> antiblep "uppercase identifier" -- Qualified lowercase identifiers: -- - module name identifier lists qlidp :: Id i => P (QLid i) qlidp = pathp (lidp >>! flip J) <|> antiblep "lowercase identifier" -- Qualified lowercase identifiers or naturals: -- - tycon occurences qlidnatp :: Id i => P (QLid i) qlidnatp = pathp (lidnatp >>! flip J) <|> antiblep "type name" -- Lowercase identifiers and operators -- - variable bindings varp :: Id i => P (Lid i) varp = lidp <|> operatorp "variable name" -- Qualified lowercase identifers and operators -- - variable occurences -- qvarp :: Id i => P (QLid i) -- qvarp = pathp (varp >>! flip J) -- Identifier expressions identp :: Id i => P (Ident i) identp = antiblep <|> pathp (flip J <$> (Var <$> varp <|> Con <$> uidp)) "identifier" -- Type variables tyvarp :: Id i => P (TyVar i) tyvarp = char '\'' *> (antiblep <|> TV <$> lidp <*> pure Qu) <|> char '`' *> (antiblep <|> TV <$> lidp <*> pure Qa) "type variable" oplevelp :: Id i => Prec -> P (Lid i) oplevelp = ( "operator") . liftM Syntax.lid . opP quantp :: P Quant quantp = Forall <$ reserved "all" <|> Exists <$ reserved "ex" <|> antiblep "quantifier" typep :: Id i => P (Type i) typep = typepP precStart typepP :: Id i => Int -> P (Type i) typepP p = "type" @@ case () of _ | p == precStart -> do tc <- tyQu <$> quantp <|> tyMu <$ reserved "mu" tvs <- many tyvarp dot t <- typepP p return (foldr tc t tvs) <|> typepP (p + 1) | p == precArr -> chainr1last (typepP (p + 1)) (choice [ tyArr <$ arrow, tyLol <$ lolli, funbraces (tyFun <$> qExpp), tybinopp (Right precArr) ]) (typepP precStart) | p == precSemi -> chainr1last (typepP (p + 1)) (tyBinOp <$> semis) (typepP precStart) | Just (Left _) <- fixities p -> chainl1last (typepP (p + 1)) (tybinopp (Left p)) (typepP precStart) | Just (Right _) <- fixities p -> chainr1last (typepP (p + 1)) (tybinopp (Right p)) (typepP precStart) | p == precApp -- this case ensures termination -> tyarg >>= tyapp' | p < precApp -> typepP (p + 1) | otherwise -> typepP precStart where tyarg :: Id i => P [Type i] tyarg = choice [ (:[]) <$> tyatom, parens $ antiblep <|> commaSep1 (typepP precStart) ] -- tyatom :: Id i => P (Type i) tyatom = tyVar <$> tyvarp <|> tyApp <$> qlidnatp <*> pure [] <|> antiblep <|> tyUn <$ qualU <|> tyAf <$ qualA <|> do ops <- many1 $ addLoc $ oplevelp (Right precBang) >>! tyApp . J [] arg <- tyatom <|> parens (typepP precStart) return (foldr (\op t -> op [t]) arg ops) -- tyapp' :: Id i => [Type i] -> P (Type i) tyapp' [t] = option t $ do tc <- qlidnatp tyapp' [tyApp tc [t]] tyapp' ts = do tc <- qlidnatp tyapp' [tyApp tc ts] tybinopp :: Id i => Prec -> P (Type i -> Type i -> Type i) tybinopp p = try $ do op <- oplevelp p when (unLid op == "-") pzero return (\t1 t2 -> tyApp (J [] op) [t1, t2]) progp :: Id i => P (Prog i) progp = choice [ do ds <- declsp when (null ds) pzero e <- antioptaroundp (reserved "in" `between` punit) exprp return (prog ds e), antioptp exprp >>! prog [] ] replp :: Id i => P [Decl i] replp = choice [ try $ do ds <- declsp when (null ds) pzero eof return ds, exprp >>! (prog2decls . prog [] . Just) ] declsp :: Id i => P [Decl i] declsp = antiblep <|> loop where loop = choice [ do d <- declp ds <- loop return (d : ds), ( "#load") $ do sharpLoad name <- stringLiteral rel <- sourceName `liftM` getPosition let mcontents = unsafePerformIO $ do mfile <- findAlmsLibRel name rel gmapM readFile mfile contents <- case mcontents of Just contents -> return contents Nothing -> fail $ "Could not load: " ++ name ds <- case parse parseProg name contents of Left e -> fail (show e) Right p -> return (prog2decls p) ds' <- loop return (ds ++ ds'), return [] ] declp :: Id i => P (Decl i) declp = "declaration" @@ choice [ do reserved "type" tyDecsp >>! dcTyp, letp, do reserved "open" modexpp >>! dcOpn, do reserved "module" choice [ do reserved "type" n <- uidp reservedOp "=" s <- sigexpp return (dcSig n s), do n <- uidp asc <- option id $ do colon sigexpp >>! flip meAsc reservedOp "=" b <- modexpp >>! asc return (dcMod n b) ], do reserved "local" ds0 <- declsp reserved "with" ds1 <- declsp reserved "end" return (dcLoc ds0 ds1), do reserved "abstype" at <- absTysp reserved "with" ds <- declsp reserved "end" return (dcAbs at ds), do reserved "exception" n <- uidp t <- antioptaroundp (reserved "of" `between` punit) typep return (dcExn n t), antiblep ] modexpp :: Id i => P (ModExp i) modexpp = "structure" @@ foldlp meAsc body ascription where body = choice [ meStr <$> between (reserved "struct") (reserved "end") declsp, meName <$> quidp <*> option [] (antilist1p comma qlidp), antiblep ] ascription = colon *> sigexpp sigexpp :: Id i => P (SigExp i) sigexpp = "signature" @@ do se <- choice [ seSig <$> between (reserved "sig") (reserved "end") (antiblep <|> many sigitemp), seName <$> quidp <*> option [] (antilist1p comma qlidp), antiblep ] specs <- many $ do reserved "with" reserved "type" flip sepBy1 (reserved "and") $ "signature specialization" @@ do (tvs, tc) <- tyAppp (antiblep <|>) tyvarp (J []) qlidnatp reservedOp "=" t <- typep return (\sig -> seWith sig tc tvs t) return (foldl (flip ($)) se (concat specs)) sigitemp :: Id i => P (SigItem i) sigitemp = "signature item" @@ choice [ do reserved "val" n <- lidp colon t <- typep return (sgVal n t), do reserved "type" sgTyp <$> tyDecsp, do reserved "module" choice [ do reserved "type" n <- uidp reservedOp "=" s <- sigexpp return (sgSig n s), do n <- uidp colon s <- sigexpp return (sgMod n s) ], do reserved "include" sgInc <$> sigexpp, do reserved "exception" n <- uidp t <- antioptaroundp (reserved "of" `between` punit) typep return (sgExn n t), antiblep ] tyDecsp :: Id i => P [TyDec i] tyDecsp = antilist1p (reserved "and") tyDecp tyDecp :: Id i => P (TyDec i) tyDecp = "type declaration" @@ addLoc $ choice [ antiblep , do optional (reservedOp "|") tp <- typatp (name, ps) <- checkHead tp case checkTVs ps of Just (True, tvs, arity) -> reservedOp "=" *> (tdDat name tvs <$> altsp <|> tryTySyn name ps) <|> tdAbs name tvs arity <$> qualsp Just (_, tvs, arity) -> reservedOp "=" *> tryTySyn name ps <|> tdAbs name tvs arity <$> qualsp Nothing -> reservedOp "=" *> tryTySyn name ps ] where tryTySyn name ps = do t <- typep alts <- many $ do reservedOp "|" tp <- typatp (name', ps') <- checkHead tp unless (name == name') $ unexpected $ "non-matching type operators `" ++ show name' ++ "' and `" ++ show name ++ "' in type pattern" reservedOp "=" ti <- typep return (ps', ti) return (tdSyn name ((ps,t):alts)) -- checkHead tp = case dataOf tp of TpApp (J [] name) ps -> return (name, ps) TpApp _ _ -> unexpected "qualified identifier" TpVar _ _ -> unexpected "type variable" TpAnti _ -> unexpected "antiquote" -- checkTVs [] = return (True, [], []) checkTVs (N _ (TpVar tv var):rest) = do (b, tvs, vars) <- checkTVs rest return (b && var == Invariant, tv:tvs, var:vars) checkTVs _ = Nothing tyAppp :: Id i => (P [a] -> P [a]) -> P a -> (Lid i -> b) -> P b -> P ([a], b) tyAppp wrap param oper suffix = choice [ do l <- oplevelp (Right precBang) p1 <- param return ([p1], oper l), try $ do p1 <- param n <- choice [ semis, operator ] when (n == "-" || precOp n == Right precBang) pzero p2 <- param return ([p1, p2], oper (Syntax.lid n)), do ps <- wrap (delimList punit parens comma param) name <- suffix return (ps, name) ] tyProtp :: Id i => P ([(Variance, TyVar i)], Lid i) tyProtp = tyAppp id paramVp id lidnatp typatp :: Id i => P (TyPat i) typatp = typatpP precStart typatpP :: Id i => Int -> P (TyPat i) typatpP p = "type pattern" @@ case () of _ | p == precSemi -> chainr1last (typatpP (p + 1)) (tpBinOp . J [] . Syntax.lid <$> semis) (typatpP precStart) | Just (Left _) <- fixities p -> chainl1last (typatpP (p + 1)) (tpBinOp . J [] <$> oplevelp (Left p)) (typatpP precStart) | Just (Right _) <- fixities p -> chainr1last (typatpP (p + 1)) (tpBinOp . J [] <$> oplevelp (Right p)) (typatpP precStart) | p == precApp -- this case ensures termination -> tparg >>= tpapp' | p < precApp -> typatpP (p + 1) | otherwise -> typatpP precStart where tpBinOp ql tp1 tp2 = tpApp ql [tp1, tp2] -- tparg :: Id i => P [TyPat i] tparg = choice [ (:[]) <$> tpatom, parens $ antiblep <|> commaSep1 (typatpP precStart) ] -- tpatom :: Id i => P (TyPat i) tpatom = uncurry (flip tpVar) <$> paramVp <|> tpApp <$> qlidnatp <*> pure [] <|> antiblep <|> tpApp (qlid "U") [] <$ qualU <|> tpApp (qlid "A") [] <$ qualA <|> do ops <- many1 $ addLoc $ oplevelp (Right precBang) >>! tpApp . J [] arg <- tpatom <|> parens (typatpP precStart) return (foldr (\op t -> op [t]) arg ops) tpapp' :: Id i => [TyPat i] -> P (TyPat i) tpapp' [t] = option t $ do tc <- qlidnatp tpapp' [tpApp tc [t]] tpapp' ts = do tc <- qlidnatp tpapp' [tpApp tc ts] letp :: Id i => P (Decl i) letp = do reserved "let" choice [ do reserved "rec" bindings <- flip sepBy1 (reserved "and") $ do f <- varp (sigma, fixt, fixe) <- afargsp colon t <- typep reservedOp "=" e <- withSigma sigma exprp return (bnBind f (fixt t) (fixe e)) let names = map (bnvar . dataOf) bindings namesExp = foldl1 exPair (map exBVar names) namesPat = foldl1 paPair (map paVar names) tempVar = Syntax.lid "#letrec" decls0 = [ dcLet (paVar tempVar) Nothing $ exLetRec bindings namesExp ] decls1 = [ dcLet (paVar (bnvar binding)) Nothing $ exLet namesPat (exBVar tempVar) $ exBVar (bnvar binding) | N _ binding <- bindings ] return $ dcLoc decls0 decls1, do f <- varp (sigma, fixt, fixe) <- afargsp t <- antioptaroundp (colon `between` punit) typep reservedOp "=" e <- withSigma sigma exprp return (dcLet (paVar f) (fmap fixt t) (fixe e)), dcLet <$> pattp <*> antioptaroundp (colon `between` punit) typep <* reservedOp "=" <*> exprp ] absTysp :: Id i => P [AbsTy i] absTysp = antilist1p (reserved "and") $ absTyp absTyp :: Id i => P (AbsTy i) absTyp = addLoc $ antiblep <|> do ((arity, tvs), name) <- tyProtp >>! first unzip quals <- qualsp reservedOp "=" alts <- altsp return (absTy arity quals (tdDat name tvs alts)) paramVp :: Id i => P (Variance, TyVar i) paramVp = do v <- variancep tv <- tyvarp return (v, tv) variancep :: P Variance variancep = choice [ char '+' >> return Covariant, char '-' >> return Contravariant, char '*' >> return Omnivariant, char '=' >> return Invariant, return Invariant ] qualsp :: Id i => P (QExp i) qualsp = option minBound $ (reserved "qualifier" <|> reservedOp ":") *> qExpp qExpp :: Id i => P (QExp i) qExpp = "qualifier expression" @@ qexp where qexp = addLoc $ qeDisj <$> sepBy1 qterm (reservedOp "\\/") qterm = addLoc $ qeConj <$> sepBy1 qfact (reservedOp "/\\") qfact = addLoc $ parens qexp <|> qatom qatom = addLoc $ qeLit Qu <$ qualU <|> qeLit Qa <$ qualA <|> clean <$> tyvarp <|> qeLid <$> lidp <|> antiblep qeLid = qeVar . flip TV Qa clean (TV _ Qu) = minBound clean tv = qeVar tv altsp :: Id i => P [(Uid i, Maybe (Type i))] altsp = sepBy1 altp (reservedOp "|") altp :: Id i => P (Uid i, Maybe (Type i)) altp = do k <- try $ uidp <* try (dot *> pzero <|> punit) t <- optionMaybe $ do reserved "of" typep return (k, t) exprp :: Id i => P (Expr i) exprp = expr0 where onlyOne [x] = [x True] onlyOne xs = map ($ False) xs mark = ("expression" @@) expr0 = mark $ choice [ do reserved "let" choice [ do reserved "rec" bs <- antilist1p (reserved "and") $ bindingp reserved "in" e2 <- expr0 return (exLetRec bs e2), do (x, sigma, lift) <- pattbangp if sigma then do reservedOp "=" e1 <- expr0 reserved "in" e2 <- withSigma True expr0 return (lift True (flip exLet e1) x e2) else do (sigma', args) <- argsp reservedOp "=" e1 <- withSigma sigma' expr0 reserved "in" e2 <- expr0 return (exLet x (args e1) e2), do reserved "let" unexpected "let", do d <- withSigma False declp reserved "in" e2 <- expr0 return (exLetDecl d e2) ], do reserved "if" ec <- expr0 clt <- addLoc $ do reserved "then" caClause (paCon (quid "true") Nothing) <$> expr0 clf <- addLoc $ do reserved "else" caClause (paCon (quid "false") Nothing) <$> expr0 return (exCase ec [clt, clf]), do reserved "match" e1 <- expr0 reserved "with" choice [ exCase e1 <$> antiblep, do optional (reservedOp "|") clauses <- flip sepBy1 (reservedOp "|") preCasealtp return (exCase e1 (onlyOne clauses)) ], do reserved "try" e1 <- expr0 reserved "with" optional (reservedOp "|") clauses <- flip sepBy1 (reservedOp "|") $ addLoc $ do (xi, sigma, lift) <- pattbangp reservedOp "->" ei <- mapSigma (sigma ||) expr0 return $ lift False (\xi' ei' -> -- TODO: Make this robust to redefinition of -- Left and Right caClause (paCon (quid "Left") (Just xi')) ei') xi ei let tryQ = qlid $ "INTERNALS.Exn.tryfun" return $ exCase (exApp (exVar tryQ) (exAbs paWild tyUnit e1)) $ caClause (paCon (quid "Right") (Just (paVar (Syntax.lid "x")))) (exVar (qlid "x")) : clauses ++ [caClause (paCon (quid "Left") (Just (paVar (Syntax.lid "e")))) (exApp (exVar (qlid "INTERNALS.Exn.raise")) (exVar (qlid "e"))) ], do reserved "fun" (sigma, build) <- choice [ argsp1, do (x, sigma, lift) <- pattbangp colon t <- typepP (precArr + 1) return (sigma, lift True (flip exAbs t) x) ] arrow withSigma sigma expr0 >>! build, expr1 ] expr1 = mark $ do e1 <- expr3 choice [ do semi e2 <- expr0 return (exSeq e1 e2), return e1 ] expr3 = mark $ chainl1last expr4 (opappp (Left 3)) expr0 expr4 = mark $ chainr1last expr5 (opappp (Right 4)) expr0 expr5 = mark $ chainl1last expr6 (opappp (Left 5)) expr0 expr6 = mark $ chainl1last expr7 (opappp (Left 6)) expr0 expr7 = expr8 expr8 = mark $ chainr1last expr9 (opappp (Right 8)) expr0 expr9 = mark $ choice [ chainl1 expr10 (addLoc (return exApp)), do reserved "Pack" t1 <- antioptaroundp brackets typep parens $ do t2 <- typep comma e <- exprN1 return (exPack t1 t2 e) ] expr10 = mark $ do ops <- many $ addLoc $ oplevelp (Right 10) >>! exBVar arg <- expr11 return (foldr exApp arg ops) expr11 = mark $ do e <- exprA ts <- many . brackets $ commaSep1 typep return (foldl exTApp e (concat ts)) exprA = mark $ choice [ identp >>! exId, litp >>! exLit, antiblep, parens (exprN1 <|> return (exBCon (Syntax.uid "()"))) ] exprN1 = mark $ do e1 <- expr0 choice [ do colon t1 <- typep let e1' = exCast e1 t1 False option e1' $ do reservedOp ":>" t2 <- typep return (exCast e1' t2 True), do reservedOp ":>" t2 <- typep return (exCast e1 t2 True), do comma es <- commaSep1 expr0 return (foldl exPair e1 es), return e1 ] preCasealtp :: Id i => P (Bool -> CaseAlt i) preCasealtp = "match clause" @@ (const <$> antiblep) <|> do (xi, sigma, lift) <- pattbangp reservedOp "->" ei <- mapSigma (sigma ||) exprp return (\b -> lift b caClause xi ei) casealtp :: Id i => P (CaseAlt i) casealtp = preCasealtp >>! ($ False) bindingp :: Id i => P (Binding i) bindingp = "let rec binding" @@ antiblep <|> do x <- varp (sigma, ft, fe) <- afargsp colon t <- typep reservedOp "=" e <- withSigma sigma exprp return (bnBind x (ft t) (fe e)) -- Parse an infix operator at given precedence opappp :: Id i => Prec -> P (Expr i -> Expr i -> Expr i) opappp p = do op <- addLoc (oplevelp p >>! exBVar) return (\e1 e2 -> op `exApp` e1 `exApp` e2) -- Zero or more of (pat:typ, ...), (), or tyvar, recognizing '|' -- to introduce affine arrows afargsp :: Id i => P (Bool, Type i -> Type i, Expr i -> Expr i) afargsp = loop tyArr where loop arrcon0 = do arrcon <- option arrcon0 $ choice [ tyFun <$> qualbox qExpp, do reservedOp "|" return tyLol ] choice [ do (tvt, tve) <- tyargp (b, ft, fe) <- loop arrcon return (b, tvt . ft, tve . fe), do (b, ft, fe) <- vargp arrcon if b then return (b, ft, fe) else do (b', fts, fes) <- loop arrcon return (b', ft . fts, fe . fes), return (False, id, id) ] -- One or more of (pat:typ, ...), (), tyvar argsp1 :: Id i => P (Bool, Expr i -> Expr i) argsp1 = do (b, fe) <- argp if b then return (b, fe) else second (fe .) `fmap` option (False, id) argsp1 -- Zero or more of (pat:typ, ...), (), tyvar argsp :: Id i => P (Bool, Expr i -> Expr i) argsp = option (False, id) $ do (b, fe) <- argp if b then return (b, fe) else second (fe .) `fmap` argsp -- Parse a (pat:typ, ...), (), or tyvar argp :: Id i => P (Bool, Expr i -> Expr i) argp = choice [ do (_, fe) <- tyargp return (False, fe), do (b, _, fe) <- vargp const return (b, fe) ] -- Parse a (pat:typ, ...) or () argument vargp :: Id i => (Type i -> Type i -> Type i) -> P (Bool, Type i -> Type i, Expr i -> Expr i) vargp arrcon = do inBang <- bangp loc <- curLoc (p, t) <- paty return (inBang, arrcon t, condSigma inBang True (flip exAbs t) p <<@ loc) -- Parse a (pat:typ, ...) or () argument paty :: Id i => P (Patt i, Type i) paty = do (p, mt) <- pamty case (dataOf p, mt) of (_, Just t) -> return (p, t) (PaCon (J [] (Uid _ "()")) Nothing, Nothing) -> return (p, tyUnit) (PaWild, Nothing) -> return (p, tyAf) _ -> pzero ":" -- Parse a (), (pat:typ, ...) or (pat) argument pamty :: Id i => P (Patt i, Maybe (Type i)) pamty = choice [ (paWild, Nothing) <$ reserved "_", parens $ do tvs <- many (tyvarp <* comma) (p, mt) <- choice [ do (p, mt) <- pamty maybe (maybecolon p) (morepts p) mt, do p <- pattp maybecolon p, return (paCon (quid "()") Nothing, Nothing) ] return (foldr paPack p tvs, fmap (\t -> foldr tyEx t tvs) mt) ] where maybecolon p = choice [ do colon t <- typep morepts p t, moreps p ] moreps p = do ps <- many (comma >> pattp) return (foldl paPair p ps, Nothing) morepts p0 t0 = do (ps, ts) <- liftM unzip . many $ do comma choice [ do (p, mt) <- pamty case mt of Just t -> return (p, t) Nothing -> colonType p, do p <- pattp colonType p ] return (foldl paPair p0 ps, Just (foldl tyTuple t0 ts)) colonType p = do colon t <- typep return (p, t) -- Parse a sequence of one or more tyvar arguments tyargp :: Id i => P (Type i -> Type i, Expr i -> Expr i) tyargp = do tvs <- liftM return loctv <|> brackets (commaSep1 loctv) return (\t -> foldr (\(_, tv) -> tyAll tv) t tvs, \e -> foldr (\(loc, tv) -> exTAbs tv <<@ loc) e tvs) where loctv = liftM2 (,) curLoc tyvarp pattbangp :: Id i => P (Patt i, Bool, Bool -> (Patt i -> Expr i -> b) -> Patt i -> Expr i -> b) pattbangp = do inSigma <- getSigma inBang <- bangp x <- pattp let trans = inBang && not inSigma wrap = inBang && inSigma return (condMakeBang wrap x, inBang, condSigma trans) condSigma :: Id i => Bool -> Bool -> (Patt i -> Expr i -> a) -> Patt i -> Expr i -> a condSigma True = exSigma condSigma False = const id condMakeBang :: Id i => Bool -> Patt i -> Patt i condMakeBang True = makeBangPatt condMakeBang False = id bangp :: P Bool bangp = (bang >> return True) <|> return False pattp :: Id i => P (Patt i) pattp = patt0 where mark = ("pattern" @@) patt0 = mark $ do x <- patt9 choice [ do reserved "as" y <- varp return (paAs x y), return x ] patt9 = mark $ choice [ do reserved "Pack" parens $ do tv <- tyvarp comma x <- pattN1 return (paPack tv x), paCon <$> quidp <*> antioptp (try pattA), pattA ] pattA = mark $ choice [ paWild <$ reserved "_", paVar <$> varp, paLit <$> litp, paCon <$> quidp <*> pure Nothing, antiblep, parens pattN1 ] pattN1 = mark $ choice [ paPack <$> try (tyvarp <* comma) <*> pattN1, do xs <- commaSep patt0 case xs of [] -> return (paCon (quid "()") Nothing) x:xs' -> return (foldl paPair x xs') ] litp :: P Lit litp = ( "literal") $ choice [ integerOrFloat >>! either LtInt LtFloat, charLiteral >>! (LtInt . fromIntegral . fromEnum), stringLiteral >>! LtStr, antiblep ] finish :: CharParser st a -> CharParser st a finish p = do optional (whiteSpace) r <- p eof return r -- | Parse a program parseProg :: Id i => P (Prog i) -- | Parse a REPL line parseRepl :: Id i => P [Decl i] -- | Parse a sequence of declarations parseDecls :: Id i => P [Decl i] -- | Parse a declaration parseDecl :: Id i => P (Decl i) -- | Parse a module expression parseModExp :: Id i => P (ModExp i) -- | Parse a type declaration parseTyDec :: Id i => P (TyDec i) -- | Parse a abstype declaration parseAbsTy :: Id i => P (AbsTy i) -- | Parse a type parseType :: Id i => P (Type i) -- | Parse a type pattern parseTyPat :: Id i => P (TyPat i) -- | Parse a qualifier expression parseQExp :: Id i => P (QExp i) -- | Parse an expression parseExpr :: Id i => P (Expr i) -- | Parse a pattern parsePatt :: Id i => P (Patt i) -- | Parse a case alternative parseCaseAlt :: Id i => P (CaseAlt i) -- | Parse a let rec binding parseBinding :: Id i => P (Binding i) -- | Parse a signature parseSigExp :: Id i => P (SigExp i) -- | Parse a signature item parseSigItem :: Id i => P (SigItem i) parseProg = finish progp parseRepl = finish replp parseDecls = finish declsp parseDecl = finish declp parseModExp = finish modexpp parseTyDec = finish tyDecp parseAbsTy = finish absTyp parseType = finish typep parseTyPat = finish typatp parseQExp = finish qExpp parseExpr = finish exprp parsePatt = finish pattp parseCaseAlt = finish casealtp parseBinding = finish bindingp parseSigExp = finish sigexpp parseSigItem = finish sigitemp -- Convenience functions for quick-and-dirty parsing: -- | Parse a program pp :: String -> Prog Renamed pp = makeQaD parseProg -- | Parse a sequence of declarations pds :: String -> [Decl Renamed] pds = makeQaD parseDecls -- | Parse a declaration pd :: String -> Decl Renamed pd = makeQaD parseDecl pme :: String -> ModExp Renamed pme = makeQaD parseModExp -- | Parse a type declaration ptd :: String -> TyDec Raw ptd = makeQaD parseTyDec -- | Parse a type pt :: String -> Type Renamed pt = makeQaD parseType -- | Parse a type pattern ptp :: String -> TyPat Renamed ptp = makeQaD parseTyPat -- | Parse a qualifier expression pqe :: String -> QExp Renamed pqe = makeQaD parseQExp -- | Parse an expression pe :: String -> Expr Renamed pe = makeQaD parseExpr -- | Parse a pattern px :: String -> Patt Renamed px = makeQaD parsePatt makeQaD :: P a -> String -> a makeQaD parser = either (error . show) id . runParser parser state0 ""