cparsing-0.1.0.0: SourceCode/SourceTree.hs
{-# LANGUAGE LambdaCase, NamedFieldPuns, DeriveFunctor, DeriveDataTypeable #-}
-- | A simpler representation of the original AST. Enables easy relative indexing of the nodes.
module SourceCode.SourceTree where
import Data.Maybe
import Data.Data
-- | Relative indexing of nodes in a 'SourceRose' tree
data NodeIndex = Current
| ParentOf NodeIndex
| NthChildOf Int NodeIndex
deriving (Eq, Ord)
instance Show NodeIndex where
show Current = "."
show (ParentOf ni) = show ni ++ "/.."
show (NthChildOf i ni) = show ni ++ "/" ++ show i
-- | Evaluates a node indexing, from the path to current elem generates the path to the indexed elem
resolveRoseInd :: Show a => NodeIndex -> [SourceRose a] -> Either String [SourceRose a]
resolveRoseInd Current path = Right path
resolveRoseInd (ParentOf i) path
= resolveRoseInd i path >>= \case (_:par) -> Right par
[] -> Left "empty path"
resolveRoseInd (NthChildOf n i) path
= resolveRoseInd i path >>=
\case (path@(SourceRose {roseChildren} : _)) ->
if n >= 0 && n < length roseChildren
then Right ((roseChildren !! n) : path)
else Left $ "no " ++ show n ++ "th child"
[] -> Left "empty path"
-- | Modifies a root index by a relative one
addRelPath :: RootIndex -> NodeIndex -> RootIndex
addRelPath ind Current = ind
addRelPath ind1 (ParentOf ind2)
= case ind1 `addRelPath` ind2 of RootIndex _ ind -> ind
_ -> error "No parent"
addRelPath ind1 (NthChildOf i2 ind2)
= RootIndex i2 (ind1 `addRelPath` ind2)
-- | Concatenates two relative indexes
addPath :: NodeIndex -> NodeIndex -> NodeIndex
ind `addPath` Current = ind
ind `addPath` (ParentOf ni) = ParentOf (ind `addPath` ni)
ind `addPath` (NthChildOf i ni) = NthChildOf i (ind `addPath` ni)
-- | Indexing of nodes in a 'SourceRose' tree from root
data RootIndex = Root | RootIndex Int RootIndex
deriving (Eq)
instance Show RootIndex where
show Root = ""
show (RootIndex i ni) = show ni ++ "/" ++ show i
rootPrefixOf :: RootIndex -> RootIndex -> Bool
Root `rootPrefixOf` Root = True
(RootIndex i1 ind1) `rootPrefixOf` (RootIndex i2 ind2) | i1 == i2
= ind1 `rootPrefixOf` ind2
ind1 `rootPrefixOf` (RootIndex _ ind2)
= ind1 `rootPrefixOf` ind2
_ `rootPrefixOf` _
= False
resolveRootInd :: RootIndex -> SourceRose a -> SourceRose a
resolveRootInd (RootIndex i ind) tree
= let SourceRose {roseChildren} = resolveRootInd ind tree
in roseChildren !! i
resolveRootInd Root tree = tree
pathToRoot :: RootIndex -> NodeIndex
pathToRoot (RootIndex _ ind) = ParentOf (pathToRoot ind)
pathToRoot Root = Current
pathFromRoot :: RootIndex -> NodeIndex
pathFromRoot (RootIndex i ind) = NthChildOf i (pathFromRoot ind)
pathFromRoot Root = Current
depth :: RootIndex -> Int
depth Root = 0
depth (RootIndex _ ind) = depth ind + 1
indRelativelyTo :: RootIndex -> RootIndex -> NodeIndex
indRelativelyTo r1 r2 = indRel r1 r2 Current
where indRel r1 r2 p
| r1 == r2
= p
indRel r1 r2@(RootIndex i2 ind2) p
| depth r1 < depth r2
= indRel r1 ind2 (ParentOf p)
indRel (RootIndex i1 ind1) r2 p
= NthChildOf i1 (indRel ind1 r2 p)
-- | A rose tree containing additional node information
data SourceRose a = SourceRose { roseInfo :: a
, original :: Bool
, roseChildren :: [SourceRose a]
} deriving (Eq, Functor, Typeable, Data)
instance Show a => Show (SourceRose a) where
show sr = show' 0 sr
where show' i (SourceRose {roseInfo,original,roseChildren})
= "\n" ++ replicate (2*i) (if original then '#' else '-')
++ show roseInfo
++ concatMap (show' (i+1)) roseChildren