eval :: String -> Shell ExitCode
eval c = eval' "" $ lines c
    where eval' :: String -> [String] -> Shell ExitCode
          eval' i rest =
              do if null rest
                    then getExitCode
                    else do let ([s],rest') = splitAt 1 rest
                            am_v <- getFlag 'v'
                            when am_v $ ePutStrLn s
                            as <- getAliases
                            case parse as (i++s) of
                              Left (err,False) -> do
                                when (null rest') $ fail err
                                eval' (i++s++"\n") rest'
                              Left (err,True) -> do
                                ePutStrLn err -- refail at eof?
                                eval' "" rest'
                              Right cs -> if hereDocsComplete cs
                                          then runCommands cs >> eval' "" rest'
                                          else if null rest'
                                               then runCommands cs
                                               else eval' (i++s++"\n") rest'
eval :: String -> Shell ExitCode
eval c = eval' "" $ lines c
    where eval' :: String -> [String] -> Shell ExitCode
          eval' i rest =
              do if null rest
                    then getExitCode
                    else do let ([s],rest') = splitAt 1 rest
                            am_v <- getFlag 'v'
                            when am_v $ ePutStrLn s
                            as <- getAliases
                            case parse as (i++s) of
                              Left (err,False) -> do
                                when (null rest') $ fail err
                                eval' (i++s++"\n") rest'
                              Left (err,True) -> do
                                ePutStrLn err -- refail at eof?
                                eval' "" rest'
                              Right cs -> if hereDocsComplete cs
                                          then runCommands cs >> eval' "" rest'
                                          else if null rest'
                                               then runCommands cs
                                               else eval' (i++s++"\n") rest'
eval c = eval' "" $ lines c
    where eval' :: String -> [String] -> Shell ExitCode
          eval' i rest =
              do if null rest
                    then getExitCode
                    else do let ([s],rest') = splitAt 1 rest
                            am_v <- getFlag 'v'
                            when am_v $ ePutStrLn s
                            as <- getAliases
                            case parse as (i++s) of
                              Left (err,False) -> do
                                when (null rest') $ fail err
                                eval' (i++s++"\n") rest'
                              Left (err,True) -> do
                                ePutStrLn err -- refail at eof?
                                eval' "" rest'
                              Right cs -> if hereDocsComplete cs
                                          then runCommands cs >> eval' "" rest'
                                          else if null rest'
                                               then runCommands cs
                                               else eval' (i++s++"\n") rest'