diff --git a/.gitignore b/.gitignore index b66b8f7..d042c78 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ cabal.project.local~ *.wat *.wasm result +*.tix diff --git a/app/Main.hs b/app/Main.hs index 736e6aa..aacc9ea 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -42,6 +42,7 @@ data CmdOptions = Options , breakpoints :: Maybe String , showTime :: Bool , showVersion :: Bool + , noVerify :: Bool } optionsParser :: Options.Applicative.Parser CmdOptions @@ -67,6 +68,7 @@ optionsParser = <*> optional (strOption (long "breakpoints" <> short 't' <> help "Breakpoints for the VM to trace (space separated list of program counter indices). -1 to trace on every instruction")) <*> switch (long "profile" <> short 'p' <> help "Show time spent parsing, compiling and running") <*> switch (long "version" <> short 'V' <> help "Show version") + <*> switch (long "no-verify" <> short 'n' <> help "Don't verify the program") prettyPrintExpr :: Expr -> Int -> String prettyPrintExpr (DoBlock exprs) i = indent i ++ "DoBlock[\n" ++ intercalate "\n" (map (\x -> prettyPrintExpr x (i + 1)) exprs) ++ "\n" ++ indent i ++ "]" @@ -97,25 +99,29 @@ inputFileBinary input = case input of potentiallyTimedOperation :: (MonadIO m) => String -> Bool -> m a -> m a potentiallyTimedOperation msg showTime action = if showTime then timeItNamed msg action else action -parseAndVerify :: String -> T.Text -> CompilerFlags -> IO (Either (ParseErrorBundle T.Text Void, Maybe Program) Program) -parseAndVerify name t cf = do - -- let (result, state) = runIdentity $ runStateT (parseProgramCf' t initCompilerFlags) (ParserState{compilerFlags = cf, validLets = [], validFunctions = []}) - let result = parseProgram t cf +parseAndVerify name input compilerFlags = + return + ( do + let result = parseProgram (T.pack input) initCompilerFlags + case result of + Left err -> return $ Left (err, Nothing) + Right program' -> do + let (Program exprs) = program' + verifierResult <- verifyProgram name (T.pack input) exprs + case verifierResult of + Left err -> return $ Left (err, Just program') + Right _ -> return $ Right program' + ) + +parseNoVerify name input compilerFlags = return $ do + let result = parseProgram (T.pack input) initCompilerFlags case result of Left err -> return $ Left (err, Nothing) - Right program' -> do - let (Program exprs) = program' - verifierResult <- verifyProgram name t exprs - case verifierResult of - Left err -> return $ Left (err, Just program') - Right _ -> return $ Right program' - --- parse :: String -> String -> CompilerFlags -> IO (Either (ParseErrorBundle T.Text Data.Void.Void) (Program)) -parse name input compilerFlags = return $ parseAndVerify name (T.pack input) initCompilerFlags + Right program' -> return $ Right program' main :: IO () main = do - Options input output debug verbose emitBytecode runBytecode breakpoints showTime showVersion <- + Options input output debug verbose emitBytecode runBytecode breakpoints showTime showVersion noVerify <- execParser $ info (optionsParser <**> helper) @@ -127,18 +133,16 @@ main = do putStrLn $ "Indigo, version " ++ version exitSuccess when (isNothing input) $ do - -- runStateT repl initREPLState newRepl exitSuccess program <- if not runBytecode then do i <- inputFile input - -- prog <- liftIO $ potentiallyTimedOperation "Parsing" showTime (parse (fromJust input) i CompilerFlags{verboseMode = verbose}) - -- let expr = case prog of - -- Left err -> error $ "Parse error: " ++ errorBundlePretty err - -- Right expr -> expr - prog <- parse (fromJust input) i CompilerFlags{verboseMode = verbose} + prog <- + if noVerify + then parseNoVerify (fromJust input) i CompilerFlags{verboseMode = verbose} + else parseAndVerify (fromJust input) i CompilerFlags{verboseMode = verbose} rprog <- prog expr <- case rprog of Left (err, expr) -> do diff --git a/examples/scratch.in b/examples/scratch.in index 12a89f2..e52100a 100644 --- a/examples/scratch.in +++ b/examples/scratch.in @@ -1,33 +1,41 @@ -# let split ([]: String sep: String) => [String] = [""] -# let split ((c:cs): String sep: String) => [String] = do -# let rest = split cs, sep -# if c == sep then do -# "" : (split cs, sep) -# else do -# (c : (head rest)) : (tail rest) -# end +# # let split ([]: String sep: String) => [String] = [""] +# # let split ((c:cs): String sep: String) => [String] = do +# # let rest = split cs, sep +# # if c == sep then do +# # "" : (split cs, sep) +# # else do +# # (c : (head rest)) : (tail rest) +# # end +# # end +# trait Number +# impl Number for Int +# impl Number for Float +# +# # let add (a: N b: N) => N = a + b +# +# let split ([]: [T] sep: T) => [T] = [""] +# +# let printNumList (l: [N] n: N) => IO = do +# # end -trait Number -impl Number for Int -impl Number for Float - -let add (a: N b: N) => N = a + b - -let split ([]: [T] sep: T) => [T] = [""] - -let printNumList (l: [N] n: N) => IO = do - -end - -let xxx (a: Int) => Int = a - -# let test (a: A b: B) => C = do +# +# let xxx (a: Int) => Int = a +# +# +# struct Child = (name: String, age: Int) satisfies (it.age < 18) +# let a+ (a: Int b: Int) => Int = a +# let main => IO = do +# println 1 a+ 2 +# # println Child {name: "John", age: 13} +# # println Child {name: "Abram", age: 20} # end -let main => IO = do - println xxx (add 1,2) - # println add 1.0, 10 - # println split [1, 2, 3, 4, 5], 3 - # printNumList [1, 2, 3, 4, 5], 3 - # println "Hello, world!" -end +# `+` :: Int -> Int -> Int +# struct Cat = (name: String, age: Int) +# # let + (a: Cat b: Cat) => Cat = Cat {name: a.name : b.name, age: a.age + b.age} +# # let add (a: Int b: Int) => Int = a + b +# # let add (a: Float b: Float) => Float = a - b +# add :: Int -> Int -> Int +# add a b = a + b +# let main => IO = println add 3.0, 4.0 +2+5 diff --git a/lib/AST.hs b/lib/AST.hs index b504ca5..b4bf1d6 100644 --- a/lib/AST.hs +++ b/lib/AST.hs @@ -213,7 +213,7 @@ typeOf (Var{}) = Any -- error "Cannot infer type of variable" typeOf (Let _ _) = error "Cannot infer type of let" typeOf (If _ b _) = typeOf b typeOf (FuncDef{}) = error "Cannot infer type of function definition" -typeOf (FuncDec{}) = error "Cannot infer type of function declaration" +typeOf x@(FuncDec{}) = error $ "Cannot infer type of function declaration " ++ show x typeOf (Function _ _) = error "Cannot infer type of modern function" typeOf (DoBlock x) = if null x then None else typeOf $ last x typeOf (ExternDec{}) = error "Cannot infer type of extern declaration" diff --git a/lib/BytecodeCompiler.hs b/lib/BytecodeCompiler.hs index e479266..75ff9fe 100644 --- a/lib/BytecodeCompiler.hs +++ b/lib/BytecodeCompiler.hs @@ -89,13 +89,16 @@ allocId = do modify (\s' -> s'{lastLabel = s + 1}) return s +preludeExpr :: IO [Parser.Expr] +preludeExpr = do + i <- liftIO preludeFile + case parseProgram (T.pack i) CompilerFlags{verboseMode = False, needsMain = False} of -- FIXME: pass on flags + Left err -> error $ "Parse error: " ++ errorBundlePretty err + Right (Parser.Program progExpr) -> return $ progExpr ++ [Parser.FuncDef "__sep" [] Parser.Placeholder] + compileProgram :: Parser.Program -> StateT (CompilerState a) IO [Instruction] compileProgram (Parser.Program expr) = do - prelude <- do - i <- liftIO preludeFile - case parseProgram (T.pack i) CompilerFlags{verboseMode = False, needsMain = False} of -- FIXME: pass on flags - Left err -> error $ "Parse error: " ++ errorBundlePretty err - Right (Parser.Program progExpr) -> return $ progExpr ++ [Parser.FuncDef "__sep" [] Parser.Placeholder] + prelude <- liftIO preludeExpr prelude' <- concatMapM compileExpr prelude freePart <- concatMapM compileExpr expr createVirtualFunctions @@ -218,27 +221,41 @@ implsFor structName = do return $ map Parser.trait impls'' compileExpr :: Parser.Expr -> StateT (CompilerState a) IO [Instruction] -compileExpr (Parser.Add x y) = doBinOp x y Add -compileExpr (Parser.Sub x y) = doBinOp x y Sub -compileExpr (Parser.Mul x y) = doBinOp x y Mul -compileExpr (Parser.Div x y) = doBinOp x y Div -compileExpr (Parser.Modulo x y) = doBinOp x y Mod -compileExpr (Parser.Power x y) = doBinOp x y Pow -compileExpr (Parser.Gt x y) = doBinOp x y Gt -compileExpr (Parser.Lt x y) = doBinOp x y Lt -compileExpr (Parser.Ge x y) = doBinOp x y Lt >>= \x' -> return (x' ++ [Not]) -compileExpr (Parser.Le x y) = doBinOp x y Gt >>= \x' -> return (x' ++ [Not]) +compileExpr (Parser.Add x y) = compileExpr (Parser.FuncCall "+" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Sub x y) = compileExpr (Parser.FuncCall "-" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Mul x y) = compileExpr (Parser.FuncCall "*" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Div x y) = compileExpr (Parser.FuncCall "/" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Modulo x y) = compileExpr (Parser.FuncCall "%" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Power x y) = compileExpr (Parser.FuncCall "^" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Gt x y) = compileExpr (Parser.FuncCall ">" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Lt x y) = compileExpr (Parser.FuncCall "<" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Ge x y) = compileExpr (Parser.FuncCall ">=" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Le x y) = compileExpr (Parser.FuncCall "<=" [x, y] zeroPosition) >>= doBinOp x y . last compileExpr (Parser.Not x) = compileExpr x >>= \x' -> return (x' ++ [Not]) -compileExpr (Parser.Eq x y) = doBinOp x y Eq -compileExpr (Parser.Neq x y) = doBinOp x y Eq >>= \x' -> return (x' ++ [Not]) -compileExpr (Parser.And x y) = doBinOp x y And -compileExpr (Parser.Or x y) = doBinOp x y Or +compileExpr (Parser.Eq x y) = compileExpr (Parser.FuncCall "==" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Neq x y) = compileExpr (Parser.FuncCall "!=" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.And x y) = compileExpr (Parser.FuncCall "&&" [x, y] zeroPosition) >>= doBinOp x y . last +compileExpr (Parser.Or x y) = compileExpr (Parser.FuncCall "||" [x, y] zeroPosition) >>= doBinOp x y . last compileExpr (Parser.IntLit x) = return [Push $ DInt $ fromIntegral x] compileExpr (Parser.UnaryMinus (Parser.FloatLit x)) = return [Push $ DFloat (-x)] compileExpr (Parser.UnaryMinus (Parser.IntLit x)) = return [Push $ DInt $ -fromInteger x] compileExpr (Parser.StringLit x) = return [Push $ DString x] compileExpr (Parser.DoBlock exprs) = concatMapM compileExpr exprs compileExpr Parser.Placeholder = return [] +compileExpr (Parser.FuncCall "unsafeAdd" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Add]) +compileExpr (Parser.FuncCall "unsafeSub" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Sub]) +compileExpr (Parser.FuncCall "unsafeMul" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Mul]) +compileExpr (Parser.FuncCall "unsafeDiv" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Div]) +compileExpr (Parser.FuncCall "unsafeMod" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Mod]) +compileExpr (Parser.FuncCall "unsafePow" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Pow]) +compileExpr (Parser.FuncCall "unsafeGt" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Gt]) +compileExpr (Parser.FuncCall "unsafeLt" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Lt]) +compileExpr (Parser.FuncCall "unsafeGe" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Lt, Not]) +compileExpr (Parser.FuncCall "unsafeLe" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Gt, Not]) +compileExpr (Parser.FuncCall "unsafeEq" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Eq]) +compileExpr (Parser.FuncCall "unsafeNeq" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Eq, Not]) +compileExpr (Parser.FuncCall "unsafeAnd" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [And]) +compileExpr (Parser.FuncCall "unsafeOr" [x, y] _) = compileExpr x >>= \x' -> compileExpr y >>= \y' -> return (x' ++ y' ++ [Or]) compileExpr (Parser.FuncCall "unsafePrint" [x] _) = compileExpr x >>= \x' -> return (x' ++ [Builtin Print]) compileExpr (Parser.FuncCall "unsafeGetLine" _ _) = return [Builtin GetLine] compileExpr (Parser.FuncCall "unsafeGetChar" _ _) = return [Builtin GetChar] diff --git a/lib/Parser.hs b/lib/Parser.hs index 2405996..f57c997 100644 --- a/lib/Parser.hs +++ b/lib/Parser.hs @@ -8,6 +8,7 @@ module Parser (Expr (..), Program (..), parseProgram', parseProgramPure, ParserS -- module Parser where import AST +import Control.Applicative.Combinators (someTill) import Control.Monad qualified import Control.Monad.Combinators ( between @@ -56,6 +57,7 @@ import Text.Megaparsec.Char ) import Text.Megaparsec.Char.Lexer qualified as L import Text.Megaparsec.Debug (dbg) +import Text.ParserCombinators.ReadP (many1) data CompilerFlags = CompilerFlags { verboseMode :: Bool @@ -96,11 +98,16 @@ binOpTable = , [binary "==" Eq, binary "!=" Neq, binary "<=" Le, binary ">=" Ge, binary "<" Lt, binary ">" Gt] , [binary "&&" And, binary "||" Or] , [binaryAny binaryFunctionCall] + -- , [prefixAny pFunctionCall] + -- , [postfixAny pFunctionCall] ] binaryFunctionCall :: String -> Expr -> Expr -> Expr binaryFunctionCall f a b = FuncCall f [a, b] anyPosition +pFunctionCall :: String -> Expr -> Expr +pFunctionCall f a = FuncCall f [a] anyPosition + binary :: Text -> (Expr -> Expr -> Expr) -> Operator Parser Expr binary name f = InfixL (f <$ symbol name) @@ -114,6 +121,12 @@ prefix, postfix :: Text -> (Expr -> Expr) -> Operator Parser Expr prefix name f = Prefix (f <$ symbol name) postfix name f = Postfix (f <$ symbol name) +prefixAny :: (String -> Expr -> Expr) -> Operator Parser Expr +prefixAny f = Prefix (f <$> identifier) + +postfixAny :: (String -> Expr -> Expr) -> Operator Parser Expr +postfixAny f = Postfix (f <$> identifier) + ref :: Parser Expr ref = do symbol "*" @@ -162,7 +175,7 @@ identifier = do then fail $ "keyword " ++ show name ++ " cannot be an identifier" else return name where - p = (:) <$> letterChar <*> many (alphaNumChar <|> char '_') + p = some (alphaNumChar <|> char '_' <|> oneOf ['+', '-', '*', '/', '=', '&', '|', '!', '?', '$', '%', '^', '~']) check x = if x `elem` rws then fail $ "keyword " ++ show x ++ " cannot be an identifier" @@ -245,11 +258,7 @@ funcDef = do FuncDef name args <$> expr "function body" gravis :: Parser String -gravis = do - symbol "`" - name <- many $ noneOf ['`'] - symbol "`" - return name +gravis = lexeme $ char '`' *> someTill L.charLiteral (char '`') funcCall :: Parser Expr funcCall = do @@ -262,7 +271,7 @@ funcCall = do letExpr :: Parser Expr letExpr = do keyword "let" - name <- identifier + name <- identifier <|> gravis symbol "=" value <- recover expr state <- get @@ -308,7 +317,7 @@ generic = do combinedFunc :: Parser Expr combinedFunc = do keyword "let" - name <- identifier "function name" + name <- identifier <|> gravis "function name" generics <- fromMaybe [] <$> optional generic (args, argTypes) <- parens argsAndTypes <|> argsAndTypes returnType <- optional (symbol "=>" >> validType "return type") diff --git a/share/std/prelude.in b/share/std/prelude.in index 66390a7..20b19ad 100644 --- a/share/std/prelude.in +++ b/share/std/prelude.in @@ -1,33 +1,46 @@ struct IO = (inner: Any) -`+` :: Any -> Any -> Any -`+` x y = x + y -`-` :: Any -> Any -> Any -`-` x y = (x) - y -`*` :: Any -> Any -> Any -`*` x y = x * y -`/` :: Any -> Any -> Any -`/` x y = x / y -`<` :: Any -> Any -> Any -`<` x y = x < y -`>` :: Any -> Any -> Any -`>` x y = x > y -`<=` :: Any -> Any -> Any -`<=` x y = x <= y -`>=` :: Any -> Any -> Any -`>=` x y = x >= y -`==` :: Any -> Any -> Any -`==` x y = x == y -`!=` :: Any -> Any -> Any -`!=` x y = x != y -`&&` :: Any -> Any -> Any -`&&` x y = x && y -`||` :: Any -> Any -> Any -`||` x y = x || y -`%` :: Any -> Any -> Any -`%` x y = x % y -`!` :: Any -> Any -`!` x = !x +# `+` :: Any -> Any -> Any +# `+` x y = x + y +# `-` :: Any -> Any -> Any +# `-` x y = (x) - y +# `*` :: Any -> Any -> Any +# `*` x y = x * y +# `/` :: Any -> Any -> Any +# `/` x y = x / y +# `<` :: Any -> Any -> Any +# `<` x y = x < y +# `>` :: Any -> Any -> Any +# `>` x y = x > y +# `<=` :: Any -> Any -> Any +# `<=` x y = x <= y +# `>=` :: Any -> Any -> Any +# `>=` x y = x >= y +# `==` :: Any -> Any -> Any +# `==` x y = x == y +# `!=` :: Any -> Any -> Any +# `!=` x y = x != y +# `&&` :: Any -> Any -> Any +# `&&` x y = x && y +# `||` :: Any -> Any -> Any +# `||` x y = x || y +# `%` :: Any -> Any -> Any +# `%` x y = x % y +# `!` :: Any -> Any +# `!` x = !x +let + (x: Int y: Int) => Int = unsafeAdd x, y +let - (x: Int y: Int) => Int = unsafeSub x, y +let * (x: Int y: Int) => Int = unsafeMul x, y +let / (x: Int y: Int) => Int = unsafeDiv x, y +let `<` (x: Int y: Int) => Int = unsafeLt x, y +let `>` (x: Int y: Int) => Int = unsafeGt x, y +let `<=` (x: Int y: Int) => Int = unsafeLe x, y +let `>=` (x: Int y: Int) => Int = unsafeGe x, y +let == (x: Int y: Int) => Int = unsafeEq x, y +let != (x: Int y: Int) => Int = unsafeNe x, y +let && (x: Int y: Int) => Int = unsafeAnd x, y +let || (x: Int y: Int) => Int = unsafeOr x, y +let % (x: Int y: Int) => Int = unsafeMod x, y let flip f: Fn{Any -> Any => Any} -> x: Any -> y: Any => Fn{Any -> Any => Any} = f y, x diff --git a/tests/BytecodeCompilerSpec.hs b/tests/BytecodeCompilerSpec.hs index 8dd103a..523bc0b 100644 --- a/tests/BytecodeCompilerSpec.hs +++ b/tests/BytecodeCompilerSpec.hs @@ -1,19 +1,23 @@ module BytecodeCompilerSpec (spec) where +import AST qualified import BytecodeCompiler -import Control.Monad.State (evalStateT) +import Control.Monad (join) +import Control.Monad.State (evalStateT, liftIO) +import Data.Functor ((<&>)) import Data.Text qualified +import Debug.Trace import Foreign +import GHC.IO (unsafePerformIO) import Parser qualified import Test.Hspec import Test.QuickCheck import Test.QuickCheck.Arbitrary.Generic import Text.Megaparsec (errorBundlePretty) import Text.RawString.QQ (r) +import Util import VM (Action (..), Data (..), Instruction (..)) --- import VM qualified - instance Arbitrary WordPtr where arbitrary = fromIntegral <$> (arbitrary :: Gen Word64) shrink x = [x] @@ -44,20 +48,24 @@ compile prog = do case p of Left err -> error $ errorBundlePretty err Right program -> do - evalStateT (compileProgramBare program) (initCompilerState program) + evalStateT + (compileProgramBare program) + (initCompilerState program) + { funcDecs = [AST.FuncDec "+" [AST.StructT "Int", AST.StructT "Int", AST.StructT "Int"] []] + } spec :: Spec spec = do describe "Addition" $ do it "Should compile 2+4" $ do compile [r|2+4|] - `shouldReturn` [Label "main", Push 2, LStore "__op_a_0", Push 4, LStore "__op_b_0", LLoad "__op_a_0", LLoad "__op_b_0", Add, Exit] + `shouldReturn` [Label "main", Push 2, LStore "__op_a_0", Push 4, LStore "__op_b_0", LLoad "__op_a_0", LLoad "__op_b_0", Call "+", Exit] it "Should work properly with function calls" $ do compile [r| f x = x + 1 let main => IO = unsafePrint (f 2) + 4|] - `shouldReturn` [Label "f#0", LStore "x", LLoad "x", LStore "__op_a_1", Push 1, LStore "__op_b_1", LLoad "__op_a_1", LLoad "__op_b_1", Add, Ret, Label "main", Push 2, Call "f#0", LStore "__op_a_2", Push 4, LStore "__op_b_2", LLoad "__op_a_2", LLoad "__op_b_2", Add, Builtin Print, Exit] + `shouldReturn` [Label "f#0", LStore "x", LLoad "x", LStore "__op_a_1", Push 1, LStore "__op_b_1", LLoad "__op_a_1", LLoad "__op_b_1", Call "+", Ret, Label "main", Push 2, Call "f#0", LStore "__op_a_2", Push 4, LStore "__op_b_2", LLoad "__op_a_2", LLoad "__op_b_2", Call "+", Builtin Print, Exit] describe "Hello World" $ do it "Should print Hello, world!" $ do compile [r|let main => IO = unsafePrint "Hello, world!"|] @@ -65,16 +73,16 @@ spec = do describe "Implicit casting" $ do it "Should cast from int to float" $ do compile [r|let main => IO = unsafePrint ^2 + 4.0|] - `shouldReturn` [Label "main", Meta "flex", Push 2, LStore "__op_a_0", Push 4.0, LStore "__op_b_0", LLoad "__op_a_0", LLoad "__op_b_0", Cast, Push 4.0, Add, Builtin Print, Exit] + `shouldReturn` [Label "main", Meta "flex", Push 2, LStore "__op_a_0", Push 4.0, LStore "__op_b_0", LLoad "__op_a_0", LLoad "__op_b_0", Cast, Push 4.0, Call "+", Builtin Print, Exit] compile [r|let main => IO = unsafePrint 2.0 + ^4|] - `shouldReturn` [Label "main", Push 2.0, LStore "__op_a_0", Meta "flex", Push 4, LStore "__op_b_0", LLoad "__op_a_0", LLoad "__op_b_0", Swp, Cast, Push 2.0, Add, Builtin Print, Exit] + `shouldReturn` [Label "main", Push 2.0, LStore "__op_a_0", Meta "flex", Push 4, LStore "__op_b_0", LLoad "__op_a_0", LLoad "__op_b_0", Swp, Cast, Push 2.0, Call "+", Builtin Print, Exit] describe "Explicit casting" $ do it "Can cast from int to float" $ do compile [r|2 as Float|] `shouldReturn` [Label "main", Push 2, Push 0.0, VM.Cast, Exit] it "Casts are compatible with binary operations" $ do compile [r|(2 as Float) + 4.0|] - `shouldReturn` [Label "main", Push 2, Push 0.0, Cast, LStore "__op_a_0", Push 4.0, LStore "__op_b_0", LLoad "__op_a_0", LLoad "__op_b_0", Add, Exit] + `shouldReturn` [Label "main", Push 2, Push 0.0, Cast, LStore "__op_a_0", Push 4.0, LStore "__op_b_0", LLoad "__op_a_0", LLoad "__op_b_0", Call "+", Exit] xdescribe "typesMatch" $ do it "Should be true for exact matches" $ property $ diff --git a/tests/ParserSpec.hs b/tests/ParserSpec.hs index a4e2e5b..66cbea9 100644 --- a/tests/ParserSpec.hs +++ b/tests/ParserSpec.hs @@ -86,11 +86,11 @@ spec = do it "Should parse operators escaped using gravis in dec correctly" $ do parseProgram [r| - `+` :: Any -> Any -> Any + + :: Any -> Any -> Any `-` :: Any -> Any -> Any - `*` :: Any -> Any -> Any - `/` :: Any -> Any -> Any - `==` :: Any -> Any -> Any + * :: Any -> Any -> Any + / :: Any -> Any -> Any + == :: Any -> Any -> Any |] parserCompilerFlags `shouldBe` Right diff --git a/wasm_reactor/flake.lock b/wasm_reactor/flake.lock new file mode 100644 index 0000000..cb2c490 --- /dev/null +++ b/wasm_reactor/flake.lock @@ -0,0 +1,125 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "ghc-wasm-meta": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1698055010, + "narHash": "sha256-OGk0mIHtIbGQi2zON+xqyXAsobSdVMgC/7jcFLvWAMo=", + "type": "tarball", + "url": "https://gitlab.haskell.org/ghc/ghc-wasm-meta/-/archive/master/ghc-wasm-meta-master.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://gitlab.haskell.org/ghc/ghc-wasm-meta/-/archive/master/ghc-wasm-meta-master.tar.gz" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1697723726, + "narHash": "sha256-SaTWPkI8a5xSHX/rrKzUe+/uVNy6zCGMXgoeMb7T9rg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "7c9cc5a6e5d38010801741ac830a3f8fd667a7a0", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1706925685, + "narHash": "sha256-hVInjWMmgH4yZgA4ZtbgJM1qEAel72SYhP5nOWX4UIM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "79a13f1437e149dc7be2d1290c74d378dad60814", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "ghc-wasm-meta": "ghc-wasm-meta", + "nixpkgs": "nixpkgs_2" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/wasm_reactor/output-info.hs b/wasm_reactor/output-info.hs new file mode 100644 index 0000000..c8a716d --- /dev/null +++ b/wasm_reactor/output-info.hs @@ -0,0 +1,5 @@ +import qualified System.Info + +main :: IO () +main = do + putStrLn System.Info.os