git.iko.soy/typeable/pandoc
on master help sign in
Simplified parsing of reference keys and notes in markdown and RST

readers: + The Reference data structure from Text.Pandoc.Shared is no longer needed, since + referenceKey and noteBlock parses return strings (as many blank lines as are occuried by the key or note) and update state themselves. + getPosition and setPosition are now used to ensure that error messages will give the correct line number. + This yields cleaner (and slightly faster) code, with more accurate parsing error messages. git-svn-id: https://pandoc.googlecode.com/svn/trunk@1012 788f1e2b-df1e-0410-8736-df70ead52e1b

commit4b4060b8ef64da355070ee016235ad3f1d4b1f9f authorfiddlosopher <fiddlosopher@788f1e2b-df1e-0410-8736-df70ead52e1b> dateWed 5 Sep 2007, 23:55 (19 years ago) parentd5e8ab7
3 files changed+54−57
src/Text/Pandoc/Readers/Markdown.hs+30−18 src/Text/Pandoc/Readers/RST.hs+24−15 src/Text/Pandoc/Shared.hs−24
src/Text/Pandoc/Readers/Markdown.hs+30−18
@@ -140,26 +140,24 @@ titleBlock = try $ do
140140parseMarkdown = do
141141 -- markdown allows raw HTML
142142 updateState (\state -> state { stateParseRaw = True })
143− (title, author, date) <- option ([],[],"") titleBlock
143+ startPos <- getPosition
144144 -- go through once just to get list of reference keys
145− refs <- manyTill (referenceKey <|> (lineClump >>= return . LineClump)) eof
146− let keys = map (\(KeyBlock label target) -> (label, target)) $
147− filter isKeyBlock refs
148− -- strip out keys
149− setInput $ concatMap (\(LineClump ln) -> ln) $ filter isLineClump refs
150− updateState (\state -> state { stateKeys = keys })
145+ -- docMinusKeys is the raw document with blanks where the keys were...
146+ docMinusKeys <- many (referenceKey <|> lineClump) >>= return . concat
147+ setInput docMinusKeys
148+ setPosition startPos
151149 st <- getState
150+ -- go through again for notes unless strict...
152151 if stateStrict st
153152 then return ()
154− else do -- go through for notes (which may contain refs - hence 2nd pass)
155− refs' <- manyTill (noteBlock <|>
156− (lineClump >>= return . LineClump)) eof
157− let notes = map (\(NoteBlock label blocks) -> (label, blocks)) $
158− filter isNoteBlock refs'
159− updateState (\state -> state { stateNotes = notes })
160− setInput $ concatMap (\(LineClump ln) -> ln) $
161− filter isLineClump refs'
162− -- go through again, with note blocks and keys stripped out
153+ else do docMinusNotes <- many (noteBlock <|> lineClump) >>= return . concat
154+ st <- getState
155+ let reversedNotes = stateNotes st
156+ updateState $ \st -> st { stateNotes = reverse reversedNotes }
157+ setInput docMinusNotes
158+ setPosition startPos
159+ -- now parse it for real...
160+ (title, author, date) <- option ([],[],"") titleBlock
163161 blocks <- parseBlocks
164162 return $ Pandoc (Meta title author date) $ filter (/= Null) blocks
165163
@@ -168,6 +166,7 @@ parseMarkdown = do
168166--
169167
170168referenceKey = try $ do
169+ startPos <- getPosition
171170 nonindentSpaces
172171 label <- reference
173172 char ':'
@@ -177,7 +176,13 @@ referenceKey = try $ do
177176 optional (char '>')
178177 tit <- option "" referenceTitle
179178 blanklines
180− return $ KeyBlock label (removeTrailingSpace src, tit)
179+ endPos <- getPosition
180+ let newkey = (label, (removeTrailingSpace src, tit))
181+ st <- getState
182+ let oldkeys = stateKeys st
183+ updateState $ \st -> st { stateKeys = newkey : oldkeys }
184+ -- return blanks so line count isn't affected
185+ return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
181186
182187referenceTitle = try $ do
183188 skipSpaces
@@ -201,15 +206,22 @@ rawLine = do
201206rawLines = many1 rawLine >>= return . concat
202207
203208noteBlock = try $ do
209+ startPos <- getPosition
204210 ref <- noteMarker
205211 char ':'
206212 optional blankline
207213 optional indentSpaces
208214 raw <- sepBy rawLines (try (blankline >> indentSpaces))
209215 optional blanklines
216+ endPos <- getPosition
210217 -- parse the extracted text, which may contain various block elements:
211218 contents <- parseFromString parseBlocks $ (joinWithSep "\n" raw) ++ "\n\n"
212− return $ NoteBlock ref contents
219+ let newnote = (ref, contents)
220+ st <- getState
221+ let oldnotes = stateNotes st
222+ updateState $ \st -> st { stateNotes = newnote : oldnotes }
223+ -- return blanks so line count isn't affected
224+ return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
213225
214226--
215227-- parsing blocks
src/Text/Pandoc/Readers/RST.hs+24−15
@@ -83,15 +83,17 @@ titleTransform ((Header 1 head1):rest) = -- title, no subtitle
8383titleTransform blocks = (blocks, [])
8484
8585parseRST = do
86− -- first pass: get keys
87− refs <- manyTill (referenceKey <|> (lineClump >>= return . LineClump)) eof
88− let keys = map (\(KeyBlock label target) -> (label, target)) $
89− filter isKeyBlock refs
90− -- second pass, with keys stripped out
91− let rawlines = map (\(LineClump ln) -> ln) $ filter isLineClump refs
92− setInput $ concat rawlines
93− updateState (\state -> state { stateKeys = keys })
94− blocks <- parseBlocks
86+ startPos <- getPosition
87+ -- go through once just to get list of reference keys
88+ -- docMinusKeys is the raw document with blanks where the keys were...
89+ docMinusKeys <- many (referenceKey <|> lineClump) >>= return . concat
90+ setInput docMinusKeys
91+ setPosition startPos
92+ st <- getState
93+ let reversedKeys = stateKeys st
94+ updateState $ \st -> st { stateKeys = reverse reversedKeys }
95+ -- now parse it for real...
96+ blocks <- parseBlocks
9597 let blocks' = filter (/= Null) blocks
9698 state <- getState
9799 let (blocks'', title) = if stateStandalone state
@@ -429,9 +431,16 @@ unknownDirective = try $ do
429431-- reference key
430432--
431433
432−referenceKey =
433− choice [imageKey, anonymousKey, regularKeyQuoted, regularKey] >>~
434+referenceKey = do
435+ startPos <- getPosition
436+ key <- choice [imageKey, anonymousKey, regularKeyQuoted, regularKey]
437+ st <- getState
438+ let oldkeys = stateKeys st
439+ updateState $ \st -> st { stateKeys = key : oldkeys }
434440 optional blanklines
441+ endPos <- getPosition
442+ -- return enough blanks to replace key
443+ return $ replicate (sourceLine endPos - sourceLine startPos) '\n'
435444
436445targetURI = do
437446 skipSpaces
@@ -447,26 +456,26 @@ imageKey = try $ do
447456 skipSpaces
448457 string "image::"
449458 src <- targetURI
450− return $ KeyBlock (normalizeSpaces ref) (removeLeadingTrailingSpace src, "")
459+ return (normalizeSpaces ref, (removeLeadingTrailingSpace src, ""))
451460
452461anonymousKey = try $ do
453462 oneOfStrings [".. __:", "__"]
454463 src <- targetURI
455464 state <- getState
456− return $ KeyBlock [Str "_"] (removeLeadingTrailingSpace src, "")
465+ return ([Str "_"], (removeLeadingTrailingSpace src, ""))
457466
458467regularKeyQuoted = try $ do
459468 string ".. _`"
460469 ref <- manyTill inline (char '`')
461470 char ':'
462471 src <- targetURI
463− return $ KeyBlock (normalizeSpaces ref) (removeLeadingTrailingSpace src, "")
472+ return (normalizeSpaces ref, (removeLeadingTrailingSpace src, ""))
464473
465474regularKey = try $ do
466475 string ".. _"
467476 ref <- manyTill inline (char ':')
468477 src <- targetURI
469− return $ KeyBlock (normalizeSpaces ref) (removeLeadingTrailingSpace src, "")
478+ return (normalizeSpaces ref, (removeLeadingTrailingSpace src, ""))
470479
471480 --
472481 -- inline
src/Text/Pandoc/Shared.hs−24
@@ -72,10 +72,6 @@ module Text.Pandoc.Shared (
7272 testStringWith,
7373 ParserState (..),
7474 defaultParserState,
75− Reference (..),
76− isNoteBlock,
77− isKeyBlock,
78− isLineClump,
7975 HeaderType (..),
8076 ParserContext (..),
8177 QuoteContext (..),
@@ -543,26 +539,6 @@ defaultParserState =
543539 stateColumns = 80,
544540 stateHeaderTable = [] }
545541
546−-- | References from preliminary parsing.
547−data Reference
548− = KeyBlock [Inline] Target -- ^ Key for reference-style link (label URL title)
549− | NoteBlock String [Block] -- ^ Footnote reference and contents
550− | LineClump String -- ^ Raw clump of lines with blanks at end
551− deriving (Eq, Read, Show)
552−
553−-- | Auxiliary functions used in preliminary parsing.
554−isNoteBlock :: Reference -> Bool
555−isNoteBlock (NoteBlock _ _) = True
556−isNoteBlock _ = False
557−
558−isKeyBlock :: Reference -> Bool
559−isKeyBlock (KeyBlock _ _) = True
560−isKeyBlock _ = False
561−
562−isLineClump :: Reference -> Bool
563−isLineClump (LineClump _) = True
564−isLineClump _ = False
565−
566542data HeaderType
567543 = SingleHeader Char -- ^ Single line of characters underneath
568544 | DoubleHeader Char -- ^ Lines of characters above and below