caml-parser-0.1.0.0: src/CamlParser/Parser/Toplevel.hs
{-# LANGUAGE OverloadedStrings #-}
module CamlParser.Parser.Toplevel where
import Control.Monad (void)
import Data.Functor (($>))
import Text.Megaparsec hiding (Token)
import CamlParser.Lexer.Token
import CamlParser.Syntax.Location
import CamlParser.Syntax.Expr
import CamlParser.Syntax.Pattern
import CamlParser.Syntax.Type
import CamlParser.Syntax.Decl
import CamlParser.Parser.Combinators
import CamlParser.Parser.Expr (parseExpr)
import CamlParser.Parser.Pattern (parsePattern)
import CamlParser.Parser.Type (parseType)
parseToplevel :: Parser (Toplevel Expr Pattern)
parseToplevel = choice
[ parseImpl
, parseIntf
]
parseImpl :: Parser (Toplevel Expr Pattern)
parseImpl = TImpl <$> parseImplPhrase
parseIntf :: Parser (Toplevel Expr Pattern)
parseIntf = TIntf <$> parseIntfPhrase
parseImplPhrase :: Parser (Decl Expr Pattern)
parseImplPhrase = choice
[ try parseExprDef
, try parseLetDef
, try parseTypeDef
, try parseExcDef
, try parseDirective
]
parseExprDef :: Parser (Decl Expr Pattern)
parseExprDef = do
e <- parseExpr
void (tok TokSemiSemi)
return $ DExpr e
parseLetDef :: Parser (Decl Expr Pattern)
parseLetDef = do
tok TokLet
rec <- option False (tok TokRec $> True)
binds <- parseBindingList
void (tok TokSemiSemi)
return $ DLet rec binds
parseBindingList :: Parser [(Pattern, Expr)]
parseBindingList = sepBy1 parseBinding (tok TokAnd)
parseBinding :: Parser (Pattern, Expr)
parseBinding = do
pat <- parsePattern
void equal
e <- parseExpr
return (pat, e)
parseTypeDef :: Parser (Decl Expr Pattern)
parseTypeDef = do
tok TokType
decls <- sepBy1 parseTypeDecl (tok TokAnd)
void (tok TokSemiSemi)
return $ DType decls
parseTypeDecl :: Parser (String, [String], TypeDecl)
parseTypeDecl = do
params <- parseTypeParams
name <- identP
def <- parseTypeDefBody
return (name, params, def)
parseTypeParams :: Parser [String]
parseTypeParams = choice
[ parens (sepBy1 parseTypeVar comma)
, fmap return parseTypeVar
, return []
]
parseTypeVar :: Parser String
parseTypeVar = tok TokQuote >> identP
parseTypeDefBody :: Parser TypeDecl
parseTypeDefBody = choice
[ try $ do equal
optionalBar
TDVariant <$> sepBy1 parseConstrDecl bar
, try $ do equal
TDRecord <$> braces (sepBy1 parseLabelDecl semi)
, try $ do tok TokEqualEqual
TDAbbrev <$> parseType
, return TDAbstract
]
parseConstrDecl :: Parser ConstrDecl
parseConstrDecl = choice
[ try $ do name <- identP
tok TokOf
ty <- parseType
return $ CD1 name ty False
, CD0 <$> identP
]
parseLabelDecl :: Parser (String, TypeExpr, Bool)
parseLabelDecl = do
mut <- option False (tok TokMutable $> True)
name <- identP
colon
ty <- parseType
return (name, ty, mut)
parseExcDef :: Parser (Decl Expr Pattern)
parseExcDef = do
tok TokException
decls <- sepBy1 parseConstrDecl (tok TokAnd)
void (tok TokSemiSemi)
return $ DExc decls
parseDirective :: Parser (Decl Expr Pattern)
parseDirective = do
tok TokSharp
dir <- identP
arg <- option "" stringP
void (tok TokSemiSemi)
return $ DDirective dir arg
parseIntfPhrase :: Parser (IntfDecl Expr Pattern)
parseIntfPhrase = choice
[ parseValueDecl
, parseIntfTypeDef
, parseIntfExcDef
, parseIntfDirective
]
parseValueDecl :: Parser (IntfDecl Expr Pattern)
parseValueDecl = do
tok TokValue
decls <- sepBy1 parseValue1Decl (tok TokAnd)
void (tok TokSemiSemi)
return $ IValue decls
parseValue1Decl :: Parser (String, TypeExpr, PrimDesc)
parseValue1Decl = do
name <- identP
colon
ty <- parseType
desc <- option NotPrim (equal >> parsePrimDecl)
return (name, ty, desc)
parsePrimDecl :: Parser PrimDesc
parsePrimDecl = do
n <- intP
s <- stringP
return $ Prim (fromIntegral n) s
parseIntfTypeDef :: Parser (IntfDecl Expr Pattern)
parseIntfTypeDef = do
tok TokType
decls <- sepBy1 parseTypeDecl (tok TokAnd)
void (tok TokSemiSemi)
return $ IType decls
parseIntfExcDef :: Parser (IntfDecl Expr Pattern)
parseIntfExcDef = do
tok TokException
decls <- sepBy1 parseConstrDecl (tok TokAnd)
void (tok TokSemiSemi)
return $ IExc decls
parseIntfDirective :: Parser (IntfDecl Expr Pattern)
parseIntfDirective = do
tok TokSharp
dir <- identP
arg <- option "" stringP
void (tok TokSemiSemi)
return $ IDirective dir arg