diff options
Diffstat (limited to 'parser')
-rw-r--r-- | parser/CC/Parser.hs | 97 |
1 files changed, 76 insertions, 21 deletions
diff --git a/parser/CC/Parser.hs b/parser/CC/Parser.hs index 2d2c4b7..66bc6cf 100644 --- a/parser/CC/Parser.hs +++ b/parser/CC/Parser.hs @@ -1,6 +1,7 @@ module CC.Parser(runPass, parseProgram) where import Control.Monad +import qualified Data.Set as Set import Text.Parsec hiding (SourcePos, getPosition, token) import qualified Text.Parsec @@ -12,7 +13,10 @@ import CC.Pretty type Parser a = Parsec String () a runPass :: Context -> RawString -> Either (PrettyShow ParseError) Program -runPass (Context path _) (RawString src) = fmapLeft PrettyShow (parseProgram path src) +runPass (Context path (Builtins _ prelude)) (RawString src) = do + prog1 <- fmapLeft PrettyShow (parseProgram "<prelude>" prelude) + prog2 <- fmapLeft PrettyShow (parseProgram path src) + return (prog1 <> prog2) where fmapLeft f (Left x) = Left (f x) fmapLeft _ (Right x) = Right x @@ -27,32 +31,63 @@ pProgram = do return prog pDecl :: Parser Decl -pDecl = Def <$> pDef +pDecl = choice + [ DeclType <$> pDeclType + , DeclAlias <$> pDeclAlias + , DeclFunc <$> pDeclFunc ] -pDef :: Parser Def -pDef = do +pDeclFunc :: Parser FuncDef +pDeclFunc = do func <- try $ do emptyLines - name <- pName0 <?> "declaration head name" + name <- pName0 LowerCase <?> "declaration head name" return name mtyp <- optionMaybe $ do symbol "::" typ <- pType whitespace >> void newline emptyLines - func' <- fst <$> pName0 + (func', _) <- pName0 LowerCase guard (fst func == func') return typ - args <- many pName + args <- many (pName LowerCase) symbol "=" expr <- pExpr - return (Function mtyp func args expr) + return (FuncDef mtyp func args expr) + +pDeclType :: Parser TypeDef +pDeclType = (\(n, a, t) -> TypeDef n a t) <$> pTypedefLike "type" + +pDeclAlias :: Parser AliasDef +pDeclAlias = (\(n, a, t) -> AliasDef n a t) <$> pTypedefLike "alias" + +pTypedefLike :: String -> Parser ((Name, SourceRange), [(Name, SourceRange)], Type) +pTypedefLike keyword = do + try (emptyLines >> string keyword >> whitespace1) + name <- pName0 UpperCase + args <- many (pName LowerCase) + symbol "=" + ty <- pType + return (name, args, ty) pType :: Parser Type -pType = chainr1 pTypeAtom (symbol "->" >> return TFun) +pType = chainr1 pTypeTerm (symbol "->" >> return TFun) + +pTypeTerm :: Parser Type +pTypeTerm = pTypeAtom <|> pTypeCall pTypeAtom :: Parser Type -pTypeAtom = (wordToken "Int" >> return TInt) <|> pParenType +pTypeAtom = choice + [ wordToken "Int" >> return TInt + , TyVar . fst <$> pName LowerCase + , pParenType + , pUnionType ] + +pTypeCall :: Parser Type +pTypeCall = do + (constr, _) <- pName UpperCase + args <- many pTypeAtom + return (TNamed constr args) pParenType :: Parser Type pParenType = do @@ -63,6 +98,19 @@ pParenType = do [ty] -> return ty _ -> return (TTup tys) +pUnionType :: Parser Type +pUnionType = do + token "{" + tys <- pType `sepBy` token "|" + token "}" + case tys of + [] -> unexpected "empty union type" + [ty] -> return ty + _ -> let tyset = Set.fromList tys + in if Set.size tyset == length tys + then return (TUnion tyset) + else unexpected "duplicate types in union" + pExpr :: Parser Expr pExpr = label (pLam <|> pLet <|> pCall) "expression" where @@ -84,7 +132,7 @@ pExpr = label (pLam <|> pLet <|> pCall) "expression" p <- getPosition void (char '\\') return p - names <- many1 pName + names <- many1 (pName LowerCase) symbol "->" body <- pExpr p2 <- getPosition @@ -100,7 +148,7 @@ pExpr = label (pLam <|> pLet <|> pCall) "expression" where afterKeyword p1 = do whitespace1 - lhs <- pName0 + lhs <- pName0 LowerCase symbol "=" rhs <- pExpr let fullRange rest = mergeRange (SourceRange p1 p1) (range rest) @@ -118,7 +166,8 @@ pExpr = label (pLam <|> pLet <|> pCall) "expression" pExprAtom :: Parser Expr pExprAtom = choice [ uncurry (flip Int) <$> pInt - , uncurry (flip Var) <$> pName + , uncurry (flip Var) <$> pName LowerCase + , uncurry (flip Constr) <$> pName UpperCase , pParenExpr ] pParenExpr :: Parser Expr @@ -141,11 +190,13 @@ pInt = try (whitespace >> pInt0) p2 <- getPosition return (num, SourceRange p1 p2) -pName0 :: Parser (Name, SourceRange) -pName0 = do +data Case = LowerCase | UpperCase + +pName0 :: Case -> Parser (Name, SourceRange) +pName0 vcase = do p1 <- getPosition s <- try $ do - c <- pWordFirstChar + c <- pWordFirstChar vcase cs <- many pWordMidChar let s = c : cs guard (s `notElem` ["let", "in"]) @@ -154,14 +205,18 @@ pName0 = do notFollowedBy pWordMidChar return (s, SourceRange p1 p2) -pWordFirstChar :: Parser Char -pWordFirstChar = letter <|> oneOf "_$#!" +pWordFirstChar :: Case -> Parser Char +pWordFirstChar LowerCase = lower <|> oneOf wordSymbols +pWordFirstChar UpperCase = upper <|> oneOf wordSymbols pWordMidChar :: Parser Char -pWordMidChar = alphaNum <|> oneOf "_$#!" +pWordMidChar = alphaNum <|> oneOf wordSymbols + +wordSymbols :: [Char] +wordSymbols = "_$#!" -pName :: Parser (Name, SourceRange) -pName = try (whitespace >> pName0) +pName :: Case -> Parser (Name, SourceRange) +pName vcase = try (whitespace >> pName0 vcase) symbol :: String -> Parser () symbol s = token s >> (eof <|> void space <|> void (oneOf "(){}[]")) |