Skip to content

Instantly share code, notes, and snippets.

@minad
Last active April 17, 2016 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save minad/45535d0be4ba52dd64f285e03b38f8c1 to your computer and use it in GitHub Desktop.
Save minad/45535d0be4ba52dd64f285e03b38f8c1 to your computer and use it in GitHub Desktop.
Indent parser for megaparsec
module LayoutParser (
LayoutParser,
indented,
linefold,
line,
saveIndent,
align,
runLayoutParser
) where
import Text.Megaparsec
import Text.Megaparsec.Text.Lazy
import qualified Data.Text.Lazy as L
import Text.Megaparsec.Pos
import Control.Monad.State
type LayoutParser a = StateT SourcePos Parser a
-- | Parses only when indented past the level of the reference
indented :: LayoutParser ()
indented = do
pos <- getPosition
s <- get
if sourceColumn pos <= sourceColumn s then fail "not indented" else do
put $ setSourceLine s (sourceLine pos)
return ()
-- | Parses only when indented past the level of the reference or on the same line
linefold :: LayoutParser ()
linefold = line <|> indented
-- | Parses only on the line as the reference
line :: LayoutParser ()
line = do
pos <- getPosition
s <- get
when (sourceLine pos /= sourceLine s) (fail "over one line")
-- | Parses using the current location for indentation reference
saveIndent :: LayoutParser a -> LayoutParser a
saveIndent x = do
a <- get
p <- getPosition
r <- put p >> x
put a >> return r
-- | Ensures the current indentation level matches that of the reference
align :: LayoutParser ()
align = do
s <- get
p <- getPosition
when (sourceColumn p /= sourceColumn s) (fail "indentation doesn't match")
runLayout :: LayoutParser a -> String -> Parser a
runLayout p file = fst <$> runStateT p (initialPos file)
runLayoutParser :: LayoutParser a -> String -> L.Text -> Either ParseError a
runLayoutParser p file source = runParser (runLayout p file) file source
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment