-- | keywords for the variance of kinds
plusT, minusT :: AParser Token
-- | a colon not followed by a question mark
-- | a colon immediately followed by a question mark
qColonT = asKey (colonS++quMark)
-- * parser for bracketed lists
-- | a generic bracket parser
bracketParser :: AParser a -> AParser Token -> AParser Token -> AParser Token
-> ([a] -> [Pos] -> b) -> AParser b
bracketParser parser op cl sep k =
(ts, ps) <- option ([], []) (parser `separatedBy` sep)
return (k ts (toPos o ps c))
-- | parser for square brackets
mkBrackets :: AParser a -> ([a] -> [Pos] -> b) -> AParser b
mkBrackets p c = bracketParser p oBracketT cBracketT anComma c
mkBraces :: AParser a -> ([a] -> [Pos] -> b) -> AParser b
mkBraces p c = bracketParser p oBraceT cBraceT anComma c
-- | parse a simple class name or the type universe as kind
parseClassId :: AParser Kind
parseClassId = fmap (\c -> if showId c "" == "Type"
then Intersection [] [posOfId c]
else ClassKind c MissingKind) classId
-- | do 'parseClassId' or a downset or an intersection kind
parseSimpleKind :: AParser Kind
parseSimpleKind = parseClassId
(cs, ps) <- kind `separatedBy` anComma
return (if isSingle cs then head cs else
Intersection cs (toPos o ps c))
return (Downset (Just i) t MissingKind
(map tokPos [o,d,j,l,p]))
-- | do 'parseSimpleKind' and check for an optional 'Variance'
parseExtKind :: AParser Kind
parseExtKind = do k <- parseSimpleKind
return (ExtKind k CoVar [tokPos s])
return (ExtKind k ContraVar [tokPos m])
-- | parse a (right associative) function kind for a given argument kind
arrowKind :: Kind -> AParser Kind
return (FunKind k1 k2 $ [tokPos a])
-- | parse a function kind but reject an extended kind
arrowKind k1 <|> case k1 of
ExtKind _ _ _ -> unexpected "variance of kind"
-- | parse a function kind but accept an extended kind
arrowKind k1 <|> return k1
-- a (simple) type variable with a 'Variance'
extVar :: AParser Id -> AParser (Id, Maybe Variance, Pos)
return (t, Just CoVar, tokPos a)
return (t, Just ContraVar, tokPos a)
<|> return (t, Nothing, nullPos)
-- several 'extTypeVar' with a 'Kind'
typeVars :: AParser [TypeArg]
typeVars = do (ts, ps) <- extVar typeVar `separatedBy` anComma
allIsInVar :: [(TypeId, Maybe Variance, Pos)] -> Bool
allIsInVar = all ( \ (_, v, _) -> isNothing v)
-- 'parseType' a 'Downset' starting with 'lessT'
typeKind :: [(TypeId, Maybe Variance, Pos)] -> [Token] -> AParser [TypeArg]
return (makeTypeArgs vs ps [tokPos c] k)
return (makeTypeArgs vs ps [tokPos c] k)
return (makeTypeArgs vs ps [tokPos l]
(Downset Nothing t MissingKind []))
<|> return (makeTypeArgs vs ps [] star)
-- | add the 'Kind' to all 'extTypeVar' and yield a 'TypeArg'
makeTypeArgs :: [(TypeId, Maybe Variance, Pos)] -> [Token]
-> [Pos] -> Kind -> [TypeArg]
makeTypeArgs ts ps qs k =
zipWith (mergeVariance Comma k) (init ts)
++ [mergeVariance Other k (last ts) qs]
where mergeVariance c e (t, Nothing, _) q =
mergeVariance c e (t, Just v, p) q =
TypeArg t (ExtKind e v [p]) c q
-- | a single 'TypeArg' (parsed by 'typeVars')
singleTypeArg :: AParser TypeArg
singleTypeArg = do as <- typeVars
_ -> unexpected "list of type arguments"
-- | a 'singleTypArg' put in parentheses
parenTypeArg :: AParser (TypeArg, [Token])
-- | a 'singleTypeArg' possibly put in parentheses
typeArg :: AParser (TypeArg, [Token])
typeArgs :: AParser ([TypeArg], [Token])
return (map fst l, concatMap snd l)
-- | a 'singleTypeArg' put in parentheses as 'TypePattern'
typePatternArg :: AParser TypePattern
do (a, ps) <- parenTypeArg
return $ TypePatternArg a $ map tokPos ps
-- * parse special identifier tokens
type TokenMode = [String]
-- | parse a 'Token' of an 'Id' (to be declared)
-- but exclude the signs in 'TokenMode'
aToken :: TokenMode -> AParser Token
aToken b = pToken (scanQuotedChar <|> scanDigit <|> scanHCWords <|> placeS <|>
-- | just 'aToken' only excluding basic HasCASL keywords
idToken = aToken [] <|> pToken scanDotWords
-- 'TypePatternToken's within 'BracketTypePattern's
-- may recusively be 'idToken's.
-- Parenthesis are only legal for a 'typePatternArg'.
primTypePatternOrId :: AParser TypePattern
primTypePatternOrId = fmap TypePatternToken idToken
<|> mkBraces typePatternOrId (BracketTypePattern Braces)
<|> mkBrackets typePatternOrId (BracketTypePattern Squares)
-- several 'primTypePatternOrId's possibly yielding a 'MixfixTypePattern'
typePatternOrId :: AParser TypePattern
typePatternOrId = do ts <- many1 primTypePatternOrId
return( if isSingle ts then head ts
else MixfixTypePattern ts)
-- | those (top-level) 'Token's (less than 'idToken')
-- that may appear in 'TypePattern's as 'TypePatternToken'.
typePatternToken :: AParser TypePattern
typePatternToken = fmap TypePatternToken (pToken (scanHCWords <|> placeS <|>
reserved [assignS, lessS, equalS] scanHCSigns))
-- | a 'typePatternToken' or something in braces (a 'typePattern'),
-- in square brackets (a 'typePatternOrId' covering compound lists)
-- or parenthesis ('typePatternArg')
primTypePattern :: AParser TypePattern
primTypePattern = typePatternToken
<|> mkBrackets typePatternOrId (BracketTypePattern Squares)
<|> mkBraces typePattern (BracketTypePattern Braces)
-- several 'primTypePatter's possibly yielding a 'MixfixTypePattern'
typePattern :: AParser TypePattern
typePattern = do ts <- many1 primTypePattern
let t = if isSingle ts then head ts
else MixfixTypePattern ts
-- a parsed type may also be interpreted as a kind (by the mixfix analysis)
-- | type tokens with some symbols removed
typeToken :: AParser Type
typeToken = fmap TypeToken (pToken (scanHCWords <|> placeS <|>
reserved (assignS : lessS : equalS : barS :
-- | 'TypeToken's within 'BracketType's may recusively be
-- 'idToken's. Parenthesis may group a mixfix type
-- or may be interpreted as 'Intersection' later in a GEN-VAR-DECL.
primTypeOrId :: AParser Type
primTypeOrId = fmap TypeToken idToken
<|> mkBrackets typeOrId (BracketType Squares)
<|> mkBraces typeOrId (BracketType Braces)
<|> bracketParser typeOrId oParenT cParenT anComma
-- | several 'primTypeOrId's possibly yielding a 'MixfixType'
-- and possibly followed by a 'kindAnno'.
typeOrId = do ts <- many1 primTypeOrId
let t = if isSingle ts then head ts
-- | a 'Kind' annotation starting with 'colT'.
kindAnno :: Type -> AParser Type
kindAnno t = do c <- colT
return (KindedType t k [tokPos c])
-- | a typeToken' or a 'BracketType'. Square brackets may contain 'typeOrId'.
<|> mkBrackets typeOrId (BracketType Squares)
<|> mkBraces parseType (BracketType Braces)
<|> bracketParser parseType oParenT cParenT anComma
-- | a 'primType' possibly preceded by 'quMarkT'
lazyType = do q <- quMarkT
return (LazyType t [tokPos q])
-- | several 'lazyType's (as 'MixfixType') possibly followed by 'kindAnno'
mixType = do ts <- many1 lazyType
let t = if isSingle ts then head ts else MixfixType ts
-- | 'mixType' possibly interspersed with 'crossT'
prodType = do (ts, ps) <- mixType `separatedBy` crossT
return $ mkProductType ts (map tokPos ps)
-- | a (right associativ) function type
parseType :: AParser Type
return $ FunType t1 (fst a) t2 [snd a]
-- | parse one of the four possible 'Arrow's
arrowT :: AParser (Arrow, Pos)
arrowT = do a <- asKey funS
return (FunArr, tokPos a)
return (PFunArr, tokPos a)
return (ContFunArr, tokPos a)
return (PContFunArr, tokPos a)
-- | parse a 'TypeScheme' using 'forallT', 'typeVars', 'dotT' and 'parseType'
typeScheme :: AParser TypeScheme
typeScheme = do f <- forallT
(ts, cs) <- typeVars `separatedBy` anSemi
TypeScheme (concat ts ++ ots) q
<|> fmap simpleTypeScheme parseType
data TypeOrTypeScheme = PartialType Type | TotalTypeScheme TypeScheme
-- a 'TypeOrTypescheme' for a possibly partial constant (given by 'qColonT')
typeOrTypeScheme :: AParser (Token, TypeOrTypeScheme)
typeOrTypeScheme = do q <- qColonT
return (q, PartialType t)
return (q, TotalTypeScheme s)
toPartialTypeScheme :: [Pos] -> TypeOrTypeScheme -> TypeScheme
toPartialTypeScheme qs ts = case ts of
PartialType t -> simpleTypeScheme
(FunType (ProductType [] qs)
partialTypeScheme :: AParser (Token, TypeScheme)
partialTypeScheme = do (c, ts) <- typeOrTypeScheme
return (c, toPartialTypeScheme [tokPos c] ts)
-- * varDecls and genVarDecls
-- | comma separated 'var' with 'varDeclType'
varDecls :: AParser [VarDecl]
varDecls = do (vs, ps) <- var `separatedBy` anComma
-- | a type ('parseType') following a 'colT'
varDeclType :: [Var] -> [Token] -> AParser [VarDecl]
varDeclType vs ps = do c <- colT
return (makeVarDecls vs ps t (tokPos c))
-- | attach the 'Type' to every 'Var'
makeVarDecls :: [Var] -> [Token] -> Type -> Pos -> [VarDecl]
makeVarDecls vs ps t q = zipWith (\ v p -> VarDecl v t Comma [tokPos p])
(init vs) ps ++ [VarDecl (last vs) t Other [q]]
-- | either like 'varDecls' or type variables with a 'typeDownset'.
-- A 'GenVarDecl' may later become a 'GenTypeVarDecl'.
genVarDecls:: AParser [GenVarDecl]
genVarDecls = do (vs, ps) <- extVar var `separatedBy` anComma
(map ( \ (i, _, _) -> i) vs) ps)
<|> fmap (map GenTypeVarDecl)
else fmap (map GenTypeVarDecl)
{- | different legal 'PatternToken's possibly excluding 'funS' or
'equalS' for case or let patterns resp. -}
tokenPattern :: TokenMode -> AParser Pattern
tokenPattern b = fmap TermToken (aToken b <|> pToken (string "_"))
-- a single underscore serves as wildcard pattern
-- | 'tokenPattern' or 'BracketPattern'
primPattern :: TokenMode -> AParser Pattern
primPattern b = tokenPattern b
<|> mkBrackets pattern (BracketTerm Squares)
<|> mkBraces pattern (BracketTerm Braces)
<|> bracketParser pattern oParenT cParenT anComma
-- | several 'typedPattern'
mixPattern :: TokenMode -> AParser Pattern
do l <- many1 $ asPattern b
return $ if isSingle l then head l else MixfixTerm l
-- | a possibly typed ('parseType') pattern
typedPattern :: TokenMode -> AParser Pattern
return (MixfixTerm [t, MixTypeTerm OfType ty [tokPos c]])
-- | top-level pattern (possibly 'AsPattern')
asPattern :: TokenMode -> AParser Pattern
TermToken tt -> if isPlace tt then return v else do
(VarDecl (mkId [tt]) (MixfixType []) Other [tokPos c])
-- | an unrestricted 'asPattern'
pattern :: AParser Pattern
-- | a 'Total' or 'Partial' lambda dot
lamDot :: AParser (Partiality, Token)
lamDot = do d <- asKey (dotS++exMark) <|> asKey (cDot++exMark)
-- | patterns between 'lamS' and 'lamDot'
lamPattern :: AParser [Pattern]
-- | an 'uninstOpId' possibly followed by types ('parseType') in brackets
-- and further places ('placeT')
instOpId :: AParser InstOpId
instOpId = do i <- uninstOpId
(ts, qs) <- option ([], [])
(mkBrackets parseType (,))
return (InstOpId i ts qs)
{- | 'Token's that may occur in 'Term's including literals
'scanFloat', 'scanString' but excluding 'ifS', 'whenS' and 'elseS'
to allow a quantifier after 'whenS'. In case terms also 'barS' will
excluded on the top-levek. -}
tToken :: TokenMode -> AParser Token
tToken b = pToken(scanFloat <|> scanString
<|> scanQuotedChar <|> scanDotWords
<|> reserved [ifS, whenS, elseS] scanHCWords
<|> reserved b scanHCSigns
-- | 'tToken' as 'Term' plus 'exEqual' and 'equalS'
termToken :: TokenMode -> AParser Term
termToken b = fmap TermToken (asKey exEqual <|> asKey equalS <|> tToken b)
-- | 'termToken' plus 'BracketTerm's
primTerm :: TokenMode -> AParser Term
<|> mkBraces termInParens (BracketTerm Braces)
<|> mkBrackets termInParens (BracketTerm Squares)
<|> bracketParser termInParens oParenT cParenT anComma
-- | how the keyword 'inS' should be treated
data InMode = NoIn -- ^ next 'inS' belongs to 'letS'
| WithIn -- ^ 'inS' is the element test
-- | all 'Term's that start with a unique keyword
baseTerm :: (InMode, TokenMode) -> AParser Term
-- | 'whenS' possibly followed by an 'elseS'
whenTerm :: (InMode, TokenMode) -> AParser Term
return (MixfixTerm [TermToken i, c, TermToken t, e])
<|> return (MixfixTerm [TermToken i, c])
-- | 'ifS' possibly followed by 'thenS' and 'elseS'
-- yielding a 'MixfixTerm'
ifTerm :: (InMode, TokenMode) -> AParser Term
return (MixfixTerm [TermToken i, c, TermToken t, e,
<|> return (MixfixTerm [TermToken i, c, TermToken t, e])
<|> return (MixfixTerm [TermToken i, c])
-- | unrestricted terms including qualified names
termInParens :: AParser Term
termInParens = term <|> varTerm <|> qualOpName <|> qualPredName
return $ QualVar $ VarDecl i t Other $ toPos v [] c
opBrand :: AParser (Token, OpBrand)
opBrand = bind (,) (asKey opS) (return Op)
<|> bind (,) (asKey functS) (return Fun)
-- | a qualified operation (with 'opBrand')
qualOpName :: AParser Term
(c, t) <- partialTypeScheme
return $ QualOp b i t $ toPos v [] c
-- | a qualified predicate
qualPredName :: AParser Term
return $ QualOp Pred i (predTypeScheme t) $ toPos v [] c
-- | a qualifier expecting a further 'Type'.
-- 'inS' is rejected for 'NoIn'
typeQual :: InMode -> AParser (TypeQual, Token)
-- | a possibly type qualified ('typeQual') 'primTerm' or a 'baseTerm'
typedTerm :: (InMode, TokenMode) -> AParser Term
return (MixfixTerm [t, MixTypeTerm q ty [tokPos p]])
-- | several 'typedTerm's yielding a 'MixfixTerm'
mixTerm :: (InMode, TokenMode) -> AParser Term
do ts <- many1 $ typedTerm b
return $ if isSingle ts then head ts else MixfixTerm ts
-- | keywords that start a new item
hasCaslStartKeywords :: [String]
dotS:cDot: (hascasl_reserved_words \\ [existsS, letS, caseS])
-- | a 'mixTerm' followed by 'whereS' and equations separated by 'optSemi'
whereTerm :: (InMode, TokenMode) -> AParser Term
(es, ps, ans) <- itemAux hasCaslStartKeywords $
patternTermPair ([equalS]) b equalS
setState (AnnoState (concat ans)) -- store back collected annotations
return (LetTerm Where es t (map tokPos (p:ps)))
-- | a 'whereTerm' called with ('WithIn', [])
term = whereTerm (WithIn, [])
-- | a 'Universal' 'QuantifiedTerm'
forallTerm :: (InMode, TokenMode) -> AParser Term
(vs, ps) <- genVarDecls `separatedBy` anSemi
return $ QuantifiedTerm Universal (concat vs) t $ toPos f ps d
-- | 'Unique' or 'Existential'
exQuant :: AParser (Token, Quantifier)
bind (,) (asKey (existsS++exMark)) (return Unique)
<|> bind (,) (asKey existsS) (return Existential)
-- | a (possibly unique) existential 'QuantifiedTerm'
exTerm :: (InMode, TokenMode) -> AParser Term
do (p, q) <- exQuant <?> existsS
(vs, ps) <- varDecls `separatedBy` anSemi
return $ QuantifiedTerm q (map GenVarDecl (concat vs)) f $ toPos p ps d
lambdaTerm :: (InMode, TokenMode) -> AParser Term
return (LambdaTerm pl k t (toPos l [] d))
-- | a 'CaseTerm' with 'funS' excluded in 'patternTermPair'
caseTerm :: (InMode, TokenMode) -> AParser Term
(ts, ps) <- patternTermPair [funS] (i, [barS]) funS
return (CaseTerm t ts (map tokPos (c:o:ps)))
-- | a 'LetTerm' with 'equalS' excluded in 'patternTermPair'
letTerm :: (InMode, TokenMode) -> AParser Term
(es, ps) <- patternTermPair [equalS] (NoIn, []) equalS
return (LetTerm Let es t (toPos l ps i))
-- | a customizable pattern equation
patternTermPair :: TokenMode -> (InMode, TokenMode) -> String -> AParser ProgEq
patternTermPair b1 b2 sep =
return (ProgEq p t (tokPos s))