0 | module Text.Markdown.Parser
6 | import Text.Markdown.Errors
7 | import Text.Markdown.Lexer
8 | import Text.Markdown.Data
10 | import Language.Reflection
11 | import Language.Reflection.Syntax
12 | import Language.Reflection.Syntax.Ops
14 | import public Text.Markdown.Tokens
17 | %language ElabReflection
25 | checkTag : String -> String -> Grammar state MarkdownToken False ()
26 | checkTag x y = if x == y then pure () else fail "tag mismatch"
30 | toListTTImp : List String -> TTImp
31 | toListTTImp [] = var "Nil"
32 | toListTTImp (x :: xs) = var "::" .$ var (fromString x) .$ (toListTTImp xs)
49 | -> Elab (List (Grammar state MarkdownToken True Inline))
50 | toListElab list = check (toListTTImp list)
57 | deletes : Eq a => List a -> List a -> List a
58 | deletes [] list = list
59 | deletes (x :: xs) list = deletes xs (delete x list)
65 | -> (q : Grammar state tok True l)
66 | -> (p : Grammar state tok c a)
67 | -> Grammar state tok True a
68 | quote q contents = q *> contents <* q
76 | listInline : List String
89 | , "textOpeningBracket"
90 | , "textClosingBracket"
91 | , "textOpeningParenthesis"
92 | , "textClosingParenthesis"
103 | blankLine : Grammar state MarkdownToken True ()
104 | blankLine = const () <$> match BlankLine
113 | blockTerminal : Grammar state MarkdownToken False ()
114 | blockTerminal = blankLine <|> eof
117 | closer : String -> Grammar state MarkdownToken True ()
119 | closeTag <- match HtmlCloseTag
120 | checkTag closeTag tag
123 | closeTag : Grammar state MarkdownToken True Inline
124 | closeTag = Text <$> match HtmlCloseTag
127 | codeBlock : Grammar state MarkdownToken True Block
128 | codeBlock = uncurry CodeBlock <$> match MdCodeBlock
131 | horizontalRules : Grammar state MarkdownToken True Block
132 | horizontalRules = const HorizontalRules <$> match MdHorizontalRules
135 | newline : Grammar state MarkdownToken True Inline
138 | const (Text "\n") <$> match MdNewLine
141 | pre : Grammar state MarkdownToken True Inline
142 | pre = Pre <$> match MdPre
145 | text : Grammar state MarkdownToken True Inline
146 | text = Text <$> match MdText
149 | textBoldSym : Grammar state MarkdownToken True Inline
150 | textBoldSym = Text <$> match BoldSym
153 | textImageStart : Grammar state MarkdownToken True Inline
154 | textImageStart = Text <$> match ImageStart
157 | textItalicsSym : Grammar state MarkdownToken True Inline
158 | textItalicsSym = Text <$> match ItalicsSym
161 | textClosingBracket : Grammar state MarkdownToken True Inline
162 | textClosingBracket = Text <$> match ClosingBracket
165 | textClosingParenthesis : Grammar state MarkdownToken True Inline
166 | textClosingParenthesis = Text <$> match ClosingParenthesis
169 | textOpeningBracket : Grammar state MarkdownToken True Inline
170 | textOpeningBracket = Text <$> match OpeningBracket
173 | textOpeningParenthesis : Grammar state MarkdownToken True Inline
174 | textOpeningParenthesis = Text <$> match OpeningParenthesis
177 | textUListSym : Grammar state MarkdownToken True Inline
178 | textUListSym = Text <$> match UListSym
181 | textUListSepSym : Grammar state MarkdownToken True Inline
182 | textUListSepSym = Text <$> match UListSepSym
186 | markdown : Grammar state MarkdownToken False Markdown
188 | els <- many $
choice
189 | [ Just <$> horizontalRules
190 | , const Nothing <$> blankLine
191 | , Just <$> codeBlock
194 | , Just <$> paragraph
196 | pure $
Doc $
mapMaybe id els
199 | inline : Grammar state MarkdownToken True Inline
200 | inline = choice (%runElab toListElab listInline)
203 | header : Grammar state MarkdownToken True Block
205 | level <- match HeadingSym
207 | contents <- someTill blockTerminal inline
208 | pure $
Header level $
toList contents
211 | uList : Grammar state MarkdownToken True Block
215 | choice $
%runElab toListElab $
delete "textUListSepSym" listInline
218 | _ <- match UListSym
219 | items <- sepBy1 (match UListSepSym) (some uListInline)
220 | pure $
UList $
toList $
map toList items
223 | paragraph : Grammar state MarkdownToken True Block
225 | contents <- some inline
226 | pure $
Paragraph $
toList contents
236 | List (Grammar state MarkdownToken True Inline)
237 | -> Grammar state MarkdownToken True Inline
238 | boldGen inlineBold =
239 | Bold . toList <$> (quote (match BoldSym) $
some $
choice inlineBold)
242 | listInlineBold : List String
243 | listInlineBold = deletes
250 | ("linkNoBold" :: "italicsNoLinkNoBold" :: listInline)
257 | bold : Grammar state MarkdownToken True Inline
258 | bold = boldGen $
%runElab toListElab $
listInlineBold
264 | boldNoItalic : Grammar state MarkdownToken True Inline
265 | boldNoItalic = boldGen
266 | $
%runElab toListElab
267 | $
delete "textItalicsSym" ("boldNoLinkNoItalic" :: listInlineBold)
273 | boldNoLinkNoItalic : Grammar state MarkdownToken True Inline
274 | boldNoLinkNoItalic = boldGen $
%runElab toListElab $
deletes
288 | List (Grammar state MarkdownToken True Inline)
289 | -> Grammar state MarkdownToken True Inline
290 | italicsGen inlineItalic =
291 | Italics . toList <$> (quote (match ItalicsSym) $
some $
choice inlineItalic)
294 | listInlineItalics : List String
295 | listInlineItalics = deletes
301 | ("linkNoItalic" :: listInline)
308 | italics : Grammar state MarkdownToken True Inline
309 | italics = italicsGen $
%runElab toListElab listInlineItalics
313 | italicsNoBold : Grammar state MarkdownToken True Inline
314 | italicsNoBold = italicsGen $
%runElab toListElab $
deletes
324 | italicsNoLinkNoBold : Grammar state MarkdownToken True Inline
325 | italicsNoLinkNoBold = italicsGen $
%runElab toListElab $
deletes
333 | image : Grammar state MarkdownToken True Inline
336 | altText = choice $
%runElab toListElab $
deletes
344 | , "textClosingBracket"
345 | , "textUListSepSym"
349 | srcText = choice $
%runElab toListElab $
deletes
357 | , "textClosingParenthesis"
358 | , "textUListSepSym"
363 | _ <- match ImageStart
364 | alt <- some altText
365 | _ <- match ClosingBracket
366 | _ <- optional (match MdNewLine)
367 | _ <- match OpeningParenthesis
368 | src <- some srcText
369 | _ <- match ClosingParenthesis
371 | Image (concatInlineVals $
toList alt) (concatInlineVals $
toList src)
379 | List (Grammar state MarkdownToken True Inline)
380 | -> Grammar state MarkdownToken True Inline
383 | descText = choice desc
384 | hrefText = choice $
%runElab toListElab $
deletes
392 | , "textClosingParenthesis"
393 | , "textUListSepSym"
398 | _ <- match OpeningBracket
399 | desc <- some descText
400 | _ <- match ClosingBracket
401 | _ <- optional (match MdNewLine)
402 | _ <- match OpeningParenthesis
403 | href <- some hrefText
404 | _ <- match ClosingParenthesis
405 | pure $
Link (toList desc) (concatInlineVals $
toList href)
409 | listInlineLink : List String
410 | listInlineLink = deletes
416 | , "textClosingBracket"
417 | , "textUListSepSym"
422 | link : Grammar state MarkdownToken True Inline
423 | link = linkGen $
%runElab toListElab listInlineLink
430 | linkNoBold : Grammar state MarkdownToken True Inline
431 | linkNoBold = linkGen $
%runElab toListElab $
deletes
439 | ("italicsNoLinkNoBold" :: listInlineLink)
447 | linkNoItalic : Grammar state MarkdownToken True Inline
448 | linkNoItalic = linkGen $
%runElab toListElab $
deletes
456 | ("boldNoLinkNoItalic" :: listInlineLink)
459 | html : Grammar state MarkdownToken True Inline
462 | htmlInline = choice $
%runElab toListElab $
deletes
473 | openTag <- match HtmlOpenTag
474 | contents <- many htmlInline
475 | _ <- optional $
closer openTag
476 | pure $
Html openTag contents
486 | parseMarkdown : List (WithBounds MarkdownToken) -> Either MdError Markdown
487 | parseMarkdown toks =
488 | case parse markdown toks of
489 | Right (result, []) => Right (normalise result)
490 | Right (_, ts@(x :: xs)) => Left $
MkMdError
494 | "cannot parse: \{show $ map val ts}"
497 | Left (e ::: _) => Left $
fromParsingError e