module HandleExtra where

import Regexp
import Re2hsBasics
{- doNest f n bef aft - 
   deals with nested comments. It assumes that it is just past
   the start of this nested comment. It continues until it reaches the end
   of that comment. At this point it calls function f.
   It assumes that from the start of this block of comments, to the
   present point, has been the text contained in bef.
   It assumes that this block of comments starts on the nth line.
   It will return an error message containing the line number of the
   start of the nested comment if there is an unterminated nested comment.
-} 

doNest :: Int		-- which line this block of comments started on
       -> String	-- everything after the current point
       -> (String,	-- everything up to and including the end of 
			-- this comment
           String)	-- everything after the end of this comment

doNest n aft = dealNest n "" aft
 where 
  dealNest n bef aft = 
       let
       matchResult1 =  searchExtS (" 1end@(-\\}(?Default_Line,Case_Sensitive))| 2start@(\\{-(?Default_Line,Case_Sensitive))") [][][]
            aft 
       in
       if (matchedSubexp matchResult1 "1end") then
       let
         end = wholeMatch matchResult1
         end_before_ = beforeMatch matchResult1
         end_after_ = afterMatch matchResult1
       in
                  
		(bef++end_before_++end, end_after_)

	 
       else if (matchedSubexp matchResult1 "2start") then
       let
         start = wholeMatch matchResult1
         start_before_ = beforeMatch matchResult1
         start_after_ = afterMatch matchResult1
       in
                    
		case dealNest n "" start_after_ of
                  (newm,a) -> 
                    dealNest n (bef++start_before_++start++newm) a

	 
       else -- if not (matchedAny matchResult1) then
          error ("unterminated nested comment, line:" ++ show n++"\n")



{- others n text -
	parses the text given looking for the beginning of the next
        piece of actual code, it therefore ignores spaces, and both sorts
	of comments.
-}

others:: Int	-- which line we're on 
      -> String -- the text after this point
      -> Maybe (String,	-- everything in the given text before the
			-- start of the real code
                String) -- everything in the given text after the 
			-- start of the real code.

others x code = dojunk x "" code

dojunk:: Int	-- which line we're on 
      -> String -- everything before current point in given text
      -> String -- the text after this point
      -> Maybe (String,	-- everything in the given text before the
			-- start of the real code
                String) -- everything in the given text after the 
			-- start of the real code.
dojunk n bef aft =
               let
               matchResult1 =  searchExtS (" 1comment@(^(?Multi_Line)--.*$(?Default_Line,Case_Sensitive))| 2spaces@(^\\s+(?Default_Line,Case_Sensitive))| 3nested@(^\\{-(?Default_Line,Case_Sensitive))") [][][]
                    aft 
               in
               if (matchedSubexp matchResult1 "1comment") then
               let
                 comment = wholeMatch matchResult1
                 comment_before_ = beforeMatch matchResult1
                 comment_after_ = afterMatch matchResult1
               in
                             
			    dojunk (n + 1) (bef ++ comment) comment_after_
		
		
               else if (matchedSubexp matchResult1 "2spaces") then
               let
                 spaces = wholeMatch matchResult1
                 spaces_before_ = beforeMatch matchResult1
                 spaces_after_ = afterMatch matchResult1
               in
                               
                             dojunk (n+ (numLines spaces)) (bef++ spaces) spaces_after_

		
               else if (matchedSubexp matchResult1 "3nested") then
               let
                 nested = wholeMatch matchResult1
                 nested_before_ = beforeMatch matchResult1
                 nested_after_ = afterMatch matchResult1
               in
                            
                          case doNest n nested_after_ of
                            (m,a) -> 
                               dojunk (n+ (numLines m)) (bef++nested++m) a

		
               else -- if not (matchedAny matchResult1) then
                 Just (bef,aft)


{- list looks for the list part of a "case list of" expression. It
   handles possibly nested case expressions in the list part, as list can
   be any valid haskell expression.
-}

list :: Int		-- what line this list starts on 
     -> String		-- the text to look through
     -> Maybe (String,	-- everything before the end of the list
	       String)	-- everything after the end of the list, start with "of"

list n  xs = case handlelist n xs of
                   (Just (text, m_after_)) ->
                     Just ((init.init) text,"of"++m_after_)
	     -- add the last of to what's after, as it's still needed parsing
	     -- above

{- handlelist calls itself recursively, looking for the "of"
   that marks the end of this expression.
-}
handlelist :: Int -> String -> Maybe (String,String)

handlelist n xs = dolist  "" xs
    where
         dolist bef aft = 
            let
            matchResult1 =  searchExtS (" 1comment@((?Multi_Line)--.*$(?Default_Line,Case_Sensitive))| 2string@(\"(?Default_Line,Case_Sensitive))| 3nested@(\\{-(?Default_Line,Case_Sensitive))| 4caseone@(\\bcase\\b(?Default_Line,Case_Sensitive))| 5ofone@(\\bof\\b(?Default_Line,Case_Sensitive))") [][][]
                 aft 
            in
            if (matchedSubexp matchResult1 "1comment") then
            let
              comment = wholeMatch matchResult1
              comment_before_ = beforeMatch matchResult1
              comment_after_ = afterMatch matchResult1
            in
                                       
			    
		           dolist (bef++comment_before_++comment) comment_after_ 

                
            else if (matchedSubexp matchResult1 "2string") then
            let
              string = wholeMatch matchResult1
              string_before_ = beforeMatch matchResult1
              string_after_ = afterMatch matchResult1
            in
                            
			 let text = bef++string_before_++string
                         in
                            case finishString (numLines text + n) "" string_after_ of
                                   (m,a) -> dolist (text++m)  a


		
            else if (matchedSubexp matchResult1 "3nested") then
            let
              nested = wholeMatch matchResult1
              nested_before_ = beforeMatch matchResult1
              nested_after_ = afterMatch matchResult1
            in
                            
			 let text = bef ++ nested_before_ ++ nested
                         in
                           case doNest (numLines text + n) nested_after_ of
			           (m,a) -> dolist (text++m) a

		
            else if (matchedSubexp matchResult1 "4caseone") then
            let
              caseone = wholeMatch matchResult1
              caseone_before_ = beforeMatch matchResult1
              caseone_after_ = afterMatch matchResult1
            in
                             	
                         let text = bef ++ caseone_before_++caseone
                         in 
                          case handlelist (numLines text + n) caseone_after_ of
                           (Just (m,a)) -> 
			     dolist (text++m) a

		
            else if (matchedSubexp matchResult1 "5ofone") then
            let
              ofone = wholeMatch matchResult1
              ofone_before_ = beforeMatch matchResult1
              ofone_after_ = afterMatch matchResult1
            in
                            
			Just (bef ++ ofone_before_++ofone, ofone_after_)

		
            else -- if not (matchedAny matchResult1) then
                 
			error ("error in case expression, \"of\" expected, line:"++show n++"\n")





{- finishString searches through a piece of Haskell code for the end
   of the current string
-}


finishString :: Int	-- which line the string starts on
	     -> String	-- what's between the start of the string and
			-- current point
             -> String	-- what's after the current point
             -> (String,-- the string
                 String)-- everything after the end of the string

finishString x bef xs = let
                        matchResult1 =  searchExtS (" 1esc@(\\\\[^n](?Default_Line,Case_Sensitive))| 2end@(\"(?Default_Line,Case_Sensitive))| 3eol@(\n(?Default_Line,Case_Sensitive))") [][][]
                             xs 
                        in
                        if (matchedSubexp matchResult1 "1esc") then
                        let
                          esc = wholeMatch matchResult1
                          esc_before_ = beforeMatch matchResult1
                          esc_after_ = afterMatch matchResult1
                        in
                                  
				finishString x (bef++esc_before_++esc) esc_after_

                         
                        else if (matchedSubexp matchResult1 "2end") then
                        let
                          end = wholeMatch matchResult1
                          end_before_ = beforeMatch matchResult1
                          end_after_ = afterMatch matchResult1
                        in
                                  
				(bef++ end_before_ ++ end, end_after_)



                         
                        else if (matchedSubexp matchResult1 "3eol") then
                        let
                          eol = wholeMatch matchResult1
                          eol_before_ = beforeMatch matchResult1
                          eol_after_ = afterMatch matchResult1
                        in
                                  
                                error ("improperly terminated string, line:"
                                 ++ show x++"\n") 

                         
                        else -- if not (matchedAny matchResult1) then
                          error ("improperly terminated string, line:"
                                 ++ show x++"\n")






