{-# LANGUAGE OverloadedStrings #-} -- simple parser for a Lisp-like syntax I wrote some time ago import Data.Void (Void) import Data.Text (Text) import qualified Data.Text as T import Text.Megaparsec.Char import Text.Megaparsec.Error (errorBundlePretty) import Text.Megaparsec hiding (State) import qualified Text.Megaparsec.Char.Lexer as L data LispVal  = Symbol Text  | List [LispVal]  | Number Integer  | String Text  | LispTrue  | LispFalse  | Nil  deriving (Show, Eq) type Parser = Parsec Void Text readStr :: Text -> Either String [LispVal] readStr t =  case parse pLisp "f" t of  Right parsed -> Right parsed  Left err -> Left $ errorBundlePretty err {-# INLINABLE readStr #-} sc :: Parser () sc = L.space space1 (L.skipLineComment ";") empty {-# INLINABLE sc #-} lexeme :: Parser a -> Parser a lexeme = L.lexeme sc {-# INLINE lexeme #-} symbol :: Text -> Parser Text symbol = L.symbol sc {-# INLINE symbol #-} symbol' :: Text -> Parser Text symbol' = L.symbol' sc {-# INLINE symbol' #-} pNil :: Parser LispVal pNil = symbol' "nil" >> return Nil {-# INLINE pNil #-} integer :: Parser Integer integer = lexeme L.decimal {-# INLINE integer #-} lispSymbols :: Parser Char lispSymbols = oneOf ("#$%&|*+-/:<=>?@^_~" :: String) {-# INLINE lispSymbols #-} pLispVal :: Parser LispVal pLispVal = choice [pList, pNumber, pSymbol, pNil, pString] {-# INLINE pLispVal #-} pSymbol :: Parser LispVal pSymbol = (Symbol . T.pack <$> lexeme (some (letterChar <|> lispSymbols))) {-# INLINABLE pSymbol #-} pList :: Parser LispVal pList = List <$> between (symbol "(") (symbol ")") (many pLispVal) {-# INLINABLE pList #-} pLisp :: Parser [LispVal] pLisp = some pLispVal {-# INLINE pLisp #-} pNumber :: Parser LispVal pNumber = Number <$> integer {-# INLINE pNumber #-} pString :: Parser LispVal pString = do  str <- char '\"' *> manyTill L.charLiteral (char '\"')  return $ String (T.pack str) {-# INLINABLE pString #-}