never executed always true always false
1 module Parse.Whitespace where
2
3 import AST.V0_16
4 import qualified Cheapskate.Types as Markdown
5 import qualified Data.Char as Char
6 import Parse.IParser
7 import qualified Parse.Markdown as Markdown
8 import qualified Parse.State as State
9 import qualified Reporting.Error.Syntax as Syntax
10 import Text.Parsec hiding (newline, spaces, State)
11
12
13 padded :: IParser a -> IParser (C2 before after a)
14 padded p =
15 do pre <- whitespace
16 out <- p
17 post <- whitespace
18 return $ C (pre, post) out
19
20
21 spaces :: IParser Comments
22 spaces =
23 let
24 blank = string " " >> return []
25 comment = ((: []) <$> multiComment)
26 space =
27 blank
28 <|> (const [CommentTrickOpener] <$> (try $ string "{--}"))
29 <|> comment
30 <?> Syntax.whitespace
31 in
32 concat <$> many1 space
33
34
35 forcedWS :: IParser Comments
36 forcedWS =
37 choice
38 [ (++) <$> spaces <*> (concat <$> many nl_space)
39 , concat <$> many1 nl_space
40 ]
41 where
42 nl_space =
43 try ((++) <$> (concat <$> many1 newline) <*> option [] spaces)
44
45
46 -- Just eats whitespace until the next meaningful character.
47 dumbWhitespace :: IParser Comments
48 dumbWhitespace =
49 concat <$> many (spaces <|> newline)
50
51
52 whitespace' :: IParser (Bool, Comments)
53 whitespace' =
54 option (False, []) ((,) True <$> forcedWS)
55
56
57 whitespace :: IParser Comments
58 whitespace =
59 snd <$> whitespace'
60
61
62 freshLine :: IParser Comments
63 freshLine =
64 concat <$> (try ((++) <$> many1 newline <*> many space_nl) <|> try (many1 space_nl)) <?> Syntax.freshLine
65 where
66 space_nl = try $ (++) <$> spaces <*> (concat <$> many1 newline)
67
68
69 newline :: IParser Comments
70 newline =
71 (simpleNewline >> return []) <|> ((\x -> [x]) <$> lineComment) <?> Syntax.newline
72
73
74 simpleNewline :: IParser ()
75 simpleNewline =
76 do _ <- try (string "\r\n") <|> string "\n"
77 updateState State.setNewline
78 return ()
79
80
81 trackNewline :: IParser a -> IParser (a, Multiline)
82 trackNewline parser =
83 do
84 updateState State.pushNewlineContext
85 a <- parser
86 state <- getState
87 updateState State.popNewlineContext
88 return (a, if State.sawNewline state then SplitAll else JoinAll)
89
90
91 lineComment :: IParser Comment
92 lineComment =
93 do _ <- try (string "--")
94 choice
95 [ const CommentTrickCloser
96 <$> try (char '}' >> many (char ' ') >> (simpleNewline <|> eof))
97 , do
98 (comment, ()) <-
99 anyUntil $ simpleNewline <|> eof
100 return $ LineComment comment
101 ]
102
103
104 restOfLine :: IParser (Maybe String)
105 restOfLine =
106 many (char ' ') *>
107 choice
108 [ Just . fst <$> (try (string "--") *> (anyUntil $ (lookAhead simpleNewline) <|> eof))
109 , return Nothing
110 ]
111
112
113 docComment :: IParser String
114 docComment =
115 do _ <- try (string "{-|")
116 _ <- many (string " ")
117 closeComment False
118
119
120 docCommentAsMarkdown :: IParser Markdown.Blocks
121 docCommentAsMarkdown =
122 Markdown.parse <$> docComment
123
124
125 multiComment :: IParser Comment
126 multiComment =
127 do _ <- try (string "{-" <* notFollowedBy (string "|") )
128 isCommentTrick <-
129 choice
130 [ char '-' >> return True
131 , return False
132 ]
133 _ <- many (string " ")
134 b <- closeComment False
135 return $
136 if isCommentTrick then
137 CommentTrickBlock b
138 else
139 BlockComment $ trimIndent $ lines b
140 where
141 trimIndent [] = []
142 trimIndent (l1:ls) =
143 let
144 leadingIndents =
145 map fst $ filter (uncurry (/=))
146 $ map (\l -> (length $ takeWhile Char.isSpace l, length l)) ls
147
148 depth =
149 case leadingIndents of
150 [] -> 0
151 _ -> minimum leadingIndents
152 in
153 l1 : map (drop depth) ls
154
155
156 closeComment :: Bool -> IParser String
157 closeComment keepClosingPunc =
158 uncurry (++) <$>
159 anyUntil
160 (choice
161 [ try ((\a b -> if keepClosingPunc then concat (a ++ [b]) else "") <$> many (string " ") <*> string "-}") <?> "the end of a comment -}"
162 , concat <$> sequence [ try (string "{-"), closeComment True, closeComment keepClosingPunc]
163 ])
164
165
166 anyUntil :: IParser a -> IParser (String, a)
167 anyUntil end =
168 go ""
169 where
170 next pre =
171 do
172 nextChar <- anyChar
173 go (nextChar : pre)
174
175 go pre =
176 ((,) (reverse pre) <$> end) <|> next pre