3 import Text.ParserCombinators.Parsec hiding (spaces)
4 import System.Environment
7 data LispVal = Atom String
9 | DottedList [LispVal] LispVal
17 symbol = oneOf "!#$%&|*+-/:<=>?@^_~"
20 spaces = skipMany space
22 nonPrintableChar :: Parser Char
23 nonPrintableChar = do c <- char '\\' >> oneOf "\\nrtf"
24 return $ case c of '\\' -> '\\'
30 parseCharacter :: Parser LispVal
31 parseCharacter = do char '\''
32 c <- noneOf ['\\', '\''] <|> try singleQuote <|> try nonPrintableChar
36 singleQuote = char '\\' >> char '\''
38 parseString :: Parser LispVal
39 parseString = do char '"'
43 where innerChar = noneOf ['\\', '"'] <|> try doubleQuote <|> try nonPrintableChar
44 doubleQuote = char '\\' >> char '"'
46 parseAtom :: Parser LispVal
48 a <- letter <|> symbol
49 b <- many (letter <|> digit <|> symbol)
56 parseNumber :: Parser LispVal
57 parseNumber = do toNum <- radix
59 let ((a,_):_) = toNum ds
61 where radix = do r <- try (char '#' >> oneOf "bodx") <|> return 'd'
66 'b' -> readInt 2 (\x -> elem x "01") (read . (:[]))
68 parseList :: Parser LispVal
69 parseList = liftM List $ sepBy parseExpr spaces
71 parseDottedList :: Parser LispVal
73 head <- endBy parseExpr spaces
74 tail <- char '.' >> spaces >> parseExpr
75 return $ DottedList head tail
77 parseQuoted :: Parser LispVal
81 return $ List [Atom "quote", x]
83 parseExpr :: Parser LispVal
84 parseExpr = parseString
87 <|> try parseCharacter
90 x <- try parseList <|> parseDottedList
94 readExpr :: String -> String
95 readExpr input = case parse parseExpr "lisp" input of
96 Left err -> "No match: " ++ show err
97 Right val -> "Found value: " ++ showVal val
99 showVal :: LispVal -> String
100 showVal (Atom atom) = atom
101 showVal (List list) = "(" ++ unwordsList list ++ ")"
102 showVal (DottedList head tail) = "(" ++ unwordsList head ++ " . " ++ showVal tail ++ ")"
103 showVal (Number n) = show n
104 showVal (String str) = "\"" ++ str ++ "\""
105 showVal (Character c) = "'" ++ [c] ++ "'"
106 showVal (Bool True) = "#t"
107 showVal (Bool False) = "#f"
109 unwordsList :: [LispVal] -> String
110 unwordsList = unwords . map showVal
115 putStrLn (readExpr args)