sourcecode:
|
module Check.AST.Indent.IfThenElse where
import Curry.SpanInfo
import Curry.Span
import Curry.Position
import Curry.Types
import Text.Pretty
import Control.Monad ( unless )
import Types
-- Applies actual check only on if-then-else constructs by
-- pattern-matching on the expression.
checkIfThenElse :: Expression a -> Int -> CSM ()
checkIfThenElse e _ =
case e of
(IfThenElse sI expr1 expr2 expr3) -> checkIfThenElse' sI
(getSpanInfo expr1)
(getSpanInfo expr2)
(getSpanInfo expr3)
_ -> return ()
-- Checks for various situations:
-- all in one line
-- if - else in one line, else expression not
-- if - then in one line, else and else expression in another -> twolines
-- if - then in one line, then expression and else in one
-- if and then not in one line, if expression and then in one
-- if then else in different lines, if and then expressions not right in front
-- if then and else
checkIfThenElse' :: SpanInfo -> SpanInfo -> SpanInfo -> SpanInfo -> CSM ()
checkIfThenElse' sI0 sI1 sI2 sI3 = case (sI0, sI1, sI2, sI3) of
(SpanInfo sp [ Span (Position lpi pi) _, Span (Position lpt pt) _, Span (Position lpe pe) _],
SpanInfo (Span _ (Position li _)) _,
SpanInfo (Span _ (Position lt _)) _,
SpanInfo (Span _ (Position le _)) _)
| lpi == le -> return ()
| lpi == lpe -> do report (Message
sp
( text "wrong formatting"
<+> colorizeKey "else expression"
)
( text "do not break"
<+> colorizeKey " else expression"
<+> text "if writing"
<+> colorizeKey "if-then-else"
<+> text "in one line"
))
| lpi == lpt && lt /= lpe -> do checkIfThenElseInTwoLines sp pt pe
checkBreakIndent "then" lpt pt sI2
checkBreakIndent "else" lpe pe sI3
| lt == lpe -> do report (Message
sp
( text "wrong formatting"
<+> colorizeKey "else"
)
( colorizeKey "else"
<+> text " should start in seperate line"
))
| li == lpt -> do report (Message
sp
( text "wrong formatting"
<+> colorizeKey "then"
)
( colorizeKey "then"
<+> text " should start in seperate line"
))
| li /= lpt && lt /= lpe -> do checkIfThenElseInThreeLines sp pi pt pe
checkBreakIndent "if" lpi pi sI1
checkBreakIndent "then" lpt pt sI2
checkBreakIndent "else" lpe pe sI3
_ -> return ()
-- `then` and `else` should alway be aligned.
checkIfThenElseInTwoLines :: Span -> Int -> Int -> CSM ()
checkIfThenElseInTwoLines sp pt pe =
unless (pt == pe) (report (Message
sp
( colorizeKey "then"
<+> text "and"
<+> colorizeKey "else"
<+> text "wrong alignement"
)
( text "align"
<+> colorizeKey "then"
<+> text "and"
<+> colorizeKey "else"
)
)
)
-- See above, but also, if then starts in another line, indent by 2.
checkIfThenElseInThreeLines :: Span -> Int -> Int -> Int -> CSM ()
checkIfThenElseInThreeLines sp pi pt pe =
if pt == pe
then unless (pe-pi == 2) (report (Message
sp
( colorizeKey "then"
<+> text "and"
<+> colorizeKey "else"
<+> text "not properly indented"
)
( text "indent by 2 from"
<+> colorizeKey "if"
)
)
)
else report (Message
sp
( colorizeKey "then"
<+> text "and"
<+> colorizeKey "else"
<+> text "not aligned"
)
( text "align"
<+> colorizeKey "then"
<+> text "and"
<+> colorizeKey "else"
)
)
-- Gets keyname as string, keypositions and the expression to check
-- if the expression is in next line, checks indent.
checkBreakIndent :: String -> Int -> Int -> SpanInfo -> CSM ()
checkBreakIndent s l c sI = do
unless (l == (getLi sI))
(unless ((getCol sI)==(c+2))
(report (Message
(getSpan sI)
( colorizeKey "expression"
<+> text "wrongly indented"
)
( colorizeKey(s ++ " expression")
<+> text "should be indented by 2 from"
<+> colorizeKey s
)
)
)
)
|