{-# OPTIONS_GHC -Wall -fno-warn-unused-do-bind #-} module Parse.Type where import Control.Applicative ((<$>),(<*>),(<*)) import Data.List (intercalate) import Text.Parsec ((<|>), (), char, many, optionMaybe, string, try) import qualified AST.Type as T import qualified AST.Variable as Var import Parse.Helpers tvar :: IParser T.RawType tvar = T.Var <$> lowVar "type variable" tuple :: IParser T.RawType tuple = do ts <- parens (commaSep expr) case ts of [t] -> return t _ -> return (T.tupleOf ts) record :: IParser T.RawType record = do char '{' whitespace rcrd <- extended <|> normal dumbWhitespace char '}' return rcrd where normal = flip T.Record Nothing <$> commaSep field -- extended record types require at least one field extended = do ext <- try (lowVar <* (whitespace >> string "|")) whitespace flip T.Record (Just (T.Var ext)) <$> commaSep1 field field = do lbl <- rLabel whitespace >> hasType >> whitespace (,) lbl <$> expr capTypeVar :: IParser String capTypeVar = intercalate "." <$> dotSep1 capVar constructor0 :: IParser T.RawType constructor0 = do name <- capTypeVar return (T.Type (Var.Raw name)) term :: IParser T.RawType term = tuple <|> record <|> tvar <|> constructor0 app :: IParser T.RawType app = do f <- constructor0 <|> try tupleCtor "type constructor" args <- spacePrefix term case args of [] -> return f _ -> return (T.App f args) where tupleCtor = do n <- length <$> parens (many (char ',')) let ctor = "_Tuple" ++ show (if n == 0 then 0 else n+1) return (T.Type (Var.Raw ctor)) expr :: IParser T.RawType expr = do t1 <- app <|> term arr <- optionMaybe $ try (whitespace >> arrow) case arr of Just _ -> T.Lambda t1 <$> (whitespace >> expr) Nothing -> return t1 constructor :: IParser (String, [T.RawType]) constructor = (,) <$> (capTypeVar "another type constructor") <*> spacePrefix term