{- |
Module : ./CASL/Formula.hs
Description : Parser for CASL terms and formulae
Copyright : (c) Christian Maeder, Uni Bremen 2002-2006
License : GPLv2 or higher, see LICENSE.txt
Maintainer : Christian.Maeder@dfki.de
Stability : provisional
Portability : portable
parse terms and formulae
-}
{-
http://www.cofi.info/Documents/CASL/Summary/
from 25 March 2001
C.2.1 Basic Specifications with Subsorts
remarks:
when-else-TERMs are non-mixfix,
because when-else has lowest precedence.
C.3.1 Precedence
Sorted (or casted) terms are not directly recognized,
because "u v : s" may be "u (v:s)" or "(u v):s"
No term or formula may start with a parenthesized argument list that
includes commas.
The arguments of qualified ops or preds can only be given by a following
parenthesized argument list.
Braced or bracketed term-lists including commas stem from a possible
%list-annotation or (for brackets) from compound lists.
C.6.3 Literal syntax for lists
`%list b1__b2, c, f'.
b1 must contain at least one open brace or bracket ("{" or [")
and all brackets must be balanced in "b1 b2" (the empty list).
all parsers are paramterized with a String list containing additional
keywords
-}
module CASL.Formula
( term
, mixTerm
, primFormula
, genPrimFormula
, formula
, anColon
, varDecl
, varDecls
, opSort
, opFunSort
, opType
, predType
, predUnitType
, qualPredName
, implKey
, ifKey
) where
import Common.AnnoState
import Common.Id
import Common.Keywords
import Common.Lexer
import Common.Parsec
import Common.Token
import CASL.AS_Basic_CASL
import Text.ParserCombinators.Parsec
simpleTerm :: [String] -> AParser st (TERM f)
simpleTerm k = fmap Mixfix_token $ pToken
( scanFloat
<|> scanString
<|> scanQuotedChar
<|> scanDotWords
<|> reserved (k ++ casl_reserved_fwords) scanAnyWords
<|> reserved (k ++ casl_reserved_fops) scanAnySigns
<|> placeS
<?> "id/literal" )
restTerms :: TermParser f => [String] -> AParser st [TERM f]
restTerms k = (tryItemEnd startKeyword >> return [])
<|> restTerm k <:> restTerms k
<|> return []
startTerm :: TermParser f => [String] -> AParser st (TERM f)
startTerm k =
parenTerm <|> braceTerm <|> bracketTerm <|> try (addAnnos >> simpleTerm k)
restTerm :: TermParser f => [String] -> AParser st (TERM f)
restTerm k = startTerm k <|> typedTerm k <|> castedTerm k
mixTerm :: TermParser f => [String] -> AParser st (TERM f)
mixTerm k = fmap ExtTERM (termParser True) <|> do
l <- startTerm k <:> restTerms k
return $ if isSingle l then head l else Mixfix_term l
-- | when-else terms
term :: TermParser f => [String] -> AParser st (TERM f)
term k = do
t <- mixTerm k
option t $ do
w <- asKey whenS
f <- formula k
e <- asKey elseS
r <- term k
return $ Conditional t f r $ toRange w [] e
anColon :: AParser st Token
anColon = wrapAnnos colonST
typedTerm :: [String] -> AParser st (TERM f)
typedTerm k = do
c <- colonT
t <- sortId k
return $ Mixfix_sorted_term t $ tokPos c
castedTerm :: [String] -> AParser st (TERM f)
castedTerm k = do
c <- asT
t <- sortId k
return $ Mixfix_cast t $ tokPos c
terms :: TermParser f => [String] -> AParser st ([TERM f], [Token])
terms k = term k `separatedBy` anComma
qualVarName :: Token -> AParser st (TERM f)
qualVarName o = do
v <- asKey varS
i <- varId []
c <- colonT
s <- sortId [] << addAnnos
p <- cParenT
return $ Qual_var i s $ toRange o [v, c] p
qualOpName :: Token -> AParser st (TERM f)
qualOpName = fmap (`mkAppl` []) . qualOpSymb
qualOpSymb :: Token -> AParser st OP_SYMB
qualOpSymb o = do
v <- asKey opS
i <- parseId []
c <- anColon
t <- opType [] << addAnnos
p <- cParenT
return $ Qual_op_name i t $ toRange o [v, c] p
opSort :: [String] -> GenParser Char st (Bool, Id, Range)
opSort k = fmap (\ s -> (False, s, nullRange)) (sortId k) <|> do
q <- quMarkT
s <- sortId k
return (True, s, tokPos q)
opFunSort :: [String] -> [Id] -> [Token] -> GenParser Char st OP_TYPE
opFunSort k ts ps = do
a <- pToken (string funS)
(b, s, qs) <- opSort k
return $ Op_type (if b then Partial else Total) ts s
$ appRange (catRange $ ps ++ [a]) qs
opType :: [String] -> AParser st OP_TYPE
opType k = do
(b, s, p) <- opSort k
if b then return $ Op_type Partial [] s p else do
c <- crossT
(ts, ps) <- sortId k `separatedBy` crossT
opFunSort k (s : ts) (c : ps)
<|> opFunSort k [s] []
<|> return (Op_type Total [] s nullRange)
parenTerm :: TermParser f => AParser st (TERM f)
parenTerm = do
o <- wrapAnnos oParenT
qualVarName o <|> qualOpName o <|> qualPredName [] o <|> do
(ts, ps) <- terms []
c <- addAnnos >> cParenT
return (Mixfix_parenthesized ts $ toRange o ps c)
braceTerm :: TermParser f => AParser st (TERM f)
braceTerm = do
o <- wrapAnnos oBraceT
(ts, ps) <- option ([], []) $ terms []
c <- addAnnos >> cBraceT
return $ Mixfix_braced ts $ toRange o ps c
bracketTerm :: TermParser f => AParser st (TERM f)
bracketTerm = do
o <- wrapAnnos oBracketT
(ts, ps) <- option ([], []) $ terms []
c <- addAnnos >> cBracketT
return $ Mixfix_bracketed ts $ toRange o ps c
quant :: AParser st (QUANTIFIER, Token)
quant = choice (map (\ (q, s) -> do
t <- asKey s
return (q, t))
[ (Unique_existential, existsS ++ exMark)
, (Existential, existsS)
, (Universal, forallS) ])
<?> "quantifier"
varDecls :: [String] -> AParser st ([VAR_DECL], [Token])
varDecls ks = separatedBy (varDecl ks) anSemiOrComma
data VarsQualOpOrPred =
VarDecls [VAR_DECL] [Token]
| BoundOp OP_NAME OP_TYPE
| BoundPred PRED_NAME PRED_TYPE
varDeclsOrQual :: [String] -> AParser st VarsQualOpOrPred
varDeclsOrQual k =
fmap (uncurry VarDecls) (varDecls k)
<|> do
o <- oParenT
do Qual_op_name i t _ <- qualOpSymb o
return $ BoundOp i t
<|> do
Qual_pred_name i t _ <- qualPredSymb k o
return $ BoundPred i t
quantFormula :: TermParser f => [String] -> AParser st (FORMULA f)
quantFormula k = do
(q, p) <- quant
vdq <- varDeclsOrQual k
d <- dotT
f <- formula k
return $ case vdq of
VarDecls vs ps -> Quantification q vs f $ toRange p ps d
BoundOp o t -> QuantOp o t f
BoundPred i t -> QuantPred i t f
varDecl :: [String] -> AParser st VAR_DECL
varDecl k = do
(vs, ps) <- varId k `separatedBy` anComma
c <- colonT
s <- sortId k
return $ Var_decl vs s (catRange ps `appRange` tokPos c)
predType :: [String] -> AParser st PRED_TYPE
predType k = do
(ts, ps) <- sortId k `separatedBy` crossT
return (Pred_type ts (catRange ps))
<|> predUnitType
predUnitType :: GenParser Char st PRED_TYPE
predUnitType = do
o <- oParenT
c <- cParenT
return $ Pred_type [] (tokPos o `appRange` tokPos c)
qualPredName :: [String] -> Token -> AParser st (TERM f)
qualPredName k = fmap Mixfix_qual_pred . qualPredSymb k
qualPredSymb :: [String] -> Token -> AParser st PRED_SYMB
qualPredSymb k o = do
v <- asKey predS
i <- parseId k
c <- colonT
s <- predType k << addAnnos
p <- cParenT
return $ Qual_pred_name i s $ toRange o [v, c] p
parenFormula :: TermParser f => [String] -> AParser st (FORMULA f)
parenFormula k = oParenT << addAnnos >>= clParenFormula k
clParenFormula :: TermParser f => [String] -> Token -> AParser st (FORMULA f)
clParenFormula k o = do
q <- qualPredName [] o <|> qualVarName o <|> qualOpName o
l <- restTerms [] -- optional arguments
termFormula k $ if null l then q else Mixfix_term $ q : l
<|> do
f <- formula k << addAnnos
case f of
Mixfix_formula t -> do
c <- cParenT
l <- restTerms k
let tt = Mixfix_parenthesized [t] $ toRange o [] c
ft = if null l then tt else Mixfix_term $ tt : l
termFormula k ft -- commas are not allowed
_ -> cParenT >> return f
termFormula :: TermParser f => [String] -> TERM f -> AParser st (FORMULA f)
termFormula k t = do
e <- asKey exEqual
r <- term k
return $ Equation t Existl r $ tokPos e
<|> do
tryString exEqual
unexpected $ "sign following " ++ exEqual
<|> do
e <- equalT
r <- term k
return $ Equation t Strong r $ tokPos e
<|> do
e <- asKey inS
s <- sortId k
return $ Membership t s $ tokPos e
<|> return (Mixfix_formula t)
primFormula :: TermParser f => [String] -> AParser st (FORMULA f)
primFormula = genPrimFormula (termParser False)
genPrimFormula :: TermParser f => AParser st f -> [String]
-> AParser st (FORMULA f)
genPrimFormula p k = do
f <- p
return $ ExtFORMULA f
<|> primCASLFormula k
primCASLFormula :: TermParser f => [String] -> AParser st (FORMULA f)
primCASLFormula k = do
c <- asKey trueS
return . Atom True . Range $ tokenRange c
<|> do
c <- asKey falseS
return . Atom False . Range $ tokenRange c
<|> do
c <- asKey defS
t <- term k
return . Definedness t $ tokPos c
<|> do
c <- asKey notS <|> asKey negS <?> "\"not\""
f <- primFormula k
return $ Negation f $ tokPos c
<|> parenFormula k
<|> quantFormula k
<|> (term k >>= termFormula k)
andKey :: AParser st Token
andKey = asKey lAnd
orKey :: AParser st Token
orKey = asKey lOr
andOrFormula :: TermParser f => [String] -> AParser st (FORMULA f)
andOrFormula k = primFormula k >>= optAndOr k
optAndOr :: TermParser f => [String] -> FORMULA f -> AParser st (FORMULA f)
optAndOr k f = do
c <- andKey
(fs, ps) <- primFormula k `separatedBy` andKey
return $ Junction Con (f : fs) $ catRange $ c : ps
<|> do
c <- orKey
(fs, ps) <- primFormula k `separatedBy` orKey
return $ Junction Dis (f : fs) $ catRange $ c : ps
<|> return f
implKey :: AParser st Token
implKey = asKey implS
ifKey :: AParser st Token
ifKey = asKey ifS
formula :: TermParser f => [String] -> AParser st (FORMULA f)
formula k = andOrFormula k >>= optImplForm k
optImplForm :: TermParser f => [String] -> FORMULA f -> AParser st (FORMULA f)
optImplForm k f = do
c <- implKey
(fs, ps) <- andOrFormula k `separatedBy` implKey
return $ makeImpl Implication (f : fs) $ catPosAux $ c : ps
<|> do
c <- ifKey
(fs, ps) <- andOrFormula k `separatedBy` ifKey
return $ makeIf (f : fs) $ catPosAux $ c : ps
<|> do
c <- asKey equivS
g <- andOrFormula k
return $ Relation f Equivalence g $ tokPos c
<|> return f
makeImpl :: Relation -> [FORMULA f] -> [Pos] -> FORMULA f
makeImpl b l p = case (l, p) of
([f, g], _) -> Relation f b g (Range p)
(f : r, c : q) -> Relation f b (makeImpl b r q) (Range [c])
_ -> error "makeImpl got illegal argument"
makeIf :: [FORMULA f] -> [Pos] -> FORMULA f
makeIf l p = makeImpl RevImpl (reverse l) $ reverse p