5 import Text.ParserCombinators.ReadP hiding ((+++), (<++), choice)
7 newtype Program = Program [AST]
10 instance Read Program where
11 readPrec = fmap Program $ lift $ do
12 asts <- sepBy1 (readS_to_P reads) $ do
20 data AST = Function String [String] Expr
21 | Extern String [String]
24 data Expr = Num Double
25 | BinOp BinOpType Expr Expr
29 | For String Expr Expr (Maybe Expr) Expr
31 data BinOpType = Add | Sub | Mul | Cmp Ordering
34 instance Read AST where
35 readPrec = parseFunction +++ parseExtern +++ (Eval <$> readPrec)
36 where parseFunction = do
37 lift $ string "def" >> skipSpaces
38 (name, params) <- parsePrototype
40 Function name params <$> readPrec
42 lift $ string "extern" >> skipSpaces
43 uncurry Extern <$> parsePrototype
44 parsePrototype = lift $ do
45 name <- munch1 isAlpha
46 params <- between (char '(') (char ')') $
47 sepBy (munch1 isAlpha) skipSpaces
50 instance Read Expr where
51 readPrec = choice [ parseParens
60 , parseBinOp ">" (Cmp GT)
61 , parseBinOp "<" (Cmp LT)
62 , parseBinOp "==" (Cmp EQ)
64 where parseParens = step $ lift $
65 between (char '(') (char ')') (readS_to_P reads)
66 parseNum = Num <$> readPrec
67 parseVar = Var <$> lift (munch1 isAlpha)
69 func <- lift (munch1 isAlpha)
70 params <- lift $ between (char '(') (char ')') $
71 sepBy (readS_to_P reads)
72 (skipSpaces >> char ',' >> skipSpaces)
73 return (Call func params)
74 parseBinOp s typ = step $ do
75 a <- prec 11 readPrec -- set recursion limit of 11
80 BinOp typ a <$> readPrec
90 thenE <- step readPrec
95 elseE <- step readPrec
96 return (If cond thenE elseE)
101 identifier <- lift (munch1 isAlpha)
102 lift $ skipSpaces >> char '=' >> skipSpaces
103 start <- step readPrec
104 lift $ skipSpaces >> char ',' >> skipSpaces
105 cond <- step readPrec
107 lift $ skipSpaces >> char ',' >> skipSpaces
108 Just <$> step readPrec) <++ pure Nothing
109 lift $ skipSpaces >> string "in" >> skipSpaces
110 body <- step readPrec
111 return (For identifier start cond step' body)