{- ----------------------------------------------------------------------------- Copyright 2019 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ----------------------------------------------------------------------------- -} -- Author: Kevin P. Barry [ta0kira@gmail.com] {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE Safe #-} module Parser.TypeCategory ( parseFilters, parseScope, parseScopedFunction, singleDefine, singleFilter, singleRefine, ) where import Text.Parsec import Text.Parsec.String import Parser.Common import Parser.TypeInstance () import Types.Positional import Types.TypeCategory import Types.TypeInstance import Types.Variance instance ParseFromSource (AnyCategory SourcePos) where sourceParser = parseValue <|> parseInstance <|> parseConcrete where open = sepAfter (string_ "{") close = sepAfter (string_ "}") parseValue = labeled "value interface" $ do c <- getPosition try $ kwValue >> kwInterface n <- sourceParser ps <- parseCategoryParams open (rs,vs) <- parseRefinesFilters fs <- flip sepBy optionalSpace $ parseScopedFunction (return ValueScope) (return n) close return $ ValueInterface [c] NoNamespace n ps rs vs fs parseInstance = labeled "type interface" $ do c <- getPosition try $ kwType >> kwInterface n <- sourceParser ps <- parseCategoryParams open vs <- parseFilters fs <- flip sepBy optionalSpace $ parseScopedFunction (return TypeScope) (return n) close return $ InstanceInterface [c] NoNamespace n ps vs fs parseConcrete = labeled "concrete type" $ do c <- getPosition try kwConcrete n <- sourceParser ps <- parseCategoryParams open (rs,ds,vs) <- parseRefinesDefinesFilters fs <- flip sepBy optionalSpace $ parseScopedFunction parseScope (return n) close return $ ValueConcrete [c] NoNamespace n ps rs ds vs fs parseCategoryParams :: Parser [ValueParam SourcePos] parseCategoryParams = do (con,inv,cov) <- none <|> try fixedOnly <|> try noFixed <|> try explicitFixed return $ map (apply Contravariant) con ++ map (apply Invariant) inv ++ map (apply Covariant) cov where none = do notFollowedBy (string "<") return ([],[],[]) fixedOnly = do -- T inv <- between (sepAfter $ string_ "<") (sepAfter $ string_ ">") (sepBy singleParam (sepAfter $ string_ ",")) return ([],inv,[]) noFixed = do -- T con <- between (sepAfter $ string_ "<") (sepAfter $ string_ "|") (sepBy singleParam (sepAfter $ string_ ",")) cov <- between nullParse (sepAfter $ string_ ">") (sepBy singleParam (sepAfter $ string_ ",")) return (con,[],cov) explicitFixed = do -- T con <- between (sepAfter $ string_ "<") (sepAfter $ string_ "|") (sepBy singleParam (sepAfter $ string_ ",")) inv <- between nullParse (sepAfter $ string_ "|") (sepBy singleParam (sepAfter $ string_ ",")) cov <- between nullParse (sepAfter $ string_ ">") (sepBy singleParam (sepAfter $ string_ ",")) return (con,inv,cov) singleParam = labeled "param declaration" $ do c <- getPosition n <- sourceParser return (c,n) apply v (c,n) = ValueParam [c] n v singleRefine :: Parser (ValueRefine SourcePos) singleRefine = do c <- getPosition try kwRefines t <- sourceParser return $ ValueRefine [c] t singleDefine :: Parser (ValueDefine SourcePos) singleDefine = do c <- getPosition try kwDefines t <- sourceParser return $ ValueDefine [c] t singleFilter :: Parser (ParamFilter SourcePos) singleFilter = try $ do c <- getPosition n <- sourceParser f <- sourceParser return $ ParamFilter [c] n f parseCategoryRefines :: Parser [ValueRefine SourcePos] parseCategoryRefines = sepAfter $ sepBy singleRefine optionalSpace parseFilters :: Parser [ParamFilter SourcePos] parseFilters = sepBy singleFilter optionalSpace parseRefinesFilters :: Parser ([ValueRefine SourcePos],[ParamFilter SourcePos]) parseRefinesFilters = parsed >>= return . merge2 where parsed = sepBy anyType optionalSpace anyType = labeled "refine or param filter" $ put12 singleRefine <|> put22 singleFilter parseRefinesDefinesFilters :: Parser ([ValueRefine SourcePos], [ValueDefine SourcePos], [ParamFilter SourcePos]) parseRefinesDefinesFilters = parsed >>= return . merge3 where parsed = sepBy anyType optionalSpace anyType = labeled "refine or define or param filter" $ put13 singleRefine <|> put23 singleDefine <|> put33 singleFilter instance ParseFromSource FunctionName where sourceParser = labeled "function name" $ do noKeywords b <- lower e <- sepAfter $ many alphaNum return $ FunctionName (b:e) parseScopedFunction :: Parser SymbolScope -> Parser CategoryName -> Parser (ScopedFunction SourcePos) parseScopedFunction sp tp = labeled "function" $ do c <- getPosition s <- try sp -- Could be a constant, i.e., nothing consumed. t <- try tp -- Same here. n <- try sourceParser ps <- fmap Positional $ noParams <|> someParams fa <- parseFilters as <- fmap Positional $ typeList "argument type" sepAfter_ (string "->") rs <- fmap Positional $ typeList "return type" return $ ScopedFunction [c] n t s as rs ps fa [] where noParams = notFollowedBy (string "<") >> return [] someParams = between (sepAfter $ string_ "<") (sepAfter $ string_ ">") (sepBy singleParam (sepAfter $ string ",")) singleParam = labeled "param declaration" $ do c <- getPosition n <- sourceParser return $ ValueParam [c] n Invariant typeList l = between (sepAfter $ string_ "(") (sepAfter $ string_ ")") (sepBy (labeled l $ singleType) (sepAfter $ string ",")) singleType = do c <- getPosition t <- sourceParser return $ PassedValue [c] t parseScope :: Parser SymbolScope parseScope = try categoryScope <|> try typeScope <|> valueScope categoryScope :: Parser SymbolScope categoryScope = kwCategory >> return CategoryScope typeScope :: Parser SymbolScope typeScope = kwType >> return TypeScope valueScope :: Parser SymbolScope valueScope = kwValue >> return ValueScope