{-|
A module for command-line argument parsing.
-}
module Lsql.Csv.Lang.Args (Program(Program), parseArgs, reloadOpts) where

import Lsql.Csv.Lang.Options

import Text.Parsec
import Text.Parsec.Prim
import Text.Parsec.Combinator
import Text.Parsec.Text
import Text.Parsec.Char

import Data.List
import qualified Data.Text as T

-- | A datatype representing all arguments for one run of the lsql-csv
data Program = Program 
  String -- ^ A lsql-csv command
  Char -- ^ A primary delimiter
  Char -- ^ A secondary delimiter (quote)
  Bool -- ^ First line naming
  deriving (Int -> Program -> ShowS
[Program] -> ShowS
Program -> String
(Int -> Program -> ShowS)
-> (Program -> String) -> ([Program] -> ShowS) -> Show Program
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Program -> ShowS
showsPrec :: Int -> Program -> ShowS
$cshow :: Program -> String
show :: Program -> String
$cshowList :: [Program] -> ShowS
showList :: [Program] -> ShowS
Show)

data Arg = Opt Option| Cmd String

load_ag :: Program -> [Arg] -> Program

load_ag :: Program -> [Arg] -> Program
load_ag Program
p [] = Program
p
load_ag (Program String
a1 Char
a2 Char
a3 Bool
a4) (Cmd String
c : [Arg]
rest) = Program -> [Arg] -> Program
load_ag (String -> Char -> Char -> Bool -> Program
Program String
c Char
a2 Char
a3 Bool
a4) [Arg]
rest
load_ag (Program String
a1 Char
a2 Char
a3 Bool
a4) (Opt (Delimiter Char
c) : [Arg]
rest) = Program -> [Arg] -> Program
load_ag (String -> Char -> Char -> Bool -> Program
Program String
a1 Char
c Char
a3 Bool
a4) [Arg]
rest
load_ag (Program String
a1 Char
a2 Char
a3 Bool
a4) (Opt (SecondaryDelimiter Char
c) : [Arg]
rest) = Program -> [Arg] -> Program
load_ag (String -> Char -> Char -> Bool -> Program
Program String
a1 Char
a2 Char
c Bool
a4) [Arg]
rest
load_ag (Program String
a1 Char
a2 Char
a3 Bool
a4) (Opt (Named Bool
c) : [Arg]
rest) = Program -> [Arg] -> Program
load_ag (String -> Char -> Char -> Bool -> Program
Program String
a1 Char
a2 Char
a3 Bool
c) [Arg]
rest


load_args :: [Arg] -> Program
load_args :: [Arg] -> Program
load_args [Arg]
args = 
  Program -> [Arg] -> Program
load_ag (String -> Char -> Char -> Bool -> Program
Program String
"" Char
',' Char
'"' Bool
False) [Arg]
args

-- | Loads additional options to a `Program`.
reloadOpts :: Program -> [Option] -> Program
reloadOpts :: Program -> [Option] -> Program
reloadOpts Program
pg [Option]
ops = Program -> [Arg] -> Program
load_ag Program
pg([Arg] -> Program) -> [Arg] -> Program
forall a b. (a -> b) -> a -> b
$ (Option -> Arg) -> [Option] -> [Arg]
forall a b. (a -> b) -> [a] -> [b]
map (Option -> Arg
Opt) [Option]
ops

   
argOptionP :: Parser Arg
argOptionP :: Parser Arg
argOptionP = do
  Option
op <- Parser Option
optionParser
  Arg -> Parser Arg
forall a. a -> ParsecT Text () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return(Arg -> Parser Arg) -> Arg -> Parser Arg
forall a b. (a -> b) -> a -> b
$ Option -> Arg
Opt Option
op

argCmdP :: Parser Arg
argCmdP :: Parser Arg
argCmdP = do
  String
op <- ParsecT Text () Identity Char -> ParsecT Text () Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT Text () Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar
  Arg -> Parser Arg
forall a. a -> ParsecT Text () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return(Arg -> Parser Arg) -> Arg -> Parser Arg
forall a b. (a -> b) -> a -> b
$ String -> Arg
Cmd String
op

argP :: Parser Arg
argP :: Parser Arg
argP = do
  Arg
ret <- (Parser Arg -> Parser Arg
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try Parser Arg
argOptionP)
  ParsecT Text () Identity Char -> ParsecT Text () Identity ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany ParsecT Text () Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
space
  Arg -> Parser Arg
forall a. a -> ParsecT Text () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return Arg
ret

fullP :: Parser [Arg]
fullP :: Parser [Arg]
fullP = do
  [Arg]
ags <- Parser Arg -> Parser [Arg]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many Parser Arg
argP
  Arg
cmd <- Parser Arg
argCmdP
  [Arg] -> Parser [Arg]
forall a. a -> ParsecT Text () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return([Arg] -> Parser [Arg]) -> [Arg] -> Parser [Arg]
forall a b. (a -> b) -> a -> b
$ [Arg]
ags [Arg] -> [Arg] -> [Arg]
forall a. [a] -> [a] -> [a]
++ [Arg
cmd]

-- | Parses given arguments to a `Program` representation.
parseArgs :: [String] -> Program
parseArgs :: [String] -> Program
parseArgs [String]
args = 
  let input :: String
input = [String] -> String
unwords [String]
args in
  case Parser [Arg] -> String -> Text -> Either ParseError [Arg]
forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
parse Parser [Arg]
fullP String
"arguments" (String -> Text
T.pack String
input) of
    Left ParseError
err -> String -> Program
forall a. HasCallStack => String -> a
error (String -> Program) -> String -> Program
forall a b. (a -> b) -> a -> b
$ ParseError -> String
forall a. Show a => a -> String
show ParseError
err
    Right [Arg]
val -> [Arg] -> Program
load_args [Arg]
val