| 1 | module AST where | |
| 2 | ||
| 3 | import Data.Char | |
| 4 | import Text.Read | |
| 5 | import Text.ParserCombinators.ReadP hiding ((+++), choice) | |
| 6 | ||
| 7 | data Expr = Num Float | |
| 8 | | Var String | |
| 9 | | BinOp BinOp Expr Expr | |
| 10 | | Call String [Expr] | |
| 11 | deriving Show | |
| 12 | ||
| 13 | data BinOp = Add | Sub | Mul | Cmp Ordering | |
| 14 | deriving Show | |
| 15 | ||
| 16 | instance Read Expr where | |
| 17 | readPrec = parens $ choice [ parseNum | |
| 18 | , parseVar | |
| 19 | , parseCall | |
| 20 | , parseBinOp "<" 10 (Cmp LT) | |
| 21 | , parseBinOp "+" 20 Add | |
| 22 | , parseBinOp "-" 20 Sub | |
| 23 | , parseBinOp "*" 40 Mul | |
| 24 | ] | |
| 25 | where parseNum = Num <$> readPrec | |
| 26 | parseVar = Var <$> lift (munch1 isAlpha) | |
| 27 | parseBinOp s prc op = prec prc $ do | |
| 28 | a <- step readPrec | |
| 29 | lift $ do | |
| 30 | skipSpaces | |
| 31 | string s | |
| 32 | skipSpaces | |
| 33 | b <- readPrec | |
| 34 | return (BinOp op a b) | |
| 35 | parseCall = do | |
| 36 | func <- lift (munch1 isAlpha) | |
| 37 | params <- lift $ between (char '(') (char ')') $ | |
| 38 | sepBy (readS_to_P reads) | |
| 39 | (skipSpaces >> char ',' >> skipSpaces) | |
| 40 | return (Call func params) | |
| 41 | ||
| 42 | data Prototype = Prototype String [String] | |
| 43 | deriving Show | |
| 44 | ||
| 45 | instance Read Prototype where | |
| 46 | readPrec = lift $ do | |
| 47 | name <- munch1 isAlpha | |
| 48 | params <- between (char '(') (char ')') $ | |
| 49 | sepBy (munch1 isAlpha) skipSpaces | |
| 50 | return (Prototype name params) | |
| 51 | ||
| 52 | data AST = Function Prototype Expr | |
| 53 | | Extern Prototype | |
| 54 | | TopLevelExpr Expr | |
| 55 | deriving Show | |
| 56 | ||
| 57 | instance Read AST where | |
| 58 | readPrec = parseFunction +++ parseExtern +++ parseTopLevel | |
| 59 | where parseFunction = do | |
| 60 | lift $ string "def" >> skipSpaces | |
| 61 | Function <$> readPrec <*> readPrec | |
| 62 | parseExtern = do | |
| 63 | lift $ string "extern" >> skipSpaces | |
| 64 | Extern <$> readPrec | |
| 65 | parseTopLevel = TopLevelExpr <$> readPrec |
| 1 | main = pure () | |
| 1 | import AST | |
| 2 | import System.IO | |
| 3 | import Text.Read | |
| 4 | main = do | |
| 5 | hPutStr stderr "ready> " | |
| 6 | ast <- (readMaybe <$> getLine) :: IO (Maybe AST) | |
| 7 | case ast of | |
| 8 | Just x -> hPrint stderr x | |
| 9 | Nothing -> hPutStrLn stderr "Couldn't parse" | |
| 10 | main |
| 1 | module AST where | |
| 2 | ||
| 3 | import Text.Read | |
| 4 | import Text.ParserCombinators.ReadP hiding ((+++)) | |
| 5 | ||
| 6 | data Expr = Num Float | |
| 7 | | Add Expr Expr | |
| 8 | deriving Show | |
| 9 | ||
| 10 | instance Read Expr where | |
| 11 | readPrec = parseNum +++ parseAdd | |
| 12 | where parseNum = Num <$> readPrec | |
| 13 | -- use 'prec 1' and 'step' so that parsing 'a' | |
| 14 | -- can only go one step deep, to prevent ininfite | |
| 15 | -- recursion | |
| 16 | parseAdd = prec 1 $ do | |
| 17 | a <- step readPrec | |
| 18 | lift $ do | |
| 19 | skipSpaces | |
| 20 | char '+' | |
| 21 | skipSpaces | |
| 22 | b <- readPrec | |
| 23 | return (Add a b) |
| 1 | 1 | module AST where |
| 2 | 2 | |
| 3 | 3 | import Text.Read |
| 4 | import Text.ParserCombinators.ReadP hiding ((+++)) | |
| 4 | import Text.ParserCombinators.ReadP hiding ((+++), choice) | |
| 5 | 5 | |
| 6 | 6 | data Expr = Num Float |
| 7 | | Add Expr Expr | |
| 7 | | BinOp BinOp Expr Expr | |
| 8 | deriving Show | |
| 9 | ||
| 10 | data BinOp = Add | Sub | Mul | Cmp Ordering | |
| 8 | 11 | deriving Show |
| 9 | 12 | |
| 10 | 13 | instance Read Expr where |
| 11 | readPrec = parseNum +++ parseAdd | |
| 14 | readPrec = choice [ parseNum | |
| 15 | , parseBinOp "<" 10 (Cmp LT) | |
| 16 | , parseBinOp "+" 20 Add | |
| 17 | , parseBinOp "-" 20 Sub | |
| 18 | , parseBinOp "*" 40 Mul | |
| 19 | ] | |
| 12 | 20 | where parseNum = Num <$> readPrec |
| 13 | 21 | -- use 'prec 1' and 'step' so that parsing 'a' |
| 14 | 22 | -- can only go one step deep, to prevent ininfite |
| 15 | 23 | -- recursion |
| 16 | parseAdd = prec 1 $ do | |
| 24 | parseBinOp s prc op = prec prc $ do | |
| 17 | 25 | a <- step readPrec |
| 18 | 26 | lift $ do |
| 19 | 27 | skipSpaces |
| 20 | char '+' | |
| 28 | string s | |
| 21 | 29 | skipSpaces |
| 22 | 30 | b <- readPrec |
| 23 | return (Add a b) | |
| 31 | return (BinOp op a b) | |
| 32 |
| 4 | 4 | import Text.ParserCombinators.ReadP hiding ((+++), choice) |
| 5 | 5 | |
| 6 | 6 | data Expr = Num Float |
| 7 | | Var String | |
| 7 | 8 | | BinOp BinOp Expr Expr |
| 8 | 9 | deriving Show |
| 9 | 10 |
⋮
| 12 | 13 | |
| 13 | 14 | instance Read Expr where |
| 14 | 15 | readPrec = choice [ parseNum |
| 16 | , parseVar | |
| 15 | 17 | , parseBinOp "<" 10 (Cmp LT) |
| 16 | 18 | , parseBinOp "+" 20 Add |
| 17 | 19 | , parseBinOp "-" 20 Sub |
| 18 | 20 | , parseBinOp "*" 40 Mul |
| 19 | 21 | ] |
| 20 | 22 | where parseNum = Num <$> readPrec |
| 23 | parseVar = Var <$> lift (munch1 isAlpha) | |
| 21 | 24 | -- use 'prec 1' and 'step' so that parsing 'a' |
| 22 | 25 | -- can only go one step deep, to prevent ininfite |
| 23 | 26 | -- recursion |
| 1 | 1 | module AST where |
| 2 | 2 | |
| 3 | import Data.Char | |
| 3 | 4 | import Text.Read |
| 4 | 5 | import Text.ParserCombinators.ReadP hiding ((+++), choice) |
| 5 | 6 |
⋮
| 21 | 22 | ] |
| 22 | 23 | where parseNum = Num <$> readPrec |
| 23 | 24 | parseVar = Var <$> lift (munch1 isAlpha) |
| 24 | -- use 'prec 1' and 'step' so that parsing 'a' | |
| 25 | -- can only go one step deep, to prevent ininfite | |
| 26 | -- recursion | |
| 27 | 25 | parseBinOp s prc op = prec prc $ do |
| 28 | 26 | a <- step readPrec |
| 29 | 27 | lift $ do |
⋮
| 33 | 31 | b <- readPrec |
| 34 | 32 | return (BinOp op a b) |
| 35 | 33 | |
| 34 | data Prototype = Prototype String [String] | |
| 35 | deriving Show | |
| 36 | ||
| 37 | instance Read Prototype where | |
| 38 | readPrec = lift $ do | |
| 39 | name <- munch1 isAlpha | |
| 40 | params <- between (char '(') (char ')') $ | |
| 41 | sepBy (munch1 isAlpha) skipSpaces | |
| 42 | return (Prototype name params) | |
| 43 | ||
| 44 | data AST = Function Prototype Expr | |
| 45 | | Extern Prototype | |
| 46 | | TopLevelExpr Expr | |
| 47 | deriving Show | |
| 48 | ||
| 49 | instance Read AST where | |
| 50 | readPrec = parseFunction +++ parseExtern +++ parseTopLevel | |
| 51 | where parseFunction = do | |
| 52 | lift $ string "def" >> skipSpaces | |
| 53 | Function <$> readPrec <*> readPrec | |
| 54 | parseExtern = do | |
| 55 | lift $ string "extern" >> skipSpaces | |
| 56 | Extern <$> readPrec | |
| 57 | parseTopLevel = TopLevelExpr <$> readPrec |
| 13 | 13 | deriving Show |
| 14 | 14 | |
| 15 | 15 | instance Read Expr where |
| 16 | readPrec = choice [ parseNum | |
| 17 | , parseVar | |
| 18 | , parseBinOp "<" 10 (Cmp LT) | |
| 19 | , parseBinOp "+" 20 Add | |
| 20 | , parseBinOp "-" 20 Sub | |
| 21 | , parseBinOp "*" 40 Mul | |
| 22 | ] | |
| 16 | readPrec = parens $ choice [ parseNum | |
| 17 | , parseVar | |
| 18 | , parseBinOp "<" 10 (Cmp LT) | |
| 19 | , parseBinOp "+" 20 Add | |
| 20 | , parseBinOp "-" 20 Sub | |
| 21 | , parseBinOp "*" 40 Mul | |
| 22 | ] | |
| 23 | 23 | where parseNum = Num <$> readPrec |
| 24 | 24 | parseVar = Var <$> lift (munch1 isAlpha) |
| 25 | 25 | parseBinOp s prc op = prec prc $ do |
| 7 | 7 | data Expr = Num Float |
| 8 | 8 | | Var String |
| 9 | 9 | | BinOp BinOp Expr Expr |
| 10 | | Call String [Expr] | |
| 10 | 11 | deriving Show |
| 11 | 12 | |
| 12 | 13 | data BinOp = Add | Sub | Mul | Cmp Ordering |
⋮
| 15 | 16 | instance Read Expr where |
| 16 | 17 | readPrec = parens $ choice [ parseNum |
| 17 | 18 | , parseVar |
| 19 | , parseCall | |
| 18 | 20 | , parseBinOp "<" 10 (Cmp LT) |
| 19 | 21 | , parseBinOp "+" 20 Add |
| 20 | 22 | , parseBinOp "-" 20 Sub |
⋮
| 30 | 32 | skipSpaces |
| 31 | 33 | b <- readPrec |
| 32 | 34 | return (BinOp op a b) |
| 35 | parseCall = do | |
| 36 | func <- lift (munch1 isAlpha) | |
| 37 | params <- lift $ between (char '(') (char ')') $ | |
| 38 | sepBy (readS_to_P reads) | |
| 39 | (skipSpaces >> char ',' >> skipSpaces) | |
| 40 | return (Call func params) | |
| 33 | 41 | |
| 34 | 42 | data Prototype = Prototype String [String] |
| 35 | 43 | deriving Show |
| 1 | main = pure () | |
| 1 | import AST | |
| 2 | import System.IO | |
| 3 | import Text.Read | |
| 4 | main = do | |
| 5 | hPutStr stderr "ready> " | |
| 6 | ast <- (readMaybe <$> getLine) :: IO (Maybe AST) | |
| 7 | case ast of | |
| 8 | Just x -> hPrint stderr x | |
| 9 | Nothing -> hPutStrLn stderr "Couldn't parse" | |
| 10 | main |
| 4 | 4 | import Text.Read |
| 5 | 5 | import Text.ParserCombinators.ReadP hiding ((+++), choice) |
| 6 | 6 | |
| 7 | data Expr = Num Float | |
| 7 | data Expr = Num Double | |
| 8 | 8 | | Var String |
| 9 | 9 | | BinOp BinOp Expr Expr |
| 10 | 10 | | Call String [Expr] |
⋮
| 18 | 18 | , parseVar |
| 19 | 19 | , parseCall |
| 20 | 20 | , parseBinOp "<" 10 (Cmp LT) |
| 21 | , parseBinOp ">" 10 (Cmp GT) | |
| 22 | , parseBinOp "==" 10 (Cmp EQ) | |
| 21 | 23 | , parseBinOp "+" 20 Add |
| 22 | 24 | , parseBinOp "-" 20 Sub |
| 23 | 25 | , parseBinOp "*" 40 Mul |
| 1 | import AST | |
| 1 | {-# LANGUAGE OverloadedStrings #-} | |
| 2 | ||
| 3 | import AST as K -- K for Kaleidoscope | |
| 4 | import Utils | |
| 5 | import Control.Monad.Trans.Reader | |
| 6 | import Control.Monad.IO.Class | |
| 7 | import Data.String | |
| 8 | import qualified Data.Map as Map | |
| 9 | import qualified Data.Text.Lazy.IO as Text | |
| 10 | import LLVM.AST.AddrSpace | |
| 11 | import LLVM.AST.Constant | |
| 12 | import LLVM.AST.Float | |
| 13 | import LLVM.AST.FloatingPointPredicate hiding (False, True) | |
| 14 | import LLVM.AST.Operand | |
| 15 | import LLVM.AST.Type as Type | |
| 16 | import LLVM.IRBuilder | |
| 17 | import LLVM.Pretty | |
| 2 | 18 | import System.IO |
| 3 | import Text.Read | |
| 4 | main = do | |
| 5 | hPutStr stderr "ready> " | |
| 6 | ast <- (readMaybe <$> getLine) :: IO (Maybe AST) | |
| 7 | case ast of | |
| 8 | Just x -> hPrint stderr x | |
| 9 | Nothing -> hPutStrLn stderr "Couldn't parse" | |
| 10 | main | |
| 19 | import System.IO.Error | |
| 20 | import Text.Read (readMaybe) | |
| 21 | ||
| 22 | main :: IO () | |
| 23 | main = buildModuleT "main" repl >>= Text.hPutStrLn stderr . ("\n" <>) . ppll | |
| 24 | ||
| 25 | repl :: ModuleBuilderT IO () | |
| 26 | repl = do | |
| 27 | liftIO $ hPutStr stderr "ready> " | |
| 28 | mline <- liftIO $ catchIOError (Just <$> getLine) eofHandler | |
| 29 | case mline of | |
| 30 | Nothing -> return () | |
| 31 | Just l -> do | |
| 32 | case readMaybe l of | |
| 33 | Nothing -> liftIO $ hPutStrLn stderr "Couldn't parse" | |
| 34 | Just ast -> do | |
| 35 | hoist $ buildAST ast | |
| 36 | mostRecentDef >>= liftIO . Text.hPutStrLn stderr . ppll | |
| 37 | repl | |
| 38 | where | |
| 39 | eofHandler e | |
| 40 | | isEOFError e = return Nothing | |
| 41 | | otherwise = ioError e | |
| 42 | ||
| 43 | type Binds = Map.Map String Operand | |
| 44 | ||
| 45 | buildAST :: AST -> ModuleBuilder Operand | |
| 46 | buildAST (Function (Prototype nameStr paramStrs) body) = do | |
| 47 | let n = fromString nameStr | |
| 48 | function n params Type.double $ \ops -> do | |
| 49 | let binds = Map.fromList (zip paramStrs ops) | |
| 50 | flip runReaderT binds $ buildExpr body >>= ret | |
| 51 | where params = zip (repeat Type.double) (map fromString paramStrs) | |
| 52 | ||
| 53 | buildAST (Extern (Prototype nameStr params)) = | |
| 54 | extern (fromString nameStr) (replicate (length params) Type.double) Type.double | |
| 55 | ||
| 56 | buildAST (TopLevelExpr x) = function "__anon_expr" [] Type.double $ | |
| 57 | const $ flip runReaderT mempty $ buildExpr x >>= ret | |
| 58 | ||
| 59 | buildExpr :: Expr -> ReaderT Binds (IRBuilderT ModuleBuilder) Operand | |
| 60 | buildExpr (Num x) = pure $ ConstantOperand (Float (Double x)) | |
| 61 | buildExpr (Var n) = do | |
| 62 | binds <- ask | |
| 63 | case binds Map.!? n of | |
| 64 | Just x -> pure x | |
| 65 | Nothing -> error $ "'" <> n <> "' doesn't exist in scope" | |
| 66 | ||
| 67 | buildExpr (BinOp op a b) = do | |
| 68 | opA <- buildExpr a | |
| 69 | opB <- buildExpr b | |
| 70 | tmp <- instr opA opB | |
| 71 | if isCmp | |
| 72 | then uitofp tmp Type.double | |
| 73 | else return tmp | |
| 74 | where isCmp | |
| 75 | | Cmp _ <- op = True | |
| 76 | | otherwise = False | |
| 77 | instr = case op of | |
| 78 | K.Add -> fadd | |
| 79 | K.Sub -> fsub | |
| 80 | K.Mul -> fmul | |
| 81 | K.Cmp LT -> fcmp OLT | |
| 82 | K.Cmp GT -> fcmp OGT | |
| 83 | K.Cmp EQ -> fcmp OEQ | |
| 84 | ||
| 85 | buildExpr (Call callee params) = do | |
| 86 | paramOps <- mapM buildExpr params | |
| 87 | let nam = fromString callee | |
| 88 | -- get a pointer to the function | |
| 89 | typ = FunctionType Type.double (replicate (length params) Type.double) False | |
| 90 | ptrTyp = Type.PointerType typ (AddrSpace 0) | |
| 91 | ref = GlobalReference ptrTyp nam | |
| 92 | call (ConstantOperand ref) (zip paramOps (repeat [])) |
| 1 | {-| | |
| 2 | Shoving away gross stuff into this one module. | |
| 3 | -} | |
| 4 | module Utils where | |
| 5 | ||
| 6 | import Control.Monad.Trans.State | |
| 7 | import Data.Functor.Identity | |
| 8 | import LLVM.AST | |
| 9 | import LLVM.IRBuilder.Module | |
| 10 | import LLVM.IRBuilder.Internal.SnocList | |
| 11 | ||
| 12 | mostRecentDef :: Monad m => ModuleBuilderT m Definition | |
| 13 | mostRecentDef = last . getSnocList . builderDefs <$> liftModuleState get | |
| 14 | ||
| 15 | hoist :: Monad m => ModuleBuilder a -> ModuleBuilderT m a | |
| 16 | hoist m = ModuleBuilderT $ StateT $ | |
| 17 | return . runIdentity . runStateT (unModuleBuilderT m) |
| 4 | 4 | import Text.Read |
| 5 | 5 | import Text.ParserCombinators.ReadP hiding ((+++), choice) |
| 6 | 6 | |
| 7 | data Expr = Num Float | |
| 7 | data Expr = Num Double | |
| 8 | 8 | | Var String |
| 9 | 9 | | BinOp BinOp Expr Expr |
| 10 | 10 | | Call String [Expr] |
| 1 | {-# LANGUAGE OverloadedStrings #-} | |
| 2 | ||
| 1 | 3 | import AST |
| 4 | import Utils | |
| 5 | import Control.Monad.IO.Class | |
| 6 | import qualified Data.Text.Lazy.IO as Text | |
| 7 | import LLVM.AST.Constant | |
| 8 | import LLVM.AST.Float | |
| 9 | import LLVM.AST.Operand | |
| 10 | import LLVM.AST.Type as Type | |
| 11 | import LLVM.IRBuilder | |
| 12 | import LLVM.Pretty | |
| 2 | 13 | import System.IO |
| 3 | import Text.Read | |
| 4 | main = do | |
| 5 | hPutStr stderr "ready> " | |
| 6 | ast <- (readMaybe <$> getLine) :: IO (Maybe AST) | |
| 14 | import Text.Read (readMaybe) | |
| 15 | ||
| 16 | main = buildModuleT "main" repl | |
| 17 | ||
| 18 | repl :: ModuleBuilderT IO () | |
| 19 | repl = do | |
| 20 | liftIO $ hPutStr stderr "ready> " | |
| 21 | ast <- liftIO $ readMaybe <$> getLine | |
| 7 | 22 | case ast of |
| 8 | Just x -> hPrint stderr x | |
| 9 | Nothing -> hPutStrLn stderr "Couldn't parse" | |
| 10 | main | |
| 23 | Nothing -> liftIO $ hPutStrLn stderr "Couldn't parse" | |
| 24 | Just x -> do | |
| 25 | hoist $ buildAST x | |
| 26 | mostRecentDef >>= liftIO . Text.hPutStrLn stderr . ppll | |
| 27 | repl | |
| 28 | where | |
| 29 | ||
| 30 | buildAST :: AST -> ModuleBuilder Operand | |
| 31 | buildAST (TopLevelExpr x) = function "__anon_expr" [] Type.double $ | |
| 32 | const $ buildExpr x >>= ret | |
| 33 | ||
| 34 | buildExpr :: Expr -> IRBuilderT ModuleBuilder Operand | |
| 35 | buildExpr (Num x) = pure $ ConstantOperand (Float (Double x)) |
| 1 | {-| | |
| 2 | Shoving away gross stuff into this one module. | |
| 3 | -} | |
| 4 | module Utils where | |
| 5 | ||
| 6 | import Control.Monad.Trans.State | |
| 7 | import Data.Functor.Identity | |
| 8 | import LLVM.AST | |
| 9 | import LLVM.IRBuilder.Module | |
| 10 | import LLVM.IRBuilder.Internal.SnocList | |
| 11 | ||
| 12 | mostRecentDef :: Monad m => ModuleBuilderT m Definition | |
| 13 | mostRecentDef = last . getSnocList . builderDefs <$> liftModuleState get | |
| 14 | ||
| 15 | hoist :: Monad m => ModuleBuilder a -> ModuleBuilderT m a | |
| 16 | hoist m = ModuleBuilderT $ StateT $ | |
| 17 | return . runIdentity . runStateT (unModuleBuilderT m) |
| 18 | 18 | , parseVar |
| 19 | 19 | , parseCall |
| 20 | 20 | , parseBinOp "<" 10 (Cmp LT) |
| 21 | , parseBinOp ">" 10 (Cmp GT) | |
| 22 | , parseBinOp "==" 10 (Cmp EQ) | |
| 21 | 23 | , parseBinOp "+" 20 Add |
| 22 | 24 | , parseBinOp "-" 20 Sub |
| 23 | 25 | , parseBinOp "*" 40 Mul |
| 1 | 1 | {-# LANGUAGE OverloadedStrings #-} |
| 2 | 2 | |
| 3 | import AST | |
| 3 | import AST as K -- K for Kaleidoscope | |
| 4 | 4 | import Utils |
| 5 | 5 | import Control.Monad.IO.Class |
| 6 | 6 | import qualified Data.Text.Lazy.IO as Text |
| 7 | 7 | import LLVM.AST.Constant |
| 8 | 8 | import LLVM.AST.Float |
| 9 | import LLVM.AST.FloatingPointPredicate hiding (False, True) | |
| 9 | 10 | import LLVM.AST.Operand |
| 10 | 11 | import LLVM.AST.Type as Type |
| 11 | 12 | import LLVM.IRBuilder |
⋮
| 33 | 34 | |
| 34 | 35 | buildExpr :: Expr -> IRBuilderT ModuleBuilder Operand |
| 35 | 36 | buildExpr (Num x) = pure $ ConstantOperand (Float (Double x)) |
| 37 | buildExpr (BinOp op a b) = do | |
| 38 | opA <- buildExpr a | |
| 39 | opB <- buildExpr b | |
| 40 | tmp <- instr opA opB | |
| 41 | if isCmp | |
| 42 | then uitofp tmp Type.double | |
| 43 | else return tmp | |
| 44 | where isCmp | |
| 45 | | Cmp _ <- op = True | |
| 46 | | otherwise = False | |
| 47 | instr = case op of | |
| 48 | K.Add -> fadd | |
| 49 | K.Sub -> fsub | |
| 50 | K.Mul -> fmul | |
| 51 | K.Cmp LT -> fcmp OLT | |
| 52 | K.Cmp GT -> fcmp OGT | |
| 53 | K.Cmp EQ -> fcmp OEQ |
| 2 | 2 | |
| 3 | 3 | import AST as K -- K for Kaleidoscope |
| 4 | 4 | import Utils |
| 5 | import Control.Monad.Trans.Reader | |
| 5 | 6 | import Control.Monad.IO.Class |
| 7 | import Data.String | |
| 8 | import qualified Data.Map as Map | |
| 6 | 9 | import qualified Data.Text.Lazy.IO as Text |
| 7 | 10 | import LLVM.AST.Constant |
| 8 | 11 | import LLVM.AST.Float |
⋮
| 28 | 31 | repl |
| 29 | 32 | where |
| 30 | 33 | |
| 34 | type Binds = Map.Map String Operand | |
| 35 | ||
| 31 | 36 | buildAST :: AST -> ModuleBuilder Operand |
| 37 | buildAST (Function (Prototype nameStr paramStrs) body) = do | |
| 38 | let n = fromString nameStr | |
| 39 | function n params Type.double $ \ops -> do | |
| 40 | let binds = Map.fromList (zip paramStrs ops) | |
| 41 | flip runReaderT binds $ buildExpr body >>= ret | |
| 42 | where params = zip (repeat Type.double) (map fromString paramStrs) | |
| 43 | ||
| 32 | 44 | buildAST (TopLevelExpr x) = function "__anon_expr" [] Type.double $ |
| 33 | const $ buildExpr x >>= ret | |
| 45 | const $ flip runReaderT mempty $ buildExpr x >>= ret | |
| 34 | 46 | |
| 35 | buildExpr :: Expr -> IRBuilderT ModuleBuilder Operand | |
| 47 | buildExpr :: Expr -> ReaderT Binds (IRBuilderT ModuleBuilder) Operand | |
| 36 | 48 | buildExpr (Num x) = pure $ ConstantOperand (Float (Double x)) |
| 49 | buildExpr (Var n) = do | |
| 50 | binds <- ask | |
| 51 | case binds Map.!? n of | |
| 52 | Just x -> pure x | |
| 53 | Nothing -> error $ "'" <> n <> "' doesn't exist in scope" | |
| 54 | ||
| 37 | 55 | buildExpr (BinOp op a b) = do |
| 38 | 56 | opA <- buildExpr a |
| 39 | 57 | opB <- buildExpr b |
| 41 | 41 | flip runReaderT binds $ buildExpr body >>= ret |
| 42 | 42 | where params = zip (repeat Type.double) (map fromString paramStrs) |
| 43 | 43 | |
| 44 | buildAST (Extern (Prototype nameStr params)) = | |
| 45 | extern (fromString nameStr) (replicate (length params) Type.double) Type.double | |
| 46 | ||
| 44 | 47 | buildAST (TopLevelExpr x) = function "__anon_expr" [] Type.double $ |
| 45 | 48 | const $ flip runReaderT mempty $ buildExpr x >>= ret |
| 46 | 49 |
| 15 | 15 | import LLVM.IRBuilder |
| 16 | 16 | import LLVM.Pretty |
| 17 | 17 | import System.IO |
| 18 | import System.IO.Error | |
| 18 | 19 | import Text.Read (readMaybe) |
| 19 | 20 | |
| 20 | main = buildModuleT "main" repl | |
| 21 | main :: IO () | |
| 22 | main = buildModuleT "main" repl >>= Text.hPutStrLn stderr . ("\n" <>) . ppll | |
| 21 | 23 | |
| 22 | 24 | repl :: ModuleBuilderT IO () |
| 23 | 25 | repl = do |
| 24 | 26 | liftIO $ hPutStr stderr "ready> " |
| 25 | ast <- liftIO $ readMaybe <$> getLine | |
| 26 | case ast of | |
| 27 | Nothing -> liftIO $ hPutStrLn stderr "Couldn't parse" | |
| 28 | Just x -> do | |
| 29 | hoist $ buildAST x | |
| 30 | mostRecentDef >>= liftIO . Text.hPutStrLn stderr . ppll | |
| 31 | repl | |
| 32 | where | |
| 27 | mline <- liftIO $ catchIOError (Just <$> getLine) eofHandler | |
| 28 | case mline of | |
| 29 | Nothing -> return () | |
| 30 | Just l -> do | |
| 31 | case readMaybe l of | |
| 32 | Nothing -> liftIO $ hPutStrLn stderr "Couldn't parse" | |
| 33 | Just ast -> do | |
| 34 | hoist $ buildAST ast | |
| 35 | mostRecentDef >>= liftIO . Text.hPutStrLn stderr . ppll | |
| 36 | repl | |
| 37 | where | |
| 38 | eofHandler e | |
| 39 | | isEOFError e = return Nothing | |
| 40 | | otherwise = ioError e | |
| 33 | 41 | |
| 34 | 42 | type Binds = Map.Map String Operand |
| 35 | 43 |
| 7 | 7 | import Data.String |
| 8 | 8 | import qualified Data.Map as Map |
| 9 | 9 | import qualified Data.Text.Lazy.IO as Text |
| 10 | import LLVM.AST.AddrSpace | |
| 10 | 11 | import LLVM.AST.Constant |
| 11 | 12 | import LLVM.AST.Float |
| 12 | 13 | import LLVM.AST.FloatingPointPredicate hiding (False, True) |
⋮
| 80 | 81 | K.Cmp LT -> fcmp OLT |
| 81 | 82 | K.Cmp GT -> fcmp OGT |
| 82 | 83 | K.Cmp EQ -> fcmp OEQ |
| 84 | ||
| 85 | buildExpr (Call callee params) = do | |
| 86 | paramOps <- mapM buildExpr params | |
| 87 | let nam = fromString callee | |
| 88 | -- get a pointer to the function | |
| 89 | typ = FunctionType Type.double (replicate (length params) Type.double) False | |
| 90 | ptrTyp = Type.PointerType typ (AddrSpace 0) | |
| 91 | ref = GlobalReference ptrTyp nam | |
| 92 | call (ConstantOperand ref) (zip paramOps (repeat [])) |
| 2 | 2 | |
| 3 | 3 | import AST as K -- K for Kaleidoscope |
| 4 | 4 | import Utils |
| 5 | import Control.Monad | |
| 6 | import Control.Monad.Trans.Class | |
| 5 | 7 | import Control.Monad.Trans.Reader |
| 6 | 8 | import Control.Monad.IO.Class |
| 7 | 9 | import Data.String |
| 8 | 10 | import qualified Data.Map as Map |
| 9 | 11 | import qualified Data.Text.Lazy.IO as Text |
| 12 | import Foreign.Ptr | |
| 10 | 13 | import LLVM.AST.AddrSpace |
| 11 | 14 | import LLVM.AST.Constant |
| 12 | 15 | import LLVM.AST.Float |
| 13 | 16 | import LLVM.AST.FloatingPointPredicate hiding (False, True) |
| 14 | 17 | import LLVM.AST.Operand |
| 15 | 18 | import LLVM.AST.Type as Type |
| 19 | import LLVM.Context | |
| 16 | 20 | import LLVM.IRBuilder |
| 21 | import LLVM.Module | |
| 22 | import LLVM.OrcJIT | |
| 23 | import LLVM.OrcJIT.CompileLayer | |
| 24 | import LLVM.PassManager | |
| 17 | 25 | import LLVM.Pretty |
| 26 | import LLVM.Target | |
| 18 | 27 | import System.IO |
| 19 | 28 | import System.IO.Error |
| 20 | 29 | import Text.Read (readMaybe) |
| 21 | 30 | |
| 31 | foreign import ccall "dynamic" mkFun :: FunPtr (IO Double) -> IO Double | |
| 32 | ||
| 33 | data JITEnv = JITEnv | |
| 34 | { jitEnvContext :: Context | |
| 35 | , jitEnvCompileLayer :: IRCompileLayer ObjectLinkingLayer | |
| 36 | , jitEnvModuleKey :: ModuleKey | |
| 37 | } | |
| 38 | ||
| 22 | 39 | main :: IO () |
| 23 | main = buildModuleT "main" repl >>= Text.hPutStrLn stderr . ("\n" <>) . ppll | |
| 40 | main = | |
| 41 | withContext $ \ctx -> withHostTargetMachineDefault $ \tm -> | |
| 42 | withExecutionSession $ \exSession -> | |
| 43 | withSymbolResolver exSession (SymbolResolver symResolver) $ \symResolverPtr -> | |
| 44 | withObjectLinkingLayer exSession (const $ pure symResolverPtr) $ \linkingLayer -> | |
| 45 | withIRCompileLayer linkingLayer tm $ \compLayer -> | |
| 46 | withModuleKey exSession $ \mdlKey -> do | |
| 47 | let env = JITEnv ctx compLayer mdlKey | |
| 48 | _ast <- runReaderT (buildModuleT "main" repl) env | |
| 49 | return () | |
| 50 | ||
| 51 | -- This can eventually be used to resolve external functions, e.g. a stdlib call | |
| 52 | symResolver :: MangledSymbol -> IO (Either JITSymbolError JITSymbol) | |
| 53 | symResolver sym = undefined | |
| 24 | 54 | |
| 25 | repl :: ModuleBuilderT IO () | |
| 55 | repl :: ModuleBuilderT (ReaderT JITEnv IO) () | |
| 26 | 56 | repl = do |
| 27 | 57 | liftIO $ hPutStr stderr "ready> " |
| 28 | 58 | mline <- liftIO $ catchIOError (Just <$> getLine) eofHandler |
⋮
| 32 | 62 | case readMaybe l of |
| 33 | 63 | Nothing -> liftIO $ hPutStrLn stderr "Couldn't parse" |
| 34 | 64 | Just ast -> do |
| 35 | hoist $ buildAST ast | |
| 36 | mostRecentDef >>= liftIO . Text.hPutStrLn stderr . ppll | |
| 65 | anon <- isAnonExpr <$> hoist (buildAST ast) | |
| 66 | def <- mostRecentDef | |
| 67 | ||
| 68 | llvmAst <- moduleSoFar "main" | |
| 69 | ctx <- lift $ asks jitEnvContext | |
| 70 | env <- lift ask | |
| 71 | liftIO $ withModuleFromAST ctx llvmAst $ \mdl -> do | |
| 72 | Text.hPutStrLn stderr $ ppll def | |
| 73 | let spec = defaultCuratedPassSetSpec { optLevel = Just 3 } | |
| 74 | -- this returns true if the module was modified | |
| 75 | withPassManager spec $ flip runPassManager mdl | |
| 76 | when anon (jit env mdl >>= hPrint stderr) | |
| 77 | ||
| 78 | when anon (removeDef def) | |
| 37 | 79 | repl |
| 38 | 80 | where |
| 39 | 81 | eofHandler e |
| 40 | 82 | | isEOFError e = return Nothing |
| 41 | 83 | | otherwise = ioError e |
| 84 | isAnonExpr (ConstantOperand (GlobalReference _ "__anon_expr")) = True | |
| 85 | isAnonExpr _ = False | |
| 86 | ||
| 87 | jit :: JITEnv -> Module -> IO Double | |
| 88 | jit JITEnv{jitEnvCompileLayer=compLayer, jitEnvModuleKey=mdlKey} mdl = | |
| 89 | withModule compLayer mdlKey mdl $ do | |
| 90 | mangled <- mangleSymbol compLayer "__anon_expr" | |
| 91 | Right (JITSymbol fPtr _) <- findSymbolIn compLayer mdlKey mangled False | |
| 92 | mkFun (castPtrToFunPtr (wordPtrToPtr fPtr)) | |
| 42 | 93 | |
| 43 | 94 | type Binds = Map.Map String Operand |
| 44 | 95 |
| 4 | 4 | module Utils where |
| 5 | 5 | |
| 6 | 6 | import Control.Monad.Trans.State |
| 7 | import Data.ByteString.Short (ShortByteString) | |
| 7 | 8 | import Data.Functor.Identity |
| 9 | import Data.List | |
| 8 | 10 | import LLVM.AST |
| 9 | 11 | import LLVM.IRBuilder.Module |
| 10 | 12 | import LLVM.IRBuilder.Internal.SnocList |
| 11 | 13 | |
| 14 | moduleSoFar :: MonadModuleBuilder m => ShortByteString -> m Module | |
| 15 | moduleSoFar nm = do | |
| 16 | s <- liftModuleState get | |
| 17 | let ds = getSnocList (builderDefs s) | |
| 18 | return $ defaultModule { moduleName = nm, moduleDefinitions = ds } | |
| 19 | ||
| 20 | removeDef :: MonadModuleBuilder m => Definition -> m () | |
| 21 | removeDef def = liftModuleState (modify update) | |
| 22 | where | |
| 23 | update (ModuleBuilderState defs typeDefs) = | |
| 24 | let newDefs = SnocList (delete def (getSnocList defs)) | |
| 25 | in ModuleBuilderState newDefs typeDefs | |
| 26 | ||
| 12 | 27 | mostRecentDef :: Monad m => ModuleBuilderT m Definition |
| 13 | 28 | mostRecentDef = last . getSnocList . builderDefs <$> liftModuleState get |
| 14 | 29 |
| 2 | 2 | |
| 3 | 3 | import AST as K -- K for Kaleidoscope |
| 4 | 4 | import Utils |
| 5 | import Control.Monad.Trans.Class | |
| 5 | 6 | import Control.Monad.Trans.Reader |
| 6 | 7 | import Control.Monad.IO.Class |
| 7 | 8 | import Data.String |
⋮
| 13 | 14 | import LLVM.AST.FloatingPointPredicate hiding (False, True) |
| 14 | 15 | import LLVM.AST.Operand |
| 15 | 16 | import LLVM.AST.Type as Type |
| 17 | import LLVM.Context | |
| 16 | 18 | import LLVM.IRBuilder |
| 19 | import LLVM.Module | |
| 20 | import LLVM.PassManager | |
| 17 | 21 | import LLVM.Pretty |
| 22 | import LLVM.Target | |
| 18 | 23 | import System.IO |
| 19 | 24 | import System.IO.Error |
| 20 | 25 | import Text.Read (readMaybe) |
| 21 | 26 | |
| 22 | 27 | main :: IO () |
| 23 | main = buildModuleT "main" repl >>= Text.hPutStrLn stderr . ("\n" <>) . ppll | |
| 28 | main = do | |
| 29 | withContext $ \ctx -> withHostTargetMachineDefault $ \tm -> do | |
| 30 | ast <- runReaderT (buildModuleT "main" repl) ctx | |
| 31 | return () | |
| 24 | 32 | |
| 25 | repl :: ModuleBuilderT IO () | |
| 33 | repl :: ModuleBuilderT (ReaderT Context IO) () | |
| 26 | 34 | repl = do |
| 27 | 35 | liftIO $ hPutStr stderr "ready> " |
| 28 | 36 | mline <- liftIO $ catchIOError (Just <$> getLine) eofHandler |
⋮
| 34 | 42 | Just ast -> do |
| 35 | 43 | hoist $ buildAST ast |
| 36 | 44 | mostRecentDef >>= liftIO . Text.hPutStrLn stderr . ppll |
| 45 | ||
| 46 | ast <- moduleSoFar "main" | |
| 47 | ctx <- lift ask | |
| 48 | liftIO $ withModuleFromAST ctx ast $ \mdl -> do | |
| 49 | let spec = defaultCuratedPassSetSpec { optLevel = Just 3 } | |
| 50 | -- this returns true if the module was modified | |
| 51 | withPassManager spec $ flip runPassManager mdl | |
| 52 | Text.hPutStrLn stderr . ("\n" <>) . ppllvm =<< moduleAST mdl | |
| 37 | 53 | repl |
| 38 | 54 | where |
| 39 | 55 | eofHandler e |
| 4 | 4 | module Utils where |
| 5 | 5 | |
| 6 | 6 | import Control.Monad.Trans.State |
| 7 | import Data.ByteString.Short (ShortByteString) | |
| 7 | 8 | import Data.Functor.Identity |
| 8 | 9 | import LLVM.AST |
| 9 | 10 | import LLVM.IRBuilder.Module |
| 10 | 11 | import LLVM.IRBuilder.Internal.SnocList |
| 11 | 12 | |
| 13 | moduleSoFar :: MonadModuleBuilder m => ShortByteString -> m Module | |
| 14 | moduleSoFar nm = do | |
| 15 | s <- liftModuleState get | |
| 16 | let ds = getSnocList (builderDefs s) | |
| 17 | return $ defaultModule { moduleName = nm, moduleDefinitions = ds } | |
| 18 | ||
| 12 | 19 | mostRecentDef :: Monad m => ModuleBuilderT m Definition |
| 13 | 20 | mostRecentDef = last . getSnocList . builderDefs <$> liftModuleState get |
| 14 | 21 |
| 2 | 2 | |
| 3 | 3 | import AST as K -- K for Kaleidoscope |
| 4 | 4 | import Utils |
| 5 | import Control.Monad | |
| 5 | 6 | import Control.Monad.Trans.Class |
| 6 | 7 | import Control.Monad.Trans.Reader |
| 7 | 8 | import Control.Monad.IO.Class |
⋮
| 17 | 18 | import LLVM.Context |
| 18 | 19 | import LLVM.IRBuilder |
| 19 | 20 | import LLVM.Module |
| 21 | import LLVM.OrcJIT | |
| 22 | import LLVM.OrcJIT.CompileLayer | |
| 20 | 23 | import LLVM.PassManager |
| 21 | 24 | import LLVM.Pretty |
| 22 | 25 | import LLVM.Target |
⋮
| 24 | 27 | import System.IO.Error |
| 25 | 28 | import Text.Read (readMaybe) |
| 26 | 29 | |
| 30 | data JITEnv = JITEnv | |
| 31 | { jitEnvContext :: Context | |
| 32 | , jitEnvCompileLayer :: IRCompileLayer ObjectLinkingLayer | |
| 33 | , jitEnvModuleKey :: ModuleKey | |
| 34 | } | |
| 35 | ||
| 27 | 36 | main :: IO () |
| 28 | main = do | |
| 29 | withContext $ \ctx -> withHostTargetMachineDefault $ \tm -> do | |
| 30 | ast <- runReaderT (buildModuleT "main" repl) ctx | |
| 31 | return () | |
| 37 | main = | |
| 38 | withContext $ \ctx -> withHostTargetMachineDefault $ \tm -> | |
| 39 | withExecutionSession $ \exSession -> | |
| 40 | withSymbolResolver exSession (SymbolResolver symResolver) $ \symResolverPtr -> | |
| 41 | withObjectLinkingLayer exSession (const $ pure symResolverPtr) $ \linkingLayer -> | |
| 42 | withIRCompileLayer linkingLayer tm $ \compLayer -> | |
| 43 | withModuleKey exSession $ \mdlKey -> do | |
| 44 | let env = JITEnv ctx compLayer mdlKey | |
| 45 | _ast <- runReaderT (buildModuleT "main" repl) env | |
| 46 | return () | |
| 47 | ||
| 48 | -- This can eventually be used to resolve external functions, e.g. a stdlib call | |
| 49 | symResolver :: MangledSymbol -> IO (Either JITSymbolError JITSymbol) | |
| 50 | symResolver sym = undefined | |
| 32 | 51 | |
| 33 | repl :: ModuleBuilderT (ReaderT Context IO) () | |
| 52 | repl :: ModuleBuilderT (ReaderT JITEnv IO) () | |
| 34 | 53 | repl = do |
| 35 | 54 | liftIO $ hPutStr stderr "ready> " |
| 36 | 55 | mline <- liftIO $ catchIOError (Just <$> getLine) eofHandler |
⋮
| 40 | 59 | case readMaybe l of |
| 41 | 60 | Nothing -> liftIO $ hPutStrLn stderr "Couldn't parse" |
| 42 | 61 | Just ast -> do |
| 43 | hoist $ buildAST ast | |
| 44 | mostRecentDef >>= liftIO . Text.hPutStrLn stderr . ppll | |
| 45 | ||
| 46 | ast <- moduleSoFar "main" | |
| 47 | ctx <- lift ask | |
| 48 | liftIO $ withModuleFromAST ctx ast $ \mdl -> do | |
| 62 | anon <- isAnonExpr <$> hoist (buildAST ast) | |
| 63 | def <- mostRecentDef | |
| 64 | ||
| 65 | llvmAst <- moduleSoFar "main" | |
| 66 | ctx <- lift $ asks jitEnvContext | |
| 67 | env <- lift ask | |
| 68 | liftIO $ withModuleFromAST ctx llvmAst $ \mdl -> do | |
| 69 | Text.hPutStrLn stderr $ ppll def | |
| 49 | 70 | let spec = defaultCuratedPassSetSpec { optLevel = Just 3 } |
| 50 | 71 | -- this returns true if the module was modified |
| 51 | 72 | withPassManager spec $ flip runPassManager mdl |
| 52 | Text.hPutStrLn stderr . ("\n" <>) . ppllvm =<< moduleAST mdl | |
| 73 | when anon (jit env mdl >>= hPrint stderr) | |
| 74 | ||
| 75 | when anon (removeDef def) | |
| 53 | 76 | repl |
| 54 | 77 | where |
| 55 | 78 | eofHandler e |
| 56 | 79 | | isEOFError e = return Nothing |
| 57 | 80 | | otherwise = ioError e |
| 81 | isAnonExpr (ConstantOperand (GlobalReference _ "__anon_expr")) = True | |
| 82 | isAnonExpr _ = False | |
| 83 | ||
| 84 | jit :: JITEnv -> Module -> IO Double | |
| 85 | jit JITEnv{jitEnvCompileLayer=compLayer, jitEnvModuleKey=mdlKey} mdl = | |
| 86 | withModule compLayer mdlKey mdl $ | |
| 87 | return 0 | |
| 58 | 88 | |
| 59 | 89 | type Binds = Map.Map String Operand |
| 60 | 90 |
| 6 | 6 | import Control.Monad.Trans.State |
| 7 | 7 | import Data.ByteString.Short (ShortByteString) |
| 8 | 8 | import Data.Functor.Identity |
| 9 | import Data.List | |
| 9 | 10 | import LLVM.AST |
| 10 | 11 | import LLVM.IRBuilder.Module |
| 11 | 12 | import LLVM.IRBuilder.Internal.SnocList |
⋮
| 16 | 17 | let ds = getSnocList (builderDefs s) |
| 17 | 18 | return $ defaultModule { moduleName = nm, moduleDefinitions = ds } |
| 18 | 19 | |
| 20 | removeDef :: MonadModuleBuilder m => Definition -> m () | |
| 21 | removeDef def = liftModuleState (modify update) | |
| 22 | where | |
| 23 | update (ModuleBuilderState defs typeDefs) = | |
| 24 | let newDefs = SnocList (delete def (getSnocList defs)) | |
| 25 | in ModuleBuilderState newDefs typeDefs | |
| 26 | ||
| 19 | 27 | mostRecentDef :: Monad m => ModuleBuilderT m Definition |
| 20 | 28 | mostRecentDef = last . getSnocList . builderDefs <$> liftModuleState get |
| 21 | 29 |
| 9 | 9 | import Data.String |
| 10 | 10 | import qualified Data.Map as Map |
| 11 | 11 | import qualified Data.Text.Lazy.IO as Text |
| 12 | import Foreign.Ptr | |
| 12 | 13 | import LLVM.AST.AddrSpace |
| 13 | 14 | import LLVM.AST.Constant |
| 14 | 15 | import LLVM.AST.Float |
⋮
| 27 | 28 | import System.IO.Error |
| 28 | 29 | import Text.Read (readMaybe) |
| 29 | 30 | |
| 31 | foreign import ccall "dynamic" mkFun :: FunPtr (IO Double) -> IO Double | |
| 32 | ||
| 30 | 33 | data JITEnv = JITEnv |
| 31 | 34 | { jitEnvContext :: Context |
| 32 | 35 | , jitEnvCompileLayer :: IRCompileLayer ObjectLinkingLayer |
⋮
| 83 | 86 | |
| 84 | 87 | jit :: JITEnv -> Module -> IO Double |
| 85 | 88 | jit JITEnv{jitEnvCompileLayer=compLayer, jitEnvModuleKey=mdlKey} mdl = |
| 86 | withModule compLayer mdlKey mdl $ | |
| 87 | return 0 | |
| 89 | withModule compLayer mdlKey mdl $ do | |
| 90 | mangled <- mangleSymbol compLayer "__anon_expr" | |
| 91 | Right (JITSymbol fPtr _) <- findSymbolIn compLayer mdlKey mangled False | |
| 92 | mkFun (castPtrToFunPtr (wordPtrToPtr fPtr)) | |
| 88 | 93 | |
| 89 | 94 | type Binds = Map.Map String Operand |
| 90 | 95 |
| 2 | 2 | |
| 3 | 3 | import Data.Char |
| 4 | 4 | import Text.Read |
| 5 | import Text.ParserCombinators.ReadP hiding ((+++), choice) | |
| 5 | import Text.ParserCombinators.ReadP hiding ((+++), (<++), choice) | |
| 6 | 6 | |
| 7 | 7 | data Expr = Num Double |
| 8 | 8 | | Var String |
| 9 | 9 | | BinOp BinOp Expr Expr |
| 10 | 10 | | Call String [Expr] |
| 11 | | If Expr Expr Expr | |
| 12 | | For String Expr Expr (Maybe Expr) Expr | |
| 11 | 13 | deriving Show |
| 12 | 14 | |
| 13 | 15 | data BinOp = Add | Sub | Mul | Cmp Ordering |
⋮
| 17 | 19 | readPrec = parens $ choice [ parseNum |
| 18 | 20 | , parseVar |
| 19 | 21 | , parseCall |
| 22 | , parseIf | |
| 23 | , parseFor | |
| 20 | 24 | , parseBinOp "<" 10 (Cmp LT) |
| 21 | 25 | , parseBinOp ">" 10 (Cmp GT) |
| 22 | 26 | , parseBinOp "==" 10 (Cmp EQ) |
⋮
| 28 | 32 | parseVar = Var <$> lift (munch1 isAlpha) |
| 29 | 33 | parseBinOp s prc op = prec prc $ do |
| 30 | 34 | a <- step readPrec |
| 31 | lift $ do | |
| 32 | skipSpaces | |
| 33 | string s | |
| 34 | skipSpaces | |
| 35 | spaced $ string s | |
| 35 | 36 | b <- readPrec |
| 36 | 37 | return (BinOp op a b) |
| 37 | 38 | parseCall = do |
⋮
| 40 | 41 | sepBy (readS_to_P reads) |
| 41 | 42 | (skipSpaces >> char ',' >> skipSpaces) |
| 42 | 43 | return (Call func params) |
| 44 | parseIf = do | |
| 45 | spaced $ string "if" | |
| 46 | cond <- readPrec | |
| 47 | spaced $ string "then" | |
| 48 | thenE <- readPrec | |
| 49 | spaced $ string "else" | |
| 50 | elseE <- readPrec | |
| 51 | return (If cond thenE elseE) | |
| 52 | parseFor = do | |
| 53 | spaced $ string "for" | |
| 54 | identifier <- lift (munch1 isAlpha) | |
| 55 | spaced $ char '=' | |
| 56 | start <- readPrec | |
| 57 | spaced $ char ',' | |
| 58 | cond <- readPrec | |
| 59 | stp <- (spaced (char ',') >> Just <$> step readPrec) | |
| 60 | <++ pure Nothing | |
| 61 | spaced $ string "in" | |
| 62 | body <- readPrec | |
| 63 | return (For identifier start cond stp body) | |
| 64 | spaced f = lift $ skipSpaces >> f >> skipSpaces | |
| 43 | 65 | |
| 44 | 66 | data Prototype = Prototype String [String] |
| 45 | 67 | deriving Show |
| 1 | 1 | {-# LANGUAGE OverloadedStrings #-} |
| 2 | {-# LANGUAGE RecursiveDo #-} | |
| 2 | 3 | |
| 3 | 4 | import AST as K -- K for Kaleidoscope |
| 4 | 5 | import Utils |
⋮
| 141 | 142 | ptrTyp = Type.PointerType typ (AddrSpace 0) |
| 142 | 143 | ref = GlobalReference ptrTyp nam |
| 143 | 144 | call (ConstantOperand ref) (zip paramOps (repeat [])) |
| 145 | ||
| 146 | buildExpr (If cond thenE elseE) = mdo | |
| 147 | _ifB <- block `named` "if" | |
| 148 | ||
| 149 | -- since everything is a double, false == 0 | |
| 150 | let zero = ConstantOperand (Float (Double 0)) | |
| 151 | condV <- buildExpr cond | |
| 152 | cmp <- fcmp ONE zero condV `named` "cmp" | |
| 153 | ||
| 154 | condBr cmp thenB elseB | |
| 155 | ||
| 156 | thenB <- block `named` "then" | |
| 157 | thenOp <- buildExpr thenE | |
| 158 | br mergeB | |
| 159 | ||
| 160 | elseB <- block `named` "else" | |
| 161 | elseOp <- buildExpr elseE | |
| 162 | br mergeB | |
| 163 | ||
| 164 | mergeB <- block `named` "ifcont" | |
| 165 | phi [(thenOp, thenB), (elseOp, elseB)] | |
| 166 | ||
| 167 | buildExpr (For name init cond mStep body) = mdo | |
| 168 | preheaderB <- block `named` "preheader" | |
| 169 | ||
| 170 | initV <- buildExpr init `named` "init" | |
| 171 | ||
| 172 | -- build the condition expression with 'i' in the bindings | |
| 173 | initCondV <- withReaderT (Map.insert name initV) $ | |
| 174 | (buildExpr cond >>= fcmp ONE zero) `named` "initcond" | |
| 175 | ||
| 176 | -- skip the loop if we don't meet the condition with the init | |
| 177 | condBr initCondV loopB afterB | |
| 178 | ||
| 179 | loopB <- block `named` "loop" | |
| 180 | i <- phi [(initV, preheaderB), (nextVar, loopB)] `named` "i" | |
| 181 | ||
| 182 | -- build the body expression with 'i' in the bindings | |
| 183 | withReaderT (Map.insert name i) $ buildExpr body `named` "body" | |
| 184 | ||
| 185 | -- default to 1 if there's no step defined | |
| 186 | stepV <- case mStep of | |
| 187 | Just step -> buildExpr step | |
| 188 | Nothing -> return $ ConstantOperand (Float (Double 1)) | |
| 189 | ||
| 190 | nextVar <- fadd i stepV `named` "nextvar" | |
| 191 | ||
| 192 | let zero = ConstantOperand (Float (Double 0)) | |
| 193 | -- again we need 'i' in the bindings | |
| 194 | condV <- withReaderT (Map.insert name i) $ | |
| 195 | (buildExpr cond >>= fcmp ONE zero) `named` "cond" | |
| 196 | condBr condV loopB afterB | |
| 197 | ||
| 198 | afterB <- block `named` "after" | |
| 199 | -- since a for loop doesn't really have a value, return 0 | |
| 200 | return $ ConstantOperand (Float (Double 0)) | |
| 201 |
| 8 | 8 | | Var String |
| 9 | 9 | | BinOp BinOp Expr Expr |
| 10 | 10 | | Call String [Expr] |
| 11 | | If Expr Expr Expr | |
| 11 | 12 | deriving Show |
| 12 | 13 | |
| 13 | 14 | data BinOp = Add | Sub | Mul | Cmp Ordering |
⋮
| 17 | 18 | readPrec = parens $ choice [ parseNum |
| 18 | 19 | , parseVar |
| 19 | 20 | , parseCall |
| 21 | , parseIf | |
| 20 | 22 | , parseBinOp "<" 10 (Cmp LT) |
| 21 | 23 | , parseBinOp ">" 10 (Cmp GT) |
| 22 | 24 | , parseBinOp "==" 10 (Cmp EQ) |
⋮
| 40 | 42 | sepBy (readS_to_P reads) |
| 41 | 43 | (skipSpaces >> char ',' >> skipSpaces) |
| 42 | 44 | return (Call func params) |
| 45 | parseIf = do | |
| 46 | lift $ skipSpaces >> string "if" >> skipSpaces | |
| 47 | cond <- readPrec | |
| 48 | lift $ skipSpaces >> string "then" >> skipSpaces | |
| 49 | thenE <- readPrec | |
| 50 | lift $ skipSpaces >> string "else" >> skipSpaces | |
| 51 | elseE <- readPrec | |
| 52 | return (If cond thenE elseE) | |
| 43 | 53 | |
| 44 | 54 | data Prototype = Prototype String [String] |
| 45 | 55 | deriving Show |
| 30 | 30 | parseVar = Var <$> lift (munch1 isAlpha) |
| 31 | 31 | parseBinOp s prc op = prec prc $ do |
| 32 | 32 | a <- step readPrec |
| 33 | lift $ do | |
| 34 | skipSpaces | |
| 35 | string s | |
| 36 | skipSpaces | |
| 33 | spaced $ string s | |
| 37 | 34 | b <- readPrec |
| 38 | 35 | return (BinOp op a b) |
| 39 | 36 | parseCall = do |
⋮
| 43 | 40 | (skipSpaces >> char ',' >> skipSpaces) |
| 44 | 41 | return (Call func params) |
| 45 | 42 | parseIf = do |
| 46 | lift $ skipSpaces >> string "if" >> skipSpaces | |
| 43 | spaced $ string "if" | |
| 47 | 44 | cond <- readPrec |
| 48 | lift $ skipSpaces >> string "then" >> skipSpaces | |
| 45 | spaced $ string "then" | |
| 49 | 46 | thenE <- readPrec |
| 50 | lift $ skipSpaces >> string "else" >> skipSpaces | |
| 47 | spaced $ string "else" | |
| 51 | 48 | elseE <- readPrec |
| 52 | 49 | return (If cond thenE elseE) |
| 50 | spaced f = lift $ skipSpaces >> f >> skipSpaces | |
| 53 | 51 | |
| 54 | 52 | data Prototype = Prototype String [String] |
| 55 | 53 | deriving Show |
| 1 | 1 | {-# LANGUAGE OverloadedStrings #-} |
| 2 | {-# LANGUAGE RecursiveDo #-} | |
| 2 | 3 | |
| 3 | 4 | import AST as K -- K for Kaleidoscope |
| 4 | 5 | import Utils |
⋮
| 141 | 142 | ptrTyp = Type.PointerType typ (AddrSpace 0) |
| 142 | 143 | ref = GlobalReference ptrTyp nam |
| 143 | 144 | call (ConstantOperand ref) (zip paramOps (repeat [])) |
| 145 | ||
| 146 | buildExpr (If cond thenE elseE) = mdo | |
| 147 | _ifB <- block `named` "if" | |
| 148 | ||
| 149 | -- since everything is a double, false == 0 | |
| 150 | let zero = ConstantOperand (Float (Double 0)) | |
| 151 | condV <- buildExpr cond | |
| 152 | cmp <- fcmp ONE zero condV `named` "cmp" | |
| 153 | ||
| 154 | condBr cmp thenB elseB | |
| 155 | ||
| 156 | thenB <- block `named` "then" | |
| 157 | thenOp <- buildExpr thenE | |
| 158 | br mergeB | |
| 159 | ||
| 160 | elseB <- block `named` "else" | |
| 161 | elseOp <- buildExpr elseE | |
| 162 | br mergeB | |
| 163 | ||
| 164 | mergeB <- block `named` "ifcont" | |
| 165 | phi [(thenOp, thenB), (elseOp, elseB)] |
| 2 | 2 | |
| 3 | 3 | import Data.Char |
| 4 | 4 | import Text.Read |
| 5 | import Text.ParserCombinators.ReadP hiding ((+++), choice) | |
| 5 | import Text.ParserCombinators.ReadP hiding ((+++), (<++), choice) | |
| 6 | 6 | |
| 7 | 7 | data Expr = Num Double |
| 8 | 8 | | Var String |
| 9 | 9 | | BinOp BinOp Expr Expr |
| 10 | 10 | | Call String [Expr] |
| 11 | 11 | | If Expr Expr Expr |
| 12 | | For String Expr Expr (Maybe Expr) Expr | |
| 12 | 13 | deriving Show |
| 13 | 14 | |
| 14 | 15 | data BinOp = Add | Sub | Mul | Cmp Ordering |
⋮
| 19 | 20 | , parseVar |
| 20 | 21 | , parseCall |
| 21 | 22 | , parseIf |
| 23 | , parseFor | |
| 22 | 24 | , parseBinOp "<" 10 (Cmp LT) |
| 23 | 25 | , parseBinOp ">" 10 (Cmp GT) |
| 24 | 26 | , parseBinOp "==" 10 (Cmp EQ) |
⋮
| 47 | 49 | spaced $ string "else" |
| 48 | 50 | elseE <- readPrec |
| 49 | 51 | return (If cond thenE elseE) |
| 52 | parseFor = do | |
| 53 | spaced $ string "for" | |
| 54 | identifier <- lift (munch1 isAlpha) | |
| 55 | spaced $ char '=' | |
| 56 | start <- readPrec | |
| 57 | spaced $ char ',' | |
| 58 | cond <- readPrec | |
| 59 | stp <- (spaced (char ',') >> Just <$> step readPrec) | |
| 60 | <++ pure Nothing | |
| 61 | spaced $ string "in" | |
| 62 | body <- readPrec | |
| 63 | return (For identifier start cond stp body) | |
| 50 | 64 | spaced f = lift $ skipSpaces >> f >> skipSpaces |
| 51 | 65 | |
| 52 | 66 | data Prototype = Prototype String [String] |
| 163 | 163 | |
| 164 | 164 | mergeB <- block `named` "ifcont" |
| 165 | 165 | phi [(thenOp, thenB), (elseOp, elseB)] |
| 166 | ||
| 167 | buildExpr (For name init cond mStep body) = mdo | |
| 168 | preheaderB <- block `named` "preheader" | |
| 169 | ||
| 170 | initV <- buildExpr init `named` "init" | |
| 171 | ||
| 172 | -- build the condition expression with 'i' in the bindings | |
| 173 | initCondV <- withReaderT (Map.insert name initV) $ | |
| 174 | (buildExpr cond >>= fcmp ONE zero) `named` "initcond" | |
| 175 | ||
| 176 | -- skip the loop if we don't meet the condition with the init | |
| 177 | condBr initCondV loopB afterB | |
| 178 | ||
| 179 | loopB <- block `named` "loop" | |
| 180 | i <- phi [(initV, preheaderB), (nextVar, loopB)] `named` "i" | |
| 181 | ||
| 182 | -- build the body expression with 'i' in the bindings | |
| 183 | withReaderT (Map.insert name i) $ buildExpr body `named` "body" | |
| 184 | ||
| 185 | -- default to 1 if there's no step defined | |
| 186 | stepV <- case mStep of | |
| 187 | Just step -> buildExpr step | |
| 188 | Nothing -> return $ ConstantOperand (Float (Double 1)) | |
| 189 | ||
| 190 | nextVar <- fadd i stepV `named` "nextvar" | |
| 191 | ||
| 192 | let zero = ConstantOperand (Float (Double 0)) | |
| 193 | -- again we need 'i' in the bindings | |
| 194 | condV <- withReaderT (Map.insert name i) $ | |
| 195 | (buildExpr cond >>= fcmp ONE zero) `named` "cond" | |
| 196 | condBr condV loopB afterB | |
| 197 | ||
| 198 | afterB <- block `named` "after" | |
| 199 | -- since a for loop doesn't really have a value, return 0 | |
| 200 | return $ ConstantOperand (Float (Double 0)) | |
| 201 |
| 1 | stdlib.dylib | |
| 2 | stdlib.o | |
| 3 | Main |
| 19 | 19 | import LLVM.AST.Type as Type |
| 20 | 20 | import LLVM.Context |
| 21 | 21 | import LLVM.IRBuilder |
| 22 | import LLVM.Linking | |
| 22 | 23 | import LLVM.Module |
| 23 | 24 | import LLVM.OrcJIT |
| 24 | 25 | import LLVM.OrcJIT.CompileLayer |
| 25 | 26 | import LLVM.PassManager |
| 26 | 27 | import LLVM.Pretty |
| 27 | 28 | import LLVM.Target |
| 29 | import Numeric | |
| 28 | 30 | import System.IO |
| 29 | 31 | import System.IO.Error |
| 30 | 32 | import Text.Read (readMaybe) |
⋮
| 38 | 40 | } |
| 39 | 41 | |
| 40 | 42 | main :: IO () |
| 41 | main = | |
| 43 | main = do | |
| 44 | loadLibraryPermanently (Just "stdlib.dylib") | |
| 42 | 45 | withContext $ \ctx -> withHostTargetMachineDefault $ \tm -> |
| 43 | 46 | withExecutionSession $ \exSession -> |
| 44 | 47 | withSymbolResolver exSession (SymbolResolver symResolver) $ \symResolverPtr -> |
⋮
| 51 | 54 | |
| 52 | 55 | -- This can eventually be used to resolve external functions, e.g. a stdlib call |
| 53 | 56 | symResolver :: MangledSymbol -> IO (Either JITSymbolError JITSymbol) |
| 54 | symResolver sym = undefined | |
| 57 | symResolver sym = do | |
| 58 | ptr <- getSymbolAddressInProcess sym | |
| 59 | putStrLn $ "Resolving " <> show sym <> " to 0x" <> showHex ptr "" | |
| 60 | return (Right (JITSymbol ptr defaultJITSymbolFlags)) | |
| 55 | 61 | |
| 56 | 62 | repl :: ModuleBuilderT (ReaderT JITEnv IO) () |
| 57 | 63 | repl = do |
| 1 | stdlib.dylib: stdlib.c | |
| 2 | clang -shared $< -o $@ | |
| 3 | ||
| 4 | # for statically linking the stdlib: | |
| 5 | # make sure to change in Main.hs | |
| 6 | # loadLibraryPermanently (Just "stdlib.dylib") | |
| 7 | # to | |
| 8 | # loadLibraryPermanently Nothing | |
| 9 | stdlib.o: stdlib.c | |
| 10 | clang -c $< -o $@ | |
| 11 | ||
| 12 | Main: Main.hs stdlib.o | |
| 13 | ghc $^ -o $@ -optl -Wl,-exported_symbols_list,stdlib.syms \ | |
| 14 | -no-keep-hi-files -no-keep-o-files |
| 1 | #include <stdio.h> | |
| 2 | // Takes a double and writes it to stdout | |
| 3 | double putchard(double x) { | |
| 4 | int res = putchar((int)x); | |
| 5 | fflush(stdout); | |
| 6 | return (double)res; | |
| 7 | } |
| 1 | _putchard |
| 1 | #include <stdio.h> | |
| 2 | // Takes a double and writes it to stdout | |
| 3 | double putchard(double x) { | |
| 4 | int res = putchar((int)x); | |
| 5 | fflush(stdout); | |
| 6 | return (double)res; | |
| 7 | } |
| 1 | stdlib.dylib |
| 1 | stdlib.dylib: stdlib.c | |
| 2 | clang -shared $< -o $@ |
| 19 | 19 | import LLVM.AST.Type as Type |
| 20 | 20 | import LLVM.Context |
| 21 | 21 | import LLVM.IRBuilder |
| 22 | import LLVM.Linking | |
| 22 | 23 | import LLVM.Module |
| 23 | 24 | import LLVM.OrcJIT |
| 24 | 25 | import LLVM.OrcJIT.CompileLayer |
⋮
| 38 | 39 | } |
| 39 | 40 | |
| 40 | 41 | main :: IO () |
| 41 | main = | |
| 42 | main = do | |
| 43 | loadLibraryPermanently (Just "stdlib.dylib") | |
| 42 | 44 | withContext $ \ctx -> withHostTargetMachineDefault $ \tm -> |
| 43 | 45 | withExecutionSession $ \exSession -> |
| 44 | 46 | withSymbolResolver exSession (SymbolResolver symResolver) $ \symResolverPtr -> |
| 26 | 26 | import LLVM.PassManager |
| 27 | 27 | import LLVM.Pretty |
| 28 | 28 | import LLVM.Target |
| 29 | import Numeric | |
| 29 | 30 | import System.IO |
| 30 | 31 | import System.IO.Error |
| 31 | 32 | import Text.Read (readMaybe) |
⋮
| 53 | 54 | |
| 54 | 55 | -- This can eventually be used to resolve external functions, e.g. a stdlib call |
| 55 | 56 | symResolver :: MangledSymbol -> IO (Either JITSymbolError JITSymbol) |
| 56 | symResolver sym = undefined | |
| 57 | symResolver sym = do | |
| 58 | ptr <- getSymbolAddressInProcess sym | |
| 59 | putStrLn $ "Resolving " <> show sym <> " to 0x" <> showHex ptr "" | |
| 60 | return (Right (JITSymbol ptr defaultJITSymbolFlags)) | |
| 57 | 61 | |
| 58 | 62 | repl :: ModuleBuilderT (ReaderT JITEnv IO) () |
| 59 | 63 | repl = do |
| 1 | 1 | stdlib.dylib |
| 2 | stdlib.o | |
| 3 | Main |
| 1 | 1 | stdlib.dylib: stdlib.c |
| 2 | 2 | clang -shared $< -o $@ |
| 3 | ||
| 4 | # for statically linking the stdlib: | |
| 5 | # make sure to change in Main.hs | |
| 6 | # loadLibraryPermanently (Just "stdlib.dylib") | |
| 7 | # to | |
| 8 | # loadLibraryPermanently Nothing | |
| 9 | stdlib.o: stdlib.c | |
| 10 | clang -c $< -o $@ | |
| 11 | ||
| 12 | Main: Main.hs stdlib.o | |
| 13 | ghc $^ -o $@ -optl -Wl,-exported_symbols_list,stdlib.syms \ | |
| 14 | -no-keep-hi-files -no-keep-o-files |
| 1 | _putchard |