module SExprParser (SExpr(..), parseSExpr) where import Text.ParserCombinators.Parsec hiding (spaces) import Control.Monad -- representation of an s-expr -- (improper lists are not supported) data SExpr = Atom String | List [SExpr] | Number Integer | Bool Bool | String String deriving Show symbol :: Parser Char symbol = oneOf "!#$%&|*+-/:<=>?@^_~" spaces :: Parser () spaces = skipMany1 space parseExpr = parseAtom <|> parseNumber <|> parseString <|> do char '(' x <- parseList char ')' return x parseAtom :: Parser SExpr parseAtom = do first <- letter <|> symbol rest <- many (letter <|> digit <|> symbol) let atom = first:rest return $ case atom of "#t" -> Bool True "#f" -> Bool False _ -> Atom atom parseList = liftM List $ sepBy parseExpr spaces parseNumber = liftM (Number . read) $ many1 digit parseString :: Parser SExpr parseString = do char '"' x <- many (noneOf "\"") char '"' return $ String x parseSExpr :: String -> SExpr parseSExpr prog = case (parse parseExpr "error" prog) of Left e -> error $ show e Right sexpr -> sexpr