-- |
-- Module      :  Configuration.Dotenv.Types
-- Copyright   :  © 2015–2020 Stack Builders Inc.
-- License     :  MIT
--
-- Maintainer  :  Stack Builders <hackage@stackbuilders.com>
-- Stability   :  experimental
-- Portability :  portable
--
-- Parser for files in dotenv format. These files generally consist of lines
-- with the form key=value. Comments and blank lines are also supported. More
-- information on the dotenv format can be found in the project README and the
-- test suite.

{-# LANGUAGE OverloadedStrings #-}

module Configuration.Dotenv.Parse (configParser) where

import           Configuration.Dotenv.ParsedVariable
import           Control.Applicative                 (empty, many, some, (<|>))
import           Control.Monad                       (void)
import           Data.Void                           (Void)
import qualified ShellWords
import           Text.Megaparsec                     (Parsec, anySingle,
                                                      between, eof, noneOf,
                                                      oneOf, sepEndBy, (<?>))
import           Text.Megaparsec.Char                (char, digitChar, eol,
                                                      letterChar, spaceChar)
import qualified Text.Megaparsec.Char.Lexer          as L

type Parser = Parsec Void String

data QuoteType = SingleQuote | DoubleQuote

-- | Returns a parser for a Dotenv configuration file. Accepts key and value
-- arguments separated by @=@. Comments in all positions are handled
-- appropriately.
configParser :: Parser [ParsedVariable]
configParser :: Parser [ParsedVariable]
configParser = ParsecT Void [Char] Identity ()
-> ParsecT Void [Char] Identity ()
-> Parser [ParsedVariable]
-> Parser [ParsedVariable]
forall (m :: * -> *) open close a.
Applicative m =>
m open -> m close -> m a -> m a
between ParsecT Void [Char] Identity ()
scn ParsecT Void [Char] Identity ()
forall e s (m :: * -> *). MonadParsec e s m => m ()
eof (ParsecT Void [Char] Identity ParsedVariable
-> ParsecT Void [Char] Identity (Tokens [Char])
-> Parser [ParsedVariable]
forall (m :: * -> *) a sep. MonadPlus m => m a -> m sep -> m [a]
sepEndBy ParsecT Void [Char] Identity ParsedVariable
envLine (ParsecT Void [Char] Identity (Tokens [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Tokens s)
eol ParsecT Void [Char] Identity (Tokens [Char])
-> ParsecT Void [Char] Identity ()
-> ParsecT Void [Char] Identity (Tokens [Char])
forall a b.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity b -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ParsecT Void [Char] Identity ()
scn))

-- | Parse a single environment variable assignment.
envLine :: Parser ParsedVariable
envLine :: ParsecT Void [Char] Identity ParsedVariable
envLine = [Char] -> VarValue -> ParsedVariable
ParsedVariable ([Char] -> VarValue -> ParsedVariable)
-> ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity (VarValue -> ParsedVariable)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity [Char]
forall a. Parser a -> Parser a
lexeme ParsecT Void [Char] Identity [Char]
variableName ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity [Char]
forall a b.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity b -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity Char
forall a. Parser a -> Parser a
lexeme (Token [Char] -> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token [Char]
'=')) ParsecT Void [Char] Identity (VarValue -> ParsedVariable)
-> ParsecT Void [Char] Identity VarValue
-> ParsecT Void [Char] Identity ParsedVariable
forall a b.
ParsecT Void [Char] Identity (a -> b)
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ParsecT Void [Char] Identity VarValue
-> ParsecT Void [Char] Identity VarValue
forall a. Parser a -> Parser a
lexeme ParsecT Void [Char] Identity VarValue
value

-- | Variables must start with a letter or underscore, and may contain
-- letters, digits or '_' character after the first character.
variableName :: Parser VarName
variableName :: ParsecT Void [Char] Identity [Char]
variableName = ((:) (Char -> [Char] -> [Char])
-> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity ([Char] -> [Char])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Void [Char] Identity Char
firstChar ParsecT Void [Char] Identity ([Char] -> [Char])
-> ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity [Char]
forall a b.
ParsecT Void [Char] Identity (a -> b)
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity [Char]
forall a.
ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ParsecT Void [Char] Identity Char
otherChar) ParsecT Void [Char] Identity [Char]
-> [Char] -> ParsecT Void [Char] Identity [Char]
forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> [Char] -> m a
<?> [Char]
"variable name"
  where
    firstChar :: ParsecT Void [Char] Identity Char
firstChar = Token [Char] -> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token [Char]
'_'  ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity Char
forall a.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ParsecT Void [Char] Identity Char
ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
letterChar
    otherChar :: ParsecT Void [Char] Identity Char
otherChar = ParsecT Void [Char] Identity Char
firstChar ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity Char
forall a.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ParsecT Void [Char] Identity Char
ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
digitChar

-- | Value: quoted or unquoted.
value :: Parser VarValue
value :: ParsecT Void [Char] Identity VarValue
value = (ParsecT Void [Char] Identity VarValue
quotedValue ParsecT Void [Char] Identity VarValue
-> ParsecT Void [Char] Identity VarValue
-> ParsecT Void [Char] Identity VarValue
forall a.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ParsecT Void [Char] Identity VarValue
unquotedValue) ParsecT Void [Char] Identity VarValue
-> [Char] -> ParsecT Void [Char] Identity VarValue
forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> [Char] -> m a
<?> [Char]
"variable value"
  where
    quotedValue :: ParsecT Void [Char] Identity VarValue
quotedValue   = QuoteType -> ParsecT Void [Char] Identity VarValue
quotedWith QuoteType
SingleQuote ParsecT Void [Char] Identity VarValue
-> ParsecT Void [Char] Identity VarValue
-> ParsecT Void [Char] Identity VarValue
forall a.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> QuoteType -> ParsecT Void [Char] Identity VarValue
quotedWith QuoteType
DoubleQuote
    unquotedValue :: ParsecT Void [Char] Identity VarValue
unquotedValue = VarContents -> VarValue
Unquoted (VarContents -> VarValue)
-> ParsecT Void [Char] Identity VarContents
-> ParsecT Void [Char] Identity VarValue
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Void [Char] Identity VarFragment
-> ParsecT Void [Char] Identity VarContents
forall a.
ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ([Char] -> ParsecT Void [Char] Identity VarFragment
fragment [Char]
"\'\" \t\n\r")

-- | Parse a value quoted with given character.
quotedWith :: QuoteType -> Parser VarValue
quotedWith :: QuoteType -> ParsecT Void [Char] Identity VarValue
quotedWith QuoteType
SingleQuote = VarContents -> VarValue
SingleQuoted (VarContents -> VarValue)
-> ParsecT Void [Char] Identity VarContents
-> ParsecT Void [Char] Identity VarValue
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity VarContents
-> ParsecT Void [Char] Identity VarContents
forall (m :: * -> *) open close a.
Applicative m =>
m open -> m close -> m a -> m a
between (Token [Char] -> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token [Char]
'\'') (Token [Char] -> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token [Char]
'\'') (ParsecT Void [Char] Identity VarFragment
-> ParsecT Void [Char] Identity VarContents
forall a.
ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ([Char] -> ParsecT Void [Char] Identity VarFragment
literalValueFragment [Char]
"\'\\"))
quotedWith QuoteType
DoubleQuote = VarContents -> VarValue
DoubleQuoted (VarContents -> VarValue)
-> ParsecT Void [Char] Identity VarContents
-> ParsecT Void [Char] Identity VarValue
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity VarContents
-> ParsecT Void [Char] Identity VarContents
forall (m :: * -> *) open close a.
Applicative m =>
m open -> m close -> m a -> m a
between (Token [Char] -> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token [Char]
'\"') (Token [Char] -> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token [Char]
'\"') (ParsecT Void [Char] Identity VarFragment
-> ParsecT Void [Char] Identity VarContents
forall a.
ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
many ([Char] -> ParsecT Void [Char] Identity VarFragment
fragment [Char]
"\""))

fragment :: String -> Parser VarFragment
fragment :: [Char] -> ParsecT Void [Char] Identity VarFragment
fragment [Char]
charsToEscape =
  ParsecT Void [Char] Identity VarFragment
interpolatedValueCommandInterpolation
    ParsecT Void [Char] Identity VarFragment
-> ParsecT Void [Char] Identity VarFragment
-> ParsecT Void [Char] Identity VarFragment
forall a.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ParsecT Void [Char] Identity VarFragment
interpolatedValueVarInterpolation
    ParsecT Void [Char] Identity VarFragment
-> ParsecT Void [Char] Identity VarFragment
-> ParsecT Void [Char] Identity VarFragment
forall a.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> [Char] -> ParsecT Void [Char] Identity VarFragment
literalValueFragment (Char
'$' Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
: Char
'\\' Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
: [Char]
charsToEscape)

interpolatedValueVarInterpolation :: Parser VarFragment
interpolatedValueVarInterpolation :: ParsecT Void [Char] Identity VarFragment
interpolatedValueVarInterpolation = [Char] -> VarFragment
VarInterpolation ([Char] -> VarFragment)
-> ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity VarFragment
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
                            (ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity [Char]
forall (m :: * -> *) open close a.
Applicative m =>
m open -> m close -> m a -> m a
between ([Char] -> ParsecT Void [Char] Identity [Char]
symbol [Char]
"${") ([Char] -> ParsecT Void [Char] Identity [Char]
symbol [Char]
"}") ParsecT Void [Char] Identity [Char]
variableName ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity [Char]
forall a.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
                            (Token [Char] -> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token [Char]
'$' ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity [Char]
forall a b.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity b -> ParsecT Void [Char] Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT Void [Char] Identity [Char]
variableName))
  where
    symbol :: Tokens [Char] -> ParsecT Void [Char] Identity (Tokens [Char])
symbol                = ParsecT Void [Char] Identity ()
-> Tokens [Char] -> ParsecT Void [Char] Identity (Tokens [Char])
forall e s (m :: * -> *).
MonadParsec e s m =>
m () -> Tokens s -> m (Tokens s)
L.symbol ParsecT Void [Char] Identity ()
sc

interpolatedValueCommandInterpolation :: Parser VarFragment
interpolatedValueCommandInterpolation :: ParsecT Void [Char] Identity VarFragment
interpolatedValueCommandInterpolation = do
  [[Char]]
ws <- ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity [[Char]]
-> ParsecT Void [Char] Identity [[Char]]
forall (m :: * -> *) open close a.
Applicative m =>
m open -> m close -> m a -> m a
between ([Char] -> ParsecT Void [Char] Identity [Char]
symbol [Char]
"$(") ([Char] -> ParsecT Void [Char] Identity [Char]
symbol [Char]
")") ParsecT Void [Char] Identity [[Char]]
ShellWords.parser
  VarFragment -> ParsecT Void [Char] Identity VarFragment
forall a. a -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (VarFragment -> ParsecT Void [Char] Identity VarFragment)
-> VarFragment -> ParsecT Void [Char] Identity VarFragment
forall a b. (a -> b) -> a -> b
$ case [[Char]]
ws of
      ([Char]
commandName:[[Char]]
arguments) -> [Char] -> [[Char]] -> VarFragment
CommandInterpolation [Char]
commandName [[Char]]
arguments
      [[Char]]
_ -> [Char] -> VarFragment
VarLiteral [Char]
"" -- Interpret "$()" as an empty value
    where
      symbol :: Tokens [Char] -> ParsecT Void [Char] Identity (Tokens [Char])
symbol = ParsecT Void [Char] Identity ()
-> Tokens [Char] -> ParsecT Void [Char] Identity (Tokens [Char])
forall e s (m :: * -> *).
MonadParsec e s m =>
m () -> Tokens s -> m (Tokens s)
L.symbol ParsecT Void [Char] Identity ()
sc

literalValueFragment :: String -> Parser VarFragment
literalValueFragment :: [Char] -> ParsecT Void [Char] Identity VarFragment
literalValueFragment [Char]
charsToEscape = [Char] -> VarFragment
VarLiteral ([Char] -> VarFragment)
-> ParsecT Void [Char] Identity [Char]
-> ParsecT Void [Char] Identity VarFragment
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity [Char]
forall a.
ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity [a]
forall (f :: * -> *) a. Alternative f => f a -> f [a]
some (ParsecT Void [Char] Identity Char
ParsecT Void [Char] Identity (Token [Char])
escapedChar ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity Char
forall a.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ParsecT Void [Char] Identity Char
ParsecT Void [Char] Identity (Token [Char])
normalChar)
  where
    escapedChar :: ParsecT Void [Char] Identity (Token [Char])
escapedChar = (Token [Char] -> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token [Char]
'\\' ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity (Token [Char])
-> ParsecT Void [Char] Identity (Token [Char])
forall a b.
ParsecT Void [Char] Identity a
-> ParsecT Void [Char] Identity b -> ParsecT Void [Char] Identity b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *). MonadParsec e s m => m (Token s)
anySingle) ParsecT Void [Char] Identity (Token [Char])
-> [Char] -> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> [Char] -> m a
<?> [Char]
"escaped character"
    normalChar :: ParsecT Void [Char] Identity (Token [Char])
normalChar  = [Token [Char]] -> ParsecT Void [Char] Identity (Token [Char])
forall (f :: * -> *) e s (m :: * -> *).
(Foldable f, MonadParsec e s m) =>
f (Token s) -> m (Token s)
noneOf [Char]
[Token [Char]]
charsToEscape ParsecT Void [Char] Identity (Token [Char])
-> [Char] -> ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> [Char] -> m a
<?> [Char]
"unescaped character"

----------------------------------------------------------------------------
-- Boilerplate and whitespace setup

-- | Lexeme wrapper that takes care of consuming of white space.
lexeme :: Parser a -> Parser a
lexeme :: forall a. Parser a -> Parser a
lexeme = ParsecT Void [Char] Identity ()
-> ParsecT Void [Char] Identity a -> ParsecT Void [Char] Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m () -> m a -> m a
L.lexeme ParsecT Void [Char] Identity ()
sc
{-# INLINE lexeme #-}

-- | Space consumer. Consumes all white space including comments, but never
-- consumes newlines.
sc :: Parser ()
sc :: ParsecT Void [Char] Identity ()
sc = ParsecT Void [Char] Identity ()
-> ParsecT Void [Char] Identity ()
-> ParsecT Void [Char] Identity ()
-> ParsecT Void [Char] Identity ()
forall e s (m :: * -> *).
MonadParsec e s m =>
m () -> m () -> m () -> m ()
L.space (ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT Void [Char] Identity Char
spaceChar') ParsecT Void [Char] Identity ()
skipLineComment ParsecT Void [Char] Identity ()
forall a. ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Alternative f => f a
empty
{-# INLINE sc #-}

-- | Just like 'sc' but also eats newlines.
scn :: Parser ()
scn :: ParsecT Void [Char] Identity ()
scn = ParsecT Void [Char] Identity ()
-> ParsecT Void [Char] Identity ()
-> ParsecT Void [Char] Identity ()
-> ParsecT Void [Char] Identity ()
forall e s (m :: * -> *).
MonadParsec e s m =>
m () -> m () -> m () -> m ()
L.space (ParsecT Void [Char] Identity Char
-> ParsecT Void [Char] Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT Void [Char] Identity Char
ParsecT Void [Char] Identity (Token [Char])
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
spaceChar) ParsecT Void [Char] Identity ()
skipLineComment ParsecT Void [Char] Identity ()
forall a. ParsecT Void [Char] Identity a
forall (f :: * -> *) a. Alternative f => f a
empty
{-# INLINE scn #-}

-- | Just like 'spaceChar', but does not consume newlines.
spaceChar' :: Parser Char
spaceChar' :: ParsecT Void [Char] Identity Char
spaceChar' = [Token [Char]] -> ParsecT Void [Char] Identity (Token [Char])
forall (f :: * -> *) e s (m :: * -> *).
(Foldable f, MonadParsec e s m) =>
f (Token s) -> m (Token s)
oneOf ([Char]
" \t" :: String)
{-# INLINE spaceChar' #-}

-- | Skip line comment and stop before newline character without consuming
-- it.
skipLineComment :: Parser ()
skipLineComment :: ParsecT Void [Char] Identity ()
skipLineComment = Tokens [Char] -> ParsecT Void [Char] Identity ()
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Tokens s -> m ()
L.skipLineComment Tokens [Char]
"#"
{-# INLINE skipLineComment #-}