packages feed

cparsing-0.1.0.0: SourceCode/ToSourceTree.hs

{-# LANGUAGE LambdaCase, DefaultSignatures, TypeOperators, MultiParamTypeClasses, FlexibleContexts
           , FlexibleInstances, OverlappingInstances, ScopedTypeVariables #-}
-- | Generically transforms an ADT into a 'SourceTree'
module SourceCode.ToSourceTree where

import GHC.Generics
import Control.Applicative
import Control.Monad.State
import Data.Either
import Data.Maybe
import Data.SmartTrav
import SourceCode.SourceTree
import SourceCode.ASTNode
import SourceCode.SourceInfo
                         
-- | An intermediate data struture. Used to construct a 'SourceRose' tree.
data SourceRoseCollect a = RoseCollect [SourceRoseCollect a]
                         | RoseInfo a
     
instance Show a => Show (SourceRoseCollect a) where
  show = show' 0
    where show' i (RoseCollect children) 
            = "\n" ++ replicate (2*i) '#' ++ concatMap (show' (i+1)) children
          show' i (RoseInfo inf) 
            = "\n" ++ replicate (2*i) '#' ++ show inf
     
-- | Transforms the intermediate representation 'SourceRoseCollect' to a 'SourceRose'     
collectRose :: forall a . (SourceInfo a) 
            => SourceRoseCollect a -> SourceRose a
collectRose = collectRose' (error "No ancestor node has source info.")
  where collectRose' ancestor (RoseCollect coll) 
          = case partitionRoses coll of 
              ([inf], branch) -> SourceRose inf True 
                                            (map (collectRose' inf) branch)
              ([], branch)    -> let children = map (collectRose' ancestor) branch
                                  in SourceRose (generateInfo ancestor (map roseInfo children)) 
                                                False children
                                            
              (infos, branch) -> SourceRose (generateInfo ancestor infos) False 
                                            (map (collectRose' ancestor) branch)
           where -- | Partition collected nodes into info nodes and subnodes
                 partitionRoses :: [SourceRoseCollect a] -> ([a], [SourceRoseCollect a])
                 partitionRoses = partitionEithers 
                                    . (map $ \case c@(RoseCollect _) -> Right c
                                                   RoseInfo i -> Left i)
           
-- | A class for converting AST tree into a more simpler rose tree, where the nodes are annotated
-- with the node info of the original nodes.
class (SourceInfo inf, SmartTrav n) => ToSourceRose n inf where
  toRose :: n inf -> SourceRose inf
  toRose tree = collectRose . toSourceRose $ tree
  
  -- | Creates an intermediate version of the rose tree
  toSourceRose :: n inf -> SourceRoseCollect inf
  toSourceRose n = evalState (toSrcRoseSt n) [[]]
    where toSrcRoseSt :: n inf -> State [[SourceRoseCollect inf]] (SourceRoseCollect inf)
          toSrcRoseSt n = smartTrav desc asc f n *> gets (RoseCollect . reverse . head)
    
          desc  = modify ([]:)
          asc   = modify (\(x:y:xs) -> ((RoseCollect (reverse x) : y) : xs))
          f inf = modify (\(x:xs) -> (RoseInfo inf : x) : xs)