module Language.Haskell.TokenUtils.TokenUtils
(
replaceTokenInCache
, replaceTokenForSrcSpan
, invariant
) where
import Control.Exception
import Data.List
import Data.Tree
import Language.Haskell.TokenUtils.Types
import Language.Haskell.TokenUtils.Utils
import qualified Data.Map as Map
import qualified Data.Tree.Zipper as Z
invariant :: a
invariant = assert False undefined
replaceTokenInCache :: (IsToken a) => TokenCache a -> Span -> a -> TokenCache a
replaceTokenInCache tk sspan tok = tk'
where
forest = getTreeFromCache sspan tk
forest' = replaceTokenForSrcSpan forest sspan tok
tk' = replaceTreeInCache sspan forest' tk
getTreeFromCache :: (IsToken a) => Span -> TokenCache a -> Tree (Entry a)
getTreeFromCache sspan tk = (tkCache tk) Map.! tid
where
tid = treeIdFromForestSpan $ srcSpanToForestSpan sspan
replaceTreeInCache :: (IsToken a) => Span -> Tree (Entry a) -> TokenCache a -> TokenCache a
replaceTreeInCache sspan tree tk = tk'
where
tid = treeIdFromForestSpan $ srcSpanToForestSpan sspan
tree' = putTidInTree tid tree
tk' = tk {tkCache = Map.insert tid tree' (tkCache tk) }
putTidInTree :: (IsToken a) => TreeId -> Tree (Entry a) -> Tree (Entry a)
putTidInTree tid (Node (Deleted fspan pg eg) subs) = (Node (Deleted fs' pg eg) subs)
where fs' = treeIdIntoForestSpan tid fspan
putTidInTree tid (Node (Entry fspan lay toks) subs) = tree'
where
subs' = map (putTidInTree tid) subs
fs' = treeIdIntoForestSpan tid fspan
tree' = Node (Entry fs' lay toks) subs'
replaceTokenForSrcSpan :: (IsToken a) => Tree (Entry a) -> Span -> a -> Tree (Entry a)
replaceTokenForSrcSpan forest sspan tok = forest'
where
tl = getSpan tok
z = openZipperToSpanDeep (srcSpanToForestSpan sspan) $ Z.fromTree forest
z' = z
(tspan,lay,toks) = case Z.tree z' of
(Node (Entry ss ly tks) []) -> (ss,ly,tks)
(Node (Entry _ _ _nullToks) _sub) -> error $ "replaceTokenForSrcSpan:tok pos" ++ (showForestSpan $ sf sspan) ++ " expecting tokens, found: " ++ (show $ Z.tree z')
(Node (Deleted _ _ _) _sub) -> error $ "replaceTokenForSrcSpan:tok pos" ++ (showForestSpan $ sf sspan) ++ " expecting Entry, found: " ++ (show $ Z.tree z')
((row,col),_) = forestSpanToSimpPos $ srcSpanToForestSpan tl
toks' = replaceTokNoReAlign toks (row,col) tok
zf = Z.setTree (Node (Entry tspan lay toks') []) z'
forest' = Z.toTree zf
openZipperToSpanDeep
:: (IsToken a)
=> ForestSpan
-> Z.TreePos Z.Full (Entry a)
-> Z.TreePos Z.Full (Entry a)
openZipperToSpanDeep sspan z = zf
where
z' = openZipperToSpan sspan z
zf = case Z.tree z' of
(Node (Entry _ (Above _ _ _ _) _) _) ->
case getChildrenAsZ z' of
[] -> z'
[x] -> if (treeStartEnd (Z.tree x) == sspan) then x else z'
_ -> z'
_ -> z'
openZipperToSpan ::
(IsToken a)
=> ForestSpan
-> Z.TreePos Z.Full (Entry a)
-> Z.TreePos Z.Full (Entry a)
openZipperToSpan sspan z
| hasVersions = openZipperToSpanAdded sspan z
| otherwise = openZipperToSpanOrig sspan z
where
(vs,_ve) = forestSpanVersions sspan
hasVersions = vs /= 0
openZipperToSpanOrig ::
(IsToken a)
=> ForestSpan
-> Z.TreePos Z.Full (Entry a)
-> Z.TreePos Z.Full (Entry a)
openZipperToSpanOrig sspan z
= if (treeStartEnd (Z.tree z) == sspan) || (Z.isLeaf z)
then z
else z'
where
childrenAsZ = getChildrenAsZ z
z' = case (filter contains childrenAsZ) of
[] -> z
[x] ->
openZipperToSpan sspan x
xx -> case (filter (\zt -> (treeStartEnd $ Z.tree zt) == sspan) xx) of
[] ->
case (filter (not .forestSpanLenChanged . treeStartEnd . Z.tree) xx) of
[] -> z
[w] -> openZipperToSpan sspan w
ww ->
case (filter (\zt -> matchVersions sspan zt) ww) of
[v] -> openZipperToSpan sspan v
_ -> error $ "openZipperToSpan:can't resolve:(sspan,ww)="++(show (sspan,map (\zt -> treeStartEnd $ Z.tree zt) ww))
[y] -> openZipperToSpan sspan y
yy ->
case (filter (\zt -> (fst $ forestSpanVersions $ treeStartEnd $ Z.tree zt) == (fst $ forestSpanVersions sspan)) xx) of
[] -> error $ "openZipperToSpan:no version match:(sspan,yy)=" ++ (show (sspan,yy))
[w] -> openZipperToSpan sspan w
_ww -> error $ "openZipperToSpan:multiple version match:" ++ (show (sspan,yy))
contains zn = spanContains (treeStartEnd $ Z.tree zn) sspan
matchVersions span1 z2 = isMatch
where
span2 = treeStartEnd $ Z.tree z2
isMatch = forestSpanVersions span1 == forestSpanVersions span2
openZipperToSpanAdded ::
(IsToken a)
=> ForestSpan
-> Z.TreePos Z.Full (Entry a)
-> Z.TreePos Z.Full (Entry a)
openZipperToSpanAdded sspan z = zf
where
treeAsList = getTreeSpansAsList $ Z.tree z
myMatch (((ForestLine _ _ vs1 rs1),cs1),((ForestLine _ _ ve1 re1),ce1))
(((ForestLine _ _ vs2 rs2),cs2),((ForestLine _ _ ve2 re2),ce2))
= vs1 == vs2 && ve1 == ve2 && ((rs1,cs1) <= (rs2,cs2)) && ((re1,ce1) >= (re2,ce2))
tl2 = dropWhile (\(_,s) -> not (myMatch s sspan)) $ reverse treeAsList
fff [] _ = []
fff acc@((cd,_cs):_) (v,sspan') = if v < cd then (v,sspan'):acc
else acc
tl3 = foldl' fff [(head tl2)] tl2
zf = foldl' (flip openZipperToSpanOrig) z $ map snd tl3
getTreeSpansAsList :: (IsToken a) => Tree (Entry a) -> [(Int,ForestSpan)]
getTreeSpansAsList = getTreeSpansAsList' 0
getTreeSpansAsList' :: (IsToken a) => Int -> Tree (Entry a) -> [(Int,ForestSpan)]
getTreeSpansAsList' level (Node (Deleted sspan _pg _eg ) _ ) = [(level,sspan)]
getTreeSpansAsList' level (Node (Entry sspan _lay _toks) ts0) = (level,sspan)
: (concatMap (getTreeSpansAsList' (level + 1)) ts0)
getChildrenAsZ :: Z.TreePos Z.Full a -> [Z.TreePos Z.Full a]
getChildrenAsZ z = go [] (Z.firstChild z)
where
go acc Nothing = acc
go acc (Just zz) = go (acc ++ [zz]) (Z.next zz)
replaceTokNoReAlign:: (IsToken a) => [a] -> SimpPos -> a -> [a]
replaceTokNoReAlign toks pos newTok =
toks1 ++ [newTok'] ++ toksRest
where
(toks1,toks2) = break (\t -> tokenPos t >= pos && tokenLen t > 0) toks
toksRest = if (null toks2) then [] else (gtail "replaceTokNoReAlign" toks2)
oldTok = if (null toks2) then newTok else (ghead "replaceTokNoReAlign" toks2)
newTok' = matchTokenPos oldTok newTok
matchTokenPos :: (IsToken a) => a -> a -> a
matchTokenPos t1 t2 = putSpan t2 (getSpan t1)