bash 0.1.1 → 0.1.2
raw patch · 5 files changed
+139/−50 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Language.Bash.PrettyPrinter.State: Word :: ByteString -> PPOp
+ Language.Bash: VarIdent :: Identifier -> VarName
+ Language.Bash: VarSpecial :: SpecialVar -> VarName
+ Language.Bash: data VarName
+ Language.Bash: varName :: ByteString -> Maybe VarName
+ Language.Bash.PrettyPrinter.State: Bytes :: ByteString -> PPOp
+ Language.Bash.PrettyPrinter.State: WordSeparator :: PPOp
+ Language.Bash.PrettyPrinter.State: hangWord :: ByteString -> State PPState ()
+ Language.Bash.PrettyPrinter.State: separated :: PPState -> Bool
- Language.Bash.PrettyPrinter.State: PPState :: [Word] -> [()] -> [()] -> Word -> Builder -> PPState
+ Language.Bash.PrettyPrinter.State: PPState :: [Word] -> [()] -> [()] -> Word -> Bool -> Builder -> PPState
Files
- Language/Bash.hs +2/−0
- Language/Bash/PrettyPrinter.hs +14/−12
- Language/Bash/PrettyPrinter/State.hs +67/−36
- bash.cabal +1/−1
- tests.bash +55/−1
Language/Bash.hs view
@@ -15,6 +15,8 @@ , Language.Bash.Syntax.identifier , Language.Bash.Syntax.SpecialVar() , Language.Bash.Syntax.specialVar+ , Language.Bash.Syntax.VarName(..)+ , Language.Bash.Syntax.varName , Language.Bash.Syntax.Redirection(..) , Language.Bash.Syntax.FileDescriptor(..) , Language.Bash.PrettyPrinter.PP(..)
Language/Bash/PrettyPrinter.hs view
@@ -89,7 +89,7 @@ outdent NoOp msg | null msg -> word ":" | otherwise -> word ":" >> (word . Esc.bytes . Esc.bash) msg- Bang t -> hang "!" >> binGrp t >> outdent+ Bang t -> hangWord "!" >> binGrp t >> outdent AndAnd t t' -> binGrp t >> word "&&" >> nl >> binGrp t' OrOr t t' -> binGrp t >> word "||" >> nl >> binGrp t' Pipe t t' -> binGrp t >> word "|" >> nl >> binGrp t'@@ -99,26 +99,28 @@ Subshell t -> roundOpen >> pp t >> roundClose >> outdent Function ident t -> do wordcat ["function ", bytes ident] inword " {" >> pp t >> outword "}"- IfThen t t' -> do hang "if" >> pp t >> outdent >> nl+ IfThen t t' -> do hangWord "if" >> pp t >> outdent >> nl inword "then" >> pp t' >> outword "fi"- IfThenElse t t' t'' -> do hang "if" >> pp t >> outdent >> nl+ 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 hang (concat ["for ", bytes var, " in"])+ For var vals t -> do hangWord (concat ["for ", bytes var, " in"]) mapM_ breakline vals outdent >> nl inword "do" >> pp t >> outword "done" Case expr cases -> do word "case" >> pp expr >> inword "in" mapM_ case_clause cases outword "esac"- While t t' -> do hang "while" >> pp t >> outdent >> nl+ While t t' -> do hangWord "while" >> pp t >> outdent >> nl inword "do" >> pp t' >> outword "done"- Until t t' -> do hang "until" >> pp t >> outdent >> nl+ Until t t' -> do hangWord "until" >> pp t >> outdent >> nl inword "do" >> pp t' >> outword "done" -- BraceBrace _ -> error "[[ ]]"- VarAssign var val -> wordcat [bytes var, "=", bytes val]+-- VarAssign var val -> wordcat [bytes var, "=", bytes val]+ VarAssign var val -> do hang (bytes var `mappend` "=")+ pp val >> outdent ArrayDecl var exprs -> do hangcat ["declare -a ", bytes var, "=("] array_pp pp exprs >> word ")" nl >> outdent@@ -137,7 +139,7 @@ Redirect stmt d fd t -> do redirectGrp stmt word (render_redirect d fd t) -hangcat = hang . concat+hangcat = hangWord . concat array_pp _ [ ] = return () array_pp ppF (h:t) = ppF h >> mapM_ ppFNL t@@ -146,7 +148,7 @@ keyset (key, val) = wordcat ["[", bytes key, "]=", bytes val] -case_clause (ptrn, stmt) = do hang (bytes ptrn `append` ") ")+case_clause (ptrn, stmt) = do hangWord (bytes ptrn `append` ") ") pp stmt >> word ";;" >> outdent >> nl render_redirect direction fd target =@@ -170,7 +172,7 @@ trimPrinter :: Trim -> ByteString trimPrinter ShortestLeading = "#" trimPrinter LongestLeading = "##"-trimPrinter ShortestTrailing = "%"+trimPrinter ShortestTrailing = "%" trimPrinter LongestTrailing = "%%" binGrp a@(Annotated _ stmt) = case stmt of@@ -190,7 +192,7 @@ breakline printable = do PPState{..} <- get when (columns + maxLineLength printed + 1 > 79 && columns /= sum indents)- (opM [Word "\\", Newline])+ (opM [Bytes "\\", Newline]) pp printable where printed = bytes printable@@ -209,7 +211,7 @@ inlineEvalPrinter open close ann = do indentPadToNextWord- hang open+ hangWord open pp ann word close outdent >> outdent
Language/Bash/PrettyPrinter/State.hs view
@@ -25,13 +25,15 @@ , curly :: [()] , round :: [()] , columns :: Word+ , separated :: Bool , string :: Builder } instance Show PPState where- show PPState{..} = "PPState { indents=" ++ show indents- ++ " curly=" ++ show curly- ++ " round=" ++ show round- ++ " columns=" ++ show columns- ++ " string=" ++ "..." ++ " }"+ show PPState{..} = "PPState { indents=" ++ show indents+ ++ " curly=" ++ show curly+ ++ " round=" ++ show round+ ++ " columns=" ++ show columns+ ++ " separated=" ++ show separated+ ++ " string=" ++ "..." ++ " }" {-| Produce a builder from a pretty printer state computation. -}@@ -44,15 +46,16 @@ {-| Pretty printer state starting on a new line indented to the given column. -} nlCol :: Word -> PPState-nlCol w = PPState [w] [()] [()] 0 Builder.empty+nlCol w = PPState [w] [()] [()] 0 True Builder.empty {-| Operations we can perform while pretty printing. -} data PPOp = Indent Word -- ^ Indent by N spaces.- | Outdent -- ^ Remove and indentation level.- | Word ByteString -- ^ Add a word to a line.+ | Outdent -- ^ Remove an indentation level.+ | Bytes ByteString -- ^ Add bytes to the script. | Newline -- ^ Move to newline.+ | WordSeparator -- ^ Separate words with space. | Curly Bool -- ^ Introduce a level of braces. | Round Bool -- ^ Introduce a level of parens. @@ -64,29 +67,38 @@ Indent w -> state { indents = w:indents } Outdent -> state { indents = tSafe indents } Curly f | f -> state { indents = 2:indents, curly = ():curly- , string = curly_s, columns = columns+2 }+ , string = curly_s, columns = columns+2+ , separated = True } | otherwise -> state { indents = tSafe indents- , curly = tSafe curly, string = s_curly }+ , curly = tSafe curly, string = s_curly+ , separated = False } Round f | f -> state { indents = 2:indents, round = ():round- , string = round_s, columns = columns+2 }+ , string = round_s, columns = columns+2+ , separated = True } | otherwise -> state { indents = tSafe indents- , round = tSafe round, string = s_round }- Newline | columns == 0 -> state- | otherwise -> state { string = sNL, columns = 0 }- Word b -> state { string = s', columns = c' }+ , round = tSafe round, string = s_round+ , separated = False }+ WordSeparator -> state { separated = False }+ Newline | columns == 0 -> state { separated = True }+ | otherwise -> state { string = sNL, columns = 0+ , separated = True }+ Bytes b -> state { string = s', columns = c' } where- c' = columns + cast (length padded)- s' = string `mappend` Builder.fromByteString padded- dent = cast (sum indents)- padded | columns == 0 = replicate dent ' ' `append` b- | otherwise = ' ' `cons` b+ c' = columns + cast (length padded + length sSep)+ s' = sappend padded+ dent = cast (sum indents) `replicate` ' '+ padded | columns == 0 = dent `mappend` b+ | otherwise = b where+ sappend = mappend string . Builder.fromByteString . mappend sSep tSafe list = if null list then [] else List.tail list- sNL = string `mappend` Builder.fromByteString "\n"- curly_s = Builder.fromByteString "{" `mappend` string- s_curly = string `mappend` Builder.fromByteString " ;}"- round_s = Builder.fromByteString "(" `mappend` string- s_round = string `mappend` Builder.fromByteString " )"+ sNL = sappend "\n"+ curly_s = sappend "{"+ s_curly = sappend ";}"+ round_s = sappend "("+ s_round = sappend ")"+ sSep | not separated = " "+ | otherwise = "" opM :: [PPOp] -> State PPState () opM = mapM_ (modify . flip op)@@ -94,33 +106,52 @@ nl :: State PPState () nl = opM [Newline] hang :: ByteString -> State PPState ()-hang b = opM [Word b, Indent (cast (length b) + 1)]+hang b = opM [Bytes b, Indent (cast (length b))]+hangWord :: ByteString -> State PPState ()+hangWord b = opM [Bytes b, Indent (cast (length b) + 1), WordSeparator] word :: ByteString -> State PPState ()-word b = opM [Word b]+word b = opM [Bytes b, WordSeparator] wordcat :: [ByteString] -> State PPState () wordcat = word . concat outdent :: State PPState () outdent = opM [Outdent] inword :: ByteString -> State PPState ()-inword b = opM [Word b, Indent 2, Newline]+inword b = opM [Bytes b, Indent 2, Newline] outword :: ByteString -> State PPState ()-outword b = opM [Newline, Outdent, Word b]+outword b = opM [Newline, Outdent, Bytes b, WordSeparator] curlyOpen :: State PPState ()-curlyOpen = opM [Curly True]+curlyOpen = opM [Curly True, WordSeparator] curlyClose :: State PPState ()-curlyClose = opM [Curly False]+curlyClose = opM [Curly False, WordSeparator] roundOpen :: State PPState ()-roundOpen = opM [Round True]+roundOpen = opM [Round True, WordSeparator] roundClose :: State PPState ()-roundClose = opM [Round False]+roundClose = opM [Round False, WordSeparator]++{-| This procedure is used in printing statements within evals, to set up+ indentation correctly for lines /following/ the first line. It ensures+ that the second and following lines are printed aligned with the first+ character of the first line of the statement, not the first character of+ the @$(@, @>(@ or @<(@ enclosing the eval.+ -} indentPadToNextWord :: State PPState () indentPadToNextWord = do PPState{..} <- get- let x = sum indents- columns' = columns + 1- indent | columns' > x = columns' - x+ let i = sum indents+ columns' | separated = columns+ | otherwise = columns + 1+ indent | columns' > i = columns' - i | otherwise = 0 opM [Indent indent] cast = fromIntegral++-- Debug renderer.+renderIndents indents = (mconcat . Prelude.reverse)+ (Prelude.map prettify_indent indents)+ where+ prettify_indent 0 = ""+ prettify_indent 1 = "|"+ prettify_indent 2 = "-|"+ prettify_indent n = "-" `mappend` prettify_indent (n-1)
bash.cabal view
@@ -1,5 +1,5 @@ name : bash-version : 0.1.1+version : 0.1.2 category : Language license : BSD3 license-file : LICENSE
tests.bash view
@@ -57,7 +57,7 @@ #> let ls = Annotated () . SimpleCommand "ls" . (:[]) #> let echo = Annotated () . SimpleCommand "echo" #> let vRANDOM = VarIdent "RANDOM"-#> let randomLT_ n = SimpleCommand "[" [ReadVar vRANDOM), "-lt", n, "]"]+#> let randomLT_ n = SimpleCommand "[" [ReadVar vRANDOM, "-lt", n, "]"] #> let randomLT n = Annotated () (randomLT_ n) #> let commented a b = Annotated (Lines a b) @@ -288,4 +288,58 @@ patterns[trailing]=ef echo "${string#"${patterns[leading]}"}" "${string%"${patterns[trailing]}"}" \ "${string#*/}" "${string##*/}" "${string%/*}" "${string%%/*}"++#redirectIn y c = Redirect (ann_ c) In 0 (Left y)+#> let redirectI f stmt = Redirect (Annotated () stmt) In 0 (Left f)+#> let redirectO f stmt = Redirect (Annotated () stmt) Out 1 (Left f)+#> let redirectE f stmt = Redirect (Annotated () stmt) Out 2 (Left f)+#> let clauseSimple ex stmt = (ex, Annotated () stmt)+#> let echo_ = SimpleCommand "echo"+#> let echo__ t = Sequence (Annotated () (echo_ [t])) (Annotated () (echo_ [t]))+#> let c__ = clauseSimple "w" (echo_ ["->w"])+##> let c2 = clauseSimple "x" (echo__ "->x")+#> let c2 = clauseSimple "x" ((Bang . Annotated()) (echo__ "->x"))+##> let c2 = clauseSimple "x" ((redirectI "i") (echo__ "->x"))+#> let cIO = clauseSimple "y" ((redirectO "o" . redirectI "i") (echo_ ["->y"]))+#> let cI_ = clauseSimple "z" (redirectI "i" (echo_ ["->z"]))+#> let read_1 = ReadVarSafe (VarSpecial Dollar1)+#> let caseClauseRedirect = Annotated () (Case read_1 [c__, c2, cI_, cIO])+#> render caseClauseRedirect+case "${1:-}" in+ w) echo $'->w' ;;+ x) ! { echo $'->x'+ echo $'->x' ;} ;;+ z) echo $'->z' 0<i ;;+esac++#> let echo2 = Annotated () ((Bang . Annotated()) (echo__ "->x"))+#> let echoFor = Annotated () $ echo2 `AndAnd` forStmt+#> render echoFor+{ ! { echo $'->x'+ echo $'->x' ;} ;} &&+for x in /var/log/apache2/*.log /var/log/httpd+do+ ls "${x:-}" ||+ echo $'Failed to `ls\':' "${x:-}" 1>&2+done++#> let (var :: Identifier) = "var"+#> let setEVAL = Annotated () (VarAssign var (Eval whileStmt))+#> render setEVAL+var="$( while if $'[' "$RANDOM" -lt 40000 $']' + then+ $'[' "$RANDOM" -lt 10000 $']' + else+ $'[' "$RANDOM" -lt 45000 $']' + fi + do+ echo ok + done )"++#> let (var :: Identifier) = "var"+#> let evalUnquotedEcho = (EvalUnquoted . Annotated ()) (echo__ "text")+#> let setEVALUNQUOTED = Annotated () (VarAssign var evalUnquotedEcho)+#> render setEVALUNQUOTED+var=$( echo text+ echo text )