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