hugs2yc-0.1: Yhc/Core/FrontEnd/Hugs/UnDict.hs
-- Dereferencing of dictionary-based calls in Hugs-produced Yhc Core.
module Yhc.Core.FrontEnd.Hugs.UnDict where
import Data.List
import Data.Maybe
import Yhc.Core.Extra
-- |Given function name, find out whether it is possibly a dictionary,
-- A successful candidate has zero arity and body consisting of only data constructor
-- applied to a saturating (>0) number of arguments. No let ... in, therefore all
-- constructor's arguments will point outside, no closures. If test is passed,
-- constructor name, and list of arguments will be returned, otherwise an empty
-- string and empty list will be returned.
possiblyDict :: Core -> CoreFuncName -> (CoreCtorName, [CoreExpr])
possiblyDict core fn = x
where
nodict = ("", [])
unpos (CorePos _ e) = unpos e
unpos e = e
x = case coreFuncMaybe core fn of
Just func@CoreFunc {coreFuncArgs = []} ->
case unpos (coreFuncBody func) of
CoreApp (CoreCon con) cargs ->
case coreCtorMaybe core con of
Just CoreCtor {coreCtorFields = cfs} | length cargs == length cfs
-> (con, cargs)
_ -> nodict
_ -> nodict
_ -> nodict
-- |This function eliminates a "dictionary pattern". The dictionary pattern
-- is an application of a selector function to a dictionary (that is, selection
-- of a data field) where data field contains a function name or a constructor name.
-- Overloaded funcitons such as "Prelude.*" are in fact selectors from given dictionaries.
-- Applications of a selector function to a dictionary yields another function
-- which may or may not be a selector again, to be applied to the subsequent arguments.
-- Elimination of such pattern statically gives benefits of one runtime dereference
-- removal, plus strictness analysis will be more accurate since strictness cannot
-- be seen through dictionaries. It is recommended to apply the following transformations
-- to Core prior to this one: coreCaseElim . coreSimplify . unLiftCtors . removeRecursiveLet.
unDict :: Core -> Core
unDict core = transformExpr (f core) core where
f core x@(CoreApp (CoreFun sel) ((CoreFun dict):rest)) =
let pblsel = coreSelectorIndex core sel
pbldict = possiblyDict core dict
in case (pblsel, pbldict) of
((dctn, idx), (dctr, exprs))
| null dctn || null dctr -> x
| dctn /= dctr -> x
| otherwise -> let e = exprs !! idx in case e of
CoreCon _ -> CoreApp e rest
CoreFun _ -> CoreApp e rest
CoreApp y z -> CoreApp (f core e) rest
_ -> x
f core x@(CoreApp (CoreFun sel) [y]) =
let pblsel = coreSelectorIndex core sel
in case pblsel of
(dctn, idx) | (not . null) dctn && idx >= 0 ->
CoreApp (CoreFun "SEL_ELEM")
[CoreCon dctn, y, CoreLit $ CoreInt (idx + 1)]
| otherwise -> x
f core x@(CoreApp (CoreFun sel) (y:ys)) =
let pblsel = coreSelectorIndex core sel
in case pblsel of
(dctn, idx) | (not . null) dctn && idx >= 0 ->
CoreApp (CoreApp (CoreFun "SEL_ELEM")
[CoreCon dctn, y, CoreLit $ CoreInt (idx + 1)]) ys
| otherwise -> x
f _ x = x