packages feed

cparsing-0.1.0.0: MiniC/SourceNotation.hs

{-# LANGUAGE TypeOperators, FlexibleInstances, FlexibleContexts, DefaultSignatures #-}
{-# LANGUAGE MultiParamTypeClasses, OverlappingInstances, LambdaCase #-}

-- | A module for representing how to print the AST in the original format
module MiniC.SourceNotation where

import SourceCode.ASTNode
import SourceCode.SourceTree

import GHC.Generics
import Control.Applicative
import Data.Maybe
import Data.Either
import Data.List
import Data.Function
import Debug.Trace
import Text.Parsec.PosOps
    
-- | A pattern that controls how the original source code can be
-- retrieved from the AST. A source template is assigned to each node.
-- It has holes where the content of an other node should be printed.
type SourceTemplate = [SourceTemplateElem]   
 
data SourceTemplateElem = TextElem String 
                        | NodeElem NodeIndex
     deriving (Eq, Ord)
     
isTextElem :: SourceTemplateElem -> Bool
isTextElem (TextElem _) = True
isTextElem _ = False

isNodeElem :: SourceTemplateElem -> Bool
isNodeElem (NodeElem _) = True
isNodeElem _ = False
      
instance Show SourceTemplateElem where
  show (TextElem s) = s
  show (NodeElem ni) = "<" ++ show ni ++ ">"
     
getIndexedNode :: SourceTemplateElem -> Maybe NodeIndex
getIndexedNode (NodeElem ni) = Just ni
getIndexedNode _ = Nothing
     
steCombine :: SourceTemplateElem -> SourceTemplateElem -> SourceTemplateElem
steCombine (TextElem s1) (TextElem s2) = TextElem (s1 ++ s2)
steCombine (TextElem "") e = e
steCombine e (TextElem "") = e
steCombine e1 e2 = error $ "Source template elements " 
                             ++ show e1 ++ " and " ++ show e2 
                             ++ " cannot be combined."

-- | Creates a template from a source range and an input string by cutting out each given node
createTemplate :: [(SourceRange, NodeIndex)] -> SourceRange -> String -> SourceTemplate
createTemplate toCutOut sr input
  = let source = takeSourceRange (rngFromStart sr) input
        sortedNodes = sortBy (flip compare `on` fst) toCutOut
     in foldl (cutOutNode sr) [TextElem source] sortedNodes
  where -- | Must be applied to the last child to cut out, so the prefix remains an intacts string
        cutOutNode :: SourceRange -> SourceTemplate -> (SourceRange, NodeIndex) -> SourceTemplate
        cutOutNode sr (TextElem txt : rest) (cutOutSr, index) = 
            let cutOutRng = cutOutSr `rangeRelativelyTo` srcRangeBegin sr
                textBefore = snd $ takeToPos' (srcRangeBegin cutOutRng) txt
                textAfter = snd $ dropToPos' (srcRangeEnd cutOutRng) txt 
             in TextElem textBefore : NodeElem index : TextElem textAfter : rest