---- Copyright (c) 2009-2010, ERICSSON AB All rights reserved.-- -- Redistribution and use in source and binary forms, with or without-- modification, are permitted provided that the following conditions are met:-- -- * Redistributions of source code must retain the above copyright notice,-- this list of conditions and the following disclaimer.-- * Redistributions in binary form must reproduce the above copyright-- notice, this list of conditions and the following disclaimer in the-- documentation and/or other materials provided with the distribution.-- * Neither the name of the ERICSSON AB nor the names of its contributors-- may be used to endorse or promote products derived from this software-- without specific prior written permission.-- -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE-- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS-- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF-- THE POSSIBILITY OF SUCH DAMAGE.--{-# LANGUAGE OverlappingInstances, UndecidableInstances #-}-- | Functions for reifying expressions ('Data' / 'Expr') to graphs ('Graph')-- and to textual format.moduleFeldspar.Core.Reify(Program(..),showCore,showCoreWithSize,printCore,printCoreWithSize,runGraph,buildSubFun,startInfo)whereimportControl.Monad.StateimportControl.Monad.WriterimportData.Map(Map)importqualifiedData.MapasMapimportData.MaybeimportData.UniqueimportFeldspar.Core.TypesimportFeldspar.Core.RefimportFeldspar.Core.ExprimportFeldspar.Core.Graphhiding(function,Function(..),Variable)importqualifiedFeldspar.Core.GraphasGraphimportFeldspar.Core.ShowdataInfo=Info{-- | Next idindex::NodeId-- | Visited references mapped to their id,visited::MapUniqueNodeId}-- | Monad for making graph building easiertypeReifya=WriterT[Node](StateInfo)astartInfo::InfostartInfo=Info0Map.emptyrunGraph::Reifya->Info->(a,([Node],Info))runGraphgraphinfo=(a,(nodes,info'))where((a,nodes),info')=runState(runWriterTgraph)infonewIndex::ReifyNodeIdnewIndex=doinfo<-getput(info{index=succ(indexinfo)})return(indexinfo)remember::Dataa->NodeId->Reify()rememberai=modify$\info->info{visited=Map.insert(dataIda)i(visitedinfo)}checkNode::Dataa->Reify(MaybeNodeId)checkNodea=gets((Map.lookup(dataIda)).visited)-- | Declare a nodenode::Dataa->Graph.Function->TupleSource->TupleStorableType->Reify()nodea@(Data__)funinTupinType=doi<-newIndexrememberaitell[NodeifuninTupinType(dataTypea)]-- | Declare a source node (one with no inputs)sourceNode::Dataa->Graph.Function->Reify()sourceNodeafun=nodeafun(Tup[])(Tup[])isPrimitive::Dataa->BoolisPrimitivea@(Data__)=casedataTypeaofOne(StorableType[]_)->True_->False-- Creates a source. The node must have been visited.source::[Int]->Dataa->ReifySourcesourcepatha=casedataToExpraofApplication(Function('g':'e':'t':'T':'u':'p':_:n:_)_)tup->source((read[n]-1):path)tup-- XXX This is a bit fragile...Valueb|isPrimitivea->letPrimitiveDatab'=storableDatabinreturn$Constantb'_->doJusti<-checkNodeareturn$Graph.Variable(i,path)traceTuple::Dataa->Reify(TupleSource)traceTuplea=casedataToExpraofApplication(Application(Function"tup2"_)b)c->dob'<-traceTuplebc'<-traceTuplecreturn(Tup[b',c'])Application(Application(Application(Function"tup3"_)b)c)d->dob'<-traceTuplebc'<-traceTuplecd'<-traceTupledreturn(Tup[b',c',d'])Application(Application(Application(Application(Function"tup4"_)b)c)d)e->dob'<-traceTuplebc'<-traceTuplecd'<-traceTuplede'<-traceTupleereturn(Tup[b',c',d',e'])_->liftMOne(source[]a)buildGraph::foralla.Dataa->Reify()buildGrapha@(Data__)=doia<-checkNodeaunless(isJustia)$list(dataToExpra)wherefuncNodefuninp=dobuildGraphinpinTup<-traceTupleinpnodeafuninTup(dataTypeinp)list::Expra->Reify()listVariable=sourceNodeaGraph.Inputlist(Valueb)|isPrimitivea=return()|otherwise=sourceNodea$Graph.Array$storableDatablist(Application(Application(Functionfun_)b)c)|fun=="tup2"=buildGraphb>>buildGraphclist(Application(Application(Application(Function"tup3"_)b)c)d)=buildGraphb>>buildGraphc>>buildGraphdlist(Application(Application(Application(Application(Function"tup4"_)b)c)d)e)=buildGraphb>>buildGraphc>>buildGraphd>>buildGraphelist(Application(Functionfun_)b)|take6fun=="getTup"=buildGraphb|otherwise=funcNode(Graph.Functionfun)b-- XXX Assumes that no other kinds of function application exist.list(NoInlinefunfb@(Data__))=doiface<-buildSubFun(dereff)funcNode(Graph.NoInlinefuniface)b-- XXX Sub-graph is not shared at the moment.list(IfThenElsecteb@(Data__))=doifaceThen<-buildSubFuntifaceElse<-buildSubFunefuncNode(Graph.IfThenElseifaceThenifaceElse)(tup2cb)list(Whilecontbodyb@(Data__))=doifaceCont<-buildSubFuncontifaceBody<-buildSubFunbodyfuncNode(Graph.WhileifaceContifaceBody)blist(Parallellixf)=doiface<-buildSubFunixffuncNode(Graph.Paralleliface)lbuildSubFun::forallab.(Typeablea,Typeableb)=>(a:->b)->ReifyInterfacebuildSubFun(Lambda_inpoutp)=doletinType=typeOf(dataSizeinp)(T::Ta)outType=typeOf(dataSizeoutp)(T::Tb)buildGraphinp-- Needed in case input is not usedbuildGraphoutpoutTup<-traceTupleoutpinfo<-getletinId=visitedinfoMap.!dataIdinpreturn(InterfaceinIdoutTupinTypeoutType)reifyD::(Typeablea,Typeableb)=>(Dataa->Datab)->GraphreifyDf=GraphnodesifacewheresubFun=lambdauniversalf(iface,(nodes,_))=runGraph(buildSubFunsubFun)startInfo-- | Types that represent core language programsclassProgramawhere-- | Converts a program to a Graphreify::a->Graph-- | Returns whether or not the program has an argument. This is needed-- because the 'Graph' type always assumes the existence of an input. So-- for programs without input, the 'Graph' representation will have a-- \"dummy\" input, which is indistinguishable from a real input.numArgs::Ta->IntinstanceComputablea=>Programawherereify=reify_computablenumArgs_=0instance(Computablea,Computableb)=>Program(a,b)wherereify=reify_computablenumArgs_=0instance(Computablea,Computableb,Computablec)=>Program(a,b,c)wherereify=reify_computablenumArgs_=0instance(Computablea,Computableb,Computablec,Computabled)=>Program(a,b,c,d)wherereify=reify_computablenumArgs_=0instance(Computablea,Computableb)=>Program(a->b)wherereify=reifyD.lowerFunnumArgs=const1instance(Computablea,Computableb,Computablec)=>Program(a->b->c)wherereifyf=reifyD$lowerFun$\(a,b)->fabnumArgs=const2instance(Computablea,Computableb,Computablec,Computabled)=>Program(a->b->c->d)wherereifyf=reifyD$lowerFun$\(a,b,c)->fabcnumArgs=const3instance(Computablea,Computableb,Computablec,Computabled,Computablee)=>Program(a->b->c->d->e)wherereifyf=reifyD$lowerFun$\(a,b,c,d)->fabcdnumArgs=const4reify_computable::foralla.Computablea=>a->Graphreify_computablea=reifyD(const(internalizea)::Data()->Data(Internala))-- | Shows the core code generated by the program.showCore::foralla.Programa=>a->StringshowCore=showGraphFalse"program"(numArgs(T::Ta)>0).reify-- | Shows the core code with size information as comments.showCoreWithSize::foralla.Programa=>a->StringshowCoreWithSize=showGraphTrue"program"(numArgs(T::Ta)>0).reify-- | @printCore = putStrLn . showCore@printCore::Programa=>a->IO()printCore=putStrLn.showCore-- | @printCoreWithSize = putStrLn . showCoreWithSize@printCoreWithSize::Programa=>a->IO()printCoreWithSize=putStrLn.showCoreWithSizeinstanceStorablea=>Show(Dataa)whereshow=showCore