CurryInfo: curry-interface-2.0.1 / CurryInterface.Parser

classes:

              
documentation:
------------------------------------------------------------------------------
--- This library defines a parser for Curry interface files.
---
--- @version January 2025
------------------------------------------------------------------------------
name:
CurryInterface.Parser
operations:
*!*> *?*> <*!* <*!*> <*?* <*?*> arity arrowType bracketType choice classDecl constrDecl constrDeclOp constraint constructorType context contextList dataDecl decl decls digit fieldDecl funDep funDeps functionDecl hiddenPragma hidingClassDecl hidingDataDecl hidingDecl iInfix iNewtype ident identList identToQualIdent identType importDecl importDecls infixDecl instanceDecl instanceType interface kind kind0 kind1 methodDecl methodImpl methodPragma missing moduleIdent modulePragma newtypeDecl operator optional pTrace parenType parenthesize parseCurryInterface parseInt parseList parseSinglePragma precedence qualIdent qualIdentOp qualIdentWithContext qualType qualTypeExpr singleton skipManyWs skipSomeWs skipWhitespace toList tokenArrow tokenBacktick tokenBracketL tokenBracketR tokenClass tokenComma tokenConstraint tokenCurlyBracketL tokenCurlyBracketR tokenData tokenDot tokenDoubleArrow tokenEqual tokenHiding tokenImport tokenInstance tokenInterface tokenNewtype tokenParenL tokenParenR tokenPipe tokenPragma tokenPragmaHiding tokenPragmaL tokenPragmaLanguage tokenPragmaMethod tokenPragmaModule tokenPragmaOptions tokenPragmaR tokenSemicolon tokenStar tokenType tokenTyping tokenWhere tupleType type0 type1 type2 typeDecl typeExpr typeExprs typeVariable typeVariableList typeVariableListNE unwrapApply variableType withOptionalKind ws
sourcecode:
module CurryInterface.Parser where

import CurryInterface.Types

import Prelude hiding ( (*>), (<*), (<*>), (<$>), (<|>), many, empty, some )
import Data.List      ( init, last )
import Data.Maybe     ( listToMaybe )
import DetParse

--- FOR TESTING
import Debug.Trace    ( trace )

-- Helper function for debugging. That is, `pTrace "fn" p` traces 
--   "fn: <first line of current parser input>"
-- before applying the parser `p` to the input string.
pTrace :: String -> Parser a -> Parser a
--pTrace _ p = p
pTrace fn p = \s -> trace (fn ++ ": " ++ takeWhile (/= '\n') s) $ p s

--- A parser for the text of a Curry interface.
parseCurryInterface :: String -> Interface
parseCurryInterface txt = case parse interface txt of
    Nothing -> error "Parsing failed"
    Just i -> i
--parseCurryInterface _ = error "parseCurryInterface not yet implemented"

--- A parser for a Curry interface.
interface :: Parser Interface
interface =
    Interface <$>
        (tokenInterface *!*> moduleIdent) <*!*>
        (tokenWhere *!*> tokenCurlyBracketL *!*> importDecls) <*>
        (decls <*!* tokenCurlyBracketR)

--- A parser for a Module Identifier.
moduleIdent :: Parser ModuleIdent
moduleIdent = ModuleIdent <$> identList

--- A parser for a list of Import Declarations.
importDecls :: Parser [IImportDecl]
importDecls = many importDecl

--- A parser for a list of Declarations.
decls :: Parser [IDecl]
decls = parseList tokenSemicolon decl

--- A parser for an Import Declaration.
importDecl :: Parser IImportDecl
importDecl = IImportDecl <$> (tokenImport *!*> moduleIdent <* tokenSemicolon <* skipSomeWs)

--- A parser for a Declaration.
decl :: Parser IDecl
decl = choice
    [ hidingDecl
    , infixDecl
    , dataDecl
    , newtypeDecl
    , typeDecl
    , classDecl
    , instanceDecl
    , functionDecl
    ]

--- A parser for an Infix Declaration | Infix Arity Op
infixDecl :: Parser IDecl
infixDecl = IInfixDecl <$> iInfix <*!*> precedence <*!*> qualIdentOp

hidingDecl :: Parser IDecl
hidingDecl = tokenHiding *!*> (hidingDataDecl <!> hidingClassDecl)

--- A parser for a Hiding Data Declaration | hiding data QualIdent [KindExpr] TypeVariableList
hidingDataDecl :: Parser IDecl
hidingDataDecl =
    (tokenData *!*> withOptionalKind HidingDataDecl qualIdent) <*>
    (map Ident <$> typeVariableList)

--- A parser for a Hiding Class Declaration | hiding class [Context =>] QualIdent [KindExpr] TypeVariable
hidingClassDecl :: Parser IDecl
hidingClassDecl = tokenClass *!*> (case1 <|> case2)
 where
  case1 :: Parser IDecl
  case1 = (tokenParenL *> qualIdent <* skipSomeWs) *>= f
  case2 :: Parser IDecl
  case2 = (qualIdent <* skipSomeWs) *>= h
  f :: QualIdent -> Parser IDecl
  f qi =
      (HidingClassDecl [] qi <$> (Just <$> (tokenTyping *!*> kind <* tokenParenR)) <*!*> (map Ident <$> typeVariableListNE) <*?*> funDeps)
       <!>
      ((HidingClassDecl <$> (((:) <$> (Constraint qi . unwrapApply <$> typeExpr) <*> (tokenComma *!*> parseList tokenComma constraint)) <* tokenParenR <*!* tokenDoubleArrow <* skipSomeWs) *>=
           (flip withOptionalKind qualIdent)) <*!*> (map Ident <$> typeVariableListNE) <*?*> funDeps)
  h :: QualIdent -> Parser IDecl
  h qi = (((HidingClassDecl <$> (singleton . Constraint qi <$> typeExprs) <*!* tokenDoubleArrow <* skipSomeWs) *>=
           (flip withOptionalKind qualIdent)) <*?*> (map Ident <$> typeVariableListNE) <*?*> funDeps) 
          <!>
         (HidingClassDecl [] qi Nothing <$> (map Ident <$> typeVariableListNE) <*?*> funDeps)

--- A parser for a Data Declaration | data QualIdent [KindExpr] TypeVariableList = ConstrDeclList
dataDecl :: Parser IDecl
dataDecl =
    tokenData *!*> withOptionalKind IDataDecl qualIdent <*>
    (map Ident <$> typeVariableList) <*>
    ((skipSomeWs *> tokenEqual *!*> parseList (skipSomeWs *> tokenPipe) constrDecl) <!> yield []) <*?*>
    hiddenPragma

    {-
    convert <$> leftSide <*!*> (tokenEqual *!*> rightSide) <*?*> pragma
    where
    convert :: (QualIdent, Maybe KindExpr, [Ident]) -> [ConstrDecl] -> [Ident] -> IDecl
    convert (qi, mk, ids) cs ps = IDataDecl qi mk ids cs ps

    leftSide :: Parser (QualIdent, Maybe KindExpr, [Ident])
    leftSide =
        (,,) <$> (tokenData *!*> qualIdent) <*> optional (skipSomeWs *> kind) <*> (map Ident <$> typeVariableList)

    rightSide :: Parser [ConstrDecl]
    rightSide = (:) <$> constrDecl <*> many (skipSomeWs *> tokenPipe *!*> constrDecl)
    -}

--- A parser for a Newtype Declaration | newtype QualIdent [KindExpr] TypeVariableList = Newtype
newtypeDecl :: Parser IDecl
newtypeDecl =
    tokenNewtype *!*> withOptionalKind INewtypeDecl qualIdent <*>
    (map Ident <$> typeVariableList) <*!*>
    (tokenEqual *!*> iNewtype) <*?*>
    hiddenPragma

    {-
    convert <$> leftSide <*!*> (tokenEqual *!*> rightSide) <*?*> pragma
    where
    convert :: (QualIdent, Maybe KindExpr, [Ident]) -> NewConstrDecl -> [Ident] -> IDecl
    convert (qi, mk, ids) nc ps = INewtypeDecl qi mk ids nc ps

    leftSide :: Parser (QualIdent, Maybe KindExpr, [Ident])
    leftSide = (,,) <$> (tokenNewtype *!*> qualIdent) <*> optional (skipSomeWs *> kind) <*> (map Ident <$> typeVariableList)

    rightSide :: Parser NewConstrDecl
    rightSide = iNewtype
    -}

--- A parser for a Type Declaration | type QualIdent [KindExpr] TypeVariableList = TypeExpr
typeDecl :: Parser IDecl
typeDecl =
    tokenType *!*> withOptionalKind ITypeDecl qualIdent <*>
    (map Ident <$> typeVariableList) <*!*>
    (tokenEqual *!*> typeExpr)

    {-
    convert <$> leftSide <*!*> (tokenEqual *!*> rightSide)
    where
    convert :: (QualIdent, Maybe KindExpr, [Ident]) -> TypeExpr -> IDecl
    convert (qi, mk, ids) t = ITypeDecl qi mk ids t

    leftSide :: Parser (QualIdent, Maybe KindExpr, [Ident])
    leftSide = (,,) <$> (tokenType *!*> qualIdent) <*> optional (skipSomeWs *> kind) <*> (map Ident <$> typeVariableList)

    rightSide :: Parser TypeExpr
    rightSide = typeExpr
    -}

--- A parser for a Function Declaration | QualIdent [MethodPragma] Arity :: QualTypeExpr
functionDecl :: Parser IDecl
functionDecl =
    IFunctionDecl <$>
        qualIdent <*!*>
        optional (skipSomeWs *> methodPragma) <*>
        arity <*!*>
        (tokenTyping *!*> qualTypeExpr)

--- A parser for a Class Declaration | class [Context =>] QualIdent [KindExpr] TypeVariable \{ MethodList \} [Pragma]
classDecl :: Parser IDecl
classDecl = tokenClass *!*> (case1 <|> case2) <*?*> (tokenCurlyBracketL *!*> parseList tokenSemicolon methodDecl <*?* tokenCurlyBracketR) <*?*> hiddenPragma
 where
  case1 :: Parser ([IMethodDecl] -> [Ident] -> IDecl)
  case1 = (tokenParenL *> qualIdent <* skipSomeWs) *>= f
  case2 :: Parser ([IMethodDecl] -> [Ident] -> IDecl)
  case2 = (qualIdent <* skipSomeWs) *>= h
  f :: QualIdent -> Parser ([IMethodDecl] -> [Ident] -> IDecl)
  f qi =
      (IClassDecl [] qi <$> (Just <$> (tokenTyping *!*> kind <* tokenParenR)) <*!*> (map Ident <$> typeVariableListNE) <*!*> funDeps)
       <!>
      ((IClassDecl <$> (((:) <$> (Constraint qi . unwrapApply <$> typeExpr) <*> (tokenComma *!*> parseList tokenComma constraint)) <* tokenParenR <*!* tokenDoubleArrow <* skipSomeWs) *>=
           (flip withOptionalKind qualIdent)) <*!*> (map Ident <$> typeVariableListNE) <*!*> funDeps)
  h :: QualIdent -> Parser ([IMethodDecl] -> [Ident] -> IDecl)
  h qi = (((IClassDecl <$> (singleton . Constraint qi <$> typeExprs) <*!* tokenDoubleArrow <* skipSomeWs) *>=
           (flip withOptionalKind qualIdent)) <*?*> (map Ident <$> typeVariableListNE) <*!*> funDeps) 
          <!>
         (IClassDecl [] qi Nothing <$> (map Ident <$> typeVariableListNE) <*!*> funDeps)

singleton :: a -> [a]
singleton x = [x]

--- A parser for a list of functional dependencies | [| funDep {, funDep}]
funDeps :: Parser [FunDep]
funDeps = (tokenPipe *> parseList tokenComma funDep) <!> yield []

--- A parser for a functional dependency | [Ident {, Ident}] -> [Ident {, Ident}]
funDep :: Parser FunDep
funDep = FunDep <$> (skipManyWs *> idents' <*?* tokenArrow) <*?*> idents'
 where
  idents' = map Ident <$> parseList empty ident

--- A parser for an Instance Declaration | instance [Context =>] QualIdent InstanceType \{ MethodImplList \} [ModulePragma]
instanceDecl :: Parser IDecl
instanceDecl =
    convert IInstanceDecl <$>
        (tokenInstance *!*> (case1 <|> case2)) <*!*>
        (tokenCurlyBracketL *!*> parseList tokenSemicolon methodImpl <*!* tokenCurlyBracketR) <*>
        (optional (skipSomeWs *> modulePragma))
    where
    case1 :: Parser (Context, QualIdent, InstanceType)
    case1 = (,,) <$> contextList <*!*> qualIdent <*!*> instanceType

    case2 :: Parser (Context, QualIdent, InstanceType)
    case2 = ((,) <$> qualIdent <*!*> instanceType) *>= decide

    decide :: (QualIdent, InstanceType) -> Parser (Context, QualIdent, InstanceType)
    decide (qi, it) = 
        (skipSomeWs *> tokenDoubleArrow *!*> ((,,) [Constraint qi it] <$> qualIdent <*!*> instanceType)) <!>
        yield ([], qi, it)

    convert :: (Context -> QualIdent -> InstanceType -> a) -> (Context, QualIdent, InstanceType) -> a
    convert f (ctx, qi, it) = f ctx qi it

--- A parser for an Infix expression | {infixl | infixr | infix}
iInfix :: Parser Infix
iInfix = word "infix" *> choice [char 'l' *> yield InfixL, char 'r' *> yield InfixR, yield Infix]

--- A parser for a Precedence
precedence :: Parser Precedence
precedence = parseInt

--- A parser for an Arity
arity :: Parser Arity
arity = parseInt

--- A parser for a Qualified Identifier or Operator | [IdentList .] {Ident | Operator}
qualIdentOp :: Parser QualIdent
qualIdentOp =
  QualIdent <$> (optional (moduleIdent <* tokenDot))
                <*> (Ident <$> (operator <!> ident))

--- A parser for a Qualified Identifier:
--- \( [IdentList .] Operator \) | [IdentList .] Ident
qualIdent :: Parser QualIdent
qualIdent =
      (tokenParenL *>
       (QualIdent <$>
         (optional (moduleIdent <* tokenDot)) <*> (Ident <$> operator))
       <* tokenParenR)
  <!> (QualIdent <$> (optional (moduleIdent <* tokenDot)) <*> (Ident <$> ident))

--- A parser for a List of Identifiers | Ident [. IdentList]
identList :: Parser [String]
identList = (:) <$> ident <*> (many (tokenDot *> ident)) <!> yield []

--- A longest-match parser for an Identifier (not operator)
ident :: Parser String
ident [] = []
ident (x:xs) | isAlpha x = let (ys,zs) = span isIdChar xs in [(x:ys,zs)]
             | otherwise = []
 where
  isIdChar c = isDigit c || isAlpha c || c == '_' || c == '\''

--- A longest-match parser for an Operator
operator :: Parser String
operator = tokenBacktick *> ident <* tokenBacktick <!> op
 where
  op xs = let (ys,zs) = span (`elem` allowed) xs
          in if null ys || ys `elem` exceptions then [] else [(ys,zs)]
  allowed = "!#$%&*+./<=>?@\\^|-~:"
  exceptions = ["..", ":", "::", "=", "\\", "|", "<-", "->", "@", "~", "=>"]

--- A longest-match parser for a Type Variable
typeVariable :: Parser String
typeVariable [] = []
typeVariable (x:xs) | isLower x = let (ys,zs) = span isVarChar xs in [(x:ys,zs)]
                    | otherwise = []
 where
  isVarChar c = isAlpha c || isDigit c

--- A parser for a Type Variable List | TypeVariable [TypeVariableList]
typeVariableList :: Parser [String]
typeVariableList = many (skipSomeWs *> typeVariable)

--- A parser for a non-empty Type Variable List | TypeVariable [TypeVariableList]
typeVariableListNE :: Parser [String]
typeVariableListNE = some (skipManyWs *> typeVariable)

--- A parser for a Hidden Pragma | ADD SYNTAX DESCRIPTION
hiddenPragma :: Parser [Ident]
hiddenPragma =
 (tokenPragmaL *!*> word "HIDING" *!*>
   (map Ident <$> parseList tokenComma ident) <*!* tokenPragmaR) <!> yield []

--- A parser for a Method Pragma | ADD SYNTAX DESCRIPTION
methodPragma :: Parser Ident
methodPragma = tokenPragmaL *!*> word "METHOD" *!*> (Ident <$> ident) <*!* tokenPragmaR

--- A parser for a Module Pragma | ADD SYNTAX DESCRIPTION
modulePragma :: Parser ModuleIdent
modulePragma = tokenPragmaL *!*> word "MODULE" *!*> moduleIdent <*!* tokenPragmaR

--- A parser for a Constructor Declaration
-- Constr ::= Ident TypeVariableList
--          | Ident '{' fieldList '}'
--          | TypeExpr Op TypeExpr
constrDecl :: Parser ConstrDecl
constrDecl = (Ident <$> ident *>= decide1) <|> constrDeclOp
    where
    decide1 :: Ident -> Parser ConstrDecl
    --decide1 i = case1 i <|> case2 i
    decide1 i = (skipSomeWs *> (case1 i <!> case2 i)) <!> decide2 i []

    case1 :: Ident -> Parser ConstrDecl
    --case1 i = RecordDecl i <$> (skipSomeWs *> tokenCurlyBracketL *!*> parseList tokenComma fieldDecl <*!* tokenCurlyBracketR)
    case1 i = RecordDecl i <$> (tokenCurlyBracketL *!*> parseList tokenComma fieldDecl <*!* tokenCurlyBracketR)

    case2 :: Ident -> Parser ConstrDecl
    --case2 i = many (skipSomeWs *> typeExpr) *>= decide2 i
    case2 i = (:) <$> type2 <*> many (skipSomeWs *> type2) *>= decide2 i

    decide2 :: Ident -> [TypeExpr] -> Parser ConstrDecl
    decide2 i ts =
        (ConOpDecl (foldl1 ApplyType (ConstructorType (identToQualIdent i):ts)) <$> (Ident <$> operator) <*!*> typeExpr) <!>
        yield (ConstrDecl i ts)

{-
--- A parser for a simple Constructor Declaration | Ident TypeExprList
constrDeclSimple :: Parser ConstrDecl
constrDeclSimple =
    (uncurry ConstrDecl) <$> parseConstructor
-}

--- A parser for an Operator Constructor Declaration | TypeExpr Op TypeExpr
constrDeclOp :: Parser ConstrDecl
constrDeclOp = ConOpDecl <$> typeExpr <*!*> (Ident <$> operator) <*!*> typeExpr

{-
--- A parser for a Record Constructor Declaration | Ident \{ FieldDeclList \}
constrDeclRecord :: Parser ConstrDecl
constrDeclRecord = 
    RecordDecl <$>
        (Ident <$> ident) <*!*>
        (
            tokenCurlyBracketL *!*> 
            parseList tokenComma fieldDecl
            <*!* tokenCurlyBracketR
        )
-}

--- A parser for a Type Expression
typeExpr :: Parser TypeExpr
typeExpr = type0

typeExprs :: Parser [TypeExpr]
typeExprs = some (skipManyWs *> typeExpr)

-- type0 ::= type1 ['->' type0]
type0 :: Parser TypeExpr
type0 = convert <$> type1 <*> (optional (skipSomeWs *> tokenArrow *!*> type0))
    where
    convert t1 Nothing   = t1
    convert t1 (Just t0) = ArrowType t1 t0

-- type1 ::= [type1] type2
type1 :: Parser TypeExpr
type1 = foldl1 ApplyType <$> some (skipWhitespace *> type2)

-- type2 ::= identType | parenType | bracketType
type2 :: Parser TypeExpr
type2 = parenType <!> bracketType <!> identType

identType :: Parser TypeExpr
identType = variableType <|> constructorType

variableType :: Parser TypeExpr
variableType = VariableType <$> (Ident <$> typeVariable)

constructorType :: Parser TypeExpr
constructorType = ConstructorType <$> qualType

-- parenType ::= '(' tupleType ')' | '(' arrowType ')'
parenType :: Parser TypeExpr
parenType = tokenParenL *> (arrowType <!> tupleType) <* tokenParenR

arrowType :: Parser TypeExpr
arrowType = word "->" *> yield (ConstructorType (QualIdent Nothing (Ident "->")))

-- tupleType ::= type0
--            |  type0 ',' type0 { ',' type0 }
--            |  
tupleType :: Parser TypeExpr
tupleType = convert <$> parseList tokenComma type0
    where
    convert ts = case ts of
        [t] -> ParenType t
        _   -> TupleType ts

-- bracketType ::= '[' type0 ']'
bracketType :: Parser TypeExpr
--bracketType = ListType <$> ((toList <$> (tokenBracketL *> type0 <* tokenBracketR)) <|> (word "[]" *> yield []))
bracketType = ListType <$> (tokenBracketL *> (toList <$> type0 <!> yield []) <* tokenBracketR)

--                   Prelude.Int -> Prelude.Int -> Prelude.Int;
-- Prelude.Show a => a           -> [Prelude.Char]            ;
--- A parser for a Qualified Type Expression | [Context =>] type0
qualTypeExpr :: Parser QualTypeExpr
qualTypeExpr = singleOrNoConstraint <!> multipleOrNoConstraints
    where
    singleOrNoConstraint :: Parser QualTypeExpr
    singleOrNoConstraint =
        (qualIdent *>= decide1) <!>
        (tokenBracketL *> (ListType <$> (toList <$> type0 <!> yield [])) <* tokenBracketR *>= decide8)

    -- starts with QualIdent, not yet sure if one constraint or not
    decide1 :: QualIdent -> Parser QualTypeExpr
    decide1 qi = 
        (skipSomeWs *>
            (
                (tokenArrow *!*> type0 *>= decide2 qi) <!>
                (type0 *>= decide3 qi)
            )
        ) <!>
        (yield (QualTypeExpr [] (constructorOrVariable qi)))

    -- starts with no constraints but with ArrowType
    decide2 :: QualIdent -> TypeExpr -> Parser QualTypeExpr
    decide2 qi t = 
        yield $ QualTypeExpr [] (ArrowType (constructorOrVariable qi) t)

    -- starts with QualIdent and TypeExpr
    decide3 :: QualIdent -> TypeExpr -> Parser QualTypeExpr
    decide3 qi t = let t' = addPrefix (constructorOrVariable qi) t 
                       ts = unwrapApply t in
        (QualTypeExpr [Constraint qi ts] <$> (skipSomeWs *> tokenDoubleArrow *!*> type0)) <!>
        (yield (QualTypeExpr [] t'))

    multipleOrNoConstraints :: Parser QualTypeExpr
    multipleOrNoConstraints =
        tokenParenL *> (
            (
                tokenParenR *> (
                    (skipSomeWs *> tokenArrow *!*> ((QualTypeExpr [] . ArrowType (TupleType [])) <$> type0)) <!>
                    (yield (QualTypeExpr [] (TupleType [])))
                )
            ) <!>
            (qualIdent *>= decide4) <!>
            (((type0 *>= (\t -> (yield (ParenType t) <* tokenParenR) <!> ((TupleType . (t:)) <$> (tokenComma *!*> parseList tokenComma type0 <* tokenParenR))))) *>= decide8)
        )
    
    -- starts with QualIdent, all cases still possible
    decide4 :: QualIdent -> Parser QualTypeExpr
    decide4 qi = 
        (
            skipSomeWs *> (
                (type0 *>= decide5 qi) <!>
                (tokenArrow *!*> type0 *>= decide6 qi)
            )
        ) <!>
        (tokenComma *!*> decide7 qi)

    -- starts with QualIdent and TypeExpr, all cases still possible
    decide5 :: QualIdent -> TypeExpr -> Parser QualTypeExpr
    decide5 qi t = let t' = addPrefix (constructorOrVariable qi) t in
        --(tokenParenR *> decide8 t') <!>
        case t of
            ArrowType _ _ -> ((tokenParenR *> yield t') <!> (finishTupleType (tokenComma *> skipSomeWs) [t'])) *>= decide8
            _             -> tokenComma *!*> decide9 [(qi, t)]

    -- starts with no context, starts with an ArrowType or a TupleType starting with an ArrowType
    decide6 :: QualIdent -> TypeExpr -> Parser QualTypeExpr
    decide6 qi t = let t' = ArrowType (constructorOrVariable qi) t in
        (tokenParenR *> decide8 t') <!>
        (finishTupleType (tokenComma *> skipSomeWs) [t'] *>= decide8)

    -- starts with no context, starts with tuple type, tuple starts with ConstructorType or VariableType
    decide7 :: QualIdent -> Parser QualTypeExpr
    decide7 qi = 
        finishTupleType empty [constructorOrVariable qi] *>= decide8

    -- starts with no context, first part of type expression parsed, rest remains to be parsed
    decide8 :: TypeExpr -> Parser QualTypeExpr
    decide8 t = 
        (
            skipSomeWs *> (
                (type0 *>= (\t' -> yield (QualTypeExpr [] (ApplyType t t')))) <!>
                (tokenArrow *!*> type0 *>= (\t' -> yield (QualTypeExpr [] (ArrowType t t'))))
            )
        ) <!>
        (yield (QualTypeExpr [] t))

    -- starts with a comma-seperated list, not yet clear if context or not
    decide9 :: [(QualIdent, TypeExpr)] -> Parser QualTypeExpr
    decide9 acc = let
            ts = map (\(qi, t) -> addPrefix (constructorOrVariable qi) t) acc'
            acc' = reverse acc
        in
            (qualIdent *>= decide10 acc) <!>
            (finishTupleType empty ts *>= decide8)
            {-
            (tokenParenR *> (
                skipSomeWs *> tokenDoubleArrow *!*> (QualTypeExpr constraints <$> type0) <|>
                decide8 ts
            ))
            -}

    -- starts with a comma-seperated list, current element starts with QualIdent, not yet clear if context or not
    decide10 :: [(QualIdent, TypeExpr)] -> QualIdent -> Parser QualTypeExpr
    decide10 acc qi = let
            acc' = reverse acc
            t' = constructorOrVariable qi
            ts = map (\(qi', t) -> addPrefix (constructorOrVariable qi') t) acc'
        in
            (finishTupleType (tokenComma *> skipSomeWs) (ts ++ [t']) *>= decide8) <!>
            (
                skipSomeWs *> (
                    ((tokenArrow *!*> type0) *>= (\t -> decide12 (ts ++ [ArrowType t' t]))) <!>
                    (type0 *>= decide11 acc qi)
                )
            ) <!>
            (tokenParenR *> decide8 (TupleType (ts ++ [t'])))
    
    -- starts with a comma-seperated list, current element starts with QualIdent and TypeExpr, not yet clear if context or not
    decide11 :: [(QualIdent, TypeExpr)] -> QualIdent -> TypeExpr -> Parser QualTypeExpr
    decide11 acc qi t = let
            acc' = reverse acc
            t' = addPrefix (constructorOrVariable qi) t
            ts = map (\(qi', t'') -> addPrefix (constructorOrVariable qi') t'') acc'
            ts' = ts ++ [t']
            constraints = map (uncurry ((. unwrapApply) . Constraint)) acc'
            constraints' = constraints ++ [Constraint qi (unwrapApply t)]
        in
            case t of
                ArrowType _ _ -> finishTupleType (tokenComma *> skipSomeWs) ts' *>= decide8
                _ ->
                    tokenComma *!*> decide9 ((qi, t):acc) <!>
                    (
                        tokenParenR *> (
                            (QualTypeExpr constraints' <$> (skipSomeWs *> tokenDoubleArrow *!*> type0)) <|>
                            (decide8 (TupleType ts))
                        )
                    ) <!>
                    (finishTupleType (tokenComma *> skipSomeWs) ts' *>= decide8)
    
    -- starts with TupleType, tuple not yet finished to be parsed
    decide12 :: [TypeExpr] -> Parser QualTypeExpr
    decide12 ts = 
        (tokenParenR *> decide8 (TupleType ts)) <!>
        (finishTupleType (tokenComma *> skipSomeWs) ts *>= decide8)
    
    addPrefix :: TypeExpr -> TypeExpr -> TypeExpr
    addPrefix p t = case t of
        ApplyType t1 t2 -> ApplyType (addPrefix p t1) t2
        ArrowType t1 t2 -> ArrowType (addPrefix p t1) t2
        _ -> ApplyType p t
    
    constructorOrVariable :: QualIdent -> TypeExpr
    constructorOrVariable qi = case qi of
        QualIdent Nothing i -> if isVariable i then VariableType i else ConstructorType qi
        _ -> ConstructorType qi
    
    isVariable :: Ident -> Bool
    isVariable (Ident s) = all isLower s
    
    finishTupleType :: Parser () -> [TypeExpr] -> Parser TypeExpr
    finishTupleType p ts = p *> ((TupleType . (ts ++)) <$> (parseList tokenComma type0 <* tokenParenR))
{-
qualTypeExpr = (QualTypeExpr <$> contextList <*!*> typeExpr) <|> (qualType *>= decide1) <|> ((QualTypeExpr []) <$> typeExpr)
    where
    decide1 :: QualIdent -> Parser QualTypeExpr
    decide1 qi = case1 qi <|> case2 qi

    -- QualTypeExpr TypeVariable ... (maybe context)
    case1 :: QualIdent -> Parser QualTypeExpr
    case1 qi = skipSomeWs *> (Ident <$> typeVariable) *>= decide2 qi

    -- QualTypeExpr ... (NOT context)
    case2 :: QualIdent -> Parser QualTypeExpr
    case2 qi = QualTypeExpr [] <$> arrowOrApply (ConstructorType qi)

    -- QualTypeExpr TypeVariable ... (maybe context)
    decide2 :: QualIdent -> Ident -> Parser QualTypeExpr
    decide2 qi i = (case3 qi i) <|> (case4 qi i)

    -- QualTypeExpr TypeVariable '=>' ... (context)
    case3 :: QualIdent -> Ident -> Parser QualTypeExpr
    case3 qi i = QualTypeExpr [Constraint qi (VariableType i)] <$> (skipSomeWs *> tokenDoubleArrow *!*> typeExpr)

    -- QualTypeExpr TypeVariable ... (no context)
    case4 :: QualIdent -> Ident -> Parser QualTypeExpr
    case4 qi i = QualTypeExpr [] <$> arrowOrApply (ApplyType (ConstructorType qi) (VariableType i))

    arrowOrApply :: TypeExpr -> Parser TypeExpr
    arrowOrApply t = (ArrowType t <$> (skipSomeWs *> tokenArrow *!*> type0)) <|> (foldl1 ApplyType <$> ((t:) <$> many (skipSomeWs *> type2)))
-}
--- A parser for a Context | {Constraint | (ConstraintList)}
context :: Parser Context
context = choice [contextList, parseSingleContext, parseNoContext]
    where
    parseSingleContext :: Parser Context
    parseSingleContext = toList <$> constraint <*!* tokenDoubleArrow

    parseNoContext :: Parser Context
    parseNoContext = yield []

--- A parser for a Constraint | QualType TypeExpr
constraint :: Parser Constraint
constraint = 
    (Constraint <$> qualType <*!*> some typeExpr)

--- A parser for a Qualified Type | ADD SYNTAX DESCRIPTION
qualType :: Parser QualIdent
qualType = check condition qualIdent
    where
    condition (QualIdent (Just (ModuleIdent ids)) (Ident id)) = all (isUpper . head) ids && (isUpper . head) id
    condition (QualIdent Nothing (Ident id)) = (isUpper . head) id

--- A parser for a Field Declaration | IdentList :: TypeExpr
fieldDecl :: Parser FieldDecl
fieldDecl =
    FieldDecl <$>
        (map Ident <$> identList) <*!*>
        (tokenTyping *!*> typeExpr)

--- A parser for a Kind Expression | NOT YET IMPLEMENTED
kind :: Parser KindExpr
kind = kind0

-- kind1 -> kind0
kind0 :: Parser KindExpr
kind0 = convert <$> kind1 <*> (optional (skipSomeWs *> tokenArrow *!*> kind0))
    where
    convert k1 Nothing   = k1
    convert k1 (Just k0) = ArrowKind k1 k0

-- * | (kind0) | Constraint
kind1 :: Parser KindExpr
kind1 = tokenStar *> yield Star 
    <!> tokenParenL *> kind0 <* tokenParenR 
    <!> tokenConstraint *> yield ConstraintKind

--- A parser for a Newtype
iNewtype :: Parser NewConstrDecl
--iNewtype = newtypeRecord <|> newtypeSimple
iNewtype = (Ident <$> ident <* skipSomeWs) *>= decide1
    where
    decide1 :: Ident -> Parser NewConstrDecl
    decide1 i =
        (NewConstrDecl i <$> typeExpr) <!>
        (NewRecordDecl i <$> (
            tokenCurlyBracketL *!*> parseNewField <*!* tokenCurlyBracketR
        ))
    
    parseNewField :: Parser (Ident, TypeExpr)
    parseNewField = (,) <$> (Ident <$> ident) <*!*> (tokenTyping *!*> typeExpr)

{-
--- A parser for a simple Newtype | Ident TypeExpr
newtypeSimple :: Parser NewConstrDecl
newtypeSimple = 
    parseConstructor *>= convert
    where
    convert :: (Ident, [TypeExpr]) -> Parser NewConstrDecl
    convert (i, ts) = case ts of
        [t] -> yield (NewConstrDecl i t)
        _ -> failure

--- A parser for a Record Newtype | Ident '{' FieldDecl '}'
newtypeRecord :: Parser NewConstrDecl
newtypeRecord =
    NewRecordDecl <$>
        (Ident <$> ident) <*!*>
        (
            tokenCurlyBracketL *!*>
            parseNewField
            <*!* tokenCurlyBracketR
        )
    where
    parseNewField :: Parser (Ident, TypeExpr)
    parseNewField = (,) <$> (Ident <$> ident) <*!*> (tokenTyping *!*> typeExpr)
-}

--- A parser for a Method Declaration | Ident [Arity] '::' QualTypeExpr
methodDecl :: Parser IMethodDecl
methodDecl = 
    IMethodDecl <$>
        (Ident <$> (ident <!> (tokenParenL *> operator <* tokenParenR))) <*!*>
        optional (arity <* skipSomeWs) <*>
        (tokenTyping *!*> qualTypeExpr)

--- A parser for an Instance Type
instanceType :: Parser InstanceType
instanceType = some (skipManyWs *> typeExpr)

--- A parser for a Method Implementation | {Ident | '(' Op ')'} Arity
methodImpl :: Parser (Ident, Arity)--IMethodImpl
methodImpl = 
    (,) <$> (Ident <$> (ident <!> (tokenParenL *> operator <* tokenParenR))) <*!*> arity

-- ################################################################
--- Helper Functions

--- Converts a value into a Singleton List
toList :: a -> [a]
toList x = [x]

identToQualIdent :: Ident -> QualIdent
identToQualIdent i = QualIdent Nothing i

-- Completely unwraps applications of type expressions
unwrapApply :: TypeExpr -> [TypeExpr]
unwrapApply t = case t of
    ApplyType l r -> unwrapApply l ++ unwrapApply r
    _ -> [t]

-- ################################################################

--- Helper parser

contextList :: Parser Context
contextList = tokenParenL *> parseList tokenComma constraint <* tokenParenR <*!* tokenDoubleArrow 

qualIdentWithContext :: Parser (Either Context (QualIdent, Maybe KindExpr, [Ident]))
qualIdentWithContext =
    (Left <$> contextList <* skipSomeWs) <!>
    ((,,) <$> qualIdent <*> optional (skipSomeWs *> kind) <*> (map Ident <$> typeVariableListNE) *>= decide)
    where 
    decide :: (QualIdent, Maybe KindExpr, [Ident]) -> Parser (Either Context (QualIdent, Maybe KindExpr, [Ident]))
    decide (qi, mk, tvs) = case mk of
        Just _ -> yield (Right (qi, mk, tvs))
        Nothing -> (skipSomeWs *> tokenDoubleArrow *!*> yield (Left [Constraint qi (map VariableType tvs)])) <!> yield (Right (qi, mk, tvs))

--- Parses a string with enclosing parantheses
parenthesize :: Parser String -> Parser String
parenthesize p = parens <$> (tokenParenL *> p <* tokenParenR)
    where
    parens s = "(" ++ s ++ ")"

--- A parser for an Integer
parseInt :: Parser Int
parseInt = read <$> some digit 

--- A parser for a digit
digit :: Parser Char
digit = check isDigit anyChar

--- Choose the first succeeding parser from a non-empty list of parsers
choice :: [Parser a] -> Parser a
choice = foldr1 (<|>)

--- Parses a list using a parser for the seperator and a parser for the list elements
parseList :: Parser () -> Parser a -> Parser [a]
parseList psep pelem = ((:) <$> pelem <*> many (psep *!*> pelem)) <!> yield []

--- Tries to parse using the given parser or returns Nothing
optional :: Parser a -> Parser (Maybe a)
optional p = Just <$> p <|> yield Nothing

--- A parser for a single Pragma with a Pragma Token
parseSinglePragma :: Parser () -> Parser Ident
parseSinglePragma token = tokenPragmaL *!*> token *!*> (Ident <$> ident) <*!* tokenPragmaR

{-
parseConstructor :: Parser (Ident, [TypeExpr])
parseConstructor = 
    (,) <$>
        (Ident <$> ident) <*>
        many (skipSomeWs *> typeExpr)
-}

withOptionalKind :: (a -> Maybe KindExpr -> b) -> Parser a -> Parser b
withOptionalKind c p = withKind <|> withoutKind
    where
    withKind =
        c <$> (tokenParenL *> p) <*!*> (tokenTyping *!*> (Just <$> kind) <* tokenParenR)
    
    withoutKind = c <$> p <*> yield Nothing
    

--- Debug function to fail with an error message of which function is not yet implemented.
missing :: String -> Parser a
missing name = (\_ -> error (name ++ " not yet implemented"))

infixl 4 <*?*>, <*?*, *?*>, <*!*>, <*!*, *!*>

(<*?*>) :: Parser (a -> b) -> Parser a -> Parser b
pa <*?*> pb = (pa <* skipManyWs) <*> pb

(<*?*) :: Parser a -> Parser b -> Parser a
pa <*?* pb = const <$> pa <*?*> pb

(*?*>) :: Parser a -> Parser b -> Parser b
pa *?*> pb = flip const <$> pa <*?*> pb

(<*!*>) :: Parser (a -> b) -> Parser a -> Parser b
pa <*!*> pb = (pa <* skipSomeWs) <*> pb

(<*!*) :: Parser a -> Parser b -> Parser a
pa <*!* pb = const <$> pa <*!*> pb

(*!*>) :: Parser a -> Parser b -> Parser b
pa *!*> pb = flip const <$> pa <*!*> pb

ws :: Parser ()
ws = check isSpace anyChar *> empty

skipManyWs :: Parser ()
skipManyWs = many ws *> empty

skipSomeWs :: Parser ()
skipSomeWs = some ws *> empty

skipWhitespace :: Parser ()
skipWhitespace = skipManyWs

-- ################################################################

--- Tokens

tokenInterface :: Parser ()
tokenInterface = word "interface"

tokenWhere :: Parser ()
tokenWhere = word "where"

tokenImport :: Parser ()
tokenImport = word "import"

tokenClass :: Parser ()
tokenClass = word "class"

tokenData :: Parser ()
tokenData = word "data"

tokenInstance :: Parser ()
tokenInstance = word "instance"

tokenHiding :: Parser ()
tokenHiding = word "hiding"

tokenCurlyBracketL :: Parser ()
tokenCurlyBracketL = char '{'

tokenCurlyBracketR :: Parser ()
tokenCurlyBracketR = char '}'

tokenSemicolon :: Parser ()
tokenSemicolon = char ';'

tokenComma :: Parser ()
tokenComma = char ','

tokenTyping :: Parser ()
tokenTyping = word "::"

tokenArrow :: Parser ()
tokenArrow = word "->"

tokenDoubleArrow :: Parser ()
tokenDoubleArrow = word "=>"

tokenPragmaL :: Parser ()
tokenPragmaL = word "{-#"

tokenPragmaR :: Parser ()
tokenPragmaR = word "#-}"

tokenEqual :: Parser ()
tokenEqual = char '='

tokenPipe :: Parser ()
tokenPipe = char '|'

tokenDot :: Parser ()
tokenDot = char '.'

tokenParenL :: Parser ()
tokenParenL = char '('

tokenParenR :: Parser ()
tokenParenR = char ')'

tokenPragma :: Parser ()
tokenPragma = choice
    [ tokenPragmaLanguage
    , tokenPragmaOptions
    , tokenPragmaHiding
    , tokenPragmaMethod
    , tokenPragmaModule
    ]

tokenPragmaLanguage :: Parser ()
tokenPragmaLanguage = word "LANGUAGE"

tokenPragmaOptions :: Parser ()
tokenPragmaOptions = word "OPTIONS"

tokenPragmaHiding :: Parser ()
tokenPragmaHiding = word "HIDING"

tokenPragmaMethod :: Parser ()
tokenPragmaMethod = word "METHOD"

tokenPragmaModule :: Parser ()
tokenPragmaModule = word "MODULE"

tokenConstraint :: Parser ()
tokenConstraint = word "Constraint"

tokenBracketL :: Parser ()
tokenBracketL = char '['

tokenBracketR :: Parser ()
tokenBracketR = char ']'

tokenNewtype :: Parser ()
tokenNewtype = word "newtype"

tokenType :: Parser ()
tokenType = word "type"

tokenBacktick :: Parser ()
tokenBacktick = char '`'

tokenStar :: Parser ()
tokenStar = char '*'
types:

              
unsafe:
unsafe due to modules Debug.Trace System.IO.Unsafe