-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathenumCalc.hs
More file actions
68 lines (52 loc) · 1.88 KB
/
enumCalc.hs
File metadata and controls
68 lines (52 loc) · 1.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
module EnumCalc ( repl
, runRepl
) where
import Control.Applicative
import Control.Monad.IO.Class
import Data.Attoparsec
import Data.Attoparsec.Char8
import Data.Attoparsec.Enumerator
import qualified Data.ByteString as B
import Data.ByteString.Char8 hiding (putStrLn, putStr)
import Data.Enumerator
import qualified Data.Enumerator.Binary as EB
import qualified Data.Enumerator.List as EL
import System.IO hiding (putStrLn)
chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a
chainl p op x = chainl1 p op <|> return x
chainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a
chainl1 p op = do x <- p
rest x
where
rest x = (do f <- op
y <- p
rest $ f x y)
<|> return x
<?> "chainl"
natural :: Parser Number
natural = skipSpace *> number <* skipSpace <?> "natural"
symbol :: String -> Parser ByteString
symbol x = skipSpace *> (string $ pack x) <* skipSpace <?> "symbol"
operator :: String -> (a -> a -> a) -> Parser (a -> a -> a)
operator x f = symbol x *> return f <?> "operator"
terminate :: Parser a -> String -> Parser a
terminate p end = do x <- p
skipSpace
string $ pack end
return x
expr = expr' `terminate` "="
expr' = chainl1 term (operator "+" (+) <|> operator "-" (-))
term = chainl1 fact (operator "*" (*) <|> operator "/" (/)) <?> "term"
fact = natural <|> symbol "(" *> expr' <* symbol ")" <?> "fact"
calc :: ByteString -> Result Number
calc = parse expr
calcI :: Iteratee ByteString IO Number
calcI = iterParser expr
printI = liftIO . putStrLn . show
prompt = liftIO . putStr
enumStdin :: Enumerator ByteString IO b
enumStdin = EB.enumHandle 100 stdin
calculator :: Iteratee ByteString IO Number
calculator = enumStdin $$ calcI
repl = prompt "$> " >> calculator >>= printI >> repl
runRepl = run_ repl