Haskell: steps 4-6. Line editing. Simpler fn calls.
[jackhill/mal.git] / haskell / Reader.hs
CommitLineData
b76aa73b
JM
1module Reader
2( read_str )
3where
4
5import Text.ParserCombinators.Parsec (
6 Parser, parse, space, char, digit, letter,
fa9a9758 7 (<|>), oneOf, noneOf, many, many1, skipMany, skipMany1, sepEndBy)
b76aa73b
JM
8import qualified Data.Map as Map
9import Control.Monad (liftM)
10
11import Types
12
13spaces :: Parser ()
fa9a9758
JM
14spaces = skipMany1 (oneOf ", \n")
15
16comment :: Parser ()
17comment = do
18 char ';'
19 skipMany (noneOf "\r\n")
20
21ignored :: Parser ()
22ignored = skipMany (spaces <|> comment)
b76aa73b
JM
23
24symbol :: Parser Char
25symbol = oneOf "!#$%&|*+-/:<=>?@^_~"
26
27escaped :: Parser Char
28escaped = do
29 char '\\'
30 x <- oneOf "\\\"n"
31 case x of
32 'n' -> return '\n'
33 _ -> return x
34
35read_number :: Parser MalVal
36read_number = liftM (MalNumber . read) $ many1 digit
37
38read_string :: Parser MalVal
39read_string = do
40 char '"'
41-- x <- stringChars
42 x <- many (escaped <|> noneOf "\\\"")
43 char '"'
44 return $ MalString x
45
46read_symbol :: Parser MalVal
47read_symbol = do
48 first <- letter <|> symbol
49 rest <- many (letter <|> digit <|> symbol)
50 let str = first:rest
51 return $ case str of
52 "true" -> MalTrue
53 "false" -> MalFalse
54 "nil" -> Nil
55 _ -> MalSymbol str
56
57read_keyword :: Parser MalVal
58read_keyword = do
59 char ':'
60 x <- many (letter <|> digit <|> symbol)
61 return $ MalKeyword x
62
63read_atom :: Parser MalVal
64read_atom = read_number
65 <|> read_string
66 <|> read_keyword
67 <|> read_symbol
68
69read_list :: Parser MalVal
70read_list = do
71 char '('
fa9a9758 72 x <- sepEndBy read_form ignored
b76aa73b
JM
73 char ')'
74 return $ MalList x
75
76read_vector :: Parser MalVal
77read_vector = do
78 char '['
fa9a9758 79 x <- sepEndBy read_form ignored
b76aa73b
JM
80 char ']'
81 return $ MalVector x
82
b76aa73b
JM
83read_hash_map :: Parser MalVal
84read_hash_map = do
85 char '{'
fa9a9758 86 x <- sepEndBy read_form ignored
b76aa73b
JM
87 char '}'
88 return $ MalHashMap $ Map.fromList $ _pairs x
89
90
91read_form :: Parser MalVal
92read_form = do
fa9a9758 93 ignored
b76aa73b
JM
94 x <- read_atom <|> read_list <|> read_vector <|> read_hash_map
95 return $ x
96
97read_str :: String -> IO MalVal
98read_str str = case parse read_form "Mal" str of
99 Left err -> error $ "Blah: " ++ (show err)
100 Right val -> return val