language-bash 0.7.1 → 0.8.0
raw patch · 9 files changed
+177/−99 lines, 9 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Language.Bash.Cond: instance GHC.Generics.Generic (Language.Bash.Cond.CondExpr a)
+ Language.Bash.Cond: instance GHC.Generics.Generic Language.Bash.Cond.BinaryOp
+ Language.Bash.Cond: instance GHC.Generics.Generic Language.Bash.Cond.UnaryOp
+ Language.Bash.Parse.Word: functionName :: Stream s m Char => ParsecT s u m String
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.AndOr
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.Assign
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.AssignOp
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.CaseClause
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.CaseTerm
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.Command
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.HeredocOp
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.IODesc
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.List
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.ListTerm
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.Pipeline
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.RValue
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.Redir
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.RedirOp
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.ShellCommand
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.Statement
+ Language.Bash.Syntax: instance GHC.Generics.Generic Language.Bash.Syntax.WordList
+ Language.Bash.Word: instance GHC.Generics.Generic Language.Bash.Word.AltOp
+ Language.Bash.Word: instance GHC.Generics.Generic Language.Bash.Word.Direction
+ Language.Bash.Word: instance GHC.Generics.Generic Language.Bash.Word.LetterCaseOp
+ Language.Bash.Word: instance GHC.Generics.Generic Language.Bash.Word.ParamSubst
+ Language.Bash.Word: instance GHC.Generics.Generic Language.Bash.Word.Parameter
+ Language.Bash.Word: instance GHC.Generics.Generic Language.Bash.Word.ProcessSubstOp
+ Language.Bash.Word: instance GHC.Generics.Generic Language.Bash.Word.Span
+ Language.Bash.Word: wordToString :: Word -> Maybe String
Files
- language-bash.cabal +3/−3
- src/Language/Bash/Cond.hs +5/−9
- src/Language/Bash/Expand.hs +1/−5
- src/Language/Bash/Parse.hs +48/−11
- src/Language/Bash/Parse/Internal.hs +12/−11
- src/Language/Bash/Parse/Word.hs +11/−4
- src/Language/Bash/Syntax.hs +26/−27
- src/Language/Bash/Word.hs +18/−10
- tests/Tests.hs +53/−19
language-bash.cabal view
@@ -1,16 +1,16 @@ name: language-bash-version: 0.7.1+version: 0.8.0 category: Language license: BSD3 license-file: LICENSE author: Kyle Raftogianis-maintainer: Kyle Raftogianis <kylerafto@gmail.com>+maintainer: Kyle Raftogianis <knrafto@gmail.com> copyright: Copyright (c) 2013-2018 Kyle Raftogianis build-type: Simple cabal-version: >= 1.8 homepage: http://github.com/knrafto/language-bash/ bug-reports: http://github.com/knrafto/language-bash/issues-tested-with: GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.1, GHC == 7.10.2, GHC == 8.0.2, GHC == 8.4.3+tested-with: GHC == 7.10.1, GHC == 7.10.2, GHC == 8.0.2, GHC == 8.4.3 synopsis: Parsing and pretty-printing Bash shell scripts description: A library for parsing, pretty-printing, and manipulating
src/Language/Bash/Cond.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE DeriveDataTypeable , DeriveFoldable- , CPP+ , DeriveGeneric , DeriveFunctor , DeriveTraversable , OverloadedStrings@@ -19,15 +19,11 @@ import Control.Applicative import Data.Data (Data) import Data.Typeable (Typeable)+import GHC.Generics (Generic) import Text.Parsec hiding ((<|>), token) import Text.Parsec.Expr hiding (Operator) import Text.PrettyPrint hiding (parens) -#if __GLASGOW_HASKELL__ < 710-import Data.Foldable (Foldable)-import Data.Traversable (Traversable)-#endif- import Language.Bash.Operator import Language.Bash.Pretty @@ -38,7 +34,7 @@ | Not (CondExpr a) | And (CondExpr a) (CondExpr a) | Or (CondExpr a) (CondExpr a)- deriving (Data, Eq, Read, Show, Typeable, Functor, Foldable, Traversable)+ deriving (Data, Eq, Read, Show, Typeable, Functor, Foldable, Traversable, Generic) instance Pretty a => Pretty (CondExpr a) where pretty = go (0 :: Int)@@ -77,7 +73,7 @@ | Varname -- ^ @-v@ | ZeroString -- ^ @-z@ | NonzeroString -- ^ @-n /string/@ or @/string/@- deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded, Generic) instance Operator UnaryOp where operatorTable =@@ -106,7 +102,7 @@ | ArithLE -- ^ @-le@ | ArithGT -- ^ @-gt@ | ArithGE -- ^ @-ge@- deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded, Generic) instance Operator BinaryOp where operatorTable =
src/Language/Bash/Expand.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverloadedStrings, PatternGuards, CPP #-}+{-# LANGUAGE OverloadedStrings, PatternGuards, DeriveGeneric #-} -- | Shell expansions. module Language.Bash.Expand ( braceExpand@@ -7,11 +7,7 @@ , splitWord ) where -#if __GLASGOW_HASKELL__ >= 710 import Prelude hiding ((<>), Word)-#else-import Data.Traversable (traverse)-#endif import Control.Applicative import Control.Monad
src/Language/Bash/Parse.hs view
@@ -58,25 +58,27 @@ duck = do u <- getState case postHeredoc u of- Nothing -> () <$ line+ Nothing -> () <$ line <* optional (char '\n') Just s -> () <$ setParserState s h <- unlines <$> heredocLines s <- getParserState return (h, s) - line = many (satisfy (/= '\n')) <* optional (char '\n')+ line = many (satisfy (/= '\n')) heredocLines = [] <$ eof <|> nextLine nextLine = do l <- process <$> line- if l == end then return [] else (l :) <$> heredocLines+ if l == end+ then return []+ else (l :) <$ optional (char '\n') <*> heredocLines -- | Parse a newline, skipping any here documents. newline :: Parser String newline = "newline" ?: do- _ <- operator "\n"+ _ <- operator "\r\n" <|> operator "\n" u <- getState case postHeredoc u of Nothing -> return ()@@ -126,7 +128,7 @@ redirOperator = selectOperator operator <?> "redirection operator" heredocOperator = selectOperator operator <?> "here document operator" --- | Skip a list of redirections.+-- | Parse a list of redirections. redirList :: Parser [Redir] redirList = many redir @@ -152,8 +154,9 @@ normalCommand = "simple command" ?: do (as, rs1) <- commandParts assign (ws, rs2) <- commandParts anyWord- guard (not $ null as && null ws)- return $ Command (SimpleCommand as ws) (rs1 ++ rs2)+ let rs = rs1 ++ rs2+ guard (not $ null as && null ws && null rs)+ return $ Command (SimpleCommand as ws) rs assignArg = Left <$> assign <|> Right <$> anyWord@@ -338,11 +341,12 @@ where expr = buildExpressionParser opTable term - term = word "(" *> expr <* word ")"+ term = operator "(" *> expr <* operator ")" <|> Cond.Unary <$> unaryOp <*> condWord <|> (condWord >>= wordTerm) - wordTerm w = Cond.Binary w <$> binaryOp <*> condWord+ wordTerm w = Cond.Binary w Cond.StrMatch <$ try (word "=~") <*> regexWord+ <|> Cond.Binary w <$> binaryOp <*> condWord <|> pure (Cond.Unary Cond.NonzeroString w) opTable =@@ -360,6 +364,39 @@ unaryOp = selectOperator condOperator <?> "unary operator" binaryOp = selectOperator condOperator <?> "binary operator" + regexWord = stringToWord . concat <$> many1 (regexPart " \t\r\n") <* skipSpace+ <?> "regular expression"++ regexPart delims = regexParens+ <|> regexSingleQuote+ <|> regexDoubleQuote+ <|> regexEscape+ <|> regexChar delims++ regexDelimiters :: Char -> Parser String -> Char -> Parser String+ regexDelimiters begin middle end = do+ _ <- char begin+ parts <- many middle+ _ <- char end+ return $ [begin] ++ concat parts ++ [end]++ regexParens = regexDelimiters '(' (regexPart ")") ')'++ regexSingleQuote = regexDelimiters '\'' singleQuoteChar '\''+ where+ singleQuoteChar = sequence [char '\\', anyChar]+ <|> (:[]) <$> noneOf "'"++ regexDoubleQuote = regexDelimiters '"' doubleQuoteChar '"'+ where+ doubleQuoteChar = sequence [char '\\', anyChar]+ <|> (:[]) <$> noneOf "\""++ regexEscape = sequence [char '\\', anyChar]++ regexChar :: [Char] -> Parser String+ regexChar delims = (:[]) <$> noneOf delims+ ------------------------------------------------------------------------------- -- Coprocesses -------------------------------------------------------------------------------@@ -383,12 +420,12 @@ <?> "function definition" where functionDef1 = FunctionDef- <$> try (word "function" *> name+ <$> try (word "function" *> functionName <* optional functionParens <* newlineList) <*> functionBody functionDef2 = FunctionDef- <$> try (name <* functionParens <* newlineList)+ <$> try (functionName <* functionParens <* newlineList) <*> functionBody functionParens = operator "(" <* operator ")"
src/Language/Bash/Parse/Internal.hs view
@@ -2,7 +2,6 @@ FlexibleContexts , FlexibleInstances , LambdaCase- , CPP , MultiParamTypeClasses , PatternGuards , RecordWildCards@@ -21,10 +20,10 @@ , anyWord , word , reservedWord- , unreservedWord , assignBuiltin , ioDesc , name+ , functionName -- * Operators , anyOperator , operator@@ -36,9 +35,7 @@ , heredocWord ) where -#if __GLASGOW_HASKELL__ >= 710 import Prelude hiding (Word)-#endif import Control.Applicative import Control.Monad@@ -155,7 +152,7 @@ operators :: [String] operators = [ "(", ")", ";;", ";&", ";;&"- , "|", "|&", "||", "&&", ";", "&", "\n"+ , "|", "|&", "||", "&&", ";", "&", "\r\n", "\n" , "<", ">", ">|", ">>", "&>", "&>>", "<<<", "<&", ">&", "<>" , "<<", "<<-" ]@@ -181,11 +178,6 @@ reservedWord :: Monad m => ParsecT D u m Word reservedWord = anyWord `satisfying` (`elem` reservedWords) <?> "reserved word" --- | Parse a word that is not reserved.-unreservedWord :: Monad m => ParsecT D u m Word-unreservedWord = anyWord `satisfying` (`notElem` reservedWords)- <?> "unreserved word"- -- | Parse an assignment builtin. assignBuiltin :: Monad m => ParsecT D u m Word assignBuiltin = anyWord `satisfying` (`elem` assignBuiltins)@@ -197,9 +189,18 @@ -- | Parse a variable name. name :: Monad m => ParsecT D u m String-name = (prettyText <$> unreservedWord) `satisfying` isName <?> "name"+name = (prettyText <$> anyWord) `satisfying` isName <?> "name" where isName s = case parse (I.name <* eof) "" (prettyText s) of+ Left _ -> False+ Right _ -> True++-- | Parse a function name.+functionName :: Monad m => ParsecT D u m String+functionName = (prettyText <$> anyWord) `satisfying` isFunctionName+ <?> "function name"+ where+ isFunctionName s = case parse (I.functionName <* eof) "" (prettyText s) of Left _ -> False Right _ -> True
src/Language/Bash/Parse/Word.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleContexts, RecordWildCards, CPP #-}+{-# LANGUAGE FlexibleContexts, RecordWildCards #-} -- | Word-level parsers. module Language.Bash.Parse.Word ( skipSpace@@ -6,14 +6,13 @@ , word , heredocWord , name+ , functionName , subscript , assign , operator ) where -#if __GLASGOW_HASKELL__ >= 710 import Prelude hiding (Word)-#endif import Control.Applicative import Control.Monad@@ -298,7 +297,7 @@ -- | Parse a word. word :: Stream s m Char => ParsecT s u m Word-word = spans " \t\n&|;()<>" True wordSpan+word = spans " \t\r\n&|;()<>" True wordSpan -- | Parse a here document as a word. This parses substitutions, but not -- most quoting.@@ -315,6 +314,14 @@ where nameStart = letter <|> char '_' nameLetter = alphaNum <|> char '_'++-- | Parse a function name.+functionName :: Stream s m Char => ParsecT s u m String+functionName = (:) <$> nameStart <*> many nameLetter+ where+ nameStart = letter <|> specialChar+ nameLetter = alphaNum <|> specialChar+ specialChar = oneOf "_-.+!" -- | Parse a special parameter name. specialName :: Stream s m Char => ParsecT s u m String
src/Language/Bash/Syntax.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveDataTypeable, OverloadedStrings, RecordWildCards, CPP #-}+{-# LANGUAGE DeriveDataTypeable, OverloadedStrings, RecordWildCards, DeriveGeneric #-} -- | Shell script types. module Language.Bash.Syntax (@@ -25,12 +25,11 @@ , RValue(..) ) where -#if __GLASGOW_HASKELL__ >= 710 import Prelude hiding ((<>), Word)-#endif import Data.Data (Data) import Data.Typeable (Typeable)+import GHC.Generics (Generic) import Text.PrettyPrint import Language.Bash.Cond (CondExpr)@@ -43,12 +42,12 @@ indent = nest 4 . pretty -- | Render a @do...done@ block.-doDone :: Pretty a => a -> Doc-doDone a = "do" $+$ indent a $+$ "done"+doDone :: Pretty a => Doc -> a -> Doc+doDone header body = header <+> "do" $+$ indent body $+$ "done" -- | A Bash command with redirections. data Command = Command ShellCommand [Redir]- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty Command where pretty (Command c rs) = pretty c <+> pretty rs@@ -89,7 +88,7 @@ | Until List List -- | A @while@ command. | While List List- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty ShellCommand where pretty (SimpleCommand as ws) = pretty as <+> pretty ws@@ -107,11 +106,11 @@ pretty (Cond e) = "[[" <+> pretty e <+> "]]" pretty (For w ws l) =- "for" <+> pretty w <+> pretty ws <> ";" $+$ doDone l+ doDone ("for" <+> pretty w <+> pretty ws <> ";") l pretty (ArithFor s l) =- "for" <+> "((" <> text s <> "))" $+$ doDone l+ doDone ("for" <+> "((" <> text s <> "))") l pretty (Select w ws l) =- "select" <+> pretty w <+> pretty ws <> ";" $+$ doDone l+ doDone ("select" <+> pretty w <+> pretty ws <> ";") l pretty (Case w cs) = "case" <+> pretty w <+> "in" $+$ (vcat $ map indent cs) $+$ "esac" pretty (If p t f) =@@ -119,15 +118,15 @@ pretty (fmap (\l -> "else" $+$ indent l) f) $+$ "fi" pretty (Until p l) =- "until" <+> pretty p <+> doDone l+ doDone ("until" <+> pretty p) l pretty (While p l) =- "while" <+> pretty p <+> doDone l+ doDone ("while" <+> pretty p) l -- | A word list or @\"$\@\"@. data WordList = Args | WordList [Word]- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty WordList where pretty Args = empty@@ -135,7 +134,7 @@ -- | A single case clause. data CaseClause = CaseClause [Word] List CaseTerm- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty CaseClause where pretty (CaseClause ps l term) =@@ -148,7 +147,7 @@ = Break -- ^ @;;@ | FallThrough -- ^ @;&@ | Continue -- ^ @;;&@- deriving (Data, Eq, Ord, Read, Show, Typeable, Bounded, Enum)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Bounded, Enum, Generic) instance Operator CaseTerm where operatorTable = zip [minBound .. maxBound] [";;", ";&", ";;&"]@@ -180,7 +179,7 @@ -- and command substitutions take place. , hereDocument :: Word }- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty Redir where pretty Redir{..} =@@ -203,7 +202,7 @@ = IONumber Int -- | A variable @{/varname/}@ to allocate a file descriptor for. | IOVar String- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty IODesc where pretty (IONumber n) = int n@@ -221,7 +220,7 @@ | InAnd -- ^ @\<&@ | OutAnd -- ^ @\>&@ | InOut -- ^ @\<\>@- deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded, Generic) instance Operator RedirOp where operatorTable = zip [minBound .. maxBound]@@ -234,7 +233,7 @@ data HeredocOp = Here -- ^ @\<\<@ | HereStrip -- ^ @\<\<-@- deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded, Generic) instance Operator HeredocOp where operatorTable = zip [Here, HereStrip] ["<<", "<<-"]@@ -244,14 +243,14 @@ -- | A compound list of statements. newtype List = List [Statement]- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty List where pretty (List as) = pretty as -- | A single statement in a list. data Statement = Statement AndOr ListTerm- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty Statement where pretty (Statement l Sequential) = pretty l <> ";"@@ -266,7 +265,7 @@ data ListTerm = Sequential -- ^ @;@ | Asynchronous -- ^ @&@- deriving (Data, Eq, Ord, Read, Show, Typeable, Bounded, Enum)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Bounded, Enum, Generic) instance Operator ListTerm where operatorTable =@@ -286,7 +285,7 @@ | And Pipeline AndOr -- | A @||@ construct. | Or Pipeline AndOr- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty AndOr where pretty (Last p) = pretty p@@ -305,7 +304,7 @@ -- @command1 |& command2@ is treated as a shorthand for -- @command1 2>&1 | command2@. , commands :: [Command]- } deriving (Data, Eq, Read, Show, Typeable)+ } deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty Pipeline where pretty Pipeline{..} =@@ -316,7 +315,7 @@ -- | An assignment. data Assign = Assign Parameter AssignOp RValue- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty Assign where pretty (Assign lhs op rhs) = pretty lhs <> pretty op <> pretty rhs@@ -325,7 +324,7 @@ data AssignOp = Equals -- ^ @=@ | PlusEquals -- ^ @+=@- deriving (Data, Eq, Ord, Read, Show, Typeable, Bounded, Enum)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Bounded, Enum, Generic) instance Operator AssignOp where operatorTable = zip [Equals, PlusEquals] ["=", "+="]@@ -339,7 +338,7 @@ = RValue Word -- | An array assignment, as @(subscript, word)@ pairs. | RArray [(Maybe Word, Word)]- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty RValue where pretty (RValue w) = pretty w
src/Language/Bash/Word.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE DeriveDataTypeable- , CPP+ , DeriveGeneric , OverloadedStrings , RecordWildCards , TypeSynonymInstances@@ -21,15 +21,15 @@ , ProcessSubstOp(..) -- * Manipulation , stringToWord+ , wordToString , unquote ) where -#if __GLASGOW_HASKELL__ >= 710 import Prelude hiding ((<>), Word)-#endif import Data.Data (Data) import Data.Typeable (Typeable)+import GHC.Generics (Generic) import Text.PrettyPrint import Language.Bash.Operator@@ -63,7 +63,7 @@ | CommandSubst String -- | A process substitution. | ProcessSubst ProcessSubstOp String- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty Span where pretty (Char c) = char c@@ -82,7 +82,7 @@ -- | A parameter name an optional subscript. data Parameter = Parameter String (Maybe Word)- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) instance Pretty Parameter where pretty (Parameter s sub) = text s <> subscript sub@@ -161,7 +161,7 @@ , convertAll :: Bool , pattern :: Word }- deriving (Data, Eq, Read, Show, Typeable)+ deriving (Data, Eq, Read, Show, Typeable, Generic) prettyParameter :: Bool -> Parameter -> Doc -> Doc prettyParameter bang param suffix =@@ -204,7 +204,7 @@ | AltAssign -- ^ '=', ':=' | AltError -- ^ '?', ':?' | AltReplace -- ^ '+', ':+'- deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded, Generic) instance Operator AltOp where operatorTable = zip [minBound .. maxBound] ["-", "=", "?", "+"]@@ -216,7 +216,7 @@ data LetterCaseOp = ToLower | ToUpper- deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded, Generic) instance Operator LetterCaseOp where operatorTable = zip [ToLower, ToUpper] [",", "^"]@@ -228,7 +228,7 @@ data Direction = Front | Back- deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded, Generic) instance Pretty Direction where pretty Front = "#"@@ -238,7 +238,7 @@ data ProcessSubstOp = ProcessIn -- ^ @\<@ | ProcessOut -- ^ @\>@- deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded)+ deriving (Data, Eq, Ord, Read, Show, Typeable, Enum, Bounded, Generic) instance Operator ProcessSubstOp where operatorTable = zip [ProcessIn, ProcessOut] ["<", ">"]@@ -249,6 +249,14 @@ -- | Convert a string to an unquoted word. stringToWord :: String -> Word stringToWord = map Char++-- | If a word is a plain, unquoted string (e.g. the result of @stringToWord@),+-- returns @Just@ that string; otherwise, returns @Nothing@.+wordToString :: Word -> Maybe String+wordToString = traverse spanToChar+ where+ spanToChar (Char c) = Just c+ spanToChar _ = Nothing -- | Remove all quoting characters from a word. unquote :: Word -> String
tests/Tests.hs view
@@ -64,16 +64,16 @@ Left err -> assertFailure $ "parseError: " ++ show err Right ans -> expected @=? ans +wrapCommands :: [Command] -> List+wrapCommands = List . map (\c -> Statement (Last Pipeline {timed = False, timedPosix = False, inverted = False, commands = [c]}) Sequential)+ wrapCommand :: Command -> List-wrapCommand c = List [Statement (Last Pipeline {timed = False, timedPosix = False, inverted = False, commands = [c]}) Sequential]+wrapCommand c = wrapCommands [c] -tp :: TestName -> Command -> TestTree-tp source expected = testMatches (filter ((/=) '\n') source)+tp :: TestName -> List -> TestTree+tp source expected = testMatches (show source) (Parse.parse "source" source)- (wrapCommand expected)--expandString :: String -> [Span]-expandString = map Char+ expected unittests :: TestTree unittests = testGroup "Unit tests"@@ -81,35 +81,69 @@ testMatches "testTest" (Cond.parseTestExpr ["!", "-e", "\"asd\""]) (Cond.Not (Cond.Unary Cond.FileExists "\"asd\""))- , tp "\"$(ls)\""+ , tp "\"$(ls)\"" $ wrapCommand (Command (SimpleCommand [] [[Double [CommandSubst "ls"]]]) [])- , tp "arguments=()"+ , tp "arguments=()" $ wrapCommand (Command (SimpleCommand [Assign (Parameter "arguments" Nothing) Equals (RArray [])] []) [])- , tp "cat <<EOF\nasd\\`\nEOF"+ , tp "cat <<EOF\nasd\\`\nEOF" $ wrapCommand (Command- (SimpleCommand [] [expandString "cat"])+ (SimpleCommand [] [stringToWord "cat"]) [Heredoc {heredocOp = Here, heredocDelim = "EOF", heredocDelimQuoted = False, hereDocument = [Char 'a',Char 's',Char 'd',Escape '`', Char '\n']}])- , tp "cat <<\"EOF\"\nasd\\`\nEOF"+ , tp "cat <<\"EOF\"\nasd\\`\nEOF" $ wrapCommand (Command- (SimpleCommand [] [expandString "cat"])+ (SimpleCommand [] [stringToWord "cat"]) [Heredoc {heredocOp = Here, heredocDelim = "EOF", heredocDelimQuoted = True,- hereDocument = expandString "asd\\`\n"}])- , tp "echo $((2 + 2))"+ hereDocument = stringToWord "asd\\`\n"}])+ , tp "echo $((2 + 2))" $ wrapCommand (Command- (SimpleCommand [] [expandString "echo", [ArithSubst "2 + 2"]])+ (SimpleCommand [] [stringToWord "echo", [ArithSubst "2 + 2"]]) [])- , tp "((2 + 2))"+ , tp "((2 + 2))" $ wrapCommand (Command (Arith "2 + 2") [])- , tp "echo $(((2 + 2)))"+ , tp "echo $(((2 + 2)))" $ wrapCommand (Command- (SimpleCommand [] [expandString "echo", [ArithSubst "(2 + 2)"]])+ (SimpleCommand [] [stringToWord "echo", [ArithSubst "(2 + 2)"]]) [])+ , tp "function foo() { true; }" $ wrapCommand+ (Command+ (FunctionDef "foo"+ (wrapCommand (Command (SimpleCommand [] [stringToWord "true"]) []))) [])+ , tp "!awesome-function-name-2.0+() { true; }" $ wrapCommand+ (Command+ (FunctionDef "!awesome-function-name-2.0+"+ (wrapCommand (Command (SimpleCommand [] [stringToWord "true"]) []))) [])+ , tp "cat <<EOF\nasd\nEOF\ntrue" $ wrapCommands+ [Command+ (SimpleCommand [] [stringToWord "cat"])+ [Heredoc {heredocOp = Here,+ heredocDelim = "EOF",+ heredocDelimQuoted = False,+ hereDocument = stringToWord "asd\n"}],+ Command (SimpleCommand [] [stringToWord "true"]) []]+ , tp "true\r\nfalse" $ wrapCommands+ [Command (SimpleCommand [] [stringToWord "true"]) [],+ Command (SimpleCommand [] [stringToWord "false"]) []]+ , tp "[[ ! ( -f foo ) ]]" $ wrapCommand+ (Command (Cond (Cond.Not (Cond.Unary Cond.RegularFile (stringToWord "foo")))) [])+ , tp "[[ foo =~ a( b )c\" d\\\"\"[e]*' f '\\ g ]]" $ wrapCommand+ (Command (Cond (Cond.Binary (stringToWord "foo") Cond.StrMatch (stringToWord "a( b )c\" d\\\"\"[e]*' f '\\ g"))) [])+ , tp "for function in foo; do true; done" $ wrapCommand+ (Command+ (For "function" (WordList [stringToWord "foo"])+ (wrapCommand (Command (SimpleCommand [] [stringToWord "true"]) []))) [])+ , tp "<<EOF\ncomment\nEOF" $ wrapCommand+ (Command+ (SimpleCommand [] [])+ [Heredoc {heredocOp = Here,+ heredocDelim = "EOF",+ heredocDelimQuoted = False,+ hereDocument = stringToWord "comment\n"}]) ] failingtests :: TestTree