X-Git-Url: https://git.lukelau.me/?p=kaleidoscope-hs-old.git;a=blobdiff_plain;f=AST.hs;h=e5ea72ad3e059e33b71cb387b82a100b4c207a3a;hp=424cfbe7b13010e0960e4b88a1675cdcfa3b3f0f;hb=d9a6be382ca58e6d1c4ed988856ccbdf76a3bcdf;hpb=51aeade75d5289fff417414b04bae5be0862fd8f diff --git a/AST.hs b/AST.hs index 424cfbe..e5ea72a 100644 --- a/AST.hs +++ b/AST.hs @@ -1,26 +1,111 @@ module AST where +import Data.Char import Text.Read -import Text.ParserCombinators.ReadP hiding ((+++), choice) +import Text.ParserCombinators.ReadP hiding ((+++), (<++), choice) -data BinOpType = Add | Sub | Mul +newtype Program = Program [AST] deriving Show -data Expr = Num Float + +instance Read Program where + readPrec = fmap Program $ lift $ do + asts <- sepBy1 (readS_to_P reads) $ do + skipSpaces + char ';' + skipSpaces + optional $ char ';' + skipSpaces + return asts + +data AST = Function String [String] Expr + | Extern String [String] + | Eval Expr + deriving Show +data Expr = Num Double | BinOp BinOpType Expr Expr + | Var String + | Call String [Expr] + | If Expr Expr Expr + | For String Expr Expr (Maybe Expr) Expr + deriving Show +data BinOpType = Add | Sub | Mul | Cmp Ordering deriving Show +instance Read AST where + readPrec = parseFunction +++ parseExtern +++ (Eval <$> readPrec) + where parseFunction = do + lift $ string "def" >> skipSpaces + (name, params) <- parsePrototype + lift skipSpaces + Function name params <$> readPrec + parseExtern = do + lift $ string "extern" >> skipSpaces + uncurry Extern <$> parsePrototype + parsePrototype = lift $ do + name <- munch1 isAlpha + params <- between (char '(') (char ')') $ + sepBy (munch1 isAlpha) skipSpaces + return (name, params) + instance Read Expr where - readPrec = choice [ parseNum - , parseBinOp '+' Add - , parseBinOp '-' Sub - , parseBinOp '*' Mul + readPrec = choice [ parseParens + , parseNum + , parseVar + , parseCall + , parseIf + , parseFor + , parseBinOp "+" Add + , parseBinOp "-" Sub + , parseBinOp "*" Mul + , parseBinOp ">" (Cmp GT) + , parseBinOp "<" (Cmp LT) + , parseBinOp "==" (Cmp EQ) ] - where parseNum = Num <$> readPrec - parseBinOp c typ = step $ do - a <- prec 11 readPrec + where parseParens = step $ lift $ + between (char '(') (char ')') (readS_to_P reads) + parseNum = Num <$> readPrec + parseVar = Var <$> lift (munch1 isAlpha) + parseCall = do + func <- lift (munch1 isAlpha) + params <- lift $ between (char '(') (char ')') $ + sepBy (readS_to_P reads) + (skipSpaces >> char ',' >> skipSpaces) + return (Call func params) + parseBinOp s typ = step $ do + a <- prec 11 readPrec -- set recursion limit of 11 + lift $ do + skipSpaces + string s + skipSpaces + BinOp typ a <$> readPrec + parseIf = do lift $ do + string "if" + skipSpaces + cond <- step readPrec + lift $ do + skipSpaces + string "then" skipSpaces - char c + thenE <- step readPrec + lift $ do + skipSpaces + string "else" + skipSpaces + elseE <- step readPrec + return (If cond thenE elseE) + parseFor = do + lift $ do + string "for" skipSpaces - b <- readPrec - return (BinOp typ a b) + identifier <- lift (munch1 isAlpha) + lift $ skipSpaces >> char '=' >> skipSpaces + start <- step readPrec + lift $ skipSpaces >> char ',' >> skipSpaces + cond <- step readPrec + step' <- (do + lift $ skipSpaces >> char ',' >> skipSpaces + Just <$> step readPrec) <++ pure Nothing + lift $ skipSpaces >> string "in" >> skipSpaces + body <- step readPrec + return (For identifier start cond step' body)