]> git.rmz.io Git - my-scheme.git/blobdiff - app/Main.hs
Show values (except Lists)
[my-scheme.git] / app / Main.hs
index 01fd038650e2e9277b72b919ba357b7acffefd19..1495605d09602a2ed23717d3b5956402874a6ef4 100644 (file)
@@ -2,12 +2,14 @@ module Main where
 import Control.Monad
 import Text.ParserCombinators.Parsec hiding (spaces)
 import System.Environment
+import Numeric
 
 data LispVal = Atom String
              | List [LispVal]
              | DottedList [LispVal] LispVal
              | Number Integer
              | String String
+             | Character Char
              | Bool Bool
              deriving Show
 
@@ -17,12 +19,29 @@ symbol = oneOf "!#$%&|*+-/:<=>?@^_~"
 spaces :: Parser ()
 spaces = skipMany space
 
+nonPrintableChar :: Parser Char
+nonPrintableChar = do c <- char '\\' >> oneOf "\\nrtf"
+                      return $ case c of '\\' -> '\\'
+                                         'n'  -> '\n'
+                                         'r'  -> '\r'
+                                         't'  -> '\t'
+                                         'f'  -> '\f'
+
+parseCharacter :: Parser LispVal
+parseCharacter = do char '\''
+                    c <- noneOf ['\\', '\''] <|> try singleQuote <|> try nonPrintableChar
+                    char '\''
+                    return $ Character c
+                 where
+                    singleQuote = char '\\' >> char '\''
+
 parseString :: Parser LispVal
-parseString = do
-    char '"'
-    x <- many (noneOf "\"")
-    char '"'
-    return $ String x
+parseString = do char '"'
+                 x <- many innerChar
+                 char '"'
+                 return $ String x
+              where innerChar = noneOf ['\\', '"'] <|> try doubleQuote <|> try nonPrintableChar
+                    doubleQuote = char '\\' >> char '"'
 
 parseAtom :: Parser LispVal
 parseAtom = do
@@ -35,21 +54,58 @@ parseAtom = do
                 _    -> Atom atom
 
 parseNumber :: Parser LispVal
-parseNumber = do ds <- many1 digit
-                 let a = read ds
+parseNumber = do toNum <- radix
+                 ds <- many1 digit
+                 let ((a,_):_) = toNum ds
                  return $ Number a
+              where radix = do r <- try (char '#' >> oneOf "bodx") <|> return 'd'
+                               return $ case r of
+                                           'd' -> readDec
+                                           'x' -> readHex
+                                           'o' -> readOct
+                                           'b' -> readInt 2 (\x -> elem x "01") (read . (:[]))
+
+parseList :: Parser LispVal
+parseList = liftM List $ sepBy parseExpr spaces
+
+parseDottedList :: Parser LispVal
+parseDottedList = do
+    head <- endBy parseExpr spaces
+    tail <- char '.' >> spaces >> parseExpr
+    return $ DottedList head tail
+
+parseQuoted :: Parser LispVal
+parseQuoted = do
+    char '\''
+    x <- parseExpr
+    return $ List [Atom "quote", x]
 
 parseExpr :: Parser LispVal
 parseExpr = parseString
-        <|> parseAtom
         <|> parseNumber
+        <|> parseAtom
+        <|> try parseCharacter
+        <|> parseQuoted
+        <|> do char '('
+               x <- try parseList <|> parseDottedList
+               char ')'
+               return x
 
 readExpr :: String -> String
 readExpr input = case parse parseExpr "lisp" input of
     Left err -> "No match: " ++ show err
-    Right val -> "Found value: " ++ show val
+    Right val -> "Found value: " ++ showVal val
+
+showVal :: LispVal -> String
+showVal (Atom atom)   = atom
+showVal (Number n)    = show n
+showVal (String str)  = "\"" ++ str ++ "\""
+showVal (Character c) = "'" ++ [c] ++ "'"
+showVal (Bool True)   = "#t"
+showVal (Bool False)  = "#f"
 
 main :: IO ()
 main = do
     args <- getLine
     putStrLn (readExpr args)
+    main