IndentParser 0.1 → 0.2
raw patch · 7 files changed
+991/−807 lines, 7 filesdep ~basedep ~parsecPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, parsec
API changes (from Hackage documentation)
- Text.ParserCombinators.Parsec.IndentParser: data IndentState st
- Text.ParserCombinators.Parsec.IndentParser: getIndentMode :: IndentParser tok st IndentMode
- Text.ParserCombinators.Parsec.IndentParser: indentMode :: IndentState st -> IndentMode
- Text.ParserCombinators.Parsec.IndentParser: instance Eq IndentMode
- Text.ParserCombinators.Parsec.IndentParser: instance Show IndentMode
- Text.ParserCombinators.Parsec.IndentParser: saveIndentMode :: IndentParser tok st a -> IndentParser tok st a
- Text.ParserCombinators.Parsec.IndentParser: setIndentMode :: IndentMode -> IndentParser tok st ()
- Text.ParserCombinators.Parsec.IndentParser: state :: IndentState st -> st
- Text.ParserCombinators.Parsec.IndentToken: angles :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: anglesOrBlock :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: anglesOrLineFold :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: braces :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: bracesOrBlock :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: bracesOrLineFold :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: brackets :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: bracketsOrBlock :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: bracketsOrLineFold :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: charLiteral :: TokenParser st -> IndentCharParser st Char
- Text.ParserCombinators.Parsec.IndentToken: colon :: TokenParser st -> IndentCharParser st String
- Text.ParserCombinators.Parsec.IndentToken: commaOrNewLineSep :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
- Text.ParserCombinators.Parsec.IndentToken: commaOrNewLineSep1 :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
- Text.ParserCombinators.Parsec.IndentToken: commaSep :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
- Text.ParserCombinators.Parsec.IndentToken: commaSep1 :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
- Text.ParserCombinators.Parsec.IndentToken: decimal :: TokenParser st -> IndentCharParser st Integer
- Text.ParserCombinators.Parsec.IndentToken: dot :: TokenParser st -> IndentCharParser st String
- Text.ParserCombinators.Parsec.IndentToken: float :: TokenParser st -> IndentCharParser st Double
- Text.ParserCombinators.Parsec.IndentToken: hexadecimal :: TokenParser st -> IndentCharParser st Integer
- Text.ParserCombinators.Parsec.IndentToken: identifier :: TokenParser st -> IndentCharParser st String
- Text.ParserCombinators.Parsec.IndentToken: integer :: TokenParser st -> IndentCharParser st Integer
- Text.ParserCombinators.Parsec.IndentToken: lexeme :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: natural :: TokenParser st -> IndentCharParser st Integer
- Text.ParserCombinators.Parsec.IndentToken: naturalOrFloat :: TokenParser st -> IndentCharParser st (Either Integer Double)
- Text.ParserCombinators.Parsec.IndentToken: octal :: TokenParser st -> IndentCharParser st Integer
- Text.ParserCombinators.Parsec.IndentToken: operator :: TokenParser st -> IndentCharParser st String
- Text.ParserCombinators.Parsec.IndentToken: parens :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: parensOrBlock :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: parensOrLineFold :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
- Text.ParserCombinators.Parsec.IndentToken: reserved :: TokenParser st -> String -> IndentCharParser st ()
- Text.ParserCombinators.Parsec.IndentToken: reservedOp :: TokenParser st -> String -> IndentCharParser st ()
- Text.ParserCombinators.Parsec.IndentToken: semi :: TokenParser st -> IndentCharParser st String
- Text.ParserCombinators.Parsec.IndentToken: semiOrNewLineSep :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
- Text.ParserCombinators.Parsec.IndentToken: semiOrNewLineSep1 :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
- Text.ParserCombinators.Parsec.IndentToken: semiSep :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
- Text.ParserCombinators.Parsec.IndentToken: semiSep1 :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
- Text.ParserCombinators.Parsec.IndentToken: stringLiteral :: TokenParser st -> IndentCharParser st String
- Text.ParserCombinators.Parsec.IndentToken: symbol :: TokenParser st -> String -> IndentCharParser st String
- Text.ParserCombinators.Parsec.IndentToken: type IndentCharParser st a = IndentParser Char st a
- Text.ParserCombinators.Parsec.IndentToken: type LanguageDef st = LanguageDef (IndentState st)
- Text.ParserCombinators.Parsec.IndentToken: type TokenParser st = TokenParser (IndentState st)
- Text.ParserCombinators.Parsec.IndentToken: whiteSpace :: TokenParser st -> IndentCharParser st ()
+ Text.ParserCombinators.Parsec.IndentParser: type IndentCharParser st a = IndentParser Char st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: angles :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: anglesOrBlock :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: anglesOrLineFold :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: braces :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: bracesOrBlock :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: bracesOrLineFold :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: brackets :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: bracketsOrBlock :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: bracketsOrLineFold :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: charLiteral :: TokenParser st -> IndentCharParser st Char
+ Text.ParserCombinators.Parsec.IndentParser.Token: colon :: TokenParser st -> IndentCharParser st String
+ Text.ParserCombinators.Parsec.IndentParser.Token: comma :: TokenParser st -> IndentCharParser st String
+ Text.ParserCombinators.Parsec.IndentParser.Token: commaOrNewLineSep :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
+ Text.ParserCombinators.Parsec.IndentParser.Token: commaOrNewLineSep1 :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
+ Text.ParserCombinators.Parsec.IndentParser.Token: commaSep :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
+ Text.ParserCombinators.Parsec.IndentParser.Token: commaSep1 :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
+ Text.ParserCombinators.Parsec.IndentParser.Token: decimal :: TokenParser st -> IndentCharParser st Integer
+ Text.ParserCombinators.Parsec.IndentParser.Token: dot :: TokenParser st -> IndentCharParser st String
+ Text.ParserCombinators.Parsec.IndentParser.Token: float :: TokenParser st -> IndentCharParser st Double
+ Text.ParserCombinators.Parsec.IndentParser.Token: hexadecimal :: TokenParser st -> IndentCharParser st Integer
+ Text.ParserCombinators.Parsec.IndentParser.Token: identifier :: TokenParser st -> IndentCharParser st String
+ Text.ParserCombinators.Parsec.IndentParser.Token: integer :: TokenParser st -> IndentCharParser st Integer
+ Text.ParserCombinators.Parsec.IndentParser.Token: lexeme :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: natural :: TokenParser st -> IndentCharParser st Integer
+ Text.ParserCombinators.Parsec.IndentParser.Token: naturalOrFloat :: TokenParser st -> IndentCharParser st (Either Integer Double)
+ Text.ParserCombinators.Parsec.IndentParser.Token: octal :: TokenParser st -> IndentCharParser st Integer
+ Text.ParserCombinators.Parsec.IndentParser.Token: operator :: TokenParser st -> IndentCharParser st String
+ Text.ParserCombinators.Parsec.IndentParser.Token: parens :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: parensOrBlock :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: parensOrLineFold :: TokenParser st -> IndentCharParser st a -> IndentCharParser st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: reserved :: TokenParser st -> String -> IndentCharParser st ()
+ Text.ParserCombinators.Parsec.IndentParser.Token: reservedOp :: TokenParser st -> String -> IndentCharParser st ()
+ Text.ParserCombinators.Parsec.IndentParser.Token: semi :: TokenParser st -> IndentCharParser st String
+ Text.ParserCombinators.Parsec.IndentParser.Token: semiOrNewLineSep :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
+ Text.ParserCombinators.Parsec.IndentParser.Token: semiOrNewLineSep1 :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
+ Text.ParserCombinators.Parsec.IndentParser.Token: semiSep :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
+ Text.ParserCombinators.Parsec.IndentParser.Token: semiSep1 :: TokenParser st -> IndentCharParser st a -> IndentCharParser st [a]
+ Text.ParserCombinators.Parsec.IndentParser.Token: stringLiteral :: TokenParser st -> IndentCharParser st String
+ Text.ParserCombinators.Parsec.IndentParser.Token: symbol :: TokenParser st -> String -> IndentCharParser st String
+ Text.ParserCombinators.Parsec.IndentParser.Token: type IndentCharParser st a = IndentParser Char st a
+ Text.ParserCombinators.Parsec.IndentParser.Token: type TokenParser st = TokenParser (st, IndentState)
+ Text.ParserCombinators.Parsec.IndentParser.Token: whiteSpace :: TokenParser st -> IndentCharParser st ()
- Text.ParserCombinators.Parsec.IndentParser: Block :: Column -> IndentMode
+ Text.ParserCombinators.Parsec.IndentParser: Block :: IndentMode
- Text.ParserCombinators.Parsec.IndentParser: LineFold :: Line -> Column -> IndentMode
+ Text.ParserCombinators.Parsec.IndentParser: LineFold :: IndentMode
- Text.ParserCombinators.Parsec.IndentParser: type IndentParser tok st a = GenParser tok (IndentState st) a
+ Text.ParserCombinators.Parsec.IndentParser: type IndentParser tok st a = GenParser tok (st, IndentState) a
Files
- ACK +3/−0
- CHANGES +23/−0
- IndentParser.cabal +5/−4
- Text/ParserCombinators/Parsec/IndentParser.hs +188/−202
- Text/ParserCombinators/Parsec/IndentParser/Prim.hs +159/−0
- Text/ParserCombinators/Parsec/IndentParser/Token.hs +613/−0
- Text/ParserCombinators/Parsec/IndentToken.hs +0/−601
+ ACK view
@@ -0,0 +1,3 @@+Martin Grabmueller <login:magr at the host cs dot tu-berlin dot de>+had send valuable bug reports after IndentParser-0.1 was uploaded to+HackageDB.
+ CHANGES view
@@ -0,0 +1,23 @@+Mon Oct 15 20:05:18 IST 2007 ppk@cse.iitk.ac.in+ * Reorganised and Nested indent Fix+ + Bugs Fix+ * Serious trouble when indentation structures are+ nested. Hopefully fixed.+ Reorganisation+ * All state manipulation parsers are moved into the+ module IndentParser.Prim which is hidden.+ * IndentToken renamed to IndentParser.Token+ * Redefined parser state of indent parser.+ ++Mon Oct 8 10:22:13 IST 2007 ppk@cse.iitk.ac.in+ tagged IndentParser-0.1++Mon Oct 8 10:19:27 IST 2007 ppk@cse.iitk.ac.in+ * Initial Version+ + Haskell modules to construct Indentation based syntactic structures.+ How to Install: via Cabal. Suggestion and bug reports are welcome+ (have a glance at TODO).+
IndentParser.cabal view
@@ -1,8 +1,8 @@ Name: IndentParser-Version: 0.1+Version: 0.2 License: GPL License-File: gplv3-Maintainer:login id is ppk and host is cse dot iitk dot ac dot in+Maintainer:login:ppk host:cse dot iitk dot ac dot in Author: Piyush P Kurur Homepage: http://www.cse.iitk.ac.in/~ppk Category: Parsing@@ -18,5 +18,6 @@ for programming languages. Exposed-modules: Text.ParserCombinators.Parsec.IndentParser- Text.ParserCombinators.Parsec.IndentToken-Extra-Source-Files: TODO+ Text.ParserCombinators.Parsec.IndentParser.Token+Other-modules: Text.ParserCombinators.Parsec.IndentParser.Prim+Extra-Source-Files: TODO ACK CHANGES
Text/ParserCombinators/Parsec/IndentParser.hs view
@@ -47,6 +47,18 @@ Haskell as well. +The module exports three combinators are @'indentParser'@, @'block'@+and @'lineFold'@. To construct parsers for indentation based grammars+one typically applies the @'indentParser'@. A block can then be+parsed using the combinator @'block'@ and a line fold using+@'lineFold'@. Generating indentation aware tokenisers could be tricky.+Given a language description via the+'Text.ParserCombinators.Parsec.Language.LanguageDef' record use module+@'Text.ParserCombinators.Parsec.IndentParser.Token'@ to generate its+tokeiser (this will apply @'indentParser'@ on all tokenisers and then+the user can forget about @'indentParser'@ combinator).++ Warning: Internally indentations are implemented using Parser states. If one@@ -61,34 +73,19 @@ module Text.ParserCombinators.Parsec.IndentParser (- -- * Parser type-+ -- * Parser type. IndentParser,- -- * Parser Combinators.- -- $combinators+ IndentCharParser,+ IndentMode(..), indentParser, noIndent, block, lineFold, betweenOrBlock, betweenOrLineFold,- -- * Primitive Parsers- -- $prim- IndentMode(..),- IndentState, state, indentMode,- saveIndentMode,- getIndentMode, setIndentMode, -- * User state manipulation.- -- $state getState, setState,- -- * Testing and Running.- -- $run- runParser, parseTest,- ---) where---+ -- * Running and testing.+ runParser, parseTest --- The functions @getState@ @setState@ and parseTest for indentation--- Parsers are exported by this module. Hence they are hidden.+) where import Text.ParserCombinators.Parsec hiding (@@ -98,69 +95,49 @@ runParser ) + import Text.ParserCombinators.Parsec.Pos-import qualified Text.ParserCombinators.Parsec.Prim as PP-import Control.Monad(fmap)+import Text.ParserCombinators.Parsec.IndentParser.Prim -getStatePrim = PP.getState-setStatePrim = PP.setState-runParserPrim = PP.runParser +-- Some comparisons of indentations. -{-| - An indentation aware parser. The parser should be of this type to- make it possible to parse indentation based grammatical structure.+indentGT :: SourcePos -> SourcePos -> Bool+indentGT pos1 pos2 = sourceColumn pos1 > sourceColumn pos2+indentGE pos1 pos2 = sourceColumn pos1 >= sourceColumn pos2+indentEq pos1 pos2 = sourceColumn pos1 == sourceColumn pos2 --} + -type IndentParser tok st a = GenParser tok (IndentState st) a --{- $combinators--The module exports three combinators are @'indentParser'@, @'block'@-and @'lineFold'@. To construct parsers for indentation based grammars-one typically applies the @'indentParser'@ to all tokenisers. In-conjunction with @'Text.ParserCombinators.Parsec.Token'@ module, one-would want to apply indentParser to all the fields of the-'Text.ParserCombinators.Parsec.Token.TokenParser' record except-@'Text.ParserCombinators.Parsec.Token.whiteSpace'@. A block can then-be parsed using the combinator @'block'@ and a line fold using-@'lineFold'@. To generate indentation aware tokeniser from the-corresponding 'Text.ParserCombinators.Parsec.Language.LanguageDef'-record see the module @'Text.ParserCombinators.Parsec.IndentToken'@.-+{-| + The combinator indentParser makes its input parser indentation+ aware. Usually one would want to make all the tokenisers indentation+ aware. -} -{-| - The combinator indentParser makes its input parser indentation- aware. Usually one would want to make all the tokenisers indentation- aware. ---} indentParser :: IndentParser tok st a -> IndentParser tok st a indentParser p = do indMode <- getIndentMode case indMode of- NoIndent -> p -- - Block c -> blockP c p- LineFold l c -> lineP l c p- where blockP c p = do col <- column- if col >= c then p else pzero - lineP l c p = do col <- column- if col > c then p else - do ln <- line- if ln == l then p else pzero-- + NoIndent -> p+ Block -> inBlockMode p+ LineFold -> inLineFoldMode p+ where inBlockMode p = do curCol <- column+ indCol <- indentColumn+ if curCol >= indCol then p else pzero + inLineFoldMode p = do curPos <- getPosition+ oldPos <- getIndentPos+ if curPos `indentGT` oldPos + || curPos == oldPos then p else pzero {-|@@ -174,220 +151,229 @@ -} noIndent :: IndentParser tok st a -> IndentParser tok st a-noIndent p = saveIndentMode $ do {setIndentMode NoIndent; p}- ---{-|+noIndent p = saveIndent (p `withIndentMode` NoIndent) -The parser @'block' p@ parses a /block/ of @p@ with the block-indentation being the current column number.+ --} -+{-|+The parser @'block' p@ parses a /block/ of @p@.+-} block :: IndentParser tok st a -> IndentParser tok st a-block p = saveIndentMode $ do col <- column- setIndentMode $ Block col- p- + {-| -The parser @lineFold p@ parses a folded line of @p@. The current line-is the starting line. The indentation of the line depends on where in-the source we are. If we are in a block then the indentation is the-indentation of the block. Otherwise the current column is the-indentation.+The parser @lineFold p@ parses a folded line of @p@. -}- lineFold :: IndentParser tok st a -> IndentParser tok st a-lineFold p = saveIndentMode $ do ln <- line- indMode <- getIndentMode- case indMode of- NoIndent -> do col <- column- setIndentMode $ LineFold ln col- Block c -> setIndentMode $ LineFold ln c- p --{-|-- The parser @betweenOrBlock open close p@ parses @p@ between @open@-and @close@. If open is matched @p@ is parsed in 'NoIndent' mode otherwise-a block @p@ is parsed in 'Block' mode. For eg. the parser for parsing-haskell where clause would look like--> whereClause = do reserved where; betweenOrBlock bindings+{- --}-betweenOrBlock :: IndentParser tok st open -> - IndentParser tok st close ->- IndentParser tok st a -> - IndentParser tok st a+The complication in the definition of block and lineFold is in the+handling of nested indentation. We now describe the rules for nesting+of blocks and lineFolds. -betweenOrBlock left right p = do left; x <- noIndent p; right; return x- <|> block p+(1) A block or a lineFold can start any where in a NoIndent chunk+(2) A block inside a lineFold or block has to be indented + more than the previous indentation, otherwise it is an empty block. -{-|+(3) A lineFold inside a lineFold has to be indented more than+ the previous indentation otherwise it is an empty lineFold+(4) A lineFold inside a block should be indented at least as much+ as the previous indentation otherwise it is an empty lineFold. -Similar to betweenOrBlock but uses lineFold instead of block.+Based on these rules we define the parsers isEmptyBlock and+isEmptyLineFold. -}-betweenOrLineFold :: IndentParser tok st open -> - IndentParser tok st close -> - IndentParser tok st a ->- IndentParser tok st a-betweenOrLineFold left right p = do left; x <- noIndent p; right; return x- <|> lineFold p --- | This returns the current line number+isEmptyBlock = do indm <- getIndentMode+ case indm of+ NoIndent -> return False+ _ -> do curCol <- column+ indCol <- indentColumn+ return (curCol <= indCol) -line :: GenParser tok st Line-line = fmap sourceLine getPosition+isEmptyLineFold = do indm <- getIndentMode+ case indm of+ NoIndent -> return False+ Block -> do curCol <- column+ indCol <- indentColumn+ return (curCol < indCol)+ LineFold -> do curCol <- column+ indCol <- indentColumn+ return (curCol <= indCol) --- | This returns the current column number -column :: GenParser tok st Column-column = fmap sourceColumn getPosition+{- + If the current block (or line fold) is empty we cannot outright+ reject because the argument parser @p@ could be some parser that+ accepts an empty string. So the stratgy we use is that in this case+ we set the indentation position to be one more than the current+ position. So this will gurantee that @p@, if it is a valid+ indentation parser will see empty input. +-} -{- $prim -We now describe the primitives that are used to build the combinators-@block@, @noIndent@ and @lineFold@. An indentation parser can be in-one of the following modes: -[@NoIndent@] In this mode the parser ignores all indentation-constraints. All tokens regardless of their indentation are accepted.+setPosBlock = do test <- isEmptyBlock+ pos <- if test then nextPos else getPosition+ setIndentPos pos+ -[@Block c@] In this mode a parser accepts only tokens which have-indentation at least @c@. A parser parsing a block that is indented-more than @c@ columns will be this mode. +setPosLineFold = do test <- isEmptyLineFold+ pos <- if test then nextPos else getPosition+ setIndentPos pos -[@LineFold l c@] In this mode a parser accepts tokens as long as it is-in the current line or is indented more than @c@. When parsing a-folded line starting at @l@ and indentation more than @c@ the parser-will be in this mode. +{- + Also a block p (lineFold p) should contain p and nothing else. So+ when we are done with it we need to ensure that there is no more+ input. This is done using the parser eobReached (eolfReached) -} -data IndentMode = NoIndent - | Block Column- | LineFold Line Column deriving (Show, Eq)- --- | This parser returns the current indentation mode. --getIndentMode :: IndentParser tok st IndentMode-getIndentMode = fmap indentMode getStatePrim+eobReached :: IndentParser tok st ()+eobReached = do indCol <- indentColumn+ col <- column+ if indCol <= col then (endOfInput <|> prematureEnd)+ else return ()+ where prematureEnd = do indPos <- getIndentPos+ pos <- getPosition+ fail ("premature block termination " +++ "started at " ++ show indPos +++ " and ended at " ++ show pos)+ + --- | This parser sets the current indentation mode--setIndentMode :: IndentMode -> IndentParser tok st ()-setIndentMode ind = do indState <- getStatePrim- PP.setState $ indState {indentMode = ind}+eolfReached = do indCol <- indentColumn+ col <- column+ if indCol < col then (endOfInput <|> prematureEnd)+ else return ()+ where prematureEnd = do indPos <- getIndentPos+ pos <- getPosition+ fail ("premature block termination " +++ "started at " ++ show indPos +++ " and ended at " ++ show pos)+ -{-| --The parser @saveIndentMode p@ saves the current indentation mode and-returns the result of running @p@. It restores back the old-indentation once @p@ has finished executing.-+{-+ Having defined these parsers we can now define the parser block and+ lineFold. -}-saveIndentMode :: IndentParser tok st a -> IndentParser tok st a-saveIndentMode p = do indMode <- getIndentMode- x <- p- setIndentMode indMode- return x+block p = saveIndent $ do setPosBlock+ x <- p `withIndentMode` Block+ eobReached+ return x +lineFold p = saveIndent $ do setPosLineFold+ x <- p `withIndentMode` LineFold+ eolfReached+ return x -{- $state -Indentation awareness is built into indentation parser by using these-parser states. To distinguish it from the actual user defined state we-call the former the indentation state and the later the user state.-+ +{-| + The parser @betweenOrBlock open close p@ parses @p@ between @open@+and @close@. If open is matched @p@ is parsed in 'NoIndent' mode otherwise+a block @p@ is parsed in 'Block' mode. For eg. the parser for parsing+haskell where clause would look like +> whereClause = do reserved where; betweenOrBlock bindings -} --- | The parser state used by Indentation Parsers.--data IndentState st = IndentState {- state :: st, -- the actual state- indentMode :: IndentMode -- the indentation mode- } ------ | Gets the current user state. Use this instead of the one exported--- from Parsec module--getState :: IndentParser tok st st-getState = fmap state getStatePrim+betweenOrBlock :: IndentParser tok st open -> + IndentParser tok st close ->+ IndentParser tok st a -> + IndentParser tok st a +betweenOrBlock left right p = do left; x <- noIndent p; right; return x+ <|> block p -{-| +{-| -This parser sets the current state of the parser to the given input-state. Use this function instead of the one exported by the parsec-library.+Similar to betweenOrBlock but uses lineFold instead of block. -}+betweenOrLineFold :: IndentParser tok st open -> + IndentParser tok st close -> + IndentParser tok st a ->+ IndentParser tok st a+betweenOrLineFold left right p = do left; x <- noIndent p; right; return x+ <|> lineFold p -setState :: st -> IndentParser tok st ()-setState st = do indState <- getStatePrim- PP.setState indState {state = st} +-- Some position parsers. +-- | This returns the current line number -{- $run+line :: GenParser tok st Line+line = fmap sourceLine getPosition - -The most generic way to run an IndentParser. Use @parseTest@ for-testing your parser instead.+-- | This returns the current column number --}-runParser :: IndentParser tok st a -- ^ the parser to be run- -> st -- ^ the initial state - -> IndentMode -- ^ the indentation mode- -> SourceName -- ^ the source file name- -> [tok] -- ^ the list of tokens- -> Either ParseError a -- ^ the result of parsing+column :: GenParser tok st Column+column = fmap sourceColumn getPosition -runParser p st imode = runParserPrim p (IndentState st imode)+indentColumn :: IndentParser tok st Column+indentColumn = fmap sourceColumn getIndentPos +nextPos :: GenParser tok st SourcePos+nextPos = do pos <- getPosition+ return (pos `incSourceColumn` 1) {-| -This is the function analogues to parseTest of the Parsec module.-Given an indent parser @p :: IndentParser tok () a@ and a list of-tokens it runs the parser and prints the result.+The parser @saveIndent p@, saves the current indentation, runs @p@,+and restores the indentation back. -} +saveIndent :: IndentParser tok st a -> IndentParser tok st a+saveIndent p = do indMode <- getIndentMode+ indPos <- getIndentPos+ x <- p+ setIndentMode indMode+ setIndentPos indPos+ return x+ +withIndentMode :: IndentParser tok st a -> IndentMode -> IndentParser tok st a+withIndentMode p indm = do setIndentMode indm+ p+ -parseTest :: Show a => IndentParser tok () a -> [tok] -> IO ()-parseTest p input = case result of- Left err -> do putStr "Error"; print err- Right a -> do print a- where result = runParser p () NoIndent "" input+{- +When an block or a lineFold is to be entered care must be taken to set+the indentation position. If the current indentation mode is NoIndent+then just set the current position. In case we are already inside+a line fold or a block then the indentation should be the max of+current position and previous indentation position + 1. The reason+we do not outright reject is because block p could be +-}+++endOfInput = do ins <- getInput+ case ins of+ [] -> return ()+ _ -> pzero
+ Text/ParserCombinators/Parsec/IndentParser/Prim.hs view
@@ -0,0 +1,159 @@+{-|+++This module contains the primitve indentation parsers. In most of+the case one would not want to use the functions of this module.+++-}++++module Text.ParserCombinators.Parsec.IndentParser.Prim+ (+ -- * Types+ IndentParser,+ IndentCharParser,+ IndentMode(..),+ IndentState,+ -- * Geting indentation modes and position.+ getIndentMode, setIndentMode,+ getIndentPos, setIndentPos,+ -- * User state manipulation.+ getState, setState,+ -- * Runing and testing+ runParser, parseTest+ + ) where ++import Text.ParserCombinators.Parsec hiding+ (getState, setState, parseTest, runParser)+import qualified Text.ParserCombinators.Parsec.Prim as PP+import Control.Monad(fmap)+import Text.ParserCombinators.Parsec.Pos(initialPos)++-- | The mode of the indentation parser.++data IndentMode = NoIndent -- ^ Ignore indentation+ | Block -- ^ In block mode+ | LineFold -- ^ In line fold mode+ deriving Eq+ +++{-|++Indentation awareness is built into indentation parser by using these+parser states. To distinguish it from the actual user defined state we+call the former the indentation state and the later the user state.+++-}++++data IndentState = IndentState {+ indentMode :: IndentMode,+ -- the indentation mode.+ indentPos :: SourcePos+ -- The position where the current + -- indentation started.+ }++++{-| + An indentation aware parser.+-} +++type IndentParser tok st a = GenParser tok (st, IndentState) a+type IndentCharParser st a = IndentParser Char st a++-- | Gets the current user state.+getState :: IndentParser tok st st+-- | Gets the current indentation state.+getIndentState :: IndentParser tok st IndentState+-- | Gets the current identation mode.+getIndentMode :: IndentParser tok st IndentMode+-- | Gets the position where the last indentation started.+getIndentPos :: IndentParser tok st SourcePos+++getState = fmap fst getStatePrim+getIndentState = fmap snd getStatePrim+getIndentMode = fmap indentMode getIndentState+getIndentPos = fmap indentPos getIndentState+++++-- | Sets the user state.+setState :: st -> IndentParser tok st ()+-- | Sets the current indentation.+setIndentPos :: SourcePos -> IndentParser tok st ()+-- | Sets the current indentation mode.+setIndentMode :: IndentMode -> IndentParser tok st ()+-- | Sets the indentation state of the parser.+setIndentState :: IndentState -> IndentParser tok st ()++setState st = do indst <- getIndentState+ setStatePrim (st,indst)+setIndentState indst = do st <- getState+ setStatePrim (st, indst)++setIndentPos sp = do indst <- getIndentState+ setIndentState $ indst {indentPos = sp}+setIndentMode indm = do indst <- getIndentState+ setIndentState $ indst {indentMode = indm}+++++{- $run++ +The most generic way to run an IndentParser. Use @parseTest@ for+testing your parser instead.++-}++runParser :: IndentParser tok st a -- ^ the parser to be run+ -> st -- ^ the initial state + -> IndentMode -- ^ the indentation mode+ -> SourceName -- ^ the source file name+ -> [tok] -- ^ the list of tokens+ -> Either ParseError a -- ^ the result of parsing++runParser p st imode sname = runParserPrim p (st, istate) sname+ where istate = IndentState { indentPos = initialPos sname,+ indentMode = imode+ }+++++{-| ++This is the function analogues to parseTest of the Parsec module.+Given an indent parser @p :: IndentParser tok () a@ and a list of+tokens it runs the parser and prints the result.++-}+++parseTest :: Show a => IndentParser tok () a -> [tok] -> IO ()+parseTest p input = case result of+ Left err -> do putStr "Error"; print err+ Right a -> do print a+ where result = runParser p () NoIndent "" input++++++++getStatePrim = PP.getState+setStatePrim = PP.setState+runParserPrim = PP.runParser
+ Text/ParserCombinators/Parsec/IndentParser/Token.hs view
@@ -0,0 +1,613 @@+{-# OPTIONS_GHC -fglasgow-exts #-}++{-++Haskell module for constructing indentation aware parser combinators.+Copyright (C) 2007 Piyush P Kurur, <http://www.cse.iitk.ac.in/~ppk>++This program is free software: you can redistribute it and/or modify+it under the terms of the GNU General Public License as published by+the Free Software Foundation, either version 3 of the License, or+(at your option) any later version.++This program is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+GNU General Public License for more details.++You should have received a copy of the GNU General Public License+along with this program. If not, see <http://www.gnu.org/licenses/>.+ ++-}++{-|++A module for constructing indentation aware tokeniser that can be used+in conjuction with @'Text.ParserCombinators.Parsec.Token'@. All the+combinator takes a @'Text.ParserCombinators.Parsec.Token.TokenParser'@+as its first argument. For every field @foo@ of+@'Text.ParserCombinators.Parsec.Token.TokenParser'@ this module+exports a combinator @foo@. To define a tokeniser for an indentation+based language a user first defines the appropriate+@'Text.ParserCombinators.Parsec.Language.LanguageDef'@ record, applies+the combinator @'Text.ParserCombinators.Parsec.Token.makeTokenParser'@+to get a @'Text.ParserCombinators.Parsec.Token.TokenParser'@ record+say @tokP@ and then, instead of selecting the field @foo@ of @tokP@,+applies the combinator @foo@ exported from this module to @tokP@. The+semantics of the combinator @foo@ is essentially same as that of the+field @foo@ of @'Text.ParserCombinators.Parsec.Token.TokenParser'@ but+the returned parsers are indentation aware. Apart from these there are+certain new combinators that are defined specifically for parsing+certain indentation based syntactic constructs. (We have not defined+squares use brackets instead)+++There are two important classes of parser combinator exported by this+module:++[Grouping Parser Combinator] A grouping parser combinator takes as+input a parser say @p@ and returns a parser that parses @p@ between+two /grouping delimiters/. There are three flavours of grouping+parsers: @foo@, @fooOrBlock@ and @fooOrLineFold@ where @foo@ can be+one of @angles@, @braces@, @parens@, @brackets@. To illustrate we take+@foo@ to be @braces@. The parser @'braces' tokP p@ parses @p@+delimited by '{' and '}'. In this case @p@ does not care about+indentation (i.e. the parser @p@ is run in+@'Text.ParserCombinators.Parsec.IndentParser.NoIndent'@ mode). The+parser @'bracesOrBlock' tokP p@ is like @braces tokP p@ but if no+explicit delimiting braces are given parses @p@ within an indented+block. Similarly @'bracesOrLineFold' tokP p@ parses @p@ between '{'+and '}' and uses line fold when no explicit braces are given. These+can be two varients can be defined as follows++> bracesOrBlock tokP p = braces tokP p <|> block p+> bracesOrLineFold tokP p = braces tokP p <|> lineFold p+++[Seperator Parser Combinator] A seperator parser combinator takes as+input a parser say @p@ and returns a parser that parses a list of @p@+seperated by a seperator. The module exports the combinators @fooSep@,+@fooSep1@, @fooOrNewLineSep@ and @fooOrNewLineSep1@, where @foo@ is+either @semi@ (in which case the seperator is a semicolon ';') or+@comma@ (in which case the seperator is a comma ',').+++To illustrate the use of this module we now give, as an incomplete+example, a parser that parses a where clause in Haskell which+illustrates the use of this module.++ +> import qualified Text.ParserCombinators.Parsec.Language as L+> import qualified Text.ParserCombinators.Parsec.Toke as T+> import qualified Text.ParserCombinator.Parsec.IndentToken as IT+++> tokP = T.makeTokenParser L.haskellDef+> semiOrNewLineSep = IT.semiOrNewLineSep tokP+> bracesOrBlock = IT.bracesOrBlock tokP+> identifier = IT.identifier tokP+> ....+> symbol = IT.symbol tokP++> binding = semiOrNewLineSep bind+> bind = do id <- identifier+> symbol (char '=')+> e <- expr+> return (id,e)+> whereClause = do reserved "where"; braceOrBlock binding+++-}+++module Text.ParserCombinators.Parsec.IndentParser.Token+ ( + -- * Types+ IndentCharParser,+ TokenParser,+ -- * Combinators+ identifier, reserved,+ operator, reservedOp,+ charLiteral, stringLiteral,+ natural, integer, float, naturalOrFloat,+ decimal, hexadecimal, octal,+ semi, colon, dot, comma,+ lexeme, symbol, whiteSpace,+ -- * Separator parser combinators+ semiSep, semiSep1, commaSep, commaSep1,+ semiOrNewLineSep, semiOrNewLineSep1,+ commaOrNewLineSep, commaOrNewLineSep1,+ -- * Grouping parser combinator+ parens,parensOrBlock, parensOrLineFold,+ braces, bracesOrBlock, bracesOrLineFold,+ angles, anglesOrBlock, anglesOrLineFold,+ brackets, bracketsOrBlock, bracketsOrLineFold+ ) where++import Text.ParserCombinators.Parsec hiding (+ getState,+ setState,+ parseTest,+ runParser+ )++import qualified Text.ParserCombinators.Parsec.Token as T+import qualified Text.ParserCombinators.Parsec.Language as L+import Text.ParserCombinators.Parsec.IndentParser+import Text.ParserCombinators.Parsec.IndentParser.Prim (IndentState)+++type TokenParser st = T.TokenParser (st,IndentState)++++++{-| Indentation aware parser to match a valid identifier of the+language. -}++identifier :: TokenParser st -> IndentCharParser st String+identifier = indentParser . T.identifier+++{-| Indentation aware parser to match a reserved word of the language.+-}++reserved :: TokenParser st ->+ String -- ^ The reserved word to be matched.+ -> IndentCharParser st ()+reserved tokP = indentParser . T.reserved tokP+++{-| The parser @reserved tokP keyword@ parses the reserved word keyword.+ The string keyword should have been declared as a reserved word in the + @'Text.ParserCombinator.Parserc.Language.LanguageDef'@+ -record. -}++operator :: TokenParser st -> IndentCharParser st String+operator = indentParser . T.operator++{-|+ Indentation aware parser to match a reserved operator of the language.+-}++reservedOp :: TokenParser st ->+ String+ -- ^ The reserved operator to be matched. Should have+ -- been declared as a reserved operator in the + -- @'Text.ParserCombinator.Parserc.Language.LanguageDef'@+ -- record.+ -> IndentCharParser st ()++reservedOp tokP = indentParser . T.reservedOp tokP++++++{-| Indentation aware parser to match a character literal (the syntax+is assumend to be that of Hasekell which matches that of most+programming language).+-}++charLiteral :: TokenParser st -> IndentCharParser st Char+charLiteral = indentParser . T.charLiteral++++{-| Indentation aware parser to match a string literal (the syntax is+assumend to be that of Hasekell which matches that of most programming+language).+-}++stringLiteral :: TokenParser st -> IndentCharParser st String+stringLiteral = indentParser . T.stringLiteral+++{-| Indentation aware parser to match a natural number. -}++natural :: TokenParser st -> IndentCharParser st Integer+natural = indentParser . T.natural++{-|+ Indentation aware parser to match an integer.+-}++integer :: TokenParser st -> IndentCharParser st Integer+integer = indentParser . T.integer++{-| Indentation aware parser to match a floating point number. -}++float :: TokenParser st -> IndentCharParser st Double +float = indentParser . T.float++{-| Indentation aware parser to match either a natural number or+Floating point number. -}++naturalOrFloat :: TokenParser st+ -> IndentCharParser st (Either Integer Double)+naturalOrFloat = indentParser . T.naturalOrFloat++-- | Indentation aware parser to match an integer in decimal.+++decimal :: TokenParser st -> IndentCharParser st Integer+decimal = indentParser . T.decimal++{-| Indentation aware parser to match an integer in hexadecimal.-}++hexadecimal :: TokenParser st -> IndentCharParser st Integer+hexadecimal = indentParser . T.hexadecimal ++{-| ++Indentation aware parser to match an integer in ocatal.++-}++octal :: TokenParser st -> IndentCharParser st Integer+octal = indentParser . T.octal+++{-| Matches a semicolon and returns ';'. -}+++semi :: TokenParser st -> IndentCharParser st String+semi = indentParser . T.semi++{-| Matches a comma and returns ",". -}++comma :: TokenParser st -> IndentCharParser st String+comma = indentParser . T.comma++{-| Matches a colon and returns ":". -}+colon :: TokenParser st -> IndentCharParser st String+colon = indentParser . T.colon++{-| Matches a dot and returns "." -}+dot :: TokenParser st -> IndentCharParser st String+dot = indentParser . T.dot+++{-| Given an indentation aware parser @p@ as argument @semiSep tokP@+ returns a parser that parses zero or more occurances of @p@+ seperated by semicolon (';') -}++semiSep :: TokenParser st + -> IndentCharParser st a + -> IndentCharParser st [a]++semiSep tokP p = p `sepBy` semicolon+ where semicolon = semi tokP+++{-| Given an indentation aware parser @p@ as argument @semiSep1 tokP@+ returns a parser that parses one or more occurances of @p@ seperated+ by semicolon (';') -}+++semiSep1 :: TokenParser st + -> IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st [a]++semiSep1 tokP p = p `sepBy1` semicolon+ where semicolon = semi tokP++++{-| Given an indentation aware parser @p@ as argument @commaSep tokP@+ returns a parser that parses zero or more occurances of @p@+ seperated by comma (',') -}++commaSep :: TokenParser st+ -> IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st [a]++commaSep tokP p = p `sepBy` virgule+ where virgule = comma tokP+++++{-| Given an indentation aware parser @p@ as argument @commaSep1 tokP@+ returns a parser that parses one or more occurances of @p@ seperated+ by comma (',') -}+++commaSep1 :: TokenParser st+ -> IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st [a]++commaSep1 tokP p = p `sepBy1` virgule+ where virgule = comma tokP+++++{-| ++Given an indentation aware parser @p@ as argument @semiOrNewLineSep1+tokP@ returns a parser that parses one or more occurances of @p@+seperated by either semicolons (';') or newline. To seperate multiple+occurance of @p@ in the same line use an explicit semicolon (';').++-}++semiOrNewLineSep1 :: TokenParser st+ -> IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st [a]++semiOrNewLineSep1 tokP p = do xs <- lineFold $ semiSep1 tokP p+ rest <- semiOrNewLineSep tokP p+ return (xs++rest)++++{-| ++Given an indentation aware parser @p@ as argument @semiOrNewLineSep+tokP@ returns a parser that parses zero or more occurances of @p@+seperated by either semicolons (';') or newlines. To seperate multiple+occurance of @p@ in the same line use an explicit semicolon (';').++-}++semiOrNewLineSep :: TokenParser st+ -> IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st [a]++semiOrNewLineSep tokP p = do xs <- lineFold $ semiSep tokP p+ case xs of+ [] -> return []+ _ -> do rest <- semiOrNewLineSep tokP p+ return (xs++rest)++++++++{-| ++Given an indentation aware parser @p@ as argument @commaOrNewLineSep1+tokP@ returns a parser that parses one or more occurances of @p@+seperated by either comma (',') or newline. To seperate multiple+occurance of @p@ in the same line use an explicit comma (',').++-}++commaOrNewLineSep1 :: TokenParser st+ -> IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st [a]++commaOrNewLineSep1 tokP p = do xs <- lineFold $ commaSep1 tokP p+ rest <- commaOrNewLineSep tokP p+ return (xs++rest)++++{-| ++Given an indentation aware parser @p@ as argument @commaOrNewLineSep+tokP@ returns a parser that parses zero or more occurances of @p@+seperated by either comma (',') or newlines. To seperate multiple+occurance of @p@ in the same line use an explicit comma (',').++-}++commaOrNewLineSep :: TokenParser st+ -> IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st [a]++commaOrNewLineSep tokP p = do xs <- lineFold $ commaSep tokP p+ case xs of+ [] -> return []+ _ -> do rest <- commaOrNewLineSep tokP p+ return (xs++rest)++++++{-|++The parser @parens tokP p@ parses @p@ between '(' and ')'. The parser+@p@ does not care about indentation i.e. @p@ is run in+@'Text.ParserCombinators.Parsec.IndentParser.NoIndent'@ mode.++-}++parens :: TokenParser st ->+ IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st a++parens tokP p = between (symbol tokP "(") (symbol tokP ")") (noIndent p)++{-| ++Similar to @'parens'@ but when no explicit '(' and ')' are given,+groups @p@ by block indentation.++-}++parensOrBlock :: TokenParser st -> + IndentCharParser st a -- ^ The input parser+ -> IndentCharParser st a++parensOrBlock tokP p = parens tokP p <|> block p++++{-| ++Similar to @'parens'@ but when no explicit '(' and ')' are given,+groups @p@ by a line fold.++-}+parensOrLineFold :: TokenParser st -> + IndentCharParser st a -- ^ The input parser+ -> IndentCharParser st a++parensOrLineFold tokP p = parens tokP p <|> lineFold p+++{-|++The parser @braces tokP p@ parses @p@ between '{' and '}'. The parser+@p@ does not care about indentation i.e. @p@ is run in+@'Text.ParserCombinators.Parsec.IndentParser.NoIndent'@ mode.++-}++braces :: TokenParser st ->+ IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st a++braces tokP p = between (symbol tokP "{") (symbol tokP "}") (noIndent p)++++{-| ++Similar to @'braces'@ but when no explicit '{' and '}' are given,+groups @p@ by block indentation.++-}+bracesOrBlock :: TokenParser st -> + IndentCharParser st a -- ^ The input parser+ -> IndentCharParser st a++bracesOrBlock tokP p = braces tokP p <|> block p+++{-| ++Similar to @'braces'@ but when no explicit '{' and '}' are given,+groups @p@ by a line fold.++-}++bracesOrLineFold :: TokenParser st -> + IndentCharParser st a -- ^ The input parser+ -> IndentCharParser st a++bracesOrLineFold tokP p = braces tokP p <|> lineFold p+++{-|++The parser @angles tokP p@ parses @p@ between angles. The parser @p@+does not care about indentation i.e. @p@ is run in+@'Text.ParserCombinators.Parsec.IndentParser.NoIndent'@ mode.++-}++angles :: TokenParser st ->+ IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st a++angles tokP p = between (symbol tokP "<") (symbol tokP ">") (noIndent p)++++{-| ++Similar to @'angles'@ but when no explicit angles are given, groups+@p@ by block indentation.++-}++anglesOrBlock :: TokenParser st -> + IndentCharParser st a -- ^ The input parser+ -> IndentCharParser st a++anglesOrBlock tokP p = angles tokP p <|> block p+++{-| ++Similar to @'angles'@ but when no explicit angles are given, groups+@p@ by a line fold.++-}++anglesOrLineFold :: TokenParser st -> + IndentCharParser st a -- ^ The input parser+ -> IndentCharParser st a++anglesOrLineFold tokP p = angles tokP p <|> lineFold p++++{-|++The parser @brackets tokP p@ parses @p@ between '[' and ']'. The+parser @p@ does not care about indentation i.e. @p@ is run in+@'Text.ParserCombinators.Parsec.IndentParser.NoIndent'@ mode.++-}++brackets :: TokenParser st ->+ IndentCharParser st a -- ^ The input Parser+ -> IndentCharParser st a++brackets tokP p = between (symbol tokP "[") (symbol tokP "]") (noIndent p)++++{-| ++Similar to @'brackets'@ but when no explicit '[' and ']' are given,+groups @p@ by block indentation.++-}+bracketsOrBlock :: TokenParser st -> + IndentCharParser st a -- ^ The input parser+ -> IndentCharParser st a++bracketsOrBlock tokP p = brackets tokP p <|> block p+++{-| ++Similar to @'brackets'@ but when no explicit '[' and ']' are given,+groups @p@ by a line fold.++-}++bracketsOrLineFold :: TokenParser st -> + IndentCharParser st a -- ^ The input parser+ -> IndentCharParser st a++bracketsOrLineFold tokP p = brackets tokP p <|> lineFold p+++{-|++Indentation aware parser that is equvalent to string str.++-}++symbol :: TokenParser st + -> String + -> IndentCharParser st String+symbol tokP = indentParser . T.symbol tokP+++{-| Creates a lexeme parser. The resultant parser skips trailing+spaces and is indentation aware. -}++lexeme :: TokenParser st + -> IndentCharParser st a -- ^ The input parser.+ -> IndentCharParser st a++lexeme tokP = indentParser . T.lexeme tokP++{-| The parser whiteSpace skips spaces and comments. This does not+care about indentation as skipping spaces should be done irrespective+of the indentation. -}++whiteSpace :: TokenParser st -> IndentCharParser st ()+whiteSpace = T.whiteSpace
− Text/ParserCombinators/Parsec/IndentToken.hs
@@ -1,601 +0,0 @@-{-# OPTIONS_GHC -fglasgow-exts #-}--{---Haskell module for constructing indentation aware parser combinators.-Copyright (C) 2007 Piyush P Kurur, <http://www.cse.iitk.ac.in/~ppk>--This program is free software: you can redistribute it and/or modify-it under the terms of the GNU General Public License as published by-the Free Software Foundation, either version 3 of the License, or-(at your option) any later version.--This program is distributed in the hope that it will be useful,-but WITHOUT ANY WARRANTY; without even the implied warranty of-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-GNU General Public License for more details.--You should have received a copy of the GNU General Public License-along with this program. If not, see <http://www.gnu.org/licenses/>.- ---}--{-|--A module for constructing indentation aware tokeniser that can be used-in conjuction with @'Text.ParserCombinators.Parsec.Token'@. All the-combinator takes a @'Text.ParserCombinators.Parsec.Token.TokenParser'@-as its first argument. For every field @foo@ of-@'Text.ParserCombinators.Parsec.Token.TokenParser'@ this module-exports a combinator @foo@. To define a tokeniser for an indentation-based language a user first defines the appropriate-@'Text.ParserCombinators.Parsec.Language.LanguageDef'@ record, applies-the combinator @'Text.ParserCombinators.Parsec.Token.makeTokenParser'@-to get a @'Text.ParserCombinators.Parsec.Token.TokenParser'@ record-say @tokP@ and then, instead of selecting the field @foo@ of @tokP@,-applies the combinator @foo@ exported from this module to @tokP@. The-semantics of the combinator @foo@ is essentially same as that of the-field @foo@ of @'Text.ParserCombinators.Parsec.Token.TokenParser'@ but-the returned parsers are indentation aware. Apart from these there are-certain new combinators that are defined specifically for parsing-certain indentation based syntactic constructs. (We have not defined-squares use brackets instead)---There are two important classes of parser combinator exported by this-module:--[Grouping Parser Combinator] A grouping parser combinator takes as-input a parser say @p@ and returns a parser that parses @p@ between-two /grouping delimiters/. There are three flavours of grouping-parsers: @foo@, @fooOrBlock@ and @fooOrLineFold@ where @foo@ can be-one of @'angles'@, @'braces'@, @'parens'@, @'brackets'@ or To-illustrate we take @foo@ to be braces. The parser @braces tokP p@-parses @p@ delimited by '{' and '}'. In this case @p@ does not care-about indentation (i.e. the parser @p@ is run in-@'Text.ParserCombinators.Parsec.IndentParser.NoIndent'@ mode). The-parser @'bracesOrBlock' tokP p@ is like @braces tokP p@ but if no-explicit delimiting braces are given parses @p@ within an indented-block. Similarly @'bracesOrLineFold' tokP p@ parses @p@ between '{'-and '}' and uses line fold when no explicit braces are given. These-can be two varients can be defined as follows--> bracesOrBlock tokP p = braces tokP $ noIndent p <|> block p-> bracesOrLineFold tokP p = braces tokP $ noIndent p <|> lineFold p---[Seperator Parser Combinator] A seperator parser combinator takes as-input a parser say @p@ and returns a parser that parses a list of @p@-seperated by a seperator. The module exports the combinators @fooSep@,-@fooSep1@, @fooOrNewLineSep@ and @fooOrNewLineSep1@, where @foo@ is-either @semi@ (in which case the seperator is a semicolon ';') or-@comma@ (in which case the seperator is a comma ',').---To illustrate the use of this module we now give, as an incomplete-example, a parser that parses a where clause in Haskell which-illustrates the use of this module.-- -> import qualified Text.ParserCombinators.Parsec.Language as L-> import qualified Text.ParserCombinators.Parsec.Toke as T-> import qualified Text.ParserCombinator.Parsec.IndentToken as IT---> tokP = T.makeTokenParser L.haskellDef-> semiOrNewLineSep = IT.semiOrNewLineSep tokP-> bracesOrBlock = IT.bracesOrBlock tokP-> identifier = IT.identifier tokP-> ....-> symbol = IT.symbol tokP--> binding = semiOrNewLineSep bind-> bind = do id <- identifier-> symbol (char '=')-> e <- expr-> return (id,e)-> whereClause = do reserved "where"; braceOrBlock binding----}---module Text.ParserCombinators.Parsec.IndentToken- ( - -- * Types- IndentCharParser,- LanguageDef,- TokenParser,- -- * Combinators- identifier, reserved,- operator, reservedOp,- charLiteral, stringLiteral,- natural, integer, float, naturalOrFloat,- decimal, hexadecimal, octal,- semi, colon, dot,- lexeme, symbol, whiteSpace,- -- * Separator parser combinators- semiSep, semiSep1, commaSep, commaSep1,- semiOrNewLineSep, semiOrNewLineSep1,- commaOrNewLineSep, commaOrNewLineSep1,- -- * Grouping parser combinator- parens,parensOrBlock, parensOrLineFold,- braces, bracesOrBlock, bracesOrLineFold,- angles, anglesOrBlock, anglesOrLineFold,- brackets, bracketsOrBlock, bracketsOrLineFold- ) where--import Text.ParserCombinators.Parsec hiding (- getState,- setState,- parseTest,- runParser- )--import qualified Text.ParserCombinators.Parsec.Token as T-import qualified Text.ParserCombinators.Parsec.Language as L-import Text.ParserCombinators.Parsec.IndentParser--type IndentCharParser st a = IndentParser Char st a-type LanguageDef st = L.LanguageDef (IndentState st)-type TokenParser st = T.TokenParser (IndentState st)-----{-| Indentation aware parser to match a valid identifier of the-language. -}--identifier :: TokenParser st -> IndentCharParser st String-identifier = indentParser . T.identifier---{-| Indentation aware parser to match a reserved word of the language.--}--reserved :: TokenParser st ->- String -- ^ The reserved word to be matched.- -> IndentCharParser st ()-reserved tokP = indentParser . T.reserved tokP---{-| The parser @reserved tokP keyword@ parses the reserved word keyword.- The string keyword should have been declared as a reserved word in the - @'Text.ParserCombinator.Parserc.Language.LanguageDef'@- -record. -}--operator :: TokenParser st -> IndentCharParser st String-operator = indentParser . T.operator--{-|- Indentation aware parser to match a reserved operator of the language.--}--reservedOp :: TokenParser st ->- String- -- ^ The reserved operator to be matched. Should have- -- been declared as a reserved operator in the - -- @'Text.ParserCombinator.Parserc.Language.LanguageDef'@- -- record.- -> IndentCharParser st ()--reservedOp tokP = indentParser . T.reservedOp tokP------{-| Indentation aware parser to match a character literal (the syntax-is assumend to be that of Hasekell which matches that of most-programming language).--}--charLiteral :: TokenParser st -> IndentCharParser st Char-charLiteral = indentParser . T.charLiteral----{-| Indentation aware parser to match a string literal (the syntax is-assumend to be that of Hasekell which matches that of most programming-language).--}--stringLiteral :: TokenParser st -> IndentCharParser st String-stringLiteral = indentParser . T.stringLiteral---{-| Indentation aware parser to match a natural number. -}--natural :: TokenParser st -> IndentCharParser st Integer-natural = indentParser . T.natural--{-|- Indentation aware parser to match an integer.--}--integer :: TokenParser st -> IndentCharParser st Integer-integer = indentParser . T.integer--{-| Indentation aware parser to match a floating point number. -}--float :: TokenParser st -> IndentCharParser st Double -float = indentParser . T.float--{-| Indentation aware parser to match either a natural number or-Floating point number. -}--naturalOrFloat :: TokenParser st- -> IndentCharParser st (Either Integer Double)-naturalOrFloat = indentParser . T.naturalOrFloat---- | Indentation aware parser to match an integer in decimal.---decimal :: TokenParser st -> IndentCharParser st Integer-decimal = indentParser . T.decimal--{-| Indentation aware parser to match an integer in hexadecimal.-}--hexadecimal :: TokenParser st -> IndentCharParser st Integer-hexadecimal = indentParser . T.hexadecimal --{-| --Indentation aware parser to match an integer in ocatal.---}--octal :: TokenParser st -> IndentCharParser st Integer-octal = indentParser . T.octal---{-| Matches a semicolon and returns ';'. -}---semi :: TokenParser st -> IndentCharParser st String-semi = indentParser . T.semi--{-| Matches a comma and returns ",". -}--comma :: TokenParser st -> IndentCharParser st String-comma = indentParser . T.comma--{-| Matches a colon and returns ":". -}-colon :: TokenParser st -> IndentCharParser st String-colon = indentParser . T.colon--{-| Matches a dot and returns "." -}-dot :: TokenParser st -> IndentCharParser st String-dot = indentParser . T.dot---{-| Given an indentation aware parser @p@ as argument @semiSep tokP@- returns a parser that parses zero or more occurances of @p@- seperated by semicolon (';') -}--semiSep :: TokenParser st - -> IndentCharParser st a - -> IndentCharParser st [a]--semiSep tokP p = p `sepBy` semicolon- where semicolon = semi tokP---{-| Given an indentation aware parser @p@ as argument @semiSep1 tokP@- returns a parser that parses one or more occurances of @p@ seperated- by semicolon (';') -}---semiSep1 :: TokenParser st - -> IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st [a]--semiSep1 tokP p = p `sepBy1` semicolon- where semicolon = semi tokP----{-| Given an indentation aware parser @p@ as argument @commaSep tokP@- returns a parser that parses zero or more occurances of @p@- seperated by comma (',') -}--commaSep :: TokenParser st- -> IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st [a]--commaSep tokP p = p `sepBy` virgule- where virgule = comma tokP-----{-| Given an indentation aware parser @p@ as argument @commaSep1 tokP@- returns a parser that parses one or more occurances of @p@ seperated- by comma (',') -}---commaSep1 :: TokenParser st- -> IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st [a]--commaSep1 tokP p = p `sepBy1` virgule- where virgule = comma tokP-----{-| --Given an indentation aware parser @p@ as argument @semiOrNewLineSep1-tokP@ returns a parser that parses one or more occurances of @p@-seperated by either semicolons (';') or newline. To seperate multiple-occurance of @p@ in the same line use an explicit semicolon (';').---}--semiOrNewLineSep1 :: TokenParser st- -> IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st [a]--semiOrNewLineSep1 tokP p = do xs <- lineFold $ semiSep1 tokP p- rest <- semiOrNewLineSep tokP p- return (xs++rest)----{-| --Given an indentation aware parser @p@ as argument @semiOrNewLineSep-tokP@ returns a parser that parses zero or more occurances of @p@-seperated by either semicolons (';') or newlines. To seperate multiple-occurance of @p@ in the same line use an explicit semicolon (';').---}--semiOrNewLineSep :: TokenParser st- -> IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st [a]--semiOrNewLineSep tokP p = semiOrNewLineSep1 tokP p <|> return []------{-| --Given an indentation aware parser @p@ as argument @commaOrNewLineSep1-tokP@ returns a parser that parses one or more occurances of @p@-seperated by either comma (',') or newline. To seperate multiple-occurance of @p@ in the same line use an explicit comma (',').---}--commaOrNewLineSep1 :: TokenParser st- -> IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st [a]--commaOrNewLineSep1 tokP p = do xs <- lineFold $ semiSep1 tokP p- rest <- semiOrNewLineSep tokP p- return (xs++rest)----{-| --Given an indentation aware parser @p@ as argument @commaOrNewLineSep-tokP@ returns a parser that parses zero or more occurances of @p@-seperated by either comma (',') or newlines. To seperate multiple-occurance of @p@ in the same line use an explicit comma (',').---}--commaOrNewLineSep :: TokenParser st- -> IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st [a]--commaOrNewLineSep tokP p = commaOrNewLineSep1 tokP p <|> return []----{-|--The parser @parens tokP p@ parses @p@ between '(' and ')'. The parser-@p@ does not care about indentation i.e. @p@ is run in-@'Text.ParserCombinators.Parsec.IndentParser.NoIndent'@ mode.---}--parens :: TokenParser st ->- IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st a--parens tokP p = between (symbol tokP "(") (symbol tokP ")") (noIndent p)--{-| --Similar to @'parens'@ but when no explicit '(' and ')' are given,-groups @p@ by block indentation.---}--parensOrBlock :: TokenParser st -> - IndentCharParser st a -- ^ The input parser- -> IndentCharParser st a--parensOrBlock tokP p = parens tokP p <|> block p----{-| --Similar to @'parens'@ but when no explicit '(' and ')' are given,-groups @p@ by a line fold.---}-parensOrLineFold :: TokenParser st -> - IndentCharParser st a -- ^ The input parser- -> IndentCharParser st a--parensOrLineFold tokP p = parens tokP p <|> lineFold p---{-|--The parser @braces tokP p@ parses @p@ between '{' and '}'. The parser-@p@ does not care about indentation i.e. @p@ is run in-@'Text.ParserCombinators.Parsec.IndentParser.NoIndent'@ mode.---}--braces :: TokenParser st ->- IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st a--braces tokP p = between (symbol tokP "{") (symbol tokP "}") (noIndent p)----{-| --Similar to @'braces'@ but when no explicit '{' and '}' are given,-groups @p@ by block indentation.---}-bracesOrBlock :: TokenParser st -> - IndentCharParser st a -- ^ The input parser- -> IndentCharParser st a--bracesOrBlock tokP p = braces tokP p <|> block p---{-| --Similar to @'braces'@ but when no explicit '{' and '}' are given,-groups @p@ by a line fold.---}--bracesOrLineFold :: TokenParser st -> - IndentCharParser st a -- ^ The input parser- -> IndentCharParser st a--bracesOrLineFold tokP p = braces tokP p <|> lineFold p---{-|--The parser @angles tokP p@ parses @p@ between angles. The parser @p@-does not care about indentation i.e. @p@ is run in-@'Text.ParserCombinators.Parsec.IndentParser.NoIndent'@ mode.---}--angles :: TokenParser st ->- IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st a--angles tokP p = between (symbol tokP "<") (symbol tokP ">") (noIndent p)----{-| --Similar to @'angles'@ but when no explicit angles are given, groups-@p@ by block indentation.---}--anglesOrBlock :: TokenParser st -> - IndentCharParser st a -- ^ The input parser- -> IndentCharParser st a--anglesOrBlock tokP p = angles tokP p <|> block p---{-| --Similar to @'angles'@ but when no explicit angles are given, groups-@p@ by a line fold.---}--anglesOrLineFold :: TokenParser st -> - IndentCharParser st a -- ^ The input parser- -> IndentCharParser st a--anglesOrLineFold tokP p = angles tokP p <|> lineFold p----{-|--The parser @brackets tokP p@ parses @p@ between '[' and ']'. The-parser @p@ does not care about indentation i.e. @p@ is run in-@'Text.ParserCombinators.Parsec.IndentParser.NoIndent'@ mode.---}--brackets :: TokenParser st ->- IndentCharParser st a -- ^ The input Parser- -> IndentCharParser st a--brackets tokP p = between (symbol tokP "[") (symbol tokP "]") (noIndent p)----{-| --Similar to @'brackets'@ but when no explicit '[' and ']' are given,-groups @p@ by block indentation.---}-bracketsOrBlock :: TokenParser st -> - IndentCharParser st a -- ^ The input parser- -> IndentCharParser st a--bracketsOrBlock tokP p = brackets tokP p <|> block p---{-| --Similar to @'brackets'@ but when no explicit '[' and ']' are given,-groups @p@ by a line fold.---}--bracketsOrLineFold :: TokenParser st -> - IndentCharParser st a -- ^ The input parser- -> IndentCharParser st a--bracketsOrLineFold tokP p = brackets tokP p <|> lineFold p---{-|--Indentation aware parser that is equvalent to string str.---}--symbol :: TokenParser st - -> String - -> IndentCharParser st String-symbol tokP = indentParser . T.symbol tokP---{-| Creates a lexeme parser. The resultant parser skips trailing-spaces and is indentation aware. -}--lexeme :: TokenParser st - -> IndentCharParser st a -- ^ The input parser.- -> IndentCharParser st a--lexeme tokP = indentParser . T.lexeme tokP--{-| The parser whiteSpace skips spaces and comments. This does not-care about indentation as skipping spaces should be done irrespective-of the indentation. -}--whiteSpace :: TokenParser st -> IndentCharParser st ()-whiteSpace = T.whiteSpace