packages feed

fsh-csv-0.1.0.0: src/FSH_CSV.hs

module FSH_CSV where

import Transform
import Text.ParserCombinators.ReadP
import Language.Haskell.Interpreter as I
import Data.List

--- PARSING

isChar = (/=',')

charParser :: ReadP [Char]
charParser = many1 (satisfy isChar)

-- This parses characters till a comma is encountered
getParsed :: ReadS [Char]
getParsed = readP_to_S charParser

-- Leading comma needs to be removed or else our parser will output []
removeLeadingComma (',':xs) = removeLeadingComma xs
removeLeadingComma str = str

-- Only the last element is of interest, rest are incomplete
getPair :: [Char] -> ([Char], [Char])
getPair line = 
  parsedPair $ getParsed.removeLeadingComma $ line
  where
    parsedPair list@(x:xs) = last list
    parsedPair [] = ("","")

{-
 - When we run getPair on a string, we get a pair of strings.
 - The first half is parsed, the second half failed our parser.
 - The second half failed because it had comma, so if we run getPair on
 - the unparsed string, it will ultimately be parsed.
 -
 - And that is the solution presented here, we run getPair,
 - pick the parsed part and put it in a list, and run getPair on unparsed part.
 - We do this till unparsed is [] ie empty and then we return the list of parsed words.
 -}

getWords' :: [[Char]] -> ([Char], [Char]) -> [[Char]]
getWords' list (parsed,[]) = list++[parsed]
getWords' list (parsed,unparsed) = return (getPair $ unparsed) >>= getWords' (if length parsed > 0 then (list++[parsed]) else [])

getWords :: [Char] -> [[Char]]
getWords line = getWords' [] ([],line)

--- END PARSING

--- TRANSFORMING

mapLines :: [[Char]] -> [[[Char]]]
mapLines = map getWords

mapQuotes :: [[String]] -> [[Char]]
mapQuotes = map ((\str->","++str).toStringList.encloseWithQuotes)

mapBraces :: [String] -> [Char]
mapBraces list = "[" ++ (tail (unwords list)) ++ "]"

parse :: [[Char]] -> [Char]
parse = mapBraces.mapQuotes.mapLines

--- END TRANSFORMING

--- EXECUTING

printList (x:xs) = putStrLn x >> printList xs
printList [] = return ()


run :: [Char] -> String -> IO ()
run functionStr processedArgs =
  do
    splits <- return (lines processedArgs)
    header <- return (head splits)
    unparsed <- return (tail splits)
    result <- runInterpreter $ setImports ["Prelude"] >> interpret (functionStr ++ " " ++ parse unparsed) (as :: [[String]])
    case result of
      (Right res) -> 
        do
          outputMatrix <- return $ (getWords header) : res
          output <- return $ map (intercalate ",") outputMatrix
          printList output
      (Left err)   -> error $ show err

--- END EXECUTING