ogmarkup 3.0.1 → 3.1.0
raw patch · 3 files changed
+47/−42 lines, 3 filesdep ~megaparsec
Dependency ranges changed: megaparsec
Files
- ogmarkup.cabal +2/−2
- src/Text/Ogmarkup.hs +4/−3
- src/Text/Ogmarkup/Private/Parser.hs +41/−37
ogmarkup.cabal view
@@ -1,5 +1,5 @@ name: ogmarkup-version: 3.0.1+version: 3.1.0 cabal-version: >=1.10 build-type: Simple license: MIT@@ -31,7 +31,7 @@ Text.Ogmarkup.Private.Config build-depends: base >=4.7 && <5,- megaparsec -any,+ megaparsec >=6 && <7, mtl -any default-language: Haskell2010 hs-source-dirs: src
src/Text/Ogmarkup.hs view
@@ -11,9 +11,10 @@ stability. Be aware the exposed interface may change in future realase. -} -{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-} module Text.Ogmarkup (@@ -48,7 +49,7 @@ -- | From a String, parse and generate an output according to a generation configuration. -- The inner definitions of the parser and the generator imply that the output -- type has to be an instance of the 'IsString' and 'Monoid' classes.-ogmarkup :: (Stream a, Token a ~ Char, IsString a, Eq a, Monoid a, IsString b, Monoid b, Conf.GenConf c b)+ogmarkup :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString a, Eq a, Monoid a, IsString b, Monoid b, Conf.GenConf c b) => a -- ^ The input string -> c -- ^ The generator configuration -> b
src/Text/Ogmarkup/Private/Parser.hs view
@@ -11,13 +11,17 @@ module. -} -{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleContexts #-} module Text.Ogmarkup.Private.Parser where import Text.Megaparsec+import Text.Megaparsec.Char import Control.Monad.State import Data.String+import Data.Void (Void) import qualified Text.Ogmarkup.Private.Ast as Ast @@ -32,7 +36,7 @@ } -- | An ogmarkup parser processes 'Char' tokens and carries a 'ParserState'.-type OgmarkupParser a = StateT ParserState (Parsec Dec a)+type OgmarkupParser a = StateT ParserState (Parsec Void a) -- | Update the 'ParserState' to guard against nested emphasis. enterEmph :: Stream a@@ -98,21 +102,21 @@ -- | A wrapper around the 'runParser' function of Megaparsec. It uses -- 'initParserState' as an initial state.-parse :: (Stream a, Token a ~ Char)+parse :: (Stream a, Token a ~ Char, IsString (Tokens a)) => OgmarkupParser a b -> String -> a- -> Either (ParseError (Token a) Dec) b+ -> Either (ParseError (Token a) Void) b parse ogma file = runParser (evalStateT ogma initParserState) file -- | Try its best to parse an ogmarkup document. When it encounters an -- error, it returns an Ast and the remaining input. -- -- See 'Ast.Document'.-document :: (Stream a, Token a ~ Char, IsString b)+document :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Document b) document = doc []- where doc :: (Stream a, Token a ~ Char, IsString b)+ where doc :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => Ast.Document b -> OgmarkupParser a (Ast.Document b) doc ast = do space@@ -120,18 +124,18 @@ let ast' = ast `mappend` sects (eof >> return ast') <|> (recover ast' >>= doc) - recover :: (Stream a, Token a ~ Char, IsString b)+ recover :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => Ast.Document b -> OgmarkupParser a (Ast.Document b) recover ast = do failure <- someTill anyChar (char '\n') return $ ast `mappend` [Ast.Failing $ fromString failure] -- | See 'Ast.Section'.-section :: (Stream a, Token a ~ Char, IsString b)+section :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Section b) section = aside <|> story -- | See 'Ast.Aside'.-aside :: (Stream a, Token a ~ Char, IsString b)+aside :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Section b) aside = do asideSeparator cls <- optional asideClass@@ -143,7 +147,7 @@ return $ Ast.Aside cls ps where- asideClass :: (Stream a, Token a ~ Char, IsString b)+ asideClass :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a b asideClass = do cls <- some letterChar asideSeparator@@ -151,29 +155,29 @@ return $ fromString cls -- | See 'Ast.Story'.-story :: (Stream a, Token a ~ Char, IsString b)+story :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Section b) story = Ast.Story `fmap` some (paragraph <* space) -- | See 'Ast.Paragraph'.-paragraph :: (Stream a, Token a ~ Char, IsString b)+paragraph :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Paragraph b) paragraph = some component <* blank -- | See 'Ast.Component'.-component :: (Stream a, Token a ~ Char, IsString b)+component :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Component b) component = try (dialogue <|> thought <|> teller) <|> illformed -- | See 'Ast.IllFormed'.-illformed :: (Stream a, Token a ~ Char, IsString b)+illformed :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Component b) illformed = Ast.IllFormed `fmap` restOfParagraph -- | Parse the rest of the current paragraph with no regards for the -- ogmarkup syntax. This Parser is used when the document is ill-formed, to -- find a new point of synchronization.-restOfParagraph :: (Stream a, Token a ~ Char, IsString b)+restOfParagraph :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a b restOfParagraph = do lookAhead anyChar notFollowedBy endOfParagraph@@ -181,23 +185,23 @@ return $ fromString str -- | See 'Ast.Teller'.-teller :: (Stream a, Token a ~ Char, IsString b)+teller :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Component b) teller = Ast.Teller `fmap` some format -- | See 'Ast.Dialogue'.-dialogue :: (Stream a, Token a ~ Char, IsString b)+dialogue :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Component b) dialogue = talk '[' ']' Ast.Dialogue -- | See 'Ast.Thought'.-thought :: (Stream a, Token a ~ Char, IsString b)+thought :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Component b) thought = talk '<' '>' Ast.Thought -- | @'talk' c c' constr@ wraps a reply surrounded by @c@ and @c'@ inside -- @constr@ (either 'Ast.Dialogue' or 'Ast.Thought').-talk :: (Stream a, Token a ~ Char, IsString b)+talk :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => Char -- ^ A character to mark the begining of a reply -> Char -- ^ A character to mark the end of a reply -> (Ast.Reply b -> Maybe b -> Ast.Component b) -- ^ Either 'Ast.Dialogue' or 'Ast.Thought' according to the situation@@ -211,7 +215,7 @@ -- | Parse the name of the character which speaks or thinks. According to -- the ogmarkup syntax, it is surrounded by parentheses.-characterName :: (Stream a, Token a ~ Char, IsString b)+characterName :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a b characterName = do char '('@@ -221,7 +225,7 @@ return $ fromString auth -- | 'reply' parses a 'Ast.Reply'.-reply :: (Stream a, Token a ~ Char, IsString b)+reply :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => Char -> Char -> OgmarkupParser a (Ast.Reply b)@@ -241,7 +245,7 @@ _ -> return $ Ast.Simple p1 -- | See 'Ast.Format'.-format :: (Stream a, Token a ~ Char, IsString b)+format :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Format b) format = choice [ raw , emph@@ -250,12 +254,12 @@ ] -- | See 'Ast.Raw'.-raw :: (Stream a, Token a ~ Char, IsString b)+raw :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Format b) raw = Ast.Raw `fmap` some atom -- | See 'Ast.Emph'.-emph :: (Stream a, Token a ~ Char, IsString b)+emph :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Format b) emph = do char '*' blank@@ -266,7 +270,7 @@ return . Ast.Emph $ (f:fs) -- | See 'Ast.StrongEmph'.-strongEmph :: (Stream a, Token a ~ Char, IsString b)+strongEmph :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Format b) strongEmph = do char '+' blank@@ -277,7 +281,7 @@ return . Ast.StrongEmph $ (f:fs) -- | See 'Ast.Quote'.-quote :: (Stream a, Token a ~ Char, IsString b)+quote :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Format b) quote = do openQuote enterQuote@@ -287,19 +291,19 @@ return . Ast.Quote $ (f:fs) -- | See 'Ast.Atom'.-atom :: (Stream a, Token a ~ Char, IsString b)+atom :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Atom b) atom = (word <|> mark <|> longword) <* blank -- | See 'Ast.Word'. This parser does not consume the following spaces, so -- the caller needs to take care of it.-word :: (Stream a, Token a ~ Char, IsString b)+word :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Atom b) word = do notFollowedBy endOfWord str <- manyTill anyChar (lookAhead $ try endOfWord) return $ Ast.Word (fromString str) where- endOfWord :: (Stream a, Token a ~ Char)+ endOfWord :: (Stream a, Token a ~ Char, IsString (Tokens a)) => OgmarkupParser a () endOfWord = eof <|> (skip spaceChar) <|> (skip $ oneOf specChar) specChar = "\"«»`+*[]<>|_\'’.,;-–—!?:"@@ -312,7 +316,7 @@ -- -- Therefore, @`@ can be used to insert normally reserved symbol -- inside a generated document.-longword :: (Stream a, Token a ~ Char, IsString b)+longword :: (Stream a, Token a ~ Char, IsString (Tokens a), IsString b) => OgmarkupParser a (Ast.Atom b) longword = do char '`' notFollowedBy (char '`')@@ -321,7 +325,7 @@ -- | See 'Ast.Punctuation'. Be aware that 'mark' does not parse the quotes -- because they are processed 'quote'.-mark :: (Stream a, Token a ~ Char)+mark :: (Stream a, Token a ~ Char, IsString (Tokens a)) => OgmarkupParser a (Ast.Atom b) mark = Ast.Punctuation `fmap` (semicolon <|> colon@@ -351,14 +355,14 @@ -- | See 'Ast.OpenQuote'. This parser consumes the following blank (see 'blank') -- and skip the result.-openQuote :: (Stream a, Token a ~ Char)+openQuote :: (Stream a, Token a ~ Char, IsString (Tokens a)) => OgmarkupParser a () openQuote = do char '«' <|> char '"' blank -- | See 'Ast.CloseQuote'. This parser consumes the following blank (see 'blank') -- and skip the result.-closeQuote :: (Stream a, Token a ~ Char)+closeQuote :: (Stream a, Token a ~ Char, IsString (Tokens a)) => OgmarkupParser a () closeQuote = do char '»' <|> char '"' blank@@ -366,7 +370,7 @@ -- | An aside section (see 'Ast.Aside') is a particular region -- surrounded by two lines of underscores (at least three). -- This parser consumes one such line.-asideSeparator :: (Stream a, Token a ~ Char)+asideSeparator :: (Stream a, Token a ~ Char, IsString (Tokens a)) => OgmarkupParser a () asideSeparator = do string "__" some (char '_')@@ -374,13 +378,13 @@ -- | The end of a paragraph is the end of the document or two blank lines -- or an aside separator, that is a line of underscores.-endOfParagraph :: (Stream a, Token a ~ Char)+endOfParagraph :: (Stream a, Token a ~ Char, IsString (Tokens a)) => OgmarkupParser a () endOfParagraph = try betweenTwoSections <|> asideSeparator <|> eof where- betweenTwoSections :: (Stream a, Token a ~ Char)+ betweenTwoSections :: (Stream a, Token a ~ Char, IsString (Tokens a)) => OgmarkupParser a () betweenTwoSections = do count 2 $ manyTill spaceChar (eof <|> skip (char '\n')) space@@ -389,7 +393,7 @@ -- | This parser consumes all the white spaces until it finds either an aside -- surrounding marker (see 'Ast.Aside'), the end of the document or -- one blank line. The latter marks the end of the current paragraph.-blank :: (Stream a, Token a ~ Char)+blank :: (Stream a, Token a ~ Char, IsString (Tokens a)) => OgmarkupParser a () blank = do skip $ optional (notFollowedBy endOfParagraph >> space)