packages feed

adp-multi-0.1.0: src/ADP/Multi/Rewriting/YieldSize.hs

module ADP.Multi.Rewriting.YieldSize where

import Data.Maybe
import Data.Map (Map)
import qualified Data.Map as Map

import ADP.Debug
import ADP.Multi.Parser
import ADP.Multi.Rewriting

{-
This module might later be re-integrated into both Rewriting implementations.
It is unclear yet if generically determining the yield size for higher parser
dimensions also needs a constraint solver.  
-}

-- for dim1 we don't need the rewriting function to determine the yield size
-- it's kept as argument anyway to make it more consistent
doDetermineYieldSize1 ::  YieldAnalysisAlgorithm Dim1
doDetermineYieldSize1 _ infos =
        let elemInfo = buildInfoMap infos
            (yieldMin,yieldMax) = combineYields (Map.elems elemInfo) 
        in trace (show elemInfo) $
           ParserInfo1 { 
                minYield = yieldMin,
                maxYield = yieldMax
           }

doDetermineYieldSize2 ::  YieldAnalysisAlgorithm Dim2
doDetermineYieldSize2 f infos =
        let elemInfo = buildInfoMap infos
            (left,right) = f (Map.keys elemInfo)
            leftYields = map (\(i,j) -> elemInfo Map.! (i,j)) left
            rightYields = map (\(i,j) -> elemInfo Map.! (i,j)) right
            (leftMin,leftMax) = combineYields leftYields
            (rightMin,rightMax) = combineYields rightYields 
        in trace (show elemInfo) $
           trace (show left) $
           trace (show right) $
           ParserInfo2 { 
                minYield2 = (leftMin,rightMin),
                maxYield2 = (leftMax,rightMax)
           }

combineYields :: [Info] -> Info
combineYields = foldl (\(minY1,maxY1) (minY2,maxY2) ->
                    ( minY1+minY2
                    , if isNothing maxY1 || isNothing maxY2 
                      then Nothing
                      else Just $ fromJust maxY1 + fromJust maxY2
                    ) ) (0,Just 0)

type YieldSizes = (Int,Maybe Int) -- min and max yield sizes
type Info = YieldSizes -- could later be extended with more static analysis data
type InfoMap = Map (Int,Int) Info

-- the input list is in reverse order, i.e. the first in the list is the last applied parser
buildInfoMap :: [ParserInfo] -> InfoMap
buildInfoMap i | trace ("buildInfoMap " ++ show i) False = undefined
buildInfoMap infos =
        let parserCount = length infos
            list = concatMap (\ (x,info) -> case info of
                       ParserInfo1 { minYield = minY, maxYield = maxY } ->
                           [ ((x,1), (minY, maxY) ) ]
                       ParserInfo2 { minYield2 = minY, maxYield2 = maxY } ->
                           [ ((x,1), (fst minY, fst maxY) )
                           , ((x,2), (snd minY, snd maxY) )
                           ]
                     ) $ zip [parserCount,parserCount-1..] infos
        in Map.fromList list