indentparser (empty) → 0.1
raw patch · 8 files changed
+941/−0 lines, 8 filesdep +basedep +mtldep +parsecsetup-changed
Dependencies added: base, mtl, parsec
Files
- Setup.lhs +3/−0
- UNLICENSE +24/−0
- examples/simple-expression.hs +69/−0
- indentparser.cabal +53/−0
- src/Text/Parsec/IndentParsec.hs +58/−0
- src/Text/Parsec/IndentParsec/Combinator.hs +82/−0
- src/Text/Parsec/IndentParsec/Prim.hs +173/−0
- src/Text/Parsec/IndentParsec/Token.hs +479/−0
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ UNLICENSE view
@@ -0,0 +1,24 @@+This is free and unencumbered software released into the public domain.++Anyone is free to copy, modify, publish, use, compile, sell, or+distribute this software, either in source code form or as a compiled+binary, for any purpose, commercial or non-commercial, and by any+means.++In jurisdictions that recognize copyright laws, the author or authors+of this software dedicate any and all copyright interest in the+software to the public domain. We make this dedication for the benefit+of the public at large and to the detriment of our heirs and+successors. We intend this dedication to be an overt act of+relinquishment in perpetuity of all present and future rights to this+software under copyright law.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR+OTHER DEALINGS IN THE SOFTWARE.++For more information, please refer to <http://unlicense.org/>
+ examples/simple-expression.hs view
@@ -0,0 +1,69 @@+import Text.Parsec+import Text.Parsec.Prim+import Text.Parsec.IndentParsec(runGIPT)++import Control.Monad.Identity+import Text.Parsec.Token (makeTokenParser, GenLanguageDef(..))+import qualified Text.Parsec.IndentParsec.Token as IT+import Text.Parsec.IndentParsec.Prim++data Expr = Const Integer+ | Var String+ | WhereClause Expr [Binding] deriving Show++type Binding = (String, Expr)++langDef = LanguageDef { commentStart = "{-"+ , commentEnd = "-}"+ , commentLine = "--"+ , identStart = letter <|> char '_'+ , identLetter = alphaNum <|> char '_'+ , opStart = oneOf "-+/*=<>"+ , opLetter = oneOf "-+/*=<>"+ , reservedNames = [ "where" ]+ , reservedOpNames = [ "=" , "+" , "-", "*", "/"]+ , caseSensitive = False+ , nestedComments = True+ }++tokP :: IT.IndentTokenParser String () Identity+tokP = makeTokenParser langDef++identifier = IT.identifier tokP+integer = IT.integer tokP+semiSep = IT.semiSepOrFoldedLines tokP+kwWhere = IT.reserved tokP "where"+assigns = IT.reservedOp tokP "="+++main = do inp <- getContents+ let x = runGIPT prog () "<stdin>" inp+ in case runIdentity x of+ Right bs -> sequence_ $ map print bs+ Left e -> do putStr "parse error: "+ print e++prog :: IndentParsecT String () Identity [Binding]+prog = do IT.whiteSpace tokP+ semiSep binding++expression = fmap Const integer+ <|> fmap Var identifier+ <|> do e <- expression+ kwWhere+ bs <- IT.bracesBlock tokP bindings+ return $ WhereClause e bs++compoundExpression = do e <- expression+ whereBlock e++whereBlock e = do try kwWhere+ bs <- IT.bracesBlock tokP bindings+ return $ WhereClause e bs+ <|> return e++bindings = semiSep binding+binding = do x <- identifier+ assigns+ e <- compoundExpression+ return (x,e)
+ indentparser.cabal view
@@ -0,0 +1,53 @@+Name: indentparser+Version: 0.1+Synopsis: A parser for indentation based structures+Homepage: http://www.cse.iitk.ac.in/users/ppk/code/HASKELL/indentparser++Description: This is a complete rewrite of the Indentparser+ package. Using the monad transformer structer of parsec 3, the+ code has been greatly simplified. Besides these changes+ the code is now in public domain.++License: PublicDomain+License-file: UNLICENSE+Author: Piyush P Kurur+Maintainer: ppk@cse.iitk.ac.in+Copyright: I, Piyush P Kurur, hereby release the software to the public domain+ I, however, do not give any warrenties what so ever. Please refer to the+ accompanying file UNLICENSE for more details.++ Also see http://cr.yp.to/publicdomain.html for an explanation of+ what it means to release under public domain in the United States+ of America.++Category: Text+Build-type: Simple+Cabal-version: >=1.6++Flag examples+ Description: Build the example code.+ Default: False++Library+ Hs-source-dirs: src+ GHC-options: -Wall+ Exposed-modules: Text.Parsec.IndentParsec+ , Text.Parsec.IndentParsec.Prim+ , Text.Parsec.IndentParsec.Combinator+ , Text.Parsec.IndentParsec.Token+ Build-depends: base >= 4.0 && < 5+ , mtl >= 2.0 && < 3+ , parsec >= 3.0 && < 4++Executable simple-expression+ Hs-source-dirs:examples, src+ Main-is:simple-expression.hs+ if !flag(examples)+ Buildable:False+ else+ Build-depends: parsec >= 3.0++Source-repository this+ type: darcs+ location: http://patch-tag.com/r/ppk/indentparser+ tag: 0.1-RELEASE
+ src/Text/Parsec/IndentParsec.hs view
@@ -0,0 +1,58 @@+{-|++A module to construct indentation aware parsers. Many programming+language have indentation based syntax rules e.g. python and Haskell.+This module exports combinators to create such parsers. This is a+rewrite of the IndentParser package. There are a few changes in the+names of functions besides the underlying code is simplified.++The input source can be thought of as a list of tokens. Abstractly+each token occurs at a line and a column and has a width. The column+number of a token measures is indentation. If t1 and t2 are two tokens+then we say that indentation of t1 is more than t2 if the column+number of occurrence of t1 is greater than that of t2.++Currently this module supports two kind of indentation based syntactic+structures which we now describe:++[Block] A block of indentation /c/ is a sequence of tokens with+indentation at least /c/. Examples for a block is a where clause of+Haskell with no explicit braces.++[Line fold] A line fold starting at line /l/ and indentation /c/ is a+sequence of tokens that start at line /l/ and possibly continue to+subsequent lines as long as the indentation is greater than /c/. Such+a sequence of lines need to be /folded/ to a single line. An example+is MIME headers. Line folding based binding separation is used in+Haskell as well.++For indentation based grammars notice the following should be true++1. Combinators for skipping whitespace/comments should skip spaces and+comments no matter what the indentation is.++2. All tokenisers of the language should check for indentation. The+combinator `tokeniser` makes its input parser indentation aware. Use+it on all tokenisers of the language.++3. All tokenisers themselves should skip trailing whitespaces and+comments, i.e. they should be lexeme parsers. Otherwise, the will be+problem matching the next token.++A block can then be parsed using the combinator 'blockOf' and a line+fold using 'foldedLinesOf'.++Generating indentation aware tokenisers could be tricky. One can use+the module "Text.Parsec.IndentParsec.Token" for this.++-}++module Text.Parsec.IndentParsec+ ( module Text.Parsec.IndentParsec.Prim+ , module Text.Parsec.IndentParsec.Combinator+ , module Text.Parsec.IndentParsec.Token+ ) where++import Text.Parsec.IndentParsec.Prim+import Text.Parsec.IndentParsec.Combinator+import Text.Parsec.IndentParsec.Token
+ src/Text/Parsec/IndentParsec/Combinator.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE FlexibleContexts #-}+{-|++Module containing combinators to parse some indentation based+structures.++-}++module Text.Parsec.IndentParsec.Combinator+ ( blockOf+ , foldedLinesOf+ , between+ , betweenBlock+ ) where++import Text.Parsec.Prim+import Text.Parsec.IndentParsec.Prim++-- | run a given parser inside a block.+blockOf :: (Monad m, Show t, Stream s (IndentT HaskellLike m) t)+ => IndentParsecT s u m a+ -> IndentParsecT s u m a+blockOf = nest Block++-- | run a given parser inside a line fold.+foldedLinesOf :: (Monad m, Show t, Stream s (IndentT HaskellLike m) t)+ => IndentParsecT s u m a+ -> IndentParsecT s u m a+foldedLinesOf = nest LineFold+++{-|++Similar to @`Text.Parsec.Combinator.between`@. However, the+@`Text.Parsec.Combinator.between`@ will not work as expected because+it will not turn off the indentation check of its input parser.++So something like++> whereClause = between lbrack rbrack bindings+> lbrack = do char '{'; spaces+> rbrack = do char '}'; spaces++will not be able to parse say++> where {+> a = 10+> }++Use the version exported by this module instead.++-}++between :: (Monad m, Indentation i, Show t, Show i, Stream s (IndentT i m) t)+ => GenIndentParsecT i s u m open -- ^ the opening delimiter+ -> GenIndentParsecT i s u m close -- ^ the closing delimiter+ -> GenIndentParsecT i s u m a -- ^ the contents+ -> GenIndentParsecT i s u m a++between open close p = do _ <- try open+ a <- neglectIndent p+ _ <- neglectIndent close+ return a+{-|++Similar to @`between`@ but if the opening and closing delimiters are+not given, uses a block to delimit the nesting. For example, a haskell+where clause will look like++> whereClause = betweenBlock lbrack rbrack bindings+> lbrack = do char '{'; spaces+> rbrack = do char '}'; spaces++-}++betweenBlock :: (Monad m, Stream s (IndentT HaskellLike m) t, Show t)+ => IndentParsecT s u m open -- ^ opening delimitor+ -> IndentParsecT s u m close -- ^ closing delimitor+ -> IndentParsecT s u m a -- ^ the contents parser+ -> IndentParsecT s u m a++betweenBlock open close p = between open close p <|> blockOf p
+ src/Text/Parsec/IndentParsec/Prim.hs view
@@ -0,0 +1,173 @@+{-# LANGUAGE FlexibleContexts #-}+{-|++In general, an indentation structure is a predicate on the position+which tells us whether the token is acceptable or not. Besides the+predicate to check if a token at a given position is acceptable, we+also need to specify how indentations can be nested. This is captured+by the type class `Indentation`.++-}++module Text.Parsec.IndentParsec.Prim+ ( Indentation(..)+ , GenIndentParsecT+ , tokeniser+ , nest+ , neglectIndent+ , HaskellLike(..)+ -- * Running parsers+ , runGIPT', runGIPT+ -- * Some convenient type aliases.+ , IndentT+ , GenIndentParsec+ , IndentParsecT+ , IndentParsec+ ) where++import Control.Monad.State+import Control.Monad.Identity++import Text.Parsec.Prim+import Text.Parsec.Error+import Text.Parsec.Pos+import Text.Parsec.Combinator++{-|++Type class that captures generic indentation rule. It should follow+the condition that @`acceptable` `never` = `const` `False`@.++-}++class Indentation i where+ never :: i -- ^ an indentation state where no tokens are+ -- accepted.+ always :: i -- ^ an indentation that will always accept+ -- tokens.+ acceptable :: i -> SourcePos -> Bool -- ^ Check if the current+ -- position is acceptable.+ nestableIn :: i -- ^ Inner indentation.+ -> i -- ^ Outer indentation.+ -> Bool -- ^ True if the inner indentation can nest+ -- inside the outer indentations.++-- | The inner monad for indent parsers.+type IndentT i m = StateT i m++-- | The indentation parser.+type GenIndentParsecT i s u m a = ParsecT s u (IndentT i m) a++-- | Build indentation awareness into the parser+tokeniser :: (Indentation i, Monad m)+ => GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m a+tokeniser p = do pos <- getPosition+ i <- lift get+ if acceptable i pos then p+ else fail $ "unexpected token at " ++ show pos++{-|++Any nested indentation starts at a position. Given an indentor+function, i.e. a function to compute the indentation state from the+current position, and a parser to parse the body of the indentation,+runs the parser inside the nested indentation context given by the+indentor.++-}++nest :: (Indentation i, Show i, Monad m, Stream s (IndentT i m) t, Show t)+ => (SourcePos -> i) -- ^ indentor function.+ -> GenIndentParsecT i s u m body -- ^ The nested parser to run+ -> GenIndentParsecT i s u m body+nest indentor p = do outerI <- lift get+ curPos <- getPosition+ let innerI = indentor curPos+ in if innerI `nestableIn` outerI+ then nestP innerI outerI p+ else nestP never outerI p++nestP :: (Indentation i, Show i, Monad m, Stream s (IndentT i m) t, Show t)+ => i -- ^ Inner indentation+ -> i -- ^ Outer indentation+ -> GenIndentParsecT i s u m body -- ^ body parser+ -> GenIndentParsecT i s u m body++nestP i o p = do lift $ put i+ x <- p+ notFollowedBy (tokeniser anyToken)+ <?> "unterminated " ++ show i+ lift $ put o+ return x++-- | run a given parser neglecting indentation.+neglectIndent :: (Monad m, Show t, Show i, Indentation i,+ Stream s (IndentT i m) t)+ => GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m a++neglectIndent p = do o <- get+ lift $ put always+ x <- p+ lift $ put o+ return x++-- | Run a given indentation aware parser with a starting indentation.+runGIPT' :: (Monad m, Stream s (IndentT i m) t)+ => i -- ^ The starting indentation,+ -> GenIndentParsecT i s u m a -- ^ The parser to run,+ -> u -- ^ The user state,+ -> SourceName -- ^ Name of the input source,+ -> s -- ^ The actual stream,+ -> m (Either ParseError a) -- ^ The result++runGIPT' i p u sname s = evalStateT (runPT p u sname s) i++-- | Same as @`runGIPT'` always@.+runGIPT :: (Monad m, Indentation i, Stream s (IndentT i m) t)+ => GenIndentParsecT i s u m a -- ^ The parser to run,+ -> u -- ^ The user state,+ -> SourceName -- ^ Name of the input source,+ -> s -- ^ The actual stream,+ -> m (Either ParseError a) -- ^ The result.++runGIPT = runGIPT' always++{-|++Type to capture Haskell like indentation. Besides `always` and `never`+the important indentations are blocks and line folds. A block starting+at position @p@ consists of all tokens that have indentation at least+as much as @p@. A folded like starting at position @p@ is++-}+data HaskellLike = Never+ | Neglect+ | Block SourcePos+ | LineFold SourcePos++instance Indentation HaskellLike where+ never = Never+ always = Neglect++ acceptable Never _ = False+ acceptable Neglect _ = True+ acceptable (Block bp) p = sourceColumn bp <= sourceColumn p+ acceptable (LineFold lp) p = sourceColumn lp < sourceColumn p ||+ lp == p+ nestableIn (Block i) (Block o) = sourceColumn o < sourceColumn i+ nestableIn (Block i) (LineFold o) = sourceColumn o < sourceColumn i+ nestableIn (LineFold i) (LineFold o) = sourceColumn o < sourceColumn i+ nestableIn (LineFold i) (Block o) = sourceColumn o <= sourceColumn i+ nestableIn _ _ = True++instance Show HaskellLike where+ show Never = "empty block"+ show Neglect = "unindented chunk"+ show (Block pos) = "block started at " ++ show pos+ show (LineFold pos) = "line fold started at " ++ show pos++type GenIndentParsec i s u a = GenIndentParsecT i s u Identity a+type IndentParsecT s u m a = GenIndentParsecT HaskellLike s u m a+type IndentParsec s u a = IndentParsecT s u Identity a
+ src/Text/Parsec/IndentParsec/Token.hs view
@@ -0,0 +1,479 @@+{-# LANGUAGE FlexibleContexts #-}+{-|++Module to create indentation aware tokenisers. Despite the simplicity+of parser combinators, getting tokenisers for common language+contructs right is tricky. The parsec way of handling this involves+the following steps.++ * Define the description of the language via the+ @`Text.Parsec.Language.LanguageDef`@ record.++ * Apply the 'Text.Parsec.Token.makeTokenParser' combinator get hold+ of @'Text.Parsec.Token.TokenParser'@. The actual tokenisers are+ the fields of this record.++This module provides a similar interfaces for generating indentation+aware tokenisers. There are few specific things that an indentation+aware tokeniser should be careful aboute++ 1. All tokenisers should be indentation aware.++ 2. Whitespaces and comments should be skipped irrespective on which+ indentation mode one is in++ 3. The tokenisers should themselves be lexeme parsers and should skip trailing+ whitespace.++Getting all this working can often be tricky.++-}++module Text.Parsec.IndentParsec.Token+ (+ -- * Usage.+ -- $usage+ GenIndentTokenParser+ , IndentTokenParser+ , identifier+ , operator+ , reserved+ , reservedOp+ , charLiteral+ , stringLiteral+ , natural+ , integer+ , float+ , naturalOrFloat+ , decimal+ , hexadecimal+ , octal+ , symbol+ , lexeme+ , whiteSpace+ , semi+ , comma+ , colon+ , dot+ , parens, parensBlock+ , braces, bracesBlock+ , angles, anglesBlock+ , brackets, bracketsBlock+ , semiSep, semiSepOrFoldedLines+ , semiSep1, semiSepOrFoldedLines1+ , commaSep, commaSepOrFoldedLines+ , commaSep1, commaSepOrFoldedLines1+ ) where+++import Text.Parsec.IndentParsec.Prim+import Text.Parsec.IndentParsec.Combinator+import Text.Parsec(many)++import qualified Text.Parsec.Token as T+import Text.Parsec(Stream)+import Text.Parsec.Combinator hiding (between)+++{- $usage++For each combinator @foo@ for every field @foo@ of the+'Text.Parsec.Token.TokenParser' with essentially the same semantics+but for the returned parser being indentation aware. There are certain+new combinators that are defined specifically for parsing indentation+based syntactic constructs:++[Grouping Parsers] A grouping parser takes an input parser @p@ and+returns a parser that parses @p@ between two /grouping delimiters/.+There are three flavours of grouping parsers: @foo@, @fooBlock@ where+@foo@ can be one of @angles@, @braces@, @parens@, @brackets@. For+example, consider the parser @'braces' tokP p@ parses @p@ delimited by+'{' and '}'. In this case @p@ does not care about indentation. The+parser @'bracesBlock' tokP p@ is like @braces tokP p@ but if no+explicit delimiting braces are given parses @p@ within an indented+block.++> bracesBlock tokP p = braces tokP p <|> blockOf p++[Seperator Parsers] A seperator parser 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@,+@fooSepOrFoldedLines@ and @fooSepOrFoldedLines1@, 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.Parsec.Language as L+> import qualified Text.Parsec.Toke as T+> import qualified Text.Parsec.IndentToken as IT+> tokP = T.makeTokenParser L.haskellDef+> mySemiSep = IT.semiSepOrFoldedLines tokP+> myBraces = IT.bracesBlock tokP+> identifier = IT.identifier tokP+> ....+> symbol = IT.symbol tokP+>+> binding = mySemiSep bind+> bind = do id <- identifier+> symbol (char '=')+> e <- expr+> return (id,e)+>+> whereClause = do reserved "where"; braceBlock binding++-}++type GenIndentTokenParser i s u m = T.GenTokenParser s u (IndentT i m)+type IndentTokenParser s u m = GenIndentTokenParser HaskellLike s u m++-- | Indentation aware tokeniser to match a valid identifier.+identifier :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+identifier = tokeniser . T.identifier++-- | Indentation aware tokeniser matches an operator.+operator :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+operator = tokeniser . T.operator++-- | Indentation aware tokeniser to match a reserved word.+reserved :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> String -- ^ The reserved word.+ -> GenIndentParsecT i s u m ()+reserved tokP = tokeniser . T.reserved tokP++-- | Indentation aware parser to match a reserved operator of the+-- language.+reservedOp :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> String -- ^ The reserved operator to be matched.+ -> GenIndentParsecT i s u m ()+reservedOp tokP = tokeniser . 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 :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m Char+charLiteral = tokeniser . 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 :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+stringLiteral = tokeniser . T.stringLiteral++-- | Indentation aware parser to match a natural number.+natural :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m Integer+natural = tokeniser . T.natural++-- | Indentation aware parser to match an integer.+integer :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m Integer+integer = tokeniser . T.integer++-- | Indentation aware tokeniser to match a floating point number.+float :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m Double+float = tokeniser . T.float++-- | Indentation aware tokensier to match either a natural number or+-- Floating point number.+naturalOrFloat :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m (Either Integer Double)+naturalOrFloat = tokeniser . T.naturalOrFloat++-- | Indentation aware tokensier to match an integer in decimal.+decimal :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m Integer+decimal = tokeniser . T.decimal++-- | Indentation aware tokeniser to match an integer in hexadecimal.+hexadecimal :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m Integer+hexadecimal = tokeniser . T.hexadecimal++-- | Indentation aware tokeniser to match an integer in ocatal.+octal :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m Integer+octal = tokeniser . T.octal++-- | Indentation aware tokeniser that is equvalent to @`string`@.+symbol :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> String+ -> GenIndentParsecT i s u m String+symbol tokP = tokeniser . T.symbol tokP++-- | Creates a lexeme tokeniser. The resultant tokeniser indentation+-- aware and skips trailing white spaces/comments.+lexeme :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m a+lexeme tokP = tokeniser . 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 :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m ()+whiteSpace = T.whiteSpace++-- | Matches a semicolon and returns ';'.+semi :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+semi = tokeniser . T.semi++-- | Matches a comma and returns ",".+comma :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+comma = tokeniser . T.comma++-- | Matches a colon and returns ":".+colon :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+colon = tokeniser . T.colon++-- | Matches a dot and returns ".".+dot :: (Indentation i, Monad m)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+dot = tokeniser . T.dot++lparen :: (Monad m, Indentation i)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+rparen :: (Monad m, Indentation i)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+lbrace :: (Monad m, Indentation i)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+rbrace :: (Monad m, Indentation i)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+langle :: (Monad m, Indentation i)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+rangle :: (Monad m, Indentation i)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+lbracket :: (Monad m, Indentation i)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String+rbracket :: (Monad m, Indentation i)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m String++lparen tokP = symbol tokP "("+rparen tokP = symbol tokP ")"++lbrace tokP = symbol tokP "{"+rbrace tokP = symbol tokP "}"++langle tokP = symbol tokP "<"+rangle tokP = symbol tokP ">"++lbracket tokP = symbol tokP "["+rbracket tokP = symbol tokP "]"++-- | Match the input parser @p@ within a pair of paranthesis.++parens :: (Indentation i, Show i,+ Monad m, Stream s (IndentT i m) t, Show t)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m a+parens tokP = lparen tokP `between` rparen tokP++{-|++Same as `parens` but if no explicit paranthesis are given, matches @p@+inside an indented block.++-}++parensBlock :: (Monad m, Stream s (IndentT HaskellLike m) t, Show t)+ => GenIndentTokenParser HaskellLike s u m+ -> GenIndentParsecT HaskellLike s u m a+ -> GenIndentParsecT HaskellLike s u m a+parensBlock tokP = lparen tokP `betweenBlock` rparen tokP++-- | Match the input parser @p@ within a pair of braces+braces :: (Indentation i, Show i,+ Monad m, Stream s (IndentT i m) t, Show t)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m a+braces tokP = lbrace tokP `between` rbrace tokP++{-|++Same as `braces` but if no explicit braces are given, matches @p@+inside an indented block.++-}++bracesBlock :: (Monad m, Stream s (IndentT HaskellLike m) t, Show t)+ => GenIndentTokenParser HaskellLike s u m+ -> GenIndentParsecT HaskellLike s u m a+ -> GenIndentParsecT HaskellLike s u m a+bracesBlock tokP = lbrace tokP `betweenBlock` rbrace tokP++{-|++Match the input parser @p@ within a pair of angular brackets, i.e. '<'+and '>'.++-}+angles :: (Indentation i, Show i, Monad m, + Stream s (IndentT i m) t, Show t)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m a+angles tokP = langle tokP `between` rangle tokP++{-|++Same as `angles` but if no explicit anglular brackets are given,+matches p inside and indented block.++-}++anglesBlock :: (Monad m, Stream s (IndentT HaskellLike m) t, Show t)+ => GenIndentTokenParser HaskellLike s u m+ -> GenIndentParsecT HaskellLike s u m a+ -> GenIndentParsecT HaskellLike s u m a+anglesBlock tokP = langle tokP `betweenBlock` rangle tokP++-- | Match p within a angular brackets i.e. '[' and ']'.+brackets :: (Indentation i, Show i, Monad m, Stream s (IndentT i m) t, Show t)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m a+brackets tokP = lbracket tokP `between` rbracket tokP++{-|++Same as `brackets` but if no explicit brackets are given, matches p+inside and indented block.++-}++bracketsBlock :: (Monad m, Stream s (IndentT HaskellLike m) t, Show t)+ => GenIndentTokenParser HaskellLike s u m+ -> GenIndentParsecT HaskellLike s u m a+ -> GenIndentParsecT HaskellLike s u m a+bracketsBlock tokP = lbracket tokP `betweenBlock` rbracket tokP++-- | Parse zero or more @p@ seperated by by a semicolon+semiSep :: (Indentation i, Monad m, Stream s (IndentT i m) t, Show t)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m [a]+semiSep tokP p = sepBy p $ semi tokP++-- | Parse one or more @p@ seperated by a semicolon+semiSep1 :: (Indentation i, Monad m, Stream s (IndentT i m) t, Show t)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m [a]+semiSep1 tokP p = sepBy1 p $ semi tokP++{-|++Parse zero or more @p@ seperated by semicolon or new line. Long lines+are continued using line folding.++-}+semiSepOrFoldedLines :: (Monad m, Stream s (IndentT HaskellLike m ) t, Show t)+ => GenIndentTokenParser HaskellLike s u m+ -> GenIndentParsecT HaskellLike s u m a+ -> GenIndentParsecT HaskellLike s u m [a]+semiSepOrFoldedLines tokP p = fmap concat . many+ . foldedLinesOf+ . sepEndBy1 p+ $ semi tokP++{-|++Parse one or more @p@ seperated by semicolon or new line. Long lines+are continued using line folding.++-}+semiSepOrFoldedLines1 :: (Monad m, Stream s (IndentT HaskellLike m ) t, Show t)+ => GenIndentTokenParser HaskellLike s u m+ -> GenIndentParsecT HaskellLike s u m a+ -> GenIndentParsecT HaskellLike s u m [a]+semiSepOrFoldedLines1 tokP p = do first <- foldedLinesOf . sepEndBy1 p+ $ semi tokP+ rest <- semiSepOrFoldedLines tokP p+ return (first ++ rest)+++-- | Parse zero or more @p@ seperated by by a comma.+commaSep :: (Indentation i, Monad m, Stream s (IndentT i m) t, Show t)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m [a]+commaSep tokP p = sepBy p $ comma tokP++-- | Parse one or more @p@ seperated by a comma.+commaSep1 :: (Indentation i, Monad m, Stream s (IndentT i m) t, Show t)+ => GenIndentTokenParser i s u m+ -> GenIndentParsecT i s u m a+ -> GenIndentParsecT i s u m [a]+commaSep1 tokP p = sepBy1 p $ comma tokP++{-|++Parse zero or more @p@ seperated by comma or new line. Long lines are+continued using line folding.++-}+commaSepOrFoldedLines :: (Monad m, Stream s (IndentT HaskellLike m ) t, Show t)+ => GenIndentTokenParser HaskellLike s u m+ -> GenIndentParsecT HaskellLike s u m a+ -> GenIndentParsecT HaskellLike s u m [a]+commaSepOrFoldedLines tokP p = fmap concat . many+ . foldedLinesOf+ . sepEndBy1 p+ $ comma tokP++{-|++Parse one or more @p@ seperated by comma or new line. Long lines are+continued using line folding.++-}+commaSepOrFoldedLines1 :: (Monad m, Stream s (IndentT HaskellLike m ) t, Show t)+ => GenIndentTokenParser HaskellLike s u m+ -> GenIndentParsecT HaskellLike s u m a+ -> GenIndentParsecT HaskellLike s u m [a]+commaSepOrFoldedLines1 tokP p = do first <- foldedLinesOf . sepEndBy1 p+ $ comma tokP+ rest <- commaSepOrFoldedLines tokP p+ return (first ++ rest)