packages feed

cparsing-0.1.0.0: MiniC/TransformInfo.hs

{-# LANGUAGE LambdaCase, ScopedTypeVariables, FlexibleContexts, MultiParamTypeClasses #-}

-- | The purpose of this module is to transform an AST with basic infos to an AST with templates.
module MiniC.TransformInfo where

import MiniC.Representation
import MiniC.SourceNotation
import MiniC.RangeTree
import MiniC.Semantics
import Control.Lens
import Control.Monad.State
import Control.Monad.Reader
import Data.SmartTrav.Class
import Data.Maybe
import Text.Parsec.PosOps
import SourceCode.SourceTree
import SourceCode.ToSourceTree
import Debug.Trace

        
-- | Creates source templates from simple source strings
transformSourceInfo :: (SmartTrav node, ToSourceRose node BI)
                    => node BI -> node NI
transformSourceInfo = cutOutTemplates . expandNodes

-- | Expands nodes to contain all their children
expandNodes :: SmartTrav node => node BI -> node BI
expandNodes n = evalState (expandNodes' n) [Nothing]
  where expandNodes' :: SmartTrav node => node BI -> State [Maybe BI] (node BI)
        expandNodes' = smartTrav desc asc f
        
        desc = modify (Nothing:)
        asc  = modify (\case (x : y : xs) -- if both exist union, otherwise keep existing
                                          -> maybe y (\x' -> maybe x (Just . (sourceInfo %~ unifyBasicInfo (x' ^. sourceInfo))) y) x : xs)
        f inf 
          = do ni <- gets head
               let newInfo = maybe inf (\ni -> inf & sourceInfo %~ unifyBasicInfo (ni ^. sourceInfo)) ni
               modify (\case (_ : xs) -> Just newInfo : xs)
               return newInfo

-- | Replaces assigned input of nodes with source templates.
-- Goes top-down and replaces the info in every node according to structure of the whole tree.
cutOutTemplates :: forall node . (SmartTrav node, ToSourceRose node BI) 
                => node BI -> node NI
cutOutTemplates ast 
  = let rose = fmap (view sourceInfo) (toRose ast)
     in evalState (runReaderT (cutOutTemplates' ast)
                              (rose, generateRangeTree Root rose))
                  (Root,0)                 

  where cutOutTemplates' :: node BI -> ReaderT (SourceRose BasicInfo, [RangeTree]) 
                                                      (State (RootIndex, Int)) 
                                                      (node NI)
        cutOutTemplates' 
          = do smartTrav ( lift $ modify (\(ri, i) -> (RootIndex i ri, 0)) )
                         ( lift $ modify (\(RootIndex i ri, _) -> (ri, i+1)) )
                         createTempInf
        createTempInf bi 
          = do (tree, rngTree) <- ask
               currInd <- gets fst
               let rng = bi ^?! sourceInfo.biRange
                   inp = bi ^?! sourceInfo.biInput
                   relativeIndAndRng ind = (info,rel)
                     where info = fromMaybe (error "No range for a node that is to be cut out")
                                    . getRange 
                                    . roseInfo 
                                    $ resolveRootInd ind tree
                           rel = ind `indRelativelyTo` currInd 
                   contained = findContainedWhere 
                                 (\rng ind -> not (emptyRange rng) 
                                                && not (ind `rootPrefixOf` currInd)) 
                                 rng rngTree
                   toRemove = map relativeIndAndRng contained 
               return $ bi & sourceInfo .~ TemplateInfo (Just rng) 
                                                        (Just $ createTemplate toRemove rng inp)