@@ -14,11 +14,13 @@ import Idris.Providers
1414import Idris.Primitives
1515import Idris.Inliner
1616import Idris.PartialEval
17+import Idris.Transforms
1718import Idris.DeepSeq
1819import Idris.Output (iputStrLn, pshow, iWarn)
1920import IRTS.Lang
2021
2122import Idris.Elab.Type
23+import Idris.Elab.Transform
2224import Idris.Elab.Utils
2325
2426import Idris.Core.TT
@@ -48,6 +50,7 @@ import Data.Char(isLetter, toLower)
4850import Data.List.Split (splitOn)
4951
5052import Util.Pretty(pretty, text)
53+import Numeric
5154
5255-- | Elaborate a collection of left-hand and right-hand pairs - that is, a
5356-- top-level definition.
@@ -81,13 +84,31 @@ elabClauses info fc opts n_in cs = let n = liftname info n_in in
8184 addIBC (IBCOpt n)
8285
8386 ist <- getIState
84− let pats = map (simple_lhs (tt_ctxt ist)) $ doTransforms ist pats_in
87+ -- Don't apply rules if this is a partial evaluation definition,
88+ -- or we'll make something that just runs itself!
89+ let tpats = case specNames opts of
90+ Nothing -> transformPats ist pats_in
91+ _ -> pats_in
92+
93+ let pats = map (simple_lhs (tt_ctxt ist)) $
94+ doPartialEval ist tpats
8595
8696 -- logLvl 3 (showSep "\n" (map (\ (l,r) ->
8797 -- show l ++ " = " ++
8898 -- show r) pats))
8999 let tcase = opt_typecase (idris_options ist)
90100
101+ -- Look for 'static' names and generate new specialised
102+ -- definitions for them, as well as generating rewrite rules
103+ -- for partially evaluated definitions
104+ mapM_ (\ e -> case e of
105+ Left _ -> return ()
106+ Right (l, r) -> elabPE info fc n r) pats
107+
108+ -- Redo transforms with the newly generated transformations
109+ ist <- getIState
110+ let pats_transformed = transformPats ist pats
111+
91112 -- Summary of what's about to happen: Definitions go:
92113 --
93114 -- pats_in -> pats -> pdef -> pdef'
@@ -97,18 +118,11 @@ elabClauses info fc opts n_in cs = let n = liftname info n_in in
97118 -- pdef is the compile-time pattern definition.
98119 -- This will get further optimised for run-time, and, separately,
99120 -- further inlined to help with totality checking.
100− let pdef = map debind pats
121+ let pdef = map debind pats_transformed
101122
102123 logLvl 5 $ "Initial typechecked patterns:\n" ++ show pats
103124 logLvl 5 $ "Initial typechecked pattern def:\n" ++ show pdef
104125
105− -- Look for 'static' names and generate new specialised
106− -- definitions for them
107−
108− mapM_ (\ e -> case e of
109− Left _ -> return ()
110− Right (l, r) -> elabPE info fc n r) pats
111−
112126 -- NOTE: Need to store original definition so that proofs which
113127 -- rely on its structure aren't affected by any changes to the
114128 -- inliner. Just use the inlined version to generate pdef' and to
@@ -120,7 +134,7 @@ elabClauses info fc opts n_in cs = let n = liftname info n_in in
120134 numArgs <- tclift $ sameLength pdef
121135
122136 case specNames opts of
123− Just _ -> logLvl 5 $ "Partially evaluated:\n" ++ show pats
137+ Just _ -> logLvl 1 $ "Partially evaluated:\n" ++ show pats
124138 _ -> return ()
125139
126140 erInfo <- getErasureInfo <$> getIState
@@ -163,7 +177,6 @@ elabClauses info fc opts n_in cs = let n = liftname info n_in in
163177 -- then case tot of
164178 -- Total _ -> return ()
165179 -- t -> tclift $ tfail (At fc (Msg (show n ++ " is " ++ show t)))
166− -- else return ()
167180 -- _ -> return ()
168181 case tree of
169182 CaseDef _ _ [] -> return ()
@@ -271,9 +284,8 @@ elabClauses info fc opts n_in cs = let n = liftname info n_in in
271284 else tfail (At fc (Msg "Clauses have differing numbers of arguments "))
272285 sameLength [] = return 0
273286
274− -- apply all transformations (just specialisation for now, add
275− -- user defined transformation rules later)
276− doTransforms ist pats =
287+ -- Partially evaluate, if the definition is marked as specialisable
288+ doPartialEval ist pats =
277289 case specNames opts of
278290 Nothing -> pats
279291 Just ns -> partial_eval (tt_ctxt ist) ns pats
@@ -285,38 +297,45 @@ elabPE info fc caller r =
285297 let sa = getSpecApps ist [] r
286298 mapM_ (mkSpecialised ist) sa
287299 where
288− -- TODO: Add a PTerm level transformation rule, which is basically the
300+ -- Make a specialised version of the application, and
301+ -- add a PTerm level transformation rule, which is basically the
289302 -- new definition in reverse (before specialising it).
290303 -- RHS => LHS where implicit arguments are left blank in the
291304 -- transformation.
292305
293− -- Apply that transformation after every PClauses elaboration
306+ -- Transformation rules are applied after every PClause elaboration
294307
295308 mkSpecialised ist specapp_in = do
296309 let (specTy, specapp) = getSpecTy ist specapp_in
297− let (n, newnm, pats) = getSpecClause ist specapp
310+ let (n, newnm, (lhs, rhs)) = getSpecClause ist specapp
298311 let undef = case lookupDef newnm (tt_ctxt ist) of
299312 [] -> True
300313 _ -> False
301− logLvl 5 $ show (newnm, map (concreteArg ist) (snd specapp))
314+ logLvl 3 $ show (newnm, map (concreteArg ist) (snd specapp))
302315 idrisCatch
303316 (when (undef && all (concreteArg ist) (snd specapp)) $ do
304317 cgns <- getAllNames n
305318 let opts = [Specialise (map (\x -> (x, Nothing)) cgns ++
306319 mapMaybe specName (snd specapp))]
307320 logLvl 3 $ "Specialising application: " ++ show specapp
308− logLvl 2 $ "New name: " ++ show newnm
309− iLOG $ "PE definition type : " ++ (show specTy)
321+ ++ " with " ++ show cgns
322+ logLvl 3 $ "New name: " ++ show newnm
323+ logLvl 3 $ "PE definition type : " ++ (show specTy)
310324 ++ "\n" ++ show opts
311− logLvl 2 $ "PE definition " ++ show newnm ++ ":\n" ++
312− showSep "\n"
313− (map (\ (lhs, rhs) ->
325+ logLvl 3 $ "PE definition " ++ show newnm ++ ":\n" ++
326+-- showSep "\n"
327+-- (map (\ (lhs, rhs) ->
314328 (showTmImpls lhs ++ " = " ++
315− showTmImpls rhs)) pats)
329+ showTmImpls rhs) -- pats)
330+
331+ logLvl 2 $ show n ++ " transformation rule: " ++
332+ show rhs ++ " ==> " ++ show lhs
333+
316334 elabType info defaultSyntax emptyDocstring [] fc opts newnm specTy
317− let def = map (\ (lhs, rhs) -> PClause fc newnm lhs [] rhs []) pats
318− elabClauses info fc opts newnm def
319− logLvl 2 $ "Specialised " ++ show newnm)
335+ let def = -- map (\ (lhs, rhs) ->
336+ [PClause fc newnm lhs [] rhs []] --) pats
337+ elabTransform info fc False rhs lhs
338+ elabClauses info fc opts newnm def)
320339 -- if it doesn't work, just don't specialise. Could happen for lots
321340 -- of valid reasons (e.g. local variables in scope which can't be
322341 -- lifted out).
@@ -351,14 +370,20 @@ elabPE info fc caller r =
351370
352371 -- get the clause of a specialised application
353372 getSpecClause ist (n, args)
354− = let newnm = sUN ("__"++show (nsroot n) ++ "_" ++
355− showSep "_" (map showArg args)) in
373+ = let newnm = sUN ("PE_"++show (nsroot n) ++ "_" ++
374+ qhash 0 (showSep "_" (map showArg args))) in
356375 -- UN (show n ++ show (map snd args)) in
357376 (n, newnm, mkPE_TermDecl ist newnm n args)
358377 where showArg (ExplicitS, n) = show n
359378 showArg (ImplicitS, n) = show n
360379 showArg _ = ""
361380
381+ -- TMP for readability! This is obviously a really bad hashing
382+ -- function.
383+ qhash :: Int -> String -> String
384+ qhash acc [] = showHex acc ""
385+ qhash acc (x:xs) = qhash (fromEnum x + acc) xs
386+
362387-- checks if the clause is a possible left hand side. Returns the term if
363388-- possible, otherwise Nothing.
364389