module Idris.ParseExpr where
import Prelude hiding (pi)
import Text.Trifecta.Delta
import Text.Trifecta hiding (span, stringLiteral, charLiteral, natural, symbol, char, string, whiteSpace, Err)
import Text.Parser.LookAhead
import Text.Parser.Expression
import qualified Text.Parser.Token as Tok
import qualified Text.Parser.Char as Chr
import qualified Text.Parser.Token.Highlight as Hi
import Idris.AbsSyntax
import Idris.ParseHelpers
import Idris.ParseOps
import Idris.DSL
import Idris.Core.TT
import Control.Applicative
import Control.Monad
import Control.Monad.State.Strict
import Data.Function (on)
import Data.Maybe
import qualified Data.List.Split as Spl
import Data.List
import Data.Monoid
import Data.Char
import qualified Data.HashSet as HS
import qualified Data.Text as T
import qualified Data.ByteString.UTF8 as UTF8
import Debug.Trace
allowImp :: SyntaxInfo -> SyntaxInfo
allowImp syn = syn { implicitAllowed = True }
disallowImp :: SyntaxInfo -> SyntaxInfo
disallowImp syn = syn { implicitAllowed = False }
fullExpr :: SyntaxInfo -> IdrisParser PTerm
fullExpr syn = do x <- expr syn
eof
i <- get
return $ debindApp syn (desugar syn i x)
tryFullExpr :: SyntaxInfo -> IState -> String -> Either Err PTerm
tryFullExpr syn st input =
case runparser (fullExpr syn) st "" input of
Success tm -> Right tm
Failure e -> Left (Msg (show e))
expr :: SyntaxInfo -> IdrisParser PTerm
expr = pi
opExpr :: SyntaxInfo -> IdrisParser PTerm
opExpr syn = do i <- get
buildExpressionParser (table (idris_infixes i)) (expr' syn)
expr' :: SyntaxInfo -> IdrisParser PTerm
expr' syn = try (externalExpr syn)
<|> internalExpr syn
<?> "expression"
externalExpr :: SyntaxInfo -> IdrisParser PTerm
externalExpr syn = do i <- get
extensions syn (syntaxRulesList $ syntax_rules i)
<?> "user-defined expression"
simpleExternalExpr :: SyntaxInfo -> IdrisParser PTerm
simpleExternalExpr syn = do i <- get
extensions syn (filter isSimple (syntaxRulesList $ syntax_rules i))
where
isSimple (Rule (Expr x:xs) _ _) = False
isSimple (Rule (SimpleExpr x:xs) _ _) = False
isSimple (Rule [Keyword _] _ _) = True
isSimple (Rule [Symbol _] _ _) = True
isSimple (Rule (_:xs) _ _) = case last xs of
Keyword _ -> True
Symbol _ -> True
_ -> False
isSimple _ = False
extensions :: SyntaxInfo -> [Syntax] -> IdrisParser PTerm
extensions syn rules = extension syn [] (filter isValid rules)
<?> "user-defined expression"
where
isValid :: Syntax -> Bool
isValid (Rule _ _ AnySyntax) = True
isValid (Rule _ _ PatternSyntax) = inPattern syn
isValid (Rule _ _ TermSyntax) = not (inPattern syn)
data SynMatch = SynTm PTerm | SynBind Name
extension :: SyntaxInfo -> [Maybe (Name, SynMatch)] -> [Syntax] -> IdrisParser PTerm
extension syn ns rules =
choice $ flip map (groupBy (ruleGroup `on` syntaxSymbols) rules) $ \rs ->
case head rs of
Rule (symb:_) _ _ -> try $ do
n <- extensionSymbol symb
extension syn (n : ns) [Rule ss t ctx | (Rule (_:ss) t ctx) <- rs]
Rule [] ptm _ -> return (flatten (update (mapMaybe id ns) ptm))
where
ruleGroup [] [] = True
ruleGroup (s1:_) (s2:_) = s1 == s2
ruleGroup _ _ = False
extensionSymbol :: SSymbol -> IdrisParser (Maybe (Name, SynMatch))
extensionSymbol (Keyword n) = do reserved (show n); return Nothing
extensionSymbol (Expr n) = do tm <- expr syn
return $ Just (n, SynTm tm)
extensionSymbol (SimpleExpr n) = do tm <- simpleExpr syn
return $ Just (n, SynTm tm)
extensionSymbol (Binding n) = do b <- fst <$> name
return $ Just (n, SynBind b)
extensionSymbol (Symbol s) = do symbol s
return Nothing
dropn :: Name -> [(Name, a)] -> [(Name, a)]
dropn n [] = []
dropn n ((x,t) : xs) | n == x = xs
| otherwise = (x,t):dropn n xs
flatten :: PTerm -> PTerm
flatten (PApp fc (PApp _ f as) bs) = flatten (PApp fc f (as ++ bs))
flatten t = t
updateB :: [(Name, SynMatch)] -> Name -> Name
updateB ns n = case lookup n ns of
Just (SynBind t) -> t
_ -> n
update :: [(Name, SynMatch)] -> PTerm -> PTerm
update ns (PRef fc n) = case lookup n ns of
Just (SynTm t) -> t
_ -> PRef fc n
update ns (PLam fc n nfc ty sc)
= PLam fc (updateB ns n) nfc (update ns ty) (update (dropn n ns) sc)
update ns (PPi p n fc ty sc)
= PPi (updTacImp ns p) (updateB ns n) fc
(update ns ty) (update (dropn n ns) sc)
update ns (PLet fc n nfc ty val sc)
= PLet fc (updateB ns n) nfc (update ns ty)
(update ns val) (update (dropn n ns) sc)
update ns (PApp fc t args)
= PApp fc (update ns t) (map (fmap (update ns)) args)
update ns (PAppBind fc t args)
= PAppBind fc (update ns t) (map (fmap (update ns)) args)
update ns (PCase fc c opts)
= PCase fc (update ns c) (map (pmap (update ns)) opts)
update ns (PIfThenElse fc c t f)
= PIfThenElse fc (update ns c) (update ns t) (update ns f)
update ns (PPair fc p l r) = PPair fc p (update ns l) (update ns r)
update ns (PDPair fc p l t r)
= PDPair fc p (update ns l) (update ns t) (update ns r)
update ns (PAlternative a as) = PAlternative a (map (update ns) as)
update ns (PHidden t) = PHidden (update ns t)
update ns (PDoBlock ds) = PDoBlock $ upd ns ds
where upd :: [(Name, SynMatch)] -> [PDo] -> [PDo]
upd ns (DoExp fc t : ds) = DoExp fc (update ns t) : upd ns ds
upd ns (DoBind fc n nfc t : ds) = DoBind fc n nfc (update ns t) : upd (dropn n ns) ds
upd ns (DoLet fc n nfc ty t : ds) = DoLet fc n nfc (update ns ty) (update ns t)
: upd (dropn n ns) ds
upd ns (DoBindP fc i t ts : ds)
= DoBindP fc (update ns i) (update ns t)
(map (\(l,r) -> (update ns l, update ns r)) ts)
: upd ns ds
upd ns (DoLetP fc i t : ds) = DoLetP fc (update ns i) (update ns t)
: upd ns ds
update ns (PGoal fc r n sc) = PGoal fc (update ns r) n (update ns sc)
update ns t = t
updTacImp ns (TacImp o st scr) = TacImp o st (update ns scr)
updTacImp _ x = x
internalExpr :: SyntaxInfo -> IdrisParser PTerm
internalExpr syn =
unifyLog syn
<|> runElab syn
<|> disamb syn
<|> noImplicits syn
<|> recordType syn
<|> if_ syn
<|> lambda syn
<|> quoteGoal syn
<|> let_ syn
<|> rewriteTerm syn
<|> doBlock syn
<|> caseExpr syn
<|> app syn
<?> "expression"
impossible :: IdrisParser PTerm
impossible = PImpossible <$ reserved "impossible"
caseExpr :: SyntaxInfo -> IdrisParser PTerm
caseExpr syn = do reserved "case"; fc <- getFC
scr <- expr syn; reserved "of";
opts <- indentedBlock1 (caseOption syn)
return (PCase fc scr opts)
<?> "case expression"
caseOption :: SyntaxInfo -> IdrisParser (PTerm, PTerm)
caseOption syn = do lhs <- expr (syn { inPattern = True })
r <- impossible <|> symbol "=>" *> expr syn
return (lhs, r)
<?> "case option"
proofExpr :: SyntaxInfo -> IdrisParser PTerm
proofExpr syn = do reserved "proof"
ts <- indentedBlock1 (tactic syn)
return $ PProof ts
<?> "proof block"
tacticsExpr :: SyntaxInfo -> IdrisParser PTerm
tacticsExpr syn = do reserved "tactics"
ts <- indentedBlock1 (tactic syn)
return $ PTactics ts
<?> "tactics block"
simpleExpr :: SyntaxInfo -> IdrisParser PTerm
simpleExpr syn =
try (simpleExternalExpr syn)
<|> do (x, FC f (l, c) end) <- try (lchar '?' *> name)
return (PMetavar (FC f (l, c1) end) x)
<|> do lchar '%'; fc <- getFC; reserved "instance"; return (PResolveTC fc)
<|> do reserved "elim_for"; fc <- getFC; t <- fst <$> fnName; return (PRef fc (SN $ ElimN t))
<|> proofExpr syn
<|> tacticsExpr syn
<|> try (do reserved "Type"; symbol "*"; return $ PUniverse AllTypes)
<|> do reserved "AnyType"; return $ PUniverse AllTypes
<|> PType <$> reservedFC "Type"
<|> do reserved "UniqueType"; return $ PUniverse UniqueType
<|> do reserved "NullType"; return $ PUniverse NullType
<|> do (c, cfc) <- constant
fc <- getFC
return (modifyConst syn fc (PConstant cfc c))
<|> do symbol "'"; fc <- getFC; str <- fst <$> name
return (PApp fc (PRef fc (sUN "Symbol_"))
[pexp (PConstant NoFC (Str (show str)))])
<|> do (x, fc) <- fnName
if inPattern syn
then option (PRef fc x)
(do reservedOp "@"
s <- simpleExpr syn
fcIn <- getFC
return (PAs fcIn x s))
else return (PRef fc x)
<|> idiom syn
<|> listExpr syn
<|> alt syn
<|> do reservedOp "!"
s <- simpleExpr syn
fc <- getFC
return (PAppBind fc s [])
<|> bracketed (disallowImp syn)
<|> quasiquote syn
<|> namequote syn
<|> unquote syn
<|> do lchar '_'; return Placeholder
<?> "expression"
bracketed :: SyntaxInfo -> IdrisParser PTerm
bracketed syn = do fc <- getFC
lchar '(' <?> "parenthesized expression"
bracketed' fc syn
bracketed' :: FC -> SyntaxInfo -> IdrisParser PTerm
bracketed' open syn =
do (FC f start (l, c)) <- getFC
lchar ')'
return $ PTrue (spanFC open (FC f start (l, c+1))) TypeOrTerm
<|> try (do ln <- fst <$> name; lchar ':';
lty <- expr syn
reservedOp "**"
fc <- getFC
r <- expr syn
lchar ')'
return (PDPair fc TypeOrTerm (PRef fc ln) lty r))
<|> try (do fc <- getFC; o <- operator; e <- expr syn; lchar ')'
if (o == "-" || o == "!")
then fail "minus not allowed in section"
else return $ PLam fc (sMN 1000 "ARG") NoFC Placeholder
(PApp fc (PRef fc (sUN o)) [pexp (PRef fc (sMN 1000 "ARG")),
pexp e]))
<|> try (do l <- simpleExpr syn
op <- option Nothing (do o <- operator
lchar ')'
return (Just o))
fc0 <- getFC
case op of
Nothing -> bracketedExpr syn l
Just o -> return $ PLam fc0 (sMN 1000 "ARG") NoFC Placeholder
(PApp fc0 (PRef fc0 (sUN o)) [pexp l,
pexp (PRef fc0 (sMN 1000 "ARG"))]))
<|> do l <- expr syn
bracketedExpr syn l
bracketedExpr :: SyntaxInfo -> PTerm -> IdrisParser PTerm
bracketedExpr syn e =
do lchar ')'; return e
<|> do fc <- do fc <- getFC
lchar ','
return fc
rs <- sepBy1 (do fc' <- getFC; r <- expr syn; return (r, fc')) (lchar ',')
lchar ')'
return $ PPair fc TypeOrTerm e (mergePairs rs)
<|> do fc <- do fc <- getFC
reservedOp "**"
return fc
r <- expr syn
lchar ')'
return (PDPair fc TypeOrTerm e Placeholder r)
<?> "end of bracketed expression"
where mergePairs :: [(PTerm, FC)] -> PTerm
mergePairs [(t, fc)] = t
mergePairs ((t, fc):rs) = PPair fc TypeOrTerm t (mergePairs rs)
modifyConst :: SyntaxInfo -> FC -> PTerm -> PTerm
modifyConst syn fc (PConstant inFC (BI x))
| not (inPattern syn)
= PAlternative FirstSuccess
(PApp fc (PRef fc (sUN "fromInteger")) [pexp (PConstant NoFC (BI (fromInteger x)))]
: consts)
| otherwise = PAlternative FirstSuccess consts
where
consts = [ PConstant inFC (BI x)
, PConstant inFC (I (fromInteger x))
, PConstant inFC (B8 (fromInteger x))
, PConstant inFC (B16 (fromInteger x))
, PConstant inFC (B32 (fromInteger x))
, PConstant inFC (B64 (fromInteger x))
]
modifyConst syn fc x = x
alt :: SyntaxInfo -> IdrisParser PTerm
alt syn = do symbol "(|"; alts <- sepBy1 (expr' syn) (lchar ','); symbol "|)"
return (PAlternative FirstSuccess alts)
hsimpleExpr :: SyntaxInfo -> IdrisParser PTerm
hsimpleExpr syn =
do lchar '.'
e <- simpleExpr syn
return $ PHidden e
<|> simpleExpr syn
<?> "expression"
unifyLog :: SyntaxInfo -> IdrisParser PTerm
unifyLog syn = do try (lchar '%' *> reserved "unifyLog")
tm <- simpleExpr syn
return (PUnifyLog tm)
<?> "unification log expression"
runElab :: SyntaxInfo -> IdrisParser PTerm
runElab syn = do try (lchar '%' *> reserved "runElab")
fc <- getFC
tm <- simpleExpr syn
i <- get
return $ PRunElab fc tm
<?> "new-style tactics expression"
disamb :: SyntaxInfo -> IdrisParser PTerm
disamb syn = do reserved "with";
ns <- sepBy1 (fst <$> name) (lchar ',')
tm <- expr' syn
return (PDisamb (map tons ns) tm)
<?> "unification log expression"
where tons (NS n s) = txt (show n) : s
tons n = [txt (show n)]
noImplicits :: SyntaxInfo -> IdrisParser PTerm
noImplicits syn = do try (lchar '%' *> reserved "noImplicits")
tm <- simpleExpr syn
return (PNoImplicits tm)
<?> "no implicits expression"
app :: SyntaxInfo -> IdrisParser PTerm
app syn = do f <- simpleExpr syn
(do try $ reservedOp "<=="
fc <- getFC
ff <- fst <$> fnName
return (PLet fc (sMN 0 "match") NoFC
f
(PMatchApp fc ff)
(PRef fc (sMN 0 "match")))
<?> "matching application expression") <|> (do
fc <- getFC
i <- get
args <- many (do notEndApp; arg syn)
case args of
[] -> return f
_ -> return (PApp fc f args))
<?> "function application"
arg :: SyntaxInfo -> IdrisParser PArg
arg syn = implicitArg syn
<|> constraintArg syn
<|> do e <- simpleExpr syn
return (pexp e)
<?> "function argument"
implicitArg :: SyntaxInfo -> IdrisParser PArg
implicitArg syn = do lchar '{'
n <- fst <$> name
fc <- getFC
v <- option (PRef fc n) (do lchar '='
expr syn)
lchar '}'
return (pimp n v True)
<?> "implicit function argument"
constraintArg :: SyntaxInfo -> IdrisParser PArg
constraintArg syn = do symbol "@{"
e <- expr syn
symbol "}"
return (pconst e)
<?> "constraint argument"
quasiquote :: SyntaxInfo -> IdrisParser PTerm
quasiquote syn = do symbol "`("
e <- expr syn { syn_in_quasiquote = (syn_in_quasiquote syn) + 1 ,
inPattern = False }
g <- optional $ do
symbol ":"
expr syn { inPattern = False }
symbol ")"
return $ PQuasiquote e g
<?> "quasiquotation"
unquote :: SyntaxInfo -> IdrisParser PTerm
unquote syn = do guard (syn_in_quasiquote syn > 0)
symbol "~"
e <- simpleExpr syn { syn_in_quasiquote = syn_in_quasiquote syn 1 }
return $ PUnquote e
<?> "unquotation"
namequote :: SyntaxInfo -> IdrisParser PTerm
namequote syn = do symbol "`{"
n <- fst <$> fnName
symbol "}"
return $ PQuoteName n
<?> "quoted name"
recordType :: SyntaxInfo -> IdrisParser PTerm
recordType syn =
do reserved "record"
lchar '{'
fgs <- fieldGetOrSet
lchar '}'
fc <- getFC
rec <- optional (simpleExpr syn)
case fgs of
Left fields ->
case rec of
Nothing ->
return (PLam fc (sMN 0 "fldx") NoFC Placeholder
(applyAll fc fields (PRef fc (sMN 0 "fldx"))))
Just v -> return (applyAll fc fields v)
Right fields ->
case rec of
Nothing ->
return (PLam fc (sMN 0 "fldx") NoFC Placeholder
(getAll fc (reverse fields)
(PRef fc (sMN 0 "fldx"))))
Just v -> return (getAll fc (reverse fields) v)
<?> "record setting expression"
where fieldSet :: IdrisParser ([Name], PTerm)
fieldSet = do ns <- fieldGet
lchar '='
e <- expr syn
return (ns, e)
<?> "field setter"
fieldGet :: IdrisParser [Name]
fieldGet = sepBy1 (fst <$> fnName) (symbol "->")
fieldGetOrSet :: IdrisParser (Either [([Name], PTerm)] [Name])
fieldGetOrSet = try (do fs <- sepBy1 fieldSet (lchar ',')
return (Left fs))
<|> do f <- fieldGet
return (Right f)
applyAll :: FC -> [([Name], PTerm)] -> PTerm -> PTerm
applyAll fc [] x = x
applyAll fc ((ns, e) : es) x
= applyAll fc es (doUpdate fc ns e x)
doUpdate fc [n] e get
= PApp fc (PRef fc (mkType n)) [pexp e, pexp get]
doUpdate fc (n : ns) e get
= PApp fc (PRef fc (mkType n))
[pexp (doUpdate fc ns e (PApp fc (PRef fc n) [pexp get])),
pexp get]
getAll :: FC -> [Name] -> PTerm -> PTerm
getAll fc [n] e = PApp fc (PRef fc n) [pexp e]
getAll fc (n:ns) e = PApp fc (PRef fc n) [pexp (getAll fc ns e)]
mkType :: Name -> Name
mkType (UN n) = sUN ("set_" ++ str n)
mkType (MN 0 n) = sMN 0 ("set_" ++ str n)
mkType (NS n s) = NS (mkType n) s
typeExpr :: SyntaxInfo -> IdrisParser PTerm
typeExpr syn = do cs <- if implicitAllowed syn then constraintList syn else return []
sc <- expr syn
return (bindList (PPi constraint) cs sc)
<?> "type signature"
lambda :: SyntaxInfo -> IdrisParser PTerm
lambda syn = do lchar '\\' <?> "lambda expression"
((do xt <- try $ tyOptDeclList syn
fc <- getFC
sc <- lambdaTail
return (bindList (PLam fc) xt sc))
<|>
(do ps <- sepBy (do fc <- getFC
e <- simpleExpr (syn { inPattern = True })
return (fc, e))
(lchar ',')
sc <- lambdaTail
return (pmList (zip [0..] ps) sc)))
<?> "lambda expression"
where pmList :: [(Int, (FC, PTerm))] -> PTerm -> PTerm
pmList [] sc = sc
pmList ((i, (fc, x)) : xs) sc
= PLam fc (sMN i "lamp") NoFC Placeholder
(PCase fc (PRef fc (sMN i "lamp"))
[(x, pmList xs sc)])
lambdaTail :: IdrisParser PTerm
lambdaTail = impossible <|> symbol "=>" *> expr syn
rewriteTerm :: SyntaxInfo -> IdrisParser PTerm
rewriteTerm syn = do reserved "rewrite"
fc <- getFC
prf <- expr syn
giving <- optional (do symbol "==>"; expr' syn)
reserved "in"; sc <- expr syn
return (PRewrite fc
(PApp fc (PRef fc (sUN "sym")) [pexp prf]) sc
giving)
<?> "term rewrite expression"
let_ :: SyntaxInfo -> IdrisParser PTerm
let_ syn = try (do reserved "let"
ls <- indentedBlock (let_binding syn)
reserved "in"; sc <- expr syn
return (buildLets ls sc))
<?> "let binding"
where buildLets [] sc = sc
buildLets ((fc, PRef nfc n, ty, v, []) : ls) sc
= PLet fc n nfc ty v (buildLets ls sc)
buildLets ((fc, pat, ty, v, alts) : ls) sc
= PCase fc v ((pat, buildLets ls sc) : alts)
let_binding syn = do fc <- getFC;
pat <- expr' (syn { inPattern = True })
ty <- option Placeholder (do lchar ':'; expr' syn)
lchar '='
v <- expr syn
ts <- option [] (do lchar '|'
sepBy1 (do_alt syn) (lchar '|'))
return (fc,pat,ty,v,ts)
if_ :: SyntaxInfo -> IdrisParser PTerm
if_ syn = (do reserved "if"
fc <- getFC
c <- expr syn
reserved "then"
t <- expr syn
reserved "else"
f <- expr syn
return (PIfThenElse fc c t f))
<?> "conditional expression"
quoteGoal :: SyntaxInfo -> IdrisParser PTerm
quoteGoal syn = do reserved "quoteGoal"; n <- fst <$> name;
reserved "by"
r <- expr syn
reserved "in"
fc <- getFC
sc <- expr syn
return (PGoal fc r n sc)
<?> "quote goal expression"
bindsymbol opts st syn
= do symbol "->"
return (Exp opts st False)
explicitPi opts st syn
= do xt <- try (lchar '(' *> typeDeclList syn <* lchar ')')
binder <- bindsymbol opts st syn
sc <- expr syn
return (bindList (PPi binder) xt sc)
autoImplicit opts st syn
= do reserved "auto"
when (st == Static) $ fail "auto implicits can not be static"
xt <- typeDeclList syn
lchar '}'
symbol "->"
sc <- expr syn
return (bindList (PPi
(TacImp [] Dynamic (PTactics [ProofSearch True True 100 Nothing []]))) xt sc)
defaultImplicit opts st syn = do
reserved "default"
when (st == Static) $ fail "default implicits can not be static"
ist <- get
script' <- simpleExpr syn
let script = debindApp syn . desugar syn ist $ script'
xt <- typeDeclList syn
lchar '}'
symbol "->"
sc <- expr syn
return (bindList (PPi (TacImp [] Dynamic script)) xt sc)
normalImplicit opts st syn = do
xt <- typeDeclList syn <* lchar '}'
symbol "->"
cs <- constraintList syn
sc <- expr syn
let (im,cl)
= if implicitAllowed syn
then (Imp opts st False Nothing,
constraint)
else (Imp opts st False (Just (Impl False)),
Imp opts st False (Just (Impl True)))
return (bindList (PPi im) xt
(bindList (PPi cl) cs sc))
implicitPi opts st syn =
autoImplicit opts st syn
<|> defaultImplicit opts st syn
<|> normalImplicit opts st syn
unboundPi opts st syn = do
x <- opExpr syn
(do binder <- bindsymbol opts st syn
sc <- expr syn
return (PPi binder (sUN "__pi_arg") NoFC x sc))
<|> return x
pi :: SyntaxInfo -> IdrisParser PTerm
pi syn =
do opts <- piOpts syn
st <- static
explicitPi opts st syn
<|> try (do lchar '{'; implicitPi opts st syn)
<|> unboundPi opts st syn
<?> "dependent type signature"
piOpts :: SyntaxInfo -> IdrisParser [ArgOpt]
piOpts syn | implicitAllowed syn =
lchar '.' *> return [InaccessibleArg]
<|> return []
piOpts syn = return []
constraintList :: SyntaxInfo -> IdrisParser [(Name, FC, PTerm)]
constraintList syn = try (constraintList1 syn)
<|> return []
constraintList1 :: SyntaxInfo -> IdrisParser [(Name, FC, PTerm)]
constraintList1 syn = try (do lchar '('
tys <- sepBy1 nexpr (lchar ',')
lchar ')'
reservedOp "=>"
return tys)
<|> try (do t <- opExpr (disallowImp syn)
reservedOp "=>"
return [(defname, NoFC, t)])
<?> "type constraint list"
where nexpr = try (do (n, fc) <- name; lchar ':'
e <- expr syn
return (n, fc, e))
<|> do e <- expr syn
return (defname, NoFC, e)
defname = sMN 0 "constrarg"
typeDeclList :: SyntaxInfo -> IdrisParser [(Name, FC, PTerm)]
typeDeclList syn = try (sepBy1 (do (x, xfc) <- fnName
lchar ':'
t <- typeExpr (disallowImp syn)
return (x, xfc, t))
(lchar ','))
<|> do ns <- sepBy1 name (lchar ',')
lchar ':'
t <- typeExpr (disallowImp syn)
return (map (\(x, xfc) -> (x, xfc, t)) ns)
<?> "type declaration list"
tyOptDeclList :: SyntaxInfo -> IdrisParser [(Name, FC, PTerm)]
tyOptDeclList syn = sepBy1 (do (x, fc) <- nameOrPlaceholder
t <- option Placeholder (do lchar ':'
expr syn)
return (x, fc, t))
(lchar ',')
<?> "type declaration list"
where nameOrPlaceholder :: IdrisParser (Name, FC)
nameOrPlaceholder = fnName
<|> do symbol "_"
return (sMN 0 "underscore", NoFC)
<?> "name or placeholder"
listExpr :: SyntaxInfo -> IdrisParser PTerm
listExpr syn = do (FC f (l, c) _) <- getFC
lchar '['; fc <- getFC;
(try . token $ do (char ']' <?> "end of list expression")
(FC _ _ (l', c')) <- getFC
return (mkNil (FC f (l, c) (l', c'))))
<|> (do x <- expr syn <?> "expression"
(do try (lchar '|') <?> "list comprehension"
qs <- sepBy1 (do_ syn) (lchar ',')
lchar ']'
return (PDoBlock (map addGuard qs ++
[DoExp fc (PApp fc (PRef fc (sUN "return"))
[pexp x])]))) <|>
(do xs <- many ((lchar ',' <?> "list element") *> expr syn)
lchar ']' <?> "end of list expression"
return (mkList fc (x:xs))))
<?> "list expression"
where
mkNil :: FC -> PTerm
mkNil fc = PRef fc (sUN "Nil")
mkList :: FC -> [PTerm] -> PTerm
mkList fc [] = PRef NoFC (sUN "Nil")
mkList fc (x : xs) = PApp fc (PRef NoFC (sUN "::")) [pexp x, pexp (mkList fc xs)]
addGuard :: PDo -> PDo
addGuard (DoExp fc e) = DoExp fc (PApp fc (PRef fc (sUN "guard"))
[pexp e])
addGuard x = x
doBlock :: SyntaxInfo -> IdrisParser PTerm
doBlock syn
= do reserved "do"
ds <- indentedBlock1 (do_ syn)
return (PDoBlock ds)
<?> "do block"
do_ :: SyntaxInfo -> IdrisParser PDo
do_ syn
= try (do reserved "let"
(i, ifc) <- name
ty <- option Placeholder (do lchar ':'
expr' syn)
reservedOp "="
fc <- getFC
e <- expr syn
return (DoLet fc i ifc ty e))
<|> try (do reserved "let"
i <- expr' syn
reservedOp "="
fc <- getFC
sc <- expr syn
return (DoLetP fc i sc))
<|> try (do (i, ifc) <- name
symbol "<-"
fc <- getFC
e <- expr syn;
option (DoBind fc i ifc e)
(do lchar '|'
ts <- sepBy1 (do_alt syn) (lchar '|')
return (DoBindP fc (PRef ifc i) e ts)))
<|> try (do i <- expr' syn
symbol "<-"
fc <- getFC
e <- expr syn;
option (DoBindP fc i e [])
(do lchar '|'
ts <- sepBy1 (do_alt syn) (lchar '|')
return (DoBindP fc i e ts)))
<|> do e <- expr syn
fc <- getFC
return (DoExp fc e)
<?> "do block expression"
do_alt syn = do l <- expr' syn
option (Placeholder, l)
(do symbol "=>"
r <- expr' syn
return (l, r))
idiom :: SyntaxInfo -> IdrisParser PTerm
idiom syn
= do symbol "[|"
fc <- getFC
e <- expr syn
symbol "|]"
return (PIdiom fc e)
<?> "expression in idiom brackets"
constants :: [(String, Idris.Core.TT.Const)]
constants =
[ ("Integer", AType (ATInt ITBig))
, ("Int", AType (ATInt ITNative))
, ("Char", AType (ATInt ITChar))
, ("Double", AType ATFloat)
, ("String", StrType)
, ("prim__WorldType", WorldType)
, ("prim__TheWorld", TheWorld)
, ("Bits8", AType (ATInt (ITFixed IT8)))
, ("Bits16", AType (ATInt (ITFixed IT16)))
, ("Bits32", AType (ATInt (ITFixed IT32)))
, ("Bits64", AType (ATInt (ITFixed IT64)))
]
constant :: IdrisParser (Idris.Core.TT.Const, FC)
constant = choice [ do fc <- reservedFC name; return (ty, fc)
| (name, ty) <- constants
]
<|> do (f, fc) <- try float; return (Fl f, fc)
<|> do (i, fc) <- natural; return (BI i, fc)
<|> do (s, fc) <- verbatimStringLiteral; return (Str s, fc)
<|> do (s, fc) <- stringLiteral; return (Str s, fc)
<|> do (c, fc) <- try charLiteral; return (Ch c, fc)
<?> "constant or literal"
verbatimStringLiteral :: MonadicParsing m => m (String, FC)
verbatimStringLiteral = token $ do (FC f start _) <- getFC
try $ string "\"\"\""
str <- manyTill anyChar $ try (string "\"\"\"")
(FC _ _ end) <- getFC
return (str, FC f start end)
static :: IdrisParser Static
static = do reserved "[static]"; return Static
<|> return Dynamic
<?> "static modifier"
data TacticArg = NameTArg
| ExprTArg
| AltsTArg
| StringLitTArg
tactics :: [([String], Maybe TacticArg, SyntaxInfo -> IdrisParser PTactic)]
tactics =
[ (["intro"], Nothing, const $
do ns <- sepBy (spaced (fst <$> name)) (lchar ','); return $ Intro ns)
, noArgs ["intros"] Intros
, noArgs ["unfocus"] Unfocus
, (["refine"], Just ExprTArg, const $
do n <- spaced (fst <$> fnName)
imps <- many imp
return $ Refine n imps)
, (["claim"], Nothing, \syn ->
do n <- indentPropHolds gtProp *> (fst <$> name)
goal <- indentPropHolds gtProp *> expr syn
return $ Claim n goal)
, (["mrefine"], Just ExprTArg, const $
do n <- spaced (fst <$> fnName)
return $ MatchRefine n)
, expressionTactic ["rewrite"] Rewrite
, expressionTactic ["case"] CaseTac
, expressionTactic ["induction"] Induction
, expressionTactic ["equiv"] Equiv
, (["let"], Nothing, \syn ->
do n <- (indentPropHolds gtProp *> (fst <$> name))
(do indentPropHolds gtProp *> lchar ':'
ty <- indentPropHolds gtProp *> expr' syn
indentPropHolds gtProp *> lchar '='
t <- indentPropHolds gtProp *> expr syn
i <- get
return $ LetTacTy n (desugar syn i ty) (desugar syn i t))
<|> (do indentPropHolds gtProp *> lchar '='
t <- indentPropHolds gtProp *> expr syn
i <- get
return $ LetTac n (desugar syn i t)))
, (["focus"], Just ExprTArg, const $
do n <- spaced (fst <$> name)
return $ Focus n)
, expressionTactic ["exact"] Exact
, expressionTactic ["applyTactic"] ApplyTactic
, expressionTactic ["byReflection"] ByReflection
, expressionTactic ["reflect"] Reflect
, expressionTactic ["fill"] Fill
, (["try"], Just AltsTArg, \syn ->
do t <- spaced (tactic syn)
lchar '|'
t1 <- spaced (tactic syn)
return $ Try t t1)
, noArgs ["compute"] Compute
, noArgs ["trivial"] Trivial
, noArgs ["unify"] DoUnify
, (["search"], Nothing, const $
do depth <- option 10 $ fst <$> natural
return (ProofSearch True True (fromInteger depth) Nothing []))
, noArgs ["instance"] TCInstance
, noArgs ["solve"] Solve
, noArgs ["attack"] Attack
, noArgs ["state"] ProofState
, noArgs ["term"] ProofTerm
, noArgs ["undo"] Undo
, noArgs ["qed"] Qed
, noArgs ["abandon", ":q"] Abandon
, noArgs ["skip"] Skip
, noArgs ["sourceLocation"] SourceFC
, expressionTactic [":e", ":eval"] TEval
, expressionTactic [":t", ":type"] TCheck
, expressionTactic [":search"] TSearch
, (["fail"], Just StringLitTArg, const $
do msg <- fst <$> stringLiteral
return $ TFail [Idris.Core.TT.TextPart msg])
, ([":doc"], Just ExprTArg, const $
do whiteSpace
doc <- (Right . fst <$> constant) <|> (Left . fst <$> fnName)
eof
return (TDocStr doc))
]
where
expressionTactic names tactic = (names, Just ExprTArg, \syn ->
do t <- spaced (expr syn)
i <- get
return $ tactic (desugar syn i t))
noArgs names tactic = (names, Nothing, const (return tactic))
spaced parser = indentPropHolds gtProp *> parser
imp :: IdrisParser Bool
imp = do lchar '?'; return False
<|> do lchar '_'; return True
tactic :: SyntaxInfo -> IdrisParser PTactic
tactic syn = choice [ do choice (map reserved names); parser syn
| (names, _, parser) <- tactics ]
<|> do lchar '{'
t <- tactic syn;
lchar ';';
ts <- sepBy1 (tactic syn) (lchar ';')
lchar '}'
return $ TSeq t (mergeSeq ts)
<|> ((lchar ':' >> empty) <?> "prover command")
<?> "tactic"
where
mergeSeq :: [PTactic] -> PTactic
mergeSeq [t] = t
mergeSeq (t:ts) = TSeq t (mergeSeq ts)
fullTactic :: SyntaxInfo -> IdrisParser PTactic
fullTactic syn = do t <- tactic syn
eof
return t