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