module Language.Sh.Parser.Internal where
import Language.Sh.Parser.Parsec
import Language.Sh.Syntax
import Data.Char ( isDigit )
import Text.ParserCombinators.Parsec ( choice )
impossible = const undefined
redirOperator :: P String
redirOperator = token $ choice [do char '>'
choice [char '&' >> return ">&"
,char '>' >> return ">>"
,char '|' >> return ">|"
,return ">"]
,do char '<'
choice [char '&' >> return "<&"
,do char '<'
choice [char '-' >> return "<<-"
,return "<<"]
,char '>' >> return "<>"
,return "<"]]
mkRedir :: String -> Maybe Int -> Word -> P Redir
mkRedir _ (Just d) _ | d > 255 = fail $ "file descriptor too large: "++show d
mkRedir op@('<':_) Nothing t = mkRedir op (Just 0) t
mkRedir op@('>':_) Nothing t = mkRedir op (Just 1) t
mkRedir "<" (Just s) t = return $ s :< t
mkRedir "<&" (Just s) t | Just t' <- wordToInt t = return $ s :<& t'
| otherwise = fail "bad file descriptor"
mkRedir "<>" (Just s) t = return $ s :<> t
mkRedir ">" (Just s) t = return $ s :> t
mkRedir ">&" (Just s) t | Just t' <- wordToInt t = return $ s :>& t'
| otherwise = fail "bad file descriptor"
mkRedir ">>" (Just s) t = return $ s :>> t
mkRedir ">|" (Just s) t = return $ s :>| t
mkHereDoc :: String -> Maybe Int -> String -> P Redir
mkHereDoc op Nothing t = mkHereDoc op (Just 0) t
mkHereDoc "<<" (Just s) t = do addHereDoc t
return $ s :<< t
mkHereDoc "<<-" (Just s) t = do addHereDoc t
return $ s :<<- t
wordToInt :: Word -> Maybe Int
wordToInt w = case fromLiteral w of
Just ds | null $ filter (not . isDigit) ds -> Just $ read ds
_ -> Nothing
addAssignment :: Assignment -> Statement -> Statement
addAssignment a (Statement ws rs as) = Statement ws rs (a:as)
addAssignment a (OrderedStatement ts) = OrderedStatement (TAssignment a:ts)
addAssignment _ (Compound _ _) = impossible "cannot add assignment to Compound"
addWord :: Word -> Statement -> Statement
addWord w (Statement ws rs as) = Statement (w:ws) rs as
addWord w (OrderedStatement ts) = OrderedStatement (TWord w:ts)
addWord _ (Compound _ _) = impossible "cannot add word to Compound"
addRedirection :: Redir -> Statement -> Statement
addRedirection r (Statement ws rs as) = Statement ws (r:rs) as
addRedirection r (OrderedStatement ts) = OrderedStatement (TRedir r:ts)
addRedirection r (Compound c rs) = Compound c (r:rs)
fromLiteral :: Word -> Maybe String
fromLiteral [] = Just []
fromLiteral (Literal c:cs) = fmap (c:) $ fromLiteral cs
fromLiteral _ = Nothing
ql :: Char -> Lexeme
ql = Quoted . Literal