3 import Text.ParserCombinators.Parsec hiding (spaces)
4 import System.Environment
7 data LispVal = Atom String
9 | DottedList [LispVal] LispVal
16 symbol = oneOf "!#$%&|*+-/:<=>?@^_~"
19 spaces = skipMany space
21 nonPrintableChar :: Parser Char
22 nonPrintableChar = do c <- char '\\' >> oneOf "\\nrtf"
23 return $ case c of '\\' -> '\\'
29 parseCharacter :: Parser LispVal
30 parseCharacter = do char '\''
31 c <- noneOf ['\\', '\''] <|> try singleQuote <|> try nonPrintableChar
35 singleQuote = char '\\' >> char '\''
37 parseString :: Parser LispVal
38 parseString = do char '"'
42 where innerChar = noneOf ['\\', '"'] <|> try doubleQuote <|> try nonPrintableChar
43 doubleQuote = char '\\' >> char '"'
45 parseAtom :: Parser LispVal
47 a <- letter <|> symbol
48 b <- many (letter <|> digit <|> symbol)
55 parseNumber :: Parser LispVal
56 parseNumber = do toNum <- radix
58 let ((a,_):_) = toNum ds
60 where radix = do r <- try (char '#' >> oneOf "bodx") <|> return 'd'
65 'b' -> readInt 2 (\x -> elem x "01") (read . (:[]))
67 parseList :: Parser LispVal
68 parseList = liftM List $ sepBy parseExpr spaces
70 parseDottedList :: Parser LispVal
72 head <- endBy parseExpr spaces
73 tail <- char '.' >> spaces >> parseExpr
74 return $ DottedList head tail
76 parseQuoted :: Parser LispVal
80 return $ List [Atom "quote", x]
82 parseExpr :: Parser LispVal
83 parseExpr = parseString
86 <|> try parseCharacter
89 x <- try parseList <|> parseDottedList
93 readExpr :: String -> String
94 readExpr input = case parse parseExpr "lisp" input of
95 Left err -> "No match: " ++ show err
96 Right val -> "Found value: " ++ showVal val
98 instance Show LispVal where show = showVal
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)