packages feed

HaRe-0.6: refactorer/RefacDupTrans.hs

module RefacDupTrans where
import System.IO.Unsafe
import PosSyntax hiding (ModuleName, HsName, SN)
import SourceNames 
import ScopeModule
import UniqueNames hiding (srcLoc)
import HsName
import HsLexerPass1
import PNT 
import TiPNT
import SimpleGraphs(reverseGraph,reachable)
import HsTokens
import PrettyPrint
import RefacTypeSyn
import RefacLocUtils
import Data.Char
import GHC.Unicode
import AbstractIO
import Maybe
import List
import Data.Function
import RefacUtils
import LocalSettings
import DuplicateCode (foldDo)

type NameToCall    = String
type NameToReplace = String
type Module        = String
type FileName      = String

refacDupTrans args
  = do         
       AbstractIO.putStrLn "refacDupTrans"
       {- let fileName = ghead "fileName'" args 
           beginRow         = read (args!!1)::Int
           beginCol         = read (args!!2)::Int
           endRow           = read (args!!3)::Int
           endCol           = read (args!!4)::Int
       -- collect the answers...
       (inscps, exps, mod, tokList)<-parseSourceFileOld fileName
       let subExp = locToExp (beginRow, beginCol) (endRow, endCol) tokList mod
       expression <- AbstractIO.readFile transFilePath
       let expressions = (read expression)::([ [(HsExpP, String)] ])
 
       let clonedExps = concat (filter (subExp `myElem`) expressions) 
           groupedClones = groupClones clonedExps  -}
           
       cloneCall <- AbstractIO.readFile classTransformPath
       answers   <- AbstractIO.readFile answerFilePath  
        
       let clonedExps = pruneCloneClass (read cloneCall::[(HsExpP, String, String)]) (filter (isAlpha) answers) 
           groupedClones = groupClones clonedExps   
               
       if clonedExps == []
         then error "Please use introduce a new definition instead; selected expression is not a member of a clone class!"
         else do 
            -- make sure all the files we need to modify
            -- are added to the project. Otherwise we run into "module not found"
            -- issues...
            let names = nub $ concatMap (map snd) groupedClones
            mods <- (mapM parseSourceFile names)
            destMods <- mapM fileNameToModName names 
            -- addFile names
            res <- createParameters (makeFullASTList mods) 1 (createAbs (map fst clonedExps)) 
            let pns  = nub $ concatMap definedPNs [(fromJust res)]
            results <- callFindSafeModules destMods (myZip mods names groupedClones) pns res
            writeRefactoredFiles False results
            AbstractIO.putStrLn "Clone Transformation Completed.\n" 
makeFullASTList gf= [mod | (inscps, exps, mod, tokList) <- gf]


pruneCloneClass :: [ (HsExpP, String, String) ] -> String -> [ (HsExpP, String) ]
pruneCloneClass ((x,y,z):xs) ('y':ys) = (x,y) : pruneCloneClass xs ys
pruneCloneClass (x:xs) ('n':ys) = pruneCloneClass xs ys
pruneCloneClass _ _ = []


retainLocs [] _ = []
retainLocs _ [] = []
retainLocs ((i,e,_,_):ms) (((_,_),(t,m)):ts)
 = (i,e,m,t) : retainLocs ms ts

myZip :: [(a,b,c,d)] -> [e] -> [f] -> [(a,b,c,d,e,f)]
myZip ((a,b,c,d):as) (e:bs) (f:fs) = (a,b,c,d,e,f) : myZip as bs fs
myZip _      _   _    = []


-- find safe Module
-- this function checks to see where there is a safe place
-- to put the abstraction.
-- 
-- given the list of the files that we are transforming,
-- we introduce a cyclic inclusion if the module
-- we want to introduce the abstraction already imports
-- another module.... Therefore the module cannot import
-- any of the modules from our transformation set.
-- findSafeModule :: Term t => [ ModuleName ] -> t -> [Bool]
findSafeModule destMods mod
  = not $ or $ map (flip elem mod) (map fst destMods)


findSafeModules destmods [] _ = -- basically we can't do imports, everywhere needs to define abstraction!
                                  return Nothing
findSafeModules destmods ((inscps, exps, mod, tokList, fileName, clonedExps@(c:cs)):mods) res
  = do
          modName <- fileNameToModName fileName
          modules <- serverModsAndFiles modName
          if findSafeModule modules destmods 
           then 
            do AbstractIO.putStrLn $ show fileName
               -- add the abstraction in this module...
               -- we also need to make sure all other modules import this module...
               ((f,m), (newToks, newMod)) <- applyRefac (addAbstraction res (map fst clonedExps))
                                                        (Just (inscps, exps, mod, tokList)) fileName  
                                            
                                                   
               return (Just (((f,m), (newToks, newMod)), mod, fileName))  
           else do rest <- findSafeModules destmods mods res
                   return rest                                 
                   

callFindSafeModules destMods mods pns res
 = do
       -- mod is the module that everything has to import...
       result <- findSafeModules destMods mods res
       if result == Nothing
            then error "All will introduce cyclic inclusion!"
            else do let (transformation, m, fName) = fromJust result
                    fFile <- fileNameToModName fName
                    transformation' <- addImports mods res m pns fName fFile 
                    -- we also need to transform the module we are left with
                    -- i.e. the module where we have added the abstraction...                    
                    return (transformation:transformation')
       
addImports [] _ _ _ _ _ = return []
addImports (t@(inscps, exps, mod, tokList, fileName, clonedExps@(c:cs)):ms) res m pns fFile f
 | mod == m  = do
                  rest <- addImports ms res m pns fFile f
                  return rest
 | otherwise = do modified <- addImports' t res pns fFile f
                  rest <- addImports ms res m pns fFile f
                  return (modified: rest)
                  
addImports' (inscps, exps2, mod, tokList, fileName, clonedExps@(c:cs)) res pns fFile f
 = do
      ((f,m), (newToks, newMod)) <- applyRefac (addImport'' res pns fFile f (map fst clonedExps)) (Just (inscps, exps2, mod, tokList)) fileName
      return ((f,m), (newToks, newMod))


addImport'' res pns fFile f exps (_,_,t)
 = do 
      replacedT <- replaceOccurrences t res exps
      t' <- addImport fFile f pns replacedT
      return t'
      

-- transformClones takes a list of [(HsExpP, String)]
-- parses the module of String, and performs a 
-- "addAbstraction" over that module and writes the 
-- refactoredFiles. 
--
-- transformClones should be called from a mapM_ to allow
-- the monadic effect to be preserved.
transformClones destMods res f clonedExps@(c:cs)
 = do
     let fileName = snd c
          
     currentMod <- fileNameToModName fileName
     origFile <- fileNameToModName f

     let pns  = nub $ concatMap definedPNs [(fromJust res)]

     (inscps, exps, mod, tokList)<-parseSourceFileOld fileName
     ((f2,m), (newToks, newMod)) <- applyRefac (extractExpression res pns fileName origFile currentMod (map fst clonedExps))
                                               (Just (inscps, exps, mod, tokList)) fileName
     return ((f2,m), (newToks, newMod))                                          
                                               
                                               
-- group the expressions by their defining module.
-- groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupClones :: [ (HsExpP, String) ] -> [ [(HsExpP, String)] ]

groupClones clones
  = groupBy checkFile clones
     where
      checkFile :: Eq b => (a,b) -> (a,b) -> Bool
      checkFile (a,b) (c,d) = b == d


myElem :: HsExpP -> [(HsExpP, String)] -> Bool
myElem _ [] = False
myElem e ((x,y):xs) 
 | toRelativeLocs e == toRelativeLocs x    = True
 | otherwise = myElem e xs
 
extractExpression decs pns fFile f fileName exps (_,_,t)
 | f /= fileName
     = do
      -- find the expressions in t that are associated
      -- with exps. Replace these expressions with a call
      -- to the abstactions.
      replacedT <- replaceOccurrences t decs exps
      return replacedT
 | otherwise = do replacedT <- replaceOccurrences t decs exps
                  return replacedT


--add a definition name to the import. If the module is not imported yet, then create a new import decl.
-- addImport::String->HsName.ModuleName->[PName]->HsModuleP->HsModuleP
addImport destFileName destModName pns mod@(HsModule _ _  _ imp _)
  =if itemIsImportedByDefault destModName mod     -- Is the definition name explicitly imported?
    then return mod                               -- Yes. Do nothing.
    else if itemsAreExplicitlyImported destModName mod  --Is the module imported and some of its items are explicitly imported?
          then addVarItemInImport1 destModName pns mod -- Yes. Then add the definition name to the list.
          else addImportDecl mod (modNameToStr destModName) False  Nothing False (map pNtoName pns)
               --addImportDecl mod (mkImportDecl destFileName destModName  False (map pNtoName pns)) --Create a new import decl.

  where  
   {- Compose a import declaration which imports the module specified by 'modName',
      and only imports the definition spcified by 'e'.
    -}
   
   itemsAreExplicitlyImported serverModName (HsModule _ _ _ imps _)
     = any (isExplicitlyImported serverModName) imps
    where
       isExplicitlyImported serverModName ((HsImportDecl _ (SN modName _) _ _ h)::HsImportDeclP)
         = serverModName == modName && isJust h && not (fst (fromJust h))



-- are items defined in the serverModName imported by the current module by default?
itemIsImportedByDefault serverModName (HsModule _ _ _ imps _) 
  = any (isImportedByDefault'  serverModName) imps
  where
    isImportedByDefault' serverModName ((HsImportDecl _ (SN modName _) _ _ h)::HsImportDeclP)
       = serverModName == modName && ( isNothing h  || (isJust h && fst(fromJust h)))


addVarItemInImport1 serverModName pns mod
   = applyTP ((once_tdTP (failTP `adhocTP` inImport))  `choiceTP` idTP) mod
  where 
    inImport (imp@(HsImportDecl loc@(SrcLoc fileName _ row col) (SN modName l) qual as (Just (b,ents))):: HsImportDeclP)
      | serverModName == modName && not b  
     =  
          addItemsToImport serverModName  Nothing (Left (map pNtoName pns)) imp
    inImport x = mzero 
                  
addAbstraction decs exps (_,_,t)
  = do
       
       replacedT <- replaceOccurrences t decs exps
       t' <- addDecl replacedT Nothing (maybeToList decs, Nothing) True
       t'' <- addItemsToExport t' Nothing False (Left (map declToName (maybeToList decs))) 
       return t''


-- replaceOccurrences :: (Term t, MonadPlus m, Monad m) => t -> [ HsDeclP ] -> [ [HsExpP] ] -> m t
-- replaceOccurrences t [] _ = return t
replaceOccurrences t _ [] = return t
replaceOccurrences t dec exps
  = do
       res <- repOcc dec exps t
       -- rest <- replaceOccurrences res dec expss
       return res

repOcc Nothing _ t = return t
repOcc (Just dec) es t
  = do
      -- get the expression on the RHS of Abstraction,
      -- and abstraction name for the call.
      let (name, rhs) = getNameAndRHS dec
      newT <- repOcc' name rhs es t
      return newT     
       where
         getNameAndRHS (Dec (HsFunBind _ [HsMatch _ name _ (HsBody e) _]))
           = (name, e)

repOcc' _ _ [] t = return t
repOcc' name rhs (x:xs) t
  = do
      res <- applyTP (once_tdTP (failTP `adhocTP` inExp)) t
      -- error $ show x
      rest <- repOcc' name rhs xs res
      return rest
    where
      inExp e@(Exp (HsDo e1))
       = do
             let new = foldAgainstAbs [] x rhs
             -- we need to actually find the bit to update...
             las <- (getStmtList2 rhs)
             -- error $ show las
             if las == [] 
               then mzero
               else do
                      let (p, newStmts) = foldStmt' (head las) [] (createFunc name (rmAllLocs new)) e1 x
                      if p 
                       then 
                        do
                           -- error $ show (e1, rhs)
                           --    new' = (render.ppi) new
                           -- n' <- update e (Exp (HsDo (HsLast (createFunc name new)))) e
                           -- n' <- RefacUtils.delete e e
                           lift $ AbstractIO.putStrLn $ show new
                           n'' <- update e (Exp (HsDo newStmts))  e
                           return n''
                       else mzero

      inExp e@(Exp (HsParen e1))
        | sameOccurrence e x
            = do 
                 let new = foldAgainstAbs [] e rhs
                     new' = (render.ppi) new
                 
                 e' <- update e (Exp (HsParen (createFunc name new))) e
                 return e'

       -- | otherwise = mzero
      inExp (e::HsExpP)
        | sameOccurrence e x
            = do 
                 let new = foldAgainstAbs [] e rhs
                     new' = (render.ppi) new
                 e' <- update e (createFunc name new) e
                 return e'
      inExp e = 
                   mzero

getStmtList2 (Exp (HsDo s))
  = return [last $ getStmtList s]
getStmtList2 _ = return []


foldStmt' :: HsStmtAtomP -> [HsPatP] -> HsExpP -> HsStmtP -> HsExpP -> (Bool, HsStmtP)
foldStmt' ss p e s (Exp (HsDo s1)) = foldStmt ss p e  s s1
foldStmt' ss p e s1 _ = (False, s1)
  
foldStmt :: HsStmtAtomP -> [HsPatP] -> HsExpP -> HsStmtP -> HsStmtP -> (Bool, HsStmtP)
foldStmt ss p e s1@(HsGenerator _ p1 e1 s0) s2@(HsGenerator _ p2 e2 s3)
 | p1 == p2 && sameOccurrence e1 e2 = foldStmt ss (p++[p1]) e s0 s3
 | otherwise = (False, s1)
foldStmt (HsLastAtom ee) p e s1@(HsQualifier e1 s3) (HsLast e2)
 | isReturn ee && e2 == defaultExp = (True, newStmt)
 | sameOccurrence e1 e2 = (True, s1)
      where
          newStmt = (HsGenerator loc0 (Pat (HsPTuple loc0 p)) e s3)
foldStmt ee p e s1@(HsQualifier e1 s0) s2@(HsQualifier e2 s3)
 | sameOccurrence e1 e2 = foldStmt ee p e s0 s3
 | otherwise = (False, s1)
foldStmt (HsLastAtom ee) p e s1@(HsLast e1) s2@(HsLast e2)
 | isReturn ee && e2 == defaultExp = (True, newStmt)
 | e2 == defaultExp = (True, s1)
 | sameOccurrence e1 e2 && isReturn ee = (True, newStmt)
 | sameOccurrence e1 e2 = (True, s1)
         where 
            newStmt = (HsGenerator loc0 (Pat (HsPTuple loc0 p)) e s1) 
foldStmt ee p e s1 s2 = (False, s1)
 
isReturn e = (render.ppi) (head (flatternApp e)) == "return"
flatternApp :: HsExpP -> [HsExpP]
flatternApp (Exp (HsApp e1 e2)) = flatternApp e1 ++ flatternApp e2
flatternApp (Exp (HsParen e)) = flatternApp e
flatternApp x = [x] 
  
grabPNT :: PNT -> [PNT] -> PNT
grabPNT x [] = x
grabPNT x (y:ys)
  | defineLoc x == defineLoc y = y
  | otherwise = grabPNT x ys  
  
checkPNTInPat :: [HsPatP] -> PNT -> Bool
checkPNTInPat [] _ = False
checkPNTInPat (p:ps) i 
        | defineLoc i == (SrcLoc "__unknown__" 0 0 0) = False
        | defineLoc i == defineLoc (patToPNT p) = True
        | otherwise = checkPNTInPat ps i
      
foldAgainstAbs :: [HsPatP] -> HsExpP -> HsExpP -> [ HsExpP ]
foldAgainstAbs _ e1 e2 
 | e1 == defaultExp || e2 == defaultExp = []
foldAgainstAbs pats e@(Exp (HsId (HsVar x))) (Exp (HsId (HsVar y)))
 | x == y && isTopLevelPNT x = []
 | x == y && isTopLevelPNT x = []
 | checkPNTInPat pats x  = []
 | otherwise = [e]
foldAgainstAbs pats e@(Exp (HsId (HsCon x))) (Exp (HsId (HsCon y)))
  | x == y    = []
  | otherwise = [e]
foldAgainstAbs pats e@(Exp (HsLit s l1)) (Exp (HsLit s2 l2))
  | l1 == l2  = []
  | otherwise = [(Exp (HsLit loc0 l1))]
foldAgainstAbs pats e@(Exp (HsInfixApp e1 o1 e2)) (Exp (HsInfixApp e3 o2 e4))
  = (e1' ++ o1' ++ e2')
     where
       e1' = foldAgainstAbs pats e1 e3
       o1' 
        | o1 == o2  = []
        | otherwise = [Exp (HsId o1)]
       e2' = foldAgainstAbs pats e2 e4
foldAgainstAbs pats e@(Exp (HsApp e1 e2)) (Exp (HsApp e3 e4))
 = (foldAgainstAbs pats e1 e3) ++ (foldAgainstAbs pats e2 e4)
foldAgainstAbs pats e@(Exp (HsNegApp s1 e1)) (Exp (HsNegApp s2 e2))
 = (foldAgainstAbs pats e1 e2)
foldAgainstAbs pats1 e@(Exp (HsLambda pats e1)) (Exp (HsLambda pats2 e2))
 = []
foldAgainstAbs pats e@(Exp (HsLet decs e1)) (Exp (HsLet decs2 e2))
 = (foldAgainstAbs pats e1 e2)
foldAgainstAbs pats e@(Exp (HsIf e1 e2 e3)) (Exp (HsIf e4 e5 e6))
 = (e1' ++ e2' ++ e3')
    where
     e1' = foldAgainstAbs pats e1 e4
     e2' = foldAgainstAbs pats e2 e5
     e3' = foldAgainstAbs pats e3 e6
foldAgainstAbs pats e@(Exp (HsCase e1 alts1)) (Exp (HsCase e2 alts2))
  = []
foldAgainstAbs pats e@(Exp (HsParen e1)) (Exp (HsParen e2))
 = (foldAgainstAbs pats e1 e2)
foldAgainstAbs pats (Exp (HsParen e1)) e2
 = foldAgainstAbs pats e1 e2
foldAgainstAbs pats e1 (Exp (HsParen e2))
 = foldAgainstAbs pats e1 e2 
foldAgainstAbs pats (Exp (HsTuple es1)) (Exp (HsTuple es2))
 = concat (foldAgainstAbs' pats es1 es2)
foldAgainstAbs pats (Exp (HsList es1)) (Exp (HsList es2))
 = concat (foldAgainstAbs' pats es1 es2)
foldAgainstAbs pats (Exp (HsLeftSection e1 o1)) (Exp (HsLeftSection e2 o2))
 = e1' ++ o1'
   where
      e1' = foldAgainstAbs pats e1 e2
      o1'
       | o1 == o2 = []
       | otherwise = [Exp (HsId o1)]
foldAgainstAbs pats (Exp (HsRightSection o1 e1)) (Exp (HsRightSection o2 e2))
 = o1' ++ e1'
  where
    e1' = foldAgainstAbs pats e1 e2
    o1'
     | o1 == o2 = []
     | otherwise = [Exp (HsId o1)]
foldAgainstAbs pats (Exp (HsEnumFrom e1)) (Exp (HsEnumFrom e2))
 = foldAgainstAbs pats e1 e2
foldAgainstAbs pats (Exp (HsEnumFromTo e1 e2)) (Exp (HsEnumFromTo e3 e4))
 = foldAgainstAbs pats e1 e2 ++ foldAgainstAbs pats e3 e4
foldAgainstAbs pats (Exp (HsEnumFromThen e1 e2)) (Exp (HsEnumFromThen e3 e4))
 = foldAgainstAbs pats e1 e2 ++ foldAgainstAbs pats e3 e4
foldAgainstAbs pats (Exp (HsEnumFromThenTo e1 e2 e3)) (Exp (HsEnumFromThenTo e4 e5 e6))
 = foldAgainstAbs pats e1 e4 ++ foldAgainstAbs pats e2 e5 ++ foldAgainstAbs pats e3 e6 
foldAgainstAbs pats (Exp (HsAsPat i1 e1)) (Exp (HsAsPat i2 e2))
 = i1' ++ e1'
   where
     e1' = foldAgainstAbs pats e1 e2
     i1'
      | i1 == i2 = []
      | otherwise = [Exp (HsId (HsVar i1))]
foldAgainstAbs pats (Exp (HsIrrPat e1)) (Exp (HsIrrPat e2))
 = foldAgainstAbs pats e1 e2 
foldAgainstAbs pats (Exp (HsDo e1)) (Exp (HsDo e2))
 = foldAgainstAbsStmts pats e1 e2    
foldAgainstAbs pats e1 e2 = [e1] 
foldAgainstAbsAlt pats as _ = as

foldAgainstAbs' pats [] [] = []
foldAgainstAbs' p x  [] = []
foldAgainstAbs' p [] x  = [] 
foldAgainstAbs' p (e:es) (x:xs) = foldAgainstAbs p e x : foldAgainstAbs' p es xs

foldAgainstAbsStmts pats a@(HsGenerator _ p1 e1 s1) b@(HsGenerator _ p2 e2 s2)
 = foldAgainstAbs (pats++[p1]++[p2]) e1 e2 ++ foldAgainstAbsStmts (pats++[p1]++[p2]) s1 s2
foldAgainstAbsStmts pats (HsQualifier e1 s1) (HsQualifier e2 s2)
 = foldAgainstAbs pats e1 e2 ++ foldAgainstAbsStmts pats s1 s2
foldAgainstAbsStmts pats (HsLast e1) (HsLast e2)
 = foldAgainstAbs pats e1 e2
foldAgainstAbsStmts pats (HsLast e1) (HsQualifier e2 s1)
 = foldAgainstAbs pats e1 e2

-- createParameters :: HsExpP -> HsDeclP
-- createParameters mod n [] = return []
createParameters mods n Nothing = return Nothing
createParameters mods n (Just e)
   = do
        numParams <- countParams e
        let nameParams = mkNewNames (length numParams) e []
        
        e' <- renameNormals e nameParams
        let newDec = createDec (transformBindings e') nameParams
        return (Just newDec)
        where
          transformBindings (Exp (HsDo stmts))
           = (Exp (HsDo (transformBind [] stmts)))
          transformBindings e = e
          
          transformBind pats (HsGenerator s p1 e1 stmts)
            = (HsGenerator s p1 e1 (transformBind (pats++[p1]) stmts))
          transformBind pats (HsQualifier e stmts)
            = (HsQualifier e (transformBind pats stmts))
          transformBind pats (HsLast e)
           | e == defaultExp
              = (HsLast (Exp (HsApp (nameToExp "return") (Exp (HsTuple (getPats pats))))))
           | pats /= [] = (HsQualifier e (HsLast (Exp (HsApp (nameToExp "return") (Exp (HsTuple (getPats pats)))))))
           | otherwise = (HsLast e)
        
          
          getPats [] = []
          getPats (p:ps) = nameToExp (pNTtoName (patToPNT p)) : getPats ps
        
          createDec e' nameParams
            = Dec (HsFunBind loc0 [HsMatch loc0 (nameToPNT newName) 
                                                (map nameToPat nameParams)
                                                (HsBody e') 
                                                [] ])
           
           
          newName = mkNewName "abs" (map pNTtoName (hsPNTs mods)) n
           
          renameNormals e [] = return e
          renameNormals e (x:xs)
             = do
                  e' <- renameANorm e x
                  res <- renameNormals e' xs
                  return res
           where
             renameANorm e x
               = applyTP (once_tdTP (failTP `adhocTP` (inPNT x))) e
             inPNT x (p::PNT) 
              | pNTtoName p == "$I" = return (nameToPNT x)
             inPNT _ _ = mzero  
        
          countParams t
            = applyTU (full_tdTU (constTU [] `adhocTU` inPNT)) t
          inPNT (p::PNT)
            | pNTtoName p == "$I" = return [p]
          inPNT x = return []
        
          mkNewNames :: Int -> HsExpP -> [String] -> [String]
          mkNewNames 0 e names = names 
          mkNewNames n e names
            = mkNewNames (n-1) e (result : names) 
              where
                result = mkNewName "p" (oldNames ++ names) n
                oldNames = map pNTtoName (hsPNTs e)
       
posToExp :: (Term t) => [PosToken] -> t -> [(SimpPos, SimpPos)] -> [HsExpP]
posToExp _ _ [] = []
posToExp toks mod ((x,y):xs) 
  = locToExp x y toks mod    : posToExp toks mod xs   

-- compareExp takes a clone class and tries to
-- figure out which parts can be extracted away or not.

-- we take all the variables out of each expression and compare them
-- the ones that match stay in the abstraction, 
createAbs' :: [ HsExpP ] -> [ HsExpP ]
createAbs' [] = []
createAbs' [x] = [compareExp [] x x]
createAbs' (x:y:es)
 = int : createAbs' (y:es)
  where 
    int = compareExp [] x y

createAbs'' :: [ HsExpP ] -> Maybe HsExpP
createAbs'' [] = Nothing
createAbs'' [x] = Just x
createAbs'' (x:y:xs)
 = createAbs'' ((compareExp [] x y):xs)

createAbs :: [ HsExpP ] -> Maybe HsExpP 
createAbs list
  = let f = createAbs' list in (createAbs'' f)


compareExp :: [HsPatP] -> HsExpP -> HsExpP -> HsExpP
compareExp pats e@(Exp (HsId (HsVar x))) (Exp (HsId (HsVar y)))
  | x == y && isTopLevelPNT x = e
  | checkPNTInPat pats x = e
  | otherwise = (Exp (HsId (HsVar (nameToPNT "$I"))))
compareExp pats e@(Exp (HsId (HsCon x))) (Exp (HsId (HsCon y)))
  | x == y    = e
  | otherwise = (Exp (HsId (HsVar (nameToPNT "$I"))))
compareExp pats e@(Exp (HsLit s l1)) (Exp (HsLit s2 l2))
  | l1 == l2  = e
  | otherwise = (Exp (HsId (HsVar (nameToPNT "$I"))))
compareExp pats e@(Exp (HsInfixApp e1 o1 e2)) (Exp (HsInfixApp e3 o2 e4))
  = Exp (HsInfixApp e1' o1' e2')
     where
       e1' = compareExp pats e1 e3
       o1' 
        | o1 == o2  = o1
        | otherwise = HsVar (nameToPNT "$I")
       e2' = compareExp pats e2 e4
compareExp pats e@(Exp (HsApp e1 e2)) (Exp (HsApp e3 e4))
 = Exp (HsApp (compareExp pats e1 e3) (compareExp pats e2 e4))
compareExp pats e@(Exp (HsNegApp s1 e1)) (Exp (HsNegApp s2 e2))
 = Exp (HsNegApp s1 (compareExp pats e1 e2))
compareExp pats1 e@(Exp (HsLambda pats e1)) (Exp (HsLambda pats2 e2))
 = Exp (HsLambda pats (compareExp pats1 e1 e2))
compareExp pats e@(Exp (HsLet decs e1)) (Exp (HsLet decs2 e2))
 = Exp (HsLet decs (compareExp pats e1 e2))
compareExp pats e@(Exp (HsIf e1 e2 e3)) (Exp (HsIf e4 e5 e6))
 = Exp (HsIf e1' e2' e3')
    where
     e1' = compareExp pats e1 e4
     e2' = compareExp pats e2 e5
     e3' = compareExp pats e3 e6
compareExp pats e@(Exp (HsCase e1 alts1)) (Exp (HsCase e2 alts2))
 = Exp (HsCase (compareExp pats e1 e2) (compareAlt pats alts1 alts2))
compareExp pats e@(Exp (HsParen e1)) (Exp (HsParen e2))
 = Exp (HsParen (compareExp pats e1 e2))
compareExp pats (Exp (HsParen e1)) e2
 = compareExp pats e1 e2
compareExp pats e1 (Exp (HsParen e2))
 = compareExp pats e1 e2 
compareExp pats (Exp (HsList es1)) (Exp (HsList es2))
 = Exp (HsList (compareExp' pats es1 es2))
compareExp pats (Exp (HsTuple es1)) (Exp (HsTuple es2))
 = Exp (HsTuple (compareExp' pats es1 es2))
compareExp pats (Exp (HsLeftSection e1 i1)) (Exp (HsLeftSection e2 i2))
 = Exp (HsLeftSection (compareExp pats e1 e2) i2')
   where
     i2' 
       | i1 == i2 = i1 
       | otherwise = HsVar (nameToPNT "$I")
compareExp pats (Exp (HsRightSection i1 e1)) (Exp (HsRightSection i2 e2))
 = Exp (HsRightSection i1' (compareExp pats e1 e2))
   where
     i1' 
      | i1 == i2 = i1
      | otherwise = HsVar (nameToPNT "$I" )
compareExp pats (Exp (HsEnumFrom e1)) (Exp (HsEnumFrom e2))
 = Exp (HsEnumFrom (compareExp pats e1 e2))
compareExp pats (Exp (HsEnumFromTo e1 e2)) (Exp (HsEnumFromTo e3 e4))
 = Exp (HsEnumFromTo (compareExp pats e1 e3) (compareExp pats e2 e4))
compareExp pats (Exp (HsEnumFromThen e1 e2)) (Exp (HsEnumFromThen e3 e4))
 = Exp (HsEnumFromThen (compareExp pats e1 e3) (compareExp pats e2 e4))
compareExp pats (Exp (HsEnumFromThenTo e1 e2 e3)) (Exp (HsEnumFromThenTo e4 e5 e6))
 = Exp (HsEnumFromThenTo (compareExp pats e1 e4) (compareExp pats e2 e5) (compareExp pats e3 e6))
compareExp pats (Exp (HsAsPat i1 e1)) (Exp (HsAsPat i2 e2))
 = Exp (HsAsPat i1' (compareExp pats e1 e2))
   where
    i1' 
     | i1 == i2 = i1
     | otherwise = (nameToPNT "$I")
compareExp pats (Exp (HsIrrPat e1)) (Exp (HsIrrPat e2))
 = Exp (HsIrrPat (compareExp pats e1 e2))
compareExp pats e1@(Exp (HsDo stmts1)) e2@(Exp (HsDo stmts2))
 = Exp (HsDo (compareStmts pats stmts1 stmts2))
compareExp pats e1 e2 = (Exp (HsId (HsVar (nameToPNT "$I"))))
compareAlt pats as _ = as

compareStmts pats (HsGenerator s p1 e1 s1) (HsGenerator _ p2 e2 s2)
 = HsGenerator s p1 (compareExp (pats++[p1]++[p2]) e1 e2) (compareStmts (pats++[p1]++[p2]) s1 s2)
compareStmts pats (HsQualifier e1 stmts1) (HsQualifier e2 stmts2)
 = HsQualifier (compareExp pats e1 e2) (compareStmts pats stmts1 stmts2)
compareStmts pats (HsLast e1) (HsLast e2)
 = HsLast (compareExp pats e1 e2)
compareStmts pats s1 s2 = s1


compareExp' p [] [] = []
compareExp' p _ [] = []
compareExp' p [] _ = []
compareExp' p (e:es) (x:xs) = compareExp p e x : compareExp' p es xs
       
catPositions :: String -> [ String ]
catPositions [] = []
catPositions ('[':ps)
   = grabbed : catPositions ps'
      where 
        (grabbed, ps') = (grabPositions ps, dropPositions ps)
        grabPositions [] = []
        grabPositions (']':xs) = []
        grabPositions ('<':'&':'>':ps)
          = ":" ++ grabPositions ps
        grabPositions (x:xs) = x : grabPositions xs
        
        dropPositions [] = []
        dropPositions (']':xs) = xs
        dropPositions (x:xs) = dropPositions xs

        
prunePositions :: String -> [String] -> [ [(SimpPos, SimpPos)] ]
prunePositions [] [] = []
prunePositions [] _  = []
prunePositions _ []  = []
prunePositions as (p:ps) 
   = createSet as p : prunePositions remAnswers ps
    where
      remAnswers = drop ((length (filter (==':') p)) + 1) as
    
      createSet :: String -> String -> [ (SimpPos, SimpPos) ]
      createSet [] [] = []
      createSet [] _  = []
      createSet _  [] = []
      createSet ('y':xs) ps    
         = ((read p2)::(SimpPos, SimpPos)) : createSet xs ps'
           where
             p2  = getPos ps 
             ps' = dropPos ps
             getPos [] = []
             getPos (':':xs) = []
             getPos (x:xs)   = x : getPos xs
             
             dropPos [] = []
             dropPos (':':xs) = xs
             dropPos (x:xs)   = dropPos xs
         
      createSet ('n':xs) ps
         = createSet xs ps'
            where
             ps' = dropPos ps
             
             dropPos [] = []
             dropPos (':':xs) = xs
             dropPos (x:xs)   = dropPos xs

      createSet _ _ = []