variance :: AParser st Variance
variance = let l = [CoVar, ContraVar] in
choice (map ( \ v -> asKey (show v) >> return v) l) <|> return NonVar
-- a (simple) type variable with a 'Variance'
extVar :: AParser st Id -> AParser st (Id, Variance)
extVar vp = pair vp variance
-- several 'extVar' with a 'Kind'
typeVars :: AParser st [TypeArg]
(ts, ps) <- extVar typeVar `separatedBy` anComma
allIsNonVar :: [(Id, Variance)] -> Bool
allIsNonVar = all ( \ (_, v) -> case v of
-- 'parseType' a 'Downset' starting with 'lessT' (True means require kind)
typeKind :: Bool -> [(Id, Variance)] -> [Token]
if allIsNonVar vs then do
return $ makeTypeArgs vs ps v (VarKind k) $ tokPos c
return $ makeTypeArgs vs ps NonVar (VarKind k) $ tokPos c
return $ makeTypeArgs vs ps NonVar (Downset t) $ tokPos l
<|> if b then unexpected "missing kind" else
return (makeTypeArgs vs ps NonVar MissingKind nullRange)
-- | add the 'Kind' to all 'extVar' and yield a 'TypeArg'
makeTypeArgs :: [(Id, Variance)] -> [Token]
-> Variance -> VarKind -> Range -> [TypeArg]
makeTypeArgs ts ps vv vk qs =
zipWith (mergeVariance Comma vv vk) (init ts)
++ [mergeVariance Other vv vk (last ts) qs]
mergeVariance c v k (t, NonVar) q = TypeArg t v k rStar 0 c q
mergeVariance c _ k (t, v) q = TypeArg t v k rStar 0 c q
-- | a single 'TypeArg' (parsed by 'typeVars')
singleTypeArg :: AParser st TypeArg
_ -> unexpected "list of type arguments"
-- | a 'singleTypeArg' put in parentheses
parenTypeArg :: AParser st (TypeArg, [Token])
-- | a 'singleTypeArg' possibly put in parentheses
typeArg :: AParser st (TypeArg, [Token])
-- | a 'singleTypeArg' put in parentheses as 'TypePattern'
typePatternArg :: AParser st TypePattern
return $ TypePatternArg a $ catRange 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 st Token
aToken b = pToken $ scanQuotedChar <|> scanDigit <|> scanHCWords <|> placeS
<|> reserved b scanHCSigns
-- | just 'aToken' only excluding basic HasCASL keywords
idToken :: AParser st Token
idToken = aToken [] <|> pToken scanDotWords
-- 'TypePatternToken's within 'BracketTypePattern's
-- may recusively be 'idToken's.
-- Parenthesis are only legal for a 'typePatternArg'.
primTypePatternOrId :: AParser st TypePattern
primTypePatternOrId = fmap TypePatternToken idToken
<|> mkBraces typePatternOrId (BracketTypePattern Braces)
<|> mkBrackets typePatternOrId (BracketTypePattern Squares)
-- several 'primTypePatternOrId's possibly yielding a 'MixfixTypePattern'
mixTypePattern :: AParser st TypePattern -> AParser st TypePattern
_ -> MixfixTypePattern ts
-- several 'primTypePatternOrId's possibly yielding a 'MixfixTypePattern'
typePatternOrId :: AParser st TypePattern
typePatternOrId = mixTypePattern primTypePatternOrId
-- | those (top-level) 'Token's (less than 'idToken')
-- that may appear in 'TypePattern's as 'TypePatternToken'.
typePatternToken :: AParser st TypePattern
typePatternToken = fmap TypePatternToken $ pToken $ scanHCWords <|> placeS
<|> reserved hascasl_reserved_tops scanHCSigns
-- | a 'typePatternToken' or something in braces (a 'typePattern'),
-- in square brackets (a 'typePatternOrId' covering compound lists)
-- or parenthesis ('typePatternArg')
primTypePattern :: AParser st TypePattern
primTypePattern = typePatternToken
<|> mkBrackets typePatternOrId (BracketTypePattern Squares)
<|> mkBraces typePattern (BracketTypePattern Braces)
-- several 'primTypePatter's possibly yielding a 'MixfixTypePattern'
typePattern :: AParser st TypePattern
typePattern = mixTypePattern primTypePattern
-- a parsed type may also be interpreted as a kind (by the mixfix analysis)
-- | type tokens with some symbols removed
typeToken :: AParser st Type
typeToken = fmap TypeToken $ pToken $ scanHCWords <|> placeS <|>
reserved (hascasl_reserved_tops ++ hascasl_type_ops)
-- | 'TypeToken's within 'BracketType's may recusively be
-- 'idToken's. Parenthesis may group a mixfix type
-- or may be interpreted as a kind later on in a GEN-VAR-DECL.
primTypeOrId :: AParser st Type
primTypeOrId = fmap TypeToken idToken
<|> mkBrackets typeOrId (BracketType Squares)
<|> mkBraces typeOrId (BracketType Braces)
<|> bracketParser typeOrId oParenT cParenT anComma (BracketType Parens)
mkMixfixType :: AParser st Type -> AParser st Type
mkKindedMixType :: AParser st Type -> AParser st Type
-- | several 'primTypeOrId's possibly yielding a 'MixfixType'
-- and possibly followed by a 'kindAnno'.
typeOrId :: AParser st Type
typeOrId = mkKindedMixType primTypeOrId
-- | a 'Kind' annotation starting with 'colT'.
kindAnno :: Type -> AParser st Type
-- | a typeToken' or a 'BracketType'. Square brackets may contain 'typeOrId'.
primType :: AParser st Type
<|> mkBrackets typeOrId (BracketType Squares)
<|> mkBraces parseType (BracketType Braces)
<|> bracketParser parseType oParenT cParenT anComma (BracketType Parens)
-- | a 'primType' possibly preceded by 'quMarkT'
lazyType :: AParser st Type
lazyType = fmap mkLazyType (quMarkT >> mkMixfixType primType) <|> primType
-- | several 'lazyType's (as 'MixfixType') possibly followed by 'kindAnno'
mixType :: AParser st Type
mixType = mkKindedMixType lazyType
-- | 'mixType' possibly interspersed with 'crossT'
prodType :: AParser st Type
(ts, ps) <- mixType `separatedBy` crossT
return $ mkProductTypeWithRange ts $ catRange ps
-- | a (right associativ) function type
parseType :: AParser st Type
(TypeName a (toRaw $ funKindWithRange $ posOfId a) 0) [t1, t2]
-- | parse one of the four possible 'Arrow's
arrowT = let l = [FunArr, PFunArr, ContFunArr, PContFunArr] in
return $ mkId [placeTok, t, placeTok]) l
-- | parse a 'TypeScheme' using 'forallT', 'typeVars', 'dotT' and 'parseType'
typeScheme :: PolyId -> AParser st TypeScheme
typeScheme (PolyId _ tys ps) = if null tys then do
(ts, cs) <- typeVars `separatedBy` anSemi
return $ TypeScheme (concat ts) t $ toRange f cs d
<|> fmap simpleTypeScheme parseType
return $ TypeScheme tys t ps
-- * varDecls and genVarDecls
-- | comma separated 'var' with 'varDeclType'
varDecls :: AParser st [VarDecl]
(vs, ps) <- var `separatedBy` anComma
-- | a type ('parseType') following a colon
varDeclType :: [Id] -> [Token] -> AParser st [VarDecl]
return $ makeVarDecls vs ps t $ tokPos c
-- | attach the 'Type' to every 'Var'
makeVarDecls :: [Id] -> [Token] -> Type -> Range -> [VarDecl]
makeVarDecls vs ps t q = zipWith ( \ v -> VarDecl v t Comma . tokPos)
(init vs) ps ++ [VarDecl (last vs) t Other q]
-- | either like 'varDecls' or declared type variables.
-- A 'GenVarDecl' may later become a 'GenTypeVarDecl'.
genVarDecls:: AParser st [GenVarDecl]
genVarDecls = fmap (map ( \ g -> case g of
GenTypeVarDecl (TypeArg i v MissingKind _ n s ps) ->
GenTypeVarDecl (TypeArg i v (VarKind universe)
(vs, ps) <- extVar var `separatedBy` anComma
let other = fmap (map GenTypeVarDecl) (typeKind True vs ps)
if allIsNonVar vs then fmap (map GenVarDecl)
(varDeclType (map fst vs) ps) <|> other
{- | different legal 'TermToken's possibly excluding 'funS' or
'equalS' for case or let patterns resp. -}
tokenPattern :: TokenMode -> AParser st Term
tokenPattern b = fmap TermToken (aToken b <|> pToken (string "_"))
-- a single underscore serves as wildcard pattern
-- | 'tokenPattern' or 'BracketTerm'
primPattern :: TokenMode -> AParser st Term
primPattern b = tokenPattern b
<|> mkBrackets pattern (BracketTerm Squares)
<|> mkBraces pattern (BracketTerm Braces)
<|> bracketParser (pattern <|> varTerm <|> qualOpName)
oParenT cParenT anComma (BracketTerm Parens)
mkMixfixTerm :: [Term] -> Term
mkMixfixTerm ts = case ts of
-- | several 'typedPattern'
mixPattern :: TokenMode -> AParser st Term
mixPattern = fmap mkMixfixTerm . many1 . asPattern
-- | a possibly typed ('parseType') pattern
typedPattern :: TokenMode -> AParser st Term
return $ MixfixTerm [t, MixTypeTerm OfType ty $ tokPos c]
-- | top-level pattern (possibly 'AsPattern')
asPattern :: TokenMode -> AParser st Term
TermToken tt -> if isPlace tt then return v else do
return $ AsPattern (VarDecl (mkId [tt]) (MixfixType [])
Other $ tokPos c) t $ tokPos c
-- | an unrestricted 'asPattern'
pattern :: AParser st Term
myChoice :: [(AParser st Token, a)] -> AParser st (a, Token)
myChoice = choice . map ( \ (p, a) -> do
-- | a 'Total' or 'Partial' lambda dot
lamDot :: AParser st (Partiality, Token)
lamDot = myChoice [ (choice $ map (asKey . (++ exMark)) [dotS, cDot], Total)
-- | patterns between 'lamS' and 'lamDot'
lamPattern :: AParser st [Term]
(lookAhead lamDot >> return []) <|> typedPattern [] <:> lamPattern
{- | '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
be excluded on the top-level. -}
tToken :: TokenMode -> AParser st Token
tToken b = pToken (scanFloat
<|> scanQuotedChar <|> scanDotWords
<|> reserved [ifS, whenS, elseS] scanHCWords
<|> reserved b scanHCSigns
-- | 'tToken' as 'Term' plus 'exEqual' and 'equalS'
termToken :: TokenMode -> AParser st Term
termToken b = fmap TermToken (asKey exEqual <|> asKey equalS <|> tToken b)
-- | 'termToken' plus 'BracketTerm's
primTerm :: TokenMode -> AParser st Term
<|> mkBraces term (BracketTerm Braces)
<|> mkBrackets term (BracketTerm Squares)
<|> bracketParser termInParens oParenT cParenT anComma (BracketTerm Parens)
-- | 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 st Term
-- | 'whenS' possibly followed by an 'elseS'
whenTerm :: (InMode, TokenMode) -> AParser st Term
let l1 = [TermToken i, c]
return $ MixfixTerm $ l1 ++ [TermToken t, e]
<|> return (MixfixTerm l1)
-- | 'ifS' possibly followed by 'thenS' and 'elseS'
-- yielding a 'MixfixTerm'
ifTerm :: (InMode, TokenMode) -> AParser st Term
let l1 = [TermToken i, c]
let l2 = l1 ++ [TermToken t, e]
return $ MixfixTerm $ l2 ++ [TermToken s, f]
<|> return (MixfixTerm l2)
<|> return (MixfixTerm l1)
-- | unrestricted terms including qualified names
termInParens :: AParser st Term
termInParens = term <|> varTerm <|> qualOpName <|> qualPredName
varTerm :: AParser st Term
return $ QualVar $ VarDecl i t Other $ toRange v [] c
opBrand :: AParser st (Token, OpBrand)
opBrand = pair (asKey opS) (return Op)
<|> pair (asKey functS) (return Fun)
parsePolyId :: AParser st PolyId
l <- try ite <|> start hcKeys
then return $ PolyId (Id l [] nullRange) [] nullRange else do
(cs, ps) <- option ([], nullRange) (try $ comps hcKeys)
(tys, qs) <- option ([], nullRange) $
bracketParser typeVars oBracketT cBracketT semiT (,)
return $ PolyId (Id (l ++ u) cs ps) (concat tys) qs
-- | a qualified operation (with 'opBrand')
qualOpName :: AParser st Term
return $ QualOp b i t [] Infer $ toRange v [] c
-- | a qualified predicate
qualPredName :: AParser st Term
return $ QualOp Pred i (predTypeScheme p t) [] Infer p
-- | a qualifier expecting a further 'Type'.
-- 'inS' is rejected for 'NoIn'
typeQual :: InMode -> AParser st (TypeQual, Token)
typeQual m = myChoice $ (colT, OfType) : (asT, AsType) : case m of
WithIn -> [(asKey inS, InType)]
-- | a qualifier plus a subsequent type as mixfix term component
qualAndType :: InMode -> AParser st Term
return $ MixTypeTerm q ty $ tokPos p
-- | a possibly type qualified ('typeQual') 'primTerm' or a 'baseTerm'
typedTerm :: (InMode, TokenMode) -> AParser st Term
tys <- many $ qualAndType i
return $ if null tys then t else MixfixTerm $ t : tys
-- | several 'typedTerm's yielding a 'MixfixTerm'
mixTerm :: (InMode, TokenMode) -> AParser st Term
mixTerm = fmap mkMixfixTerm . many1 . typedTerm
-- | 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 st Term
(es, ps, _ans) <- itemAux hasCaslStartKeywords $
patternTermPair [equalS] b equalS
-- ignore collected annotations
return $ LetTerm Where es t $ catRange $ p : ps
-- | a 'whereTerm' called with ('WithIn', [])
term = whereTerm (WithIn, [])
-- | a 'Universal', 'Unique' or 'Existential' 'QuantifiedTerm'
exQuant :: AParser st (Token, Quantifier)
exQuant = choice $ map (\ (v, s) -> pair (asKey s) $ return v)
, (Unique, existsS ++ exMark)
, (Existential, existsS) ]
-- | a (possibly unique) existential 'QuantifiedTerm'
exTerm :: (InMode, TokenMode) -> AParser st Term
(vs, ps) <- varDecls `separatedBy` anSemi
return $ QuantifiedTerm q (map GenVarDecl $ concat vs) f $ toRange p ps d
lamDecls :: AParser st [Term]
(vs, _) <- separatedBy varDecls anSemi
return $ case concat vs of
[(VarDecl (Id [t] [] _) ty _ ps)] ->
-- this may be a constant constructor
[MixfixTerm [TermToken t, MixTypeTerm OfType ty ps]]
vss -> map QualVar vss) <?> "VAR-DECL") <|> lamPattern
lambdaTerm :: (InMode, TokenMode) -> AParser st Term
return $ LambdaTerm (if null pl then [BracketTerm Parens [] nullRange]
else pl) k t $ toRange l [] d
-- | a 'CaseTerm' with 'funS' excluded in 'patternTermPair'
caseTerm :: (InMode, TokenMode) -> AParser st Term
(ts, ps) <- patternTermPair [funS] (i, [barS]) funS `separatedBy` barT
return $ CaseTerm t ts $ catRange $ c : o : ps
-- | a 'LetTerm' with 'equalS' excluded in 'patternTermPair'
letTerm :: (InMode, TokenMode) -> AParser st Term
(es, ps) <- patternTermPair [equalS] (NoIn, []) equalS `separatedBy` anSemi
return $ LetTerm Let es t $ toRange l ps i
-- | a customizable pattern equation
patternTermPair :: TokenMode -> (InMode, TokenMode) -> String
patternTermPair b1 b2 sep = do
return $ ProgEq p t $ tokPos s