sexpr-parser-0.2.0.0: lib/Text/SExpression/Internal.hs
{-|
Module : Text.SExpression.Internal
Description : Internal parser functions
Copyright : (C) Richard Cook, 2019
Licence : MIT
Maintainer : rcook@rcook.org
Stability : stable
Portability : portable
This module provides internal parser functions.
-}
{-# OPTIONS_GHC -Wall -Werror #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE RecordWildCards #-}
#undef MEGAPARSEC_7_OR_LATER
#ifdef MIN_VERSION_GLASGOW_HASKELL
-- GHC >= 7.10.1.0
#if MIN_VERSION_GLASGOW_HASKELL(8,0,0,0)
-- GHC >= 8.0.0.0
#if MIN_VERSION_megaparsec(7,0,0)
#define MEGAPARSEC_7_OR_LATER
#endif
#endif
#endif
module Text.SExpression.Internal
( -- * S-expression parser
parseSExpr
, -- * S-expression value parsers
parseAtom
, parseConsList
, parseList
, parseQuoted
, parseStringDef
, parseNumberDef
, parseBoolDef
, mkLiteralParsers
, overrideBoolP
, overrideNumberP
, overrideStringP
) where
import Control.Applicative (empty)
import Control.Monad (void)
import Text.Megaparsec
( (<|>)
, endBy
, many
#ifdef MEGAPARSEC_7_OR_LATER
, oneOf
#endif
, sepBy
, try
)
import Text.Megaparsec.Char
( char
, digitChar
, letterChar
#ifndef MEGAPARSEC_7_OR_LATER
, oneOf
#endif
, space1
)
import Text.Megaparsec.Char.Lexer
( space
, skipLineComment
)
import Text.SExpression.Types (Parser, SExpr(..))
import Text.SExpression.Default
sc :: Parser ()
sc = space space1 lineComment empty
where
lineComment = skipLineComment ";"
symbol :: Parser Char
symbol = oneOf "!$%&|*+-/:<=>?@^_~#"
-- | S-expression parser
parseSExpr ::
LiteralParsers ->
Parser SExpr -- ^ parser
parseSExpr lp@(LiteralParsers{..}) =
try parseBool
<|> parseAtom
<|> parseString
<|> parseNumber
<|> parseQuoted lp
<|> do
void $ char '('
lst <- (try $ parseList lp) <|> parseConsList lp
void $ char ')' >> sc
pure lst
-- | Parse s-expression atom
parseAtom ::
Parser SExpr -- ^ parser
parseAtom = do
h <- letterChar <|> symbol
t <- many (letterChar <|> digitChar <|> symbol)
return . Atom $ h : t
-- | Parse s-expression list
parseList ::
LiteralParsers ->
Parser SExpr -- ^ parser
parseList lp =
List <$> parseSExpr lp `sepBy` sc
-- | Parse s-expression cons list
parseConsList ::
LiteralParsers ->
Parser SExpr -- ^ parser
parseConsList lp = do
h <- parseSExpr lp `endBy` sc
t <- char '.' >> sc >> parseSExpr lp
pure $ ConsList h t
-- | Parse s-expression quoted expression
parseQuoted ::
LiteralParsers ->
Parser SExpr -- ^ parser
parseQuoted lp = do
void $ char '\''
e <- parseSExpr lp
pure $ List [Atom "quote", e]