on master help sign in
Begin implementation of reflected elab monad
commita0346b662dcd5928877917850641f3ba195db7a9 authorDavid Raymond Christiansen <david@davidchristiansen.dk> dateWed 18 Feb 2015, 02:54 (12 years ago) parentfca8309
11 files changed+189−13
libs/prelude/Language/Reflection/Tactical.idr+53 libs/prelude/prelude.ipkg+1−1 src/Idris/AbsSyntax.hs+4 src/Idris/AbsSyntaxTree.hs+2−1 src/Idris/Core/Elaborate.hs+1−1 src/Idris/DeepSeq.hs+1 src/Idris/ElabQuasiquote.hs+2 src/Idris/ElabTerm.hs+107−9 src/Idris/IBC.hs+5−1 src/Idris/IdrisDoc.hs+1 src/Idris/ParseExpr.hs+12
libs/prelude/Language/Reflection/Tactical.idrnew file+53
@@ -0,0 +1,53 @@
1+module Language.Reflection.Tactical
2+
3+import Builtins
4+import Prelude.Applicative
5+import Prelude.Functor
6+import Prelude.List
7+import Prelude.Maybe
8+import Prelude.Monad
9+import Language.Reflection
10+
11+data Tactical : Type -> Type where
12+ -- obligatory control stuff
13+ PureTactical : a -> Tactical a
14+ BindTactical : {a, b : Type} -> Tactical a -> (a -> Tactical b) -> Tactical b
15+
16+ Try : {a : Type} -> Tactical a -> Tactical a -> Tactical a
17+ Skip : Tactical ()
18+ Fail : {a : Type} -> List ErrorReportPart -> Tactical a
19+
20+ Env : Tactical (List (TTName, Binder TT))
21+ Goal : Tactical (TTName, TT)
22+ Holes : Tactical (List TTName)
23+ Guess : Tactical (Maybe TT)
24+
25+ Forget : TT -> Tactical Raw
26+
27+ Gensym : String -> Tactical TTName
28+
29+ Solve : Tactical ()
30+ Fill : Raw -> Tactical ()
31+ Focus : TTName -> Tactical ()
32+ Unfocus : TTName -> Tactical ()
33+ Attack : Tactical ()
34+
35+ Claim : TTName -> Raw -> Tactical ()
36+
37+
38+instance Functor Tactical where
39+ map f t = BindTactical t (\x => PureTactical (f x))
40+
41+instance Applicative Tactical where
42+ pure x = PureTactical x
43+ f <$> x = BindTactical f $ \g =>
44+ BindTactical x $ \y =>
45+ PureTactical $ g y
46+
47+instance Alternative Tactical where
48+ empty = Fail [TextPart "empty"]
49+ x <|> y = Try x y
50+
51+instance Monad Tactical where
52+ x >>= f = BindTactical x f
53+
libs/prelude/prelude.ipkg+1−1
@@ -10,7 +10,7 @@ modules = Builtins, Prelude, IO,
1010 Prelude.Foldable, Prelude.Traversable, Prelude.Bits, Prelude.Stream,
1111 Prelude.Uninhabited, Prelude.Pairs,
1212
13− Language.Reflection, Language.Reflection.Errors,
13+ Language.Reflection, Language.Reflection.Errors, Language.Reflection.Tactical,
1414
1515 Decidable.Equality
1616
src/Idris/AbsSyntax.hs+4
@@ -974,6 +974,7 @@ expandParams dec ps ns infs tm = en tm
974974 en (PApp fc f as) = PApp fc (en f) (map (fmap en) as)
975975 en (PAppBind fc f as) = PAppBind fc (en f) (map (fmap en) as)
976976 en (PCase fc c os) = PCase fc (en c) (map (pmap en) os)
977+ en (PRunTactics tm) = PRunTactics (en tm)
977978 en t = t
978979
979980 nselem x [] = False
@@ -1444,6 +1445,7 @@ implicitise syn ignore ist tm = -- trace ("INCOMING " ++ showImp True tm) $
14441445 imps top env (PHidden tm) = imps False env tm
14451446 imps top env (PUnifyLog tm) = imps False env tm
14461447 imps top env (PNoImplicits tm) = imps False env tm
1448+ imps top env (PRunTactics tm) = imps False env tm
14471449 imps top env _ = return ()
14481450
14491451 pibind using [] sc = sc
@@ -1565,6 +1567,7 @@ addImpl' inpat env infns ist ptm
15651567 ai qq env ds (PQuasiquote tm g) = PQuasiquote (ai True env ds tm)
15661568 (fmap (ai True env ds) g)
15671569 ai qq env ds (PUnquote tm) = PUnquote (ai False env ds tm)
1570+ ai qq env ds (PRunTactics tm) = PRunTactics (ai False env ds tm)
15681571 ai qq env ds tm = tm
15691572
15701573 handleErr (Left err) = PElabError err
@@ -2089,4 +2092,5 @@ mkUniqueNames env tm = evalState (mkUniq tm) (S.fromList env) where
20892092 mkUniq (PNoImplicits t) = liftM PNoImplicits (mkUniq t)
20902093 mkUniq (PProof ts) = liftM PProof (mapM mkUniqT ts)
20912094 mkUniq (PTactics ts) = liftM PTactics (mapM mkUniqT ts)
2095+ mkUniq (PRunTactics ts) = liftM PRunTactics (mkUniq ts)
20922096 mkUniq t = return t
src/Idris/AbsSyntaxTree.hs+2−1
@@ -790,7 +790,8 @@ data PTerm = PQuote Raw -- ^ Inclusion of a core term into the high-level langua
790790 | PUnifyLog PTerm -- ^ dump a trace of unifications when building term
791791 | PNoImplicits PTerm -- ^ never run implicit converions on the term
792792 | PQuasiquote PTerm (Maybe PTerm) -- ^ `(Term [: Term])
793− | PUnquote PTerm -- ^ ,Term
793+ | PUnquote PTerm -- ^ ~Term
794+ | PRunTactics PTerm -- ^ %run_tactics tm - New-style proof script
794795 deriving (Eq, Data, Typeable)
795796
796797
src/Idris/Core/Elaborate.hs+1−1
@@ -190,7 +190,7 @@ get_term :: Elab' aux Term
190190get_term = do ES p _ _ <- get
191191 return $! (getProofTerm (pterm (fst p)))
192192
193−-- | get the proof term
193+-- | modify the proof term
194194update_term :: (Term -> Term) -> Elab' aux ()
195195update_term f = do ES (p,a) logs prev <- get
196196 let p' = p { pterm = mkProofTerm (f (getProofTerm (pterm p))) }
src/Idris/DeepSeq.hs+1
@@ -239,6 +239,7 @@ instance NFData PTerm where
239239 rnf (PNoImplicits x1) = rnf x1 `seq` ()
240240 rnf (PQuasiquote x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
241241 rnf (PUnquote x1) = rnf x1 `seq` ()
242+ rnf (PRunTactics x1) = rnf x1 `seq` ()
242243
243244instance (NFData t) => NFData (PTactic' t) where
244245 rnf (Intro x1) = rnf x1 `seq` ()
src/Idris/ElabQuasiquote.hs+2
@@ -170,6 +170,8 @@ extractUnquotes n (PUnquote tm)
170170 return (PRef (fileFC "(unquote)") n, [(n, tm)])
171171 | otherwise = fmap (\(tm', ex) -> (PUnquote tm', ex)) $
172172 extractUnquotes (n-1) tm
173+extractUnquotes n (PRunTactics tm)
174+ = fmap (\(tm', ex) -> (PRunTactics tm', ex)) $ extractUnquotes n tm
173175extractUnquotes n x = return (x, []) -- no subterms!
174176
175177
src/Idris/ElabTerm.hs+107−9
@@ -1,4 +1,4 @@
1−{-# LANGUAGE PatternGuards #-}
1+{-# LANGUAGE PatternGuards, ViewPatterns #-}
22
33module Idris.ElabTerm where
44
@@ -1029,6 +1029,20 @@ elab ist info emode opts fn tm
10291029 delayElab $ do focus h
10301030 dotterm
10311031 elab' ina fc t
1032+ elab' ina fc (PRunTactics tm) =
1033+ do attack
1034+ n <- getNameFrom (sMN 0 "tacticScript")
1035+ n' <- getNameFrom (sMN 0 "tacticExpr")
1036+ let scriptTy = RApp (Var (sNS (sUN "Tactical") ["Tactical", "Reflection", "Language"])) (Var unitTy)
1037+ claim n scriptTy
1038+ movelast n
1039+ letbind n' scriptTy (Var n)
1040+ focus n
1041+ elab' ina fc tm
1042+ env <- get_env
1043+ ctxt <- get_context
1044+ runTactical ctxt env (P Bound n' Erased)
1045+ solve
10321046 elab' ina fc x = fail $ "Unelaboratable syntactic form " ++ showTmImpls x
10331047
10341048 delayElab t = updateAux (\e -> e { delayed_elab = delayed_elab e ++ [t] })
@@ -1451,6 +1465,86 @@ case_ ind autoSolve ist fn tm = do
14511465 else casetac (forget val)
14521466 when autoSolve solveAll
14531467
1468+runTactical :: Context -> Env -> Term -> ElabD ()
1469+runTactical ctxt env tm = runTacTm (eval tm) >> return ()
1470+ where
1471+ eval = normaliseAll ctxt env
1472+ tacN str = sNS (sUN str) ["Tactical", "Reflection", "Language"]
1473+ returnUnit = fmap fst $ get_type_val (Var unitCon)
1474+
1475+ -- | Do a step in the reflected elaborator monad. The input is the
1476+ -- step, the output is the (reflected) term returned.
1477+ runTacTm :: Term -> ElabD Term
1478+ runTacTm (unApply -> tac@(P _ n _, args))
1479+ | n == tacN "Solve", [] <- args
1480+ = do solve
1481+ returnUnit
1482+ | n == tacN "Goal", [] <- args
1483+ = do (h:_) <- get_holes
1484+ t <- goal
1485+ fmap fst . get_type_val $
1486+ rawPair (Var (reflm "TTName"), Var (reflm "TT"))
1487+ (reflectName h, reflect t)
1488+ | n == tacN "Holes", [] <- args
1489+ = do hs <- get_holes
1490+ fmap fst . get_type_val $
1491+ mkList (Var $ reflm "TTName") (map reflectName hs)
1492+ | n == tacN "Guess", [] <- args
1493+ = do ok <- is_guess
1494+ if ok
1495+ then do guess <- fmap forget get_guess
1496+ fmap fst . get_type_val $
1497+ RApp (RApp (Var (sNS (sUN "Just") ["Maybe", "Prelude"]))
1498+ (Var (reflm "TT")))
1499+ guess
1500+ else fmap fst . get_type_val $
1501+ RApp (Var (sNS (sUN "Nothing") ["Maybe", "Prelude"]))
1502+ (Var (reflm "TT"))
1503+ | n == tacN "Env", [] <- args
1504+ = do env <- get_env
1505+ fmap fst . get_type_val $ reflectEnv env
1506+ | n == tacN "Fail", [_a, errs] <- args
1507+ = do parts <- reifyReportParts (eval errs)
1508+ lift . tfail $ ReflectionError [parts] (Msg "")
1509+ | n == tacN "PureTactical", [_a, tm] <- args
1510+ = return tm
1511+ | n == tacN "BindTactical", [_a, _b, first, andThen] <- args
1512+ = do let first' = eval first
1513+ res <- runTacTm first'
1514+ let next = eval (App andThen res)
1515+ runTacTm next
1516+ | n == tacN "Try", [_a, first, alt] <- args
1517+ = do let first' = eval first
1518+ let alt' = eval alt
1519+ try' (runTacTm first') (runTacTm alt') True
1520+ | n == tacN "Fill", [raw] <- args
1521+ = do raw' <- reifyRaw raw
1522+ apply raw' []
1523+ returnUnit
1524+ | n == tacN "Gensym", [eval -> Constant (Str hint)] <- args
1525+ = do n <- getNameFrom (sMN 0 hint)
1526+ fmap fst $ get_type_val (reflectName n)
1527+ | n == tacN "Claim", [n, ty] <- args
1528+ = do n' <- reifyTTName n
1529+ ty' <- reifyRaw ty
1530+ claim n' ty'
1531+ returnUnit
1532+ | n == tacN "Forget", [tt] <- args
1533+ = do tt' <- reifyTT tt
1534+ fmap fst . get_type_val $ reflect tt'
1535+ | n == tacN "Attack", [] <- args
1536+ = do attack
1537+ returnUnit
1538+ | n == tacN "Focus", [what] <- args
1539+ = do n' <- reifyTTName what
1540+ focus n'
1541+ returnUnit
1542+ | n == tacN "Unfocus", [what] <- args
1543+ = do n' <- reifyTTName what
1544+ movelast n'
1545+ returnUnit
1546+ runTacTm x = lift . tfail . InternalMsg $ "tactical is not implemented for " ++ show x
1547+
14541548-- Running tactics directly
14551549-- if a tactic adds unification problems, return an error
14561550
@@ -1776,16 +1870,20 @@ reifyApp ist t [n, tt', t']
17761870 t'' <- reifyTT t'
17771871 return $ LetTacTy n' (delab ist tt'') (delab ist t'')
17781872reifyApp ist t [errs]
1779− | t == reflm "Fail" = case unList errs of
1780− Nothing -> fail "Failed to reify errors"
1781− Just errs' ->
1782− let parts = mapM reifyReportPart errs' in
1783− case parts of
1784− Left err -> fail $ "Couldn't reify \"Fail\" tactic - " ++ show err
1785− Right errs'' ->
1786− return $ TFail errs''
1873+ | t == reflm "Fail" = fmap TFail (reifyReportParts errs)
17871874reifyApp _ f args = fail ("Unknown tactic " ++ show (f, args)) -- shouldn't happen
17881875
1876+reifyReportParts :: Term -> ElabD [ErrorReportPart]
1877+reifyReportParts errs =
1878+ case unList errs of
1879+ Nothing -> fail "Failed to reify errors"
1880+ Just errs' ->
1881+ let parts = mapM reifyReportPart errs' in
1882+ case parts of
1883+ Left err -> fail $ "Couldn't reify \"Fail\" tactic - " ++ show err
1884+ Right errs'' ->
1885+ return errs''
1886+
17891887-- | Reify terms from their reflected representation
17901888reifyTT :: Term -> ElabD Term
17911889reifyTT t@(App _ _)
src/Idris/IBC.hs+5−1
@@ -36,7 +36,7 @@ import Codec.Compression.Zlib (compress)
3636import Util.Zlib (decompressEither)
3737
3838ibcVersion :: Word8
39−ibcVersion = 96
39+ibcVersion = 97
4040
4141data IBCFile = IBCFile { ver :: Word8,
4242 sourcefile :: FilePath,
@@ -1571,6 +1571,8 @@ instance Binary PTerm where
15711571 put x2
15721572 PUniverse x1 -> do putWord8 38
15731573 put x1
1574+ PRunTactics x1 -> do putWord8 39
1575+ put x1
15741576
15751577 get
15761578 = do i <- getWord8
@@ -1689,6 +1691,8 @@ instance Binary PTerm where
16891691 return (PDisamb x1 x2)
16901692 38 -> do x1 <- get
16911693 return (PUniverse x1)
1694+ 39 -> do x1 <- get
1695+ return (PRunTactics x1)
16921696 _ -> error "Corrupted binary data for PTerm"
16931697
16941698instance (Binary t) => Binary (PTactic' t) where
src/Idris/IdrisDoc.hs+1
@@ -318,6 +318,7 @@ extractPTermNames (PCoerced p) = extract p
318318extractPTermNames (PDisamb _ p) = extract p
319319extractPTermNames (PUnifyLog p) = extract p
320320extractPTermNames (PNoImplicits p) = extract p
321+extractPTermNames (PRunTactics p) = extract p
321322extractPTermNames _ = []
322323
323324-- | Shorter name for extractPTermNames
src/Idris/ParseExpr.hs+12
@@ -221,6 +221,7 @@ InternalExpr ::=
221221internalExpr :: SyntaxInfo -> IdrisParser PTerm
222222internalExpr syn =
223223 unifyLog syn
224+ <|> runTactics syn
224225 <|> disamb syn
225226 <|> noImplicits syn
226227 <|> recordType syn
@@ -487,6 +488,17 @@ unifyLog syn = do try (lchar '%' *> reserved "unifyLog")
487488 return (PUnifyLog tm)
488489 <?> "unification log expression"
489490
491+{- | Parses a new-style tactics expression
492+RunTactics ::=
493+ '%' 'runTactics' SimpleExpr
494+ ;
495+-}
496+runTactics :: SyntaxInfo -> IdrisParser PTerm
497+runTactics syn = do try (lchar '%' *> reserved "runTactics")
498+ tm <- simpleExpr syn
499+ return (PRunTactics tm)
500+ <?> "new-style tactics expression"
501+
490502{- | Parses a disambiguation expression
491503Disamb ::=
492504 '%' 'disamb' NameList Expr