packages feed

caml-parser-0.1.0.0: src/CamlParser/Parser/Pattern.hs

{-# LANGUAGE OverloadedStrings #-}
module CamlParser.Parser.Pattern where

import Control.Monad (void)
import Data.Maybe (fromMaybe)
import Text.Megaparsec hiding (Token)
import CamlParser.Lexer.Token
import CamlParser.Syntax.Location
import CamlParser.Syntax.Constant
import CamlParser.Syntax.Pattern
import CamlParser.Syntax.Type
import CamlParser.Parser.Combinators
import CamlParser.Parser.Type (parseType)

parsePattern :: Parser Pattern
parsePattern = parseOrPattern

locatedPattern :: Parser (PatternF Pattern) -> Parser Pattern
locatedPattern p = do
  Located _ loc1 <- lookAhead anySingle
  pf <- p
  mbLoc <- optional (locatedLoc <$> lookAhead anySingle)
  return $ Pattern pf (loc1 <> fromMaybe loc1 mbLoc)

parseOrPattern :: Parser Pattern
parseOrPattern = do
  p <- parseConsPattern
  rest <- many (bar >> parseConsPattern)
  return $ foldr1 mkOr (p : rest)
  where
    mkOr a b = Pattern (POr a b) (patLoc a <> patLoc b)

parseConsPattern :: Parser Pattern
parseConsPattern = do
  p <- parseCtorAppOrAtomic
  (do tok TokColonColon
      q <- parseConsPattern
      return $ Pattern (PConstr1 "::" (Pattern (PTuple [p, q]) (patLoc p <> patLoc q))) (patLoc p <> patLoc q)
   ) <|> return p

parseCtorAppOrAtomic :: Parser Pattern
parseCtorAppOrAtomic = choice
  [ try parseCtorApp
  , parseAtomicPattern
  ]

parseCtorApp :: Parser Pattern
parseCtorApp = do
  c <- identP
  args <- some parseAtomicPattern
  return $ Pattern (PConstr1 c (mkTuplePat args)) emptyLoc

mkTuplePat :: [Pattern] -> Pattern
mkTuplePat [p] = p
mkTuplePat ps  = Pattern (PTuple ps) emptyLoc

parseAtomicPattern :: Parser Pattern
parseAtomicPattern = locatedPattern $ choice
  [ PWild <$ tok TokUnderscore
  , parseConstPattern
  , PVar <$> identP
  , PTuple <$> parens (sepBy1 parsePattern comma)
  , parseListPattern
  , parseRecordPattern
  , PConstraint <$> parens parsePattern <*> (colon >> parseType)
  ]

parseConstPattern :: Parser (PatternF Pattern)
parseConstPattern = choice
  [ PConstant . CInt <$> intP
  , PConstant . CFloat <$> floatP
  , PConstant . CString <$> stringP
  , PConstant . CChar <$> charP
  , do s <- subtractiveP
       case s of
         "-" -> PConstant . CInt . negate <$> intP
         "-." -> PConstant . CFloat . negate <$> floatP
         _ -> empty
  ]

parseListPattern :: Parser (PatternF Pattern)
parseListPattern = do
  ps <- brackets (sepBy parsePattern semi)
  return $ foldr (\x r -> PConstr1 "::" (Pattern (PTuple [x, Pattern r emptyLoc]) emptyLoc)) (PConstr0 "[]") ps

parseRecordPattern :: Parser (PatternF Pattern)
parseRecordPattern = do
  fields <- braces (sepBy fieldP semi)
  return $ PRecord fields
  where
    fieldP = do
      f <- identP
      void equal
      p <- parsePattern
      return (f, p)