packages feed

bash 0.1.7 → 0.1.8

raw patch · 7 files changed

+162/−52 lines, 7 filessetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Language.Bash: ArrayAssign :: Identifier -> [Expression t] -> Statement t
- Language.Bash: ArrayDecl :: Identifier -> [Expression t] -> Statement t
- Language.Bash: DictAssign :: Identifier -> [(Expression t, Expression t)] -> Statement t
- Language.Bash: DictDecl :: Identifier -> [(Identifier, Expression t)] -> Statement t
- Language.Bash: VarAssign :: Identifier -> (Expression t) -> Statement t
- Language.Bash.Syntax: ArrayAssign :: Identifier -> [Expression t] -> Statement t
- Language.Bash.Syntax: ArrayDecl :: Identifier -> [Expression t] -> Statement t
- Language.Bash.Syntax: DictAssign :: Identifier -> [(Expression t, Expression t)] -> Statement t
- Language.Bash.Syntax: DictDecl :: Identifier -> [(Identifier, Expression t)] -> Statement t
- Language.Bash.Syntax: VarAssign :: Identifier -> (Expression t) -> Statement t
+ Language.Bash: Array :: Identifier -> [Expression t] -> Assignment t
+ Language.Bash: Assign :: (Assignment t) -> Statement t
+ Language.Bash: Declare :: (Assignment t) -> Statement t
+ Language.Bash: Dict :: Identifier -> [(Expression t, Expression t)] -> Assignment t
+ Language.Bash: ElementsSafe :: Identifier -> Expression t
+ Language.Bash: Fancy :: ByteString -> FuncName
+ Language.Bash: IsSet :: VarName -> Statement t
+ Language.Bash: Local :: (Assignment t) -> Statement t
+ Language.Bash: Simple :: Identifier -> FuncName
+ Language.Bash: Var :: Identifier -> (Expression t) -> Assignment t
+ Language.Bash: data Assignment t
+ Language.Bash: data FuncName
+ Language.Bash: funcName :: ByteString -> Maybe FuncName
+ Language.Bash.Lib: dev_null :: Monoid m => Statement m -> Statement m
+ Language.Bash.PrettyPrinter: braces_ :: ByteString -> ByteString
+ Language.Bash.PrettyPrinter: escapeWords :: ByteString -> ByteString
+ Language.Bash.PrettyPrinter: instance PP FuncName
+ Language.Bash.Syntax: Array :: Identifier -> [Expression t] -> Assignment t
+ Language.Bash.Syntax: Assign :: (Assignment t) -> Statement t
+ Language.Bash.Syntax: Declare :: (Assignment t) -> Statement t
+ Language.Bash.Syntax: Dict :: Identifier -> [(Expression t, Expression t)] -> Assignment t
+ Language.Bash.Syntax: ElementsSafe :: Identifier -> Expression t
+ Language.Bash.Syntax: Fancy :: ByteString -> FuncName
+ Language.Bash.Syntax: IsSet :: VarName -> Statement t
+ Language.Bash.Syntax: Local :: (Assignment t) -> Statement t
+ Language.Bash.Syntax: Simple :: Identifier -> FuncName
+ Language.Bash.Syntax: Var :: Identifier -> (Expression t) -> Assignment t
+ Language.Bash.Syntax: data Assignment t
+ Language.Bash.Syntax: data FuncName
+ Language.Bash.Syntax: funcName :: ByteString -> Maybe FuncName
+ Language.Bash.Syntax: instance Eq FuncName
+ Language.Bash.Syntax: instance Eq t => Eq (Assignment t)
+ Language.Bash.Syntax: instance Foldable Assignment
+ Language.Bash.Syntax: instance Functor Assignment
+ Language.Bash.Syntax: instance IsString FuncName
+ Language.Bash.Syntax: instance Ord FuncName
+ Language.Bash.Syntax: instance Ord t => Ord (Assignment t)
+ Language.Bash.Syntax: instance Show FuncName
+ Language.Bash.Syntax: instance Show t => Show (Assignment t)
- Language.Bash: Function :: Identifier -> (Annotated t) -> Statement t
+ Language.Bash: Function :: FuncName -> (Annotated t) -> Statement t
- Language.Bash.Lib: esed :: Monoid m => Identifier -> Bool -> Annotated m
+ Language.Bash.Lib: esed :: Monoid m => Identifier -> Annotated m
- Language.Bash.Syntax: Function :: Identifier -> (Annotated t) -> Statement t
+ Language.Bash.Syntax: Function :: FuncName -> (Annotated t) -> Statement t

Files

Language/Bash.hs view
@@ -17,8 +17,11 @@   , Language.Bash.Syntax.specialVar   , Language.Bash.Syntax.VarName(..)   , Language.Bash.Syntax.varName+  , Language.Bash.Syntax.FuncName(..)+  , Language.Bash.Syntax.funcName   , Language.Bash.Syntax.Redirection(..)   , Language.Bash.Syntax.FileDescriptor(..)+  , Language.Bash.Syntax.Assignment(..)   , Language.Bash.PrettyPrinter.PP(..)   , Language.Bash.PrettyPrinter.bytes   , Language.Bash.PrettyPrinter.builder
Language/Bash/Lib.hs view
@@ -21,17 +21,15 @@     regular expressions, checking for GNU or BSD @sed@. The 'Bool' argument     determines whether to insert the declaration or not.  -}-esed :: (Monoid m) => Identifier -> Bool -> Annotated m-esed ident d | not d         =  setGNUorBSD-             | otherwise     =  ann_ (Sequence decl setGNUorBSD)+esed :: (Monoid m) => Identifier -> Annotated m+esed ident                   =  setGNUorBSD  where-  [sed, fgrep, decl, setr, setE, checkGNU, setGNUorBSD] = fmap ann_+  [sed, fgrep, setr, setE, checkGNU, setGNUorBSD] = fmap ann_     [ cmd "sed" ["--version"]     , cmd "fgrep" ["-q", "GNU"]-    , ArrayDecl ident []-    , ArrayAssign ident ["sed", "-r"]-    , ArrayAssign ident ["sed", "-E"]-    , Pipe sed fgrep+    , Assign (Array ident ["sed", "-r"])+    , Assign (Array ident ["sed", "-E"])+    , dev_null (Pipe sed fgrep)     , IfThenElse checkGNU setr setE ]  @@ -69,6 +67,16 @@ sudo_write path              =  Redirect (ann_ tee) Out 1 (Left "/dev/null")  where   tee                        =  SimpleCommand "sudo" ["tee", path]+++{-| A statement that allows one to redirect output to a file as root. This is+    what you might expect @sudo echo x > privileged_file@ would do (though+    that does not actually work).+ -}+dev_null                    ::  (Monoid m) => Statement m -> Statement m+dev_null stmt                =  Redirect (ann_ r2)   Out 1 (Left "/dev/null")+ where+  r2                         =  Redirect (ann_ stmt) Out 2 (Left "/dev/null")   {-| Annotate a statement with the 0 value of a monoid.
Language/Bash/PrettyPrinter.hs view
@@ -10,11 +10,13 @@  -} module Language.Bash.PrettyPrinter where +import Control.Applicative import qualified Data.List as List import Data.ByteString.Char8 import Data.Binary.Builder (Builder) import Data.Monoid-import Prelude hiding (concat, length, replicate, lines, drop, null)+import Prelude hiding ( words, unwords, concat, null+                      , replicate, lines, drop, length ) import Control.Monad.State.Strict  import qualified Text.ShellEscape as Esc@@ -41,6 +43,9 @@   pp                        ::  t -> State PPState () instance PP Identifier where   pp (Identifier b)          =  word b+instance PP FuncName where+  pp (Simple ident)          =  pp ident+  pp (Fancy b)               =  word b instance PP SpecialVar where   pp                         =  word . specialVarBytes instance PP FileDescriptor where@@ -51,7 +56,7 @@   pp QuestionMark            =  word "?"   pp Tilde                   =  word "~"   pp (ReadVar var) = (word . quote) (if s == "$!" then "${!}" else s)-   where -- Need to be careful to avoid history expansion of @"@.+   where -- Need to be careful to avoid history expansion.     s                        =  (('$' `cons`) . identpart) var   pp (ReadVarSafe var)       =  (word . quote . braces0 . identpart) var   pp (ReadArray ident expr)  =  (word . quote . braces)@@ -67,6 +72,8 @@   pp (ARGVLength)            =  word "$#"   pp (Elements ident)        =  (word . quote . braces)                                 (bytes ident `append` "[@]")+  pp (ElementsSafe ident)    =  (word . quote . braces_)+                                (bytes ident `append` "[@]")   pp (Keys ident)            =  (word . quote . braces)                                 ('!' `cons` bytes ident `append` "[@]")   pp (Length ident)          =  (word . quote . braces)@@ -89,7 +96,7 @@                                    mapM_ breakline args                                    outdent     NoOp msg | null msg     ->  word ":"-             | otherwise    ->  word ":" >> (word . Esc.bytes . Esc.bash) msg+             | otherwise    ->  word ":" >> (word . escapeWords) msg     Bang t                  ->  hangWord "!" >> binGrp t >> outdent     AndAnd t t'             ->  if isSimple t && (isSimple t' || isAndAnd t')                                 then pp t     >> word "&&" >> nl >> pp t'@@ -104,15 +111,15 @@     Background t t'         ->  binGrp t >> word "&"  >> nl >> pp t'     Group t                 ->  curlyOpen >> pp t     >> curlyClose >> outdent     Subshell t              ->  roundOpen >> pp t     >> roundClose >> outdent-    Function ident t        ->  do wordcat ["function ", bytes ident]+    Function fname t        ->  do wordcat ["function ", bytes fname]                                    inword "{" >> pp t >> outword "}"-    IfThen t t'             ->  do hangWord "if" >> pp t  >> outdent >> nl-                                   inword "then" >> pp t' >> outword "fi"-    IfThenElse t t' t''     ->  do hangWord "if" >> pp t >> outdent >> nl-                                   inword "then"       >> pp t'     >> outdent-                                   nl-                                   inword "else"       >> pp t''-                                   outword "fi"+    IfThen t t'             ->  do hangWord "if"   >> pp t  >> outdent >> nl+                                   inword   "then" >> pp t'+                                   outword  "fi"+    IfThenElse t t' t''     ->  do hangWord "if"   >> pp t  >> outdent >> nl+                                   inword   "then" >> pp t' >> outdent >> nl+                                   inword   "else" >> pp t''+                                   outword  "fi"     For var vals t          ->  do hangWord (concat ["for ", bytes var, " in"])                                    mapM_ breakline vals                                    outdent >> nl@@ -125,25 +132,36 @@     Until t t'              ->  do hangWord "until" >> pp t >> outdent >> nl                                    inword "do" >> pp t' >> outword "done" --  BraceBrace _            ->  error "[[ ]]"-    VarAssign var val       ->  do hang (bytes var `mappend` "=")+    Assign (Var var val)    ->  do hang (bytes var `mappend` "=")                                    pp val >> outdent-    Export var val          ->  do hangcat ["export ", bytes var, "="]+    Assign (Array var exps) ->  do hangcat [bytes var, "=("]+                                   array_pp pp exps >> word ")"+                                   nl >> outdent+    Assign (Dict var pairs) ->  do hangcat [bytes var, "=("]+                                   array_pp keyset pairs+                                   nl >> outdent >> word ")"+    Declare (Var var val)   ->  do hang $ concat ["declare ", bytes var, "="]                                    pp val >> outdent-    ArrayDecl var exprs     ->  do hangcat ["declare -a ", bytes var, "=("]-                                   array_pp pp exprs >> word ")"+    Declare (Array var exps) -> do hangcat ["declare -a ", bytes var, "=("]+                                   array_pp pp exps >> word ")"                                    nl >> outdent-    ArrayUpdate var key val ->  pp (DictUpdate var key val)-    ArrayAssign var exprs   ->  do hangcat [bytes var, "=("]-                                   array_pp pp exprs >> word ")"+    Declare (Dict var pairs) -> do hangcat ["declare -A ", bytes var, "=("]+                                   array_pp keyset pairs >> word ")"                                    nl >> outdent-    DictDecl var pairs      ->  do hangcat ["declare -A ", bytes var, "=("]+    Local (Var var val)     ->  do hang $ concat ["local ", bytes var, "="]+                                   pp val >> outdent+    Local (Array var exps)  ->  do hangcat ["local -a ", bytes var, "=("]+                                   array_pp pp exps >> word ")"+                                   nl >> outdent+    Local (Dict var pairs)  ->  do hangcat ["local -A ", bytes var, "=("]                                    array_pp keyset pairs >> word ")"                                    nl >> outdent+    Export var val          ->  do hangcat ["export ", bytes var, "="]+                                   pp val >> outdent+    IsSet var               ->  wordcat ["[[ ${",identpart var,":+true} ]]"]+    ArrayUpdate var key val ->  pp (DictUpdate var key val)     DictUpdate var key val  ->  wordcat                                 [bytes var, "[", bytes key, "]=", bytes val]-    DictAssign var pairs    ->  do hangcat [bytes var, "=("]-                                   array_pp keyset pairs-                                   nl >> outdent >> word ")"     Redirect stmt d fd t    ->  do redirectGrp stmt                                    word (render_redirect d fd t) @@ -172,6 +190,8 @@  braces0 b                    =  "${" `append` b `append` ":-}" +braces_ b                    =  concat ["${", b, ":+${", b, "}}"]+ brackets b                   =  cons '[' b `snoc` ']'  identpart (VarSpecial special) = (drop 1 . bytes) special@@ -235,4 +255,6 @@   pp ann   word close   outdent >> outdent++escapeWords s = unwords ((Esc.bytes . Esc.bash) <$> words s) 
Language/Bash/Syntax.hs view
@@ -11,7 +11,7 @@  -} module Language.Bash.Syntax where -import Prelude hiding (all)+import Prelude hiding (all, any, elem) import Control.Applicative import Control.Arrow ((***)) import Control.Monad@@ -20,7 +20,7 @@ import Data.Maybe import Data.Word (Word8) import Data.ByteString.Char8-import Data.Foldable hiding (all)+import Data.Foldable hiding (all, any, elem) import Data.Monoid  import qualified Text.ShellEscape as Esc@@ -55,7 +55,7 @@   | Background      (Annotated t)       (Annotated t)   | Group           (Annotated t)   | Subshell        (Annotated t)-  | Function        Identifier          (Annotated t)+  | Function        FuncName            (Annotated t)   | IfThen          (Annotated t)       (Annotated t)   | IfThenElse      (Annotated t)       (Annotated t)       (Annotated t)   | For             Identifier          [Expression t]      (Annotated t)@@ -63,14 +63,13 @@   | While           (Annotated t)       (Annotated t)   | Until           (Annotated t)       (Annotated t) --  BraceBrace      (ConditionalExpression t)-  | VarAssign       Identifier          (Expression t)+  | Assign          (Assignment t)+  | Declare         (Assignment t)+  | Local           (Assignment t)   | Export          Identifier          (Expression t)-  | ArrayDecl       Identifier          [Expression t]+  | IsSet           VarName   | ArrayUpdate     Identifier          (Expression t)      (Expression t)-  | ArrayAssign     Identifier          [Expression t]-  | DictDecl        Identifier          [(Identifier, Expression t)]   | DictUpdate      Identifier          (Expression t)      (Expression t)-  | DictAssign      Identifier          [(Expression t, Expression t)]   | Redirect        (Annotated t)       Redirection                     FileDescriptor      (Either (Expression t) FileDescriptor) deriving instance (Eq t) => Eq (Statement t)@@ -89,7 +88,7 @@     Background ann ann'     ->  Background (f' ann) (f' ann')     Group ann               ->  Group (f' ann)     Subshell ann            ->  Subshell (f' ann)-    Function ident ann      ->  Function ident (f' ann)+    Function fname ann      ->  Function fname (f' ann)     IfThen ann ann'         ->  IfThen (f' ann) (f' ann')     IfThenElse a a' a''     ->  IfThenElse (f' a) (f' a') (f' a'')     For ident args ann      ->  For ident (fmap f' args) (f' ann)@@ -97,14 +96,13 @@     While ann ann'          ->  While (f' ann) (f' ann')     Until ann ann'          ->  Until (f' ann) (f' ann') --  BraceBrace      (ConditionalExpression t)-    VarAssign ident expr    ->  VarAssign ident (f' expr)+    Assign a                ->  Assign (f' a)+    Declare a               ->  Declare (f' a)+    Local a                 ->  Local (f' a)     Export ident expr       ->  Export ident (f' expr)-    ArrayDecl ident assigns ->  ArrayDecl ident (fmap f' assigns)+    IsSet var               ->  IsSet var     ArrayUpdate ident a b   ->  ArrayUpdate ident (f' a) (f' b)-    ArrayAssign ident assigns -> ArrayAssign ident (fmap f' assigns)-    DictDecl ident assigns  ->  DictDecl ident (fmap (id *** f') assigns)     DictUpdate ident a b    ->  DictUpdate ident (f' a) (f' b)-    DictAssign ident assigns -> DictAssign ident (fmap (f' *** f') assigns)     Redirect ann r fd chan  ->  Redirect (f' ann) r fd (fmapExprFD chan)    where     f'                       =  fmap f@@ -131,14 +129,13 @@     While ann ann'          ->  f' ann `mappend` f' ann'     Until ann ann'          ->  f' ann `mappend` f' ann' --  BraceBrace      ConditionalExpression-    VarAssign _ expr        ->  f' expr+    Assign a                ->  f' a+    Declare a               ->  f' a+    Local a                 ->  f' a     Export _ expr           ->  f' expr-    ArrayDecl _ assigns     ->  foldMap f' assigns+    IsSet _                 ->  mempty     ArrayUpdate _ a b       ->  f' a `mappend` f' b-    ArrayAssign _ assigns   ->  foldMap f' assigns-    DictDecl _ assigns      ->  foldMap (f' . snd) assigns     DictUpdate _ a b        ->  f' a `mappend` f' b-    DictAssign _ assigns    ->  foldMap foldMapPair assigns     Redirect ann _ _ chan   ->  f' ann `mappend` foldMapExprFD chan    where     f'                       =  foldMap f@@ -160,6 +157,7 @@                              |  ARGVElements                              |  ARGVLength                              |  Elements Identifier+                             |  ElementsSafe Identifier                              |  Keys Identifier                              |  Length VarName                              |  Trim Trim VarName (Expression t)@@ -189,6 +187,7 @@     ARGVElements            ->  ARGVElements     ARGVLength              ->  ARGVLength     Elements ident          ->  Elements ident+    ElementsSafe ident      ->  Elements ident     Keys ident              ->  Keys ident     Length ident            ->  Length ident     Trim trim v expr        ->  Trim trim v (fmap f expr)@@ -211,6 +210,7 @@     ARGVElements            ->  mempty     ARGVLength              ->  mempty     Elements _              ->  mempty+    ElementsSafe _          ->  mempty     Keys _                  ->  mempty     Length _                ->  mempty     Trim _ _ expr           ->  foldMap f expr@@ -259,6 +259,59 @@   okayTail c                 =  (isAlphaNum c || c == '_') && isAscii c   okayHead c                 =  (isAlpha c || c == '_') && isAscii c +{-| Bash functions can have surprising names. Once the word containing the+    name of the function has been identified by the Bash parser, the only+    constraint as of this writing is that it not be all digits and contain+    neither quotes nor dollar signs. Thus the following are all callable+    functions:++ >  function http://duckduckgo.com { curl -sSfL http://duckduckgo.com?q="$1" ;}+ >  function 123.0 { echo 123.0 ;}+ >  function + { echo "$@" | sed 's/ / + /g' | bc ;}++    Yet a function name may only be parsed if its surroundings constitute a+    valid function declaration. So we are not able to declare these functions:++ >  function par()ens { echo '(' "$@" ')' ;}+ >  function (parens) { echo '(' "$@" ')' ;}++    (The parser thinks the parens are there to separate the function name from+    the function body.)++    Some functions can be declared but not called. For example:++ >  function for { echo for ;}+ >  function x=y { echo x is y ;}++    Calling the former results in a syntax error. A call to the latter is+    parsed as an assignment.++    It is possible to override important builtins with function declarations.+    For example:++ >  function set { echo Haha! ;}+ >  function declare { echo Surprise! ;}++    Overall, Bash function names are quite flexible but inconsistent and+    potentially a cause of grave errors.++ -}+data FuncName                =  Simple Identifier | Fancy ByteString+deriving instance Eq FuncName+deriving instance Ord FuncName+deriving instance Show FuncName+instance IsString FuncName where+  fromString                 =  fromJust . funcName . fromString++{-| Produce a 'FuncName', choosing the 'Simple' constructor if the name is a+    simple identifier.+ -}+funcName                    ::  ByteString -> Maybe FuncName+funcName bytes               =  (Simple <$> identifier bytes)+                            <|> Fancy bytes <$ guard (not invalid)+ where+  invalid = all isDigit bytes || any (`elem` "()$'\"") bytes+ {-| The names of special variables, with otherwise illegal identifiers, are     represented by this type.  -}@@ -382,4 +435,26 @@ deriving instance (Ord t) => Ord (ConditionalExpression t) deriving instance (Show t) => Show (ConditionalExpression t) +data Assignment t+  = Var             Identifier          (Expression t)+  | Array           Identifier          [Expression t]+  | Dict            Identifier          [(Expression t, Expression t)]+deriving instance (Eq t) => Eq (Assignment t)+deriving instance (Ord t) => Ord (Assignment t)+deriving instance (Show t) => Show (Assignment t)+instance Functor Assignment where+  fmap f assign              =  case assign of+    Var ident expr          ->  Var ident (f' expr)+    Array ident assigns     ->  Array ident (fmap f' assigns)+    Dict ident assigns      ->  Dict ident (fmap (f' *** f') assigns)+   where+    f'                       =  fmap f+instance Foldable Assignment where+  foldMap f assign           =  case assign of+    Var _ expr              ->  f' expr+    Array _ assigns         ->  foldMap f' assigns+    Dict _ assigns          ->  foldMap foldMapPair assigns+   where+    f'                       =  foldMap f+    foldMapPair (x, y)       =  f' x `mappend` f' y 
Setup.hs view
@@ -1,2 +1,4 @@ import Distribution.Simple-main = defaultMain++main                         =  defaultMain+
bash.cabal view
@@ -1,5 +1,5 @@ name                          : bash-version                       : 0.1.7+version                       : 0.1.8 category                      : Language license                       : BSD3 license-file                  : LICENSE
tests.bash view
@@ -7,7 +7,7 @@ set -o nounset -o errexit -o pipefail  declare -a esed=()-if sed --version | fgrep -q GNU &>/dev/null+if { sed --version | fgrep -q GNU ;} &>/dev/null then   esed=(sed -r) else