diff --git a/src/Dreamberd/Bytecode/Decode.hs b/src/Dreamberd/Bytecode/Decode.hs index e0a841a..3f89ee9 100644 --- a/src/Dreamberd/Bytecode/Decode.hs +++ b/src/Dreamberd/Bytecode/Decode.hs @@ -6,6 +6,17 @@ import Data.Bits (shiftL, (.|.)) import Data.Char (ord) import Dreamberd.Vm (Call (..), DefineEnvType (..), Insts (..), Value (..)) +parseSize :: [Char] -> Either String (Int, [Char]) +parseSize (size : bytes) | length bytes >= sized = Right (parseUnsignedInt val sized, rest) + where + sized = fromEnum size + (val, rest) = splitAt sized bytes +parseSize _ = Left "Not enough space for a size" + +parseUnsignedInt :: [Char] -> Int -> Int +parseUnsignedInt [] _ = 0 +parseUnsignedInt (x : xs) idx = max (256 ^ (idx - 1)) 1 * fromEnum x + parseUnsignedInt xs (idx - 1) + parseInt :: [Char] -> Either String (Int, [Char]) parseInt (b1 : b2 : b3 : b4 : b5 : b6 : b7 : b8 : rest) = Right ((ord b1 `shiftL` 56) .|. (ord b2 `shiftL` 48) .|. (ord b3 `shiftL` 40) .|. (ord b4 `shiftL` 32) .|. (ord b5 `shiftL` 24) .|. (ord b6 `shiftL` 16) .|. (ord b7 `shiftL` 8) .|. ord b8, rest) parseInt _ = Left "Not enough space for an int" @@ -17,13 +28,13 @@ parseInteger' _ _ = Left "Not enough space for an integer" parseInteger :: [Char] -> Either String (Integer, [Char]) parseInteger (c : bytes) - | fromEnum c == 0x51 = parseInt bytes >>= uncurry parseInteger' - | fromEnum c == 0x52 = parseInt bytes >>= \(size, rest) -> parseInteger' size rest >>= \(val, rest') -> Right (-val, rest') + | fromEnum c == 0x51 = parseSize bytes >>= uncurry parseInteger' + | fromEnum c == 0x52 = parseSize bytes >>= \(size, rest) -> parseInteger' size rest >>= \(val, rest') -> Right (-val, rest') parseInteger _ = Left "Not enough space for an integer" parseString :: [Char] -> Either String (String, [Char]) parseString bytes = - parseInt bytes >>= \(val, rest) -> + parseSize bytes >>= \(val, rest) -> if length rest < val then Left "Wrong string length" else Right (splitAt val rest) parseCall :: [Char] -> Either String (Call, [Char]) @@ -47,8 +58,8 @@ parseValue (c : bytes) = case fromEnum c of 0x14 -> parseString bytes >>= \(val, rest) -> Right (String val, rest) 0x15 -> parseCall bytes >>= \(val, rest) -> Right (Symbol val, rest) 0x16 -> - parseInt bytes >>= \(args, rest) -> - parseInt rest >>= \(len, rest') -> + parseSize bytes >>= \(args, rest) -> + parseSize rest >>= \(len, rest') -> let (insts, rest'') = splitAt len rest' in parseInstructions insts >>= \func -> if length rest' < len then Left "Wrong lambda body length" else Right (Lambda args func, rest'') 0x17 -> Right (Void, bytes) _ -> Left "Unknown value type" @@ -80,7 +91,7 @@ parseInstructions :: [Char] -> Either String [Insts] parseInstructions [] = Right [] parseInstructions (c : bytes) = case fromEnum c of 0x01 -> parseValue bytes >>= \(val, rest) -> pursueParsing (Push val) rest - 0x02 -> parseInt bytes >>= \(val, rest) -> pursueParsing (PushArg val) rest + 0x02 -> parseSize bytes >>= \(val, rest) -> pursueParsing (PushArg val) rest 0x03 -> parseString bytes >>= \(val, rest) -> pursueParsing (PushEnv val) rest 0x04 -> pursueParsing Call bytes 0x05 -> parseString bytes >>= uncurry parseDefineEnv >>= uncurry pursueParsing diff --git a/src/Dreamberd/Bytecode/Encode.hs b/src/Dreamberd/Bytecode/Encode.hs index 547ce80..71593bb 100644 --- a/src/Dreamberd/Bytecode/Encode.hs +++ b/src/Dreamberd/Bytecode/Encode.hs @@ -2,6 +2,7 @@ module Dreamberd.Bytecode.Encode ( transpileCall, transpileInt, transpileInteger, + transpileSize, transpileString, transpileValue, transpileInstruction, @@ -16,35 +17,45 @@ import System.Endian (Endianness (..), getSystemEndianness) getIntegerSize :: Integer -> Int getIntegerSize nb = if nb == 0 then 0 else 1 + getIntegerSize (nb `shiftR` 8) -transpileInt :: Int -> [Char] -transpileInt nb = case getSystemEndianness of - LittleEndian -> map chr $ reverse $ map (`mod` 256) $ take 8 $ iterate (`shiftR` 8) nb - BigEndian -> map (chr . (`mod` 256)) (take 8 $ iterate (`shiftR` 8) nb) +transpileSize :: Int -> [Char] +transpileSize nb = toEnum size : transpileInt nb size + where + size = getNumberSize nb 0 + +getNumberSize :: Int -> Int -> Int +getNumberSize nb idx + | nb < 256 = idx + 1 + | otherwise = getNumberSize (nb `shiftR` 8) (idx + 1) + +transpileInt :: Int -> Int -> [Char] +transpileInt nb size = case getSystemEndianness of + LittleEndian -> map chr $ reverse $ map (`mod` 256) $ take size $ iterate (`shiftR` 8) nb + BigEndian -> reverse $ take size $ map (chr . (`mod` 256)) (take 8 $ iterate (`shiftR` 8) nb) transpileInteger :: Integer -> [Char] transpileInteger nb = - (if nb >= 0 then toEnum 0x51 else toEnum 0x52) : transpileInt size ++ case getSystemEndianness of + (if nb >= 0 then toEnum 0x51 else toEnum 0x52) : transpileSize size ++ case getSystemEndianness of LittleEndian -> map chr $ reverse $ map (`mod` 256) $ take size $ iterate (`shiftR` 8) (fromInteger (abs nb)) BigEndian -> map (chr . (`mod` 256)) (take size $ iterate (`shiftR` 8) (fromInteger (abs nb))) where size = getIntegerSize (abs nb) transpileString :: String -> [Char] -transpileString str = transpileInt (length str) ++ str +transpileString str = transpileSize (length str) ++ str transpileCall :: Call -> [Char] transpileCall (Operator op) = toEnum 0x21 : [toEnum (0x31 + fromEnum op)] transpileCall (Builtin builtin) = toEnum 0x22 : [toEnum (0x25 + fromEnum builtin)] transpileValue :: Value -> [Char] -transpileValue (Integer nb) = toEnum 0x11 : transpileInt nb -transpileValue (Float nb) = toEnum 0x12 : transpileInteger l ++ transpileInt r +transpileValue (Integer nb) = toEnum 0x11 : transpileInt nb 8 +transpileValue (Float nb) = toEnum 0x12 : transpileInteger l ++ transpileInt r 8 where (l, r) = decodeFloat nb transpileValue (Bool b) = toEnum 0x13 : (if b then [toEnum 1] else [toEnum 0]) transpileValue (String str) = toEnum 0x14 : transpileString str transpileValue (Symbol call) = toEnum 0x15 : transpileCall call -transpileValue (Lambda args insts) = toEnum 0x16 : transpileInt args ++ transpileInt (length nested) ++ nested +transpileValue (Lambda args insts) = toEnum 0x16 : transpileSize args ++ transpileSize (length nested) ++ nested where nested = foldMap transpileInstruction insts transpileValue Void = [toEnum 0x17] @@ -55,16 +66,16 @@ transpileDefineValue (Just val) = toEnum 0x51 : transpileValue val transpileInstruction :: Insts -> [Char] transpileInstruction (Push v) = toEnum 0x01 : transpileValue v -transpileInstruction (PushArg idx) = toEnum 0x02 : transpileInt idx +transpileInstruction (PushArg idx) = toEnum 0x02 : transpileSize idx transpileInstruction (PushEnv env) = toEnum 0x03 : transpileString env transpileInstruction Call = [toEnum 0x04] transpileInstruction (DefineEnv name Define value) = toEnum 0x05 : transpileString name ++ [toEnum 0x41] ++ transpileDefineValue value transpileInstruction (DefineEnv name Redefine value) = toEnum 0x05 : transpileString name ++ [toEnum 0x42] ++ transpileDefineValue value transpileInstruction (DefineEnv name Override value) = toEnum 0x05 : transpileString name ++ [toEnum 0x43] ++ transpileDefineValue value transpileInstruction (EraseEnv name) = toEnum 0x06 : transpileString name -transpileInstruction (Jump nb (Just True)) = toEnum 0x07 : transpileInt nb ++ [toEnum 0x51] -transpileInstruction (Jump nb (Just False)) = toEnum 0x07 : transpileInt nb ++ [toEnum 0x52] -transpileInstruction (Jump nb Nothing) = toEnum 0x07 : transpileInt nb ++ [toEnum 0x53] +transpileInstruction (Jump nb (Just True)) = toEnum 0x07 : transpileInt nb 8 ++ [toEnum 0x51] +transpileInstruction (Jump nb (Just False)) = toEnum 0x07 : transpileInt nb 8 ++ [toEnum 0x52] +transpileInstruction (Jump nb Nothing) = toEnum 0x07 : transpileInt nb 8 ++ [toEnum 0x53] transpileInstruction Ret = [toEnum 0x08] transpileIntoBytecode :: [Insts] -> [Char] diff --git a/test/Unit/Dreamberd/TestDreamberdBytecode.hs b/test/Unit/Dreamberd/TestDreamberdBytecode.hs index 46cc801..98e743a 100644 --- a/test/Unit/Dreamberd/TestDreamberdBytecode.hs +++ b/test/Unit/Dreamberd/TestDreamberdBytecode.hs @@ -24,22 +24,21 @@ testDreamberdBytecode = testTypesTranspilation :: Test testTypesTranspilation = TestList - [ TestCase $ assertEqual "Transpile Int" (transpileInt 1) "\x00\x00\x00\x00\x00\x00\x00\x01" - , TestCase $ assertEqual "Transpile Int Zero" (transpileInt 0) "\x00\x00\x00\x00\x00\x00\x00\x00" - , TestCase $ assertEqual "Transpile Int Negative" (transpileInt (-1)) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" - , TestCase $ assertEqual "Transpile Float" (transpileInstruction (Push (Float 1.0))) "\SOH\DC2Q\NUL\NUL\NUL\NUL\NUL\NUL\NUL\a\DLE\NUL\NUL\NUL\NUL\NUL\NUL\255\255\255\255\255\255\255\204" - , TestCase $ assertEqual "Transpile String" (transpileString "Hello") "\x00\x00\x00\x00\x00\x00\x00\x05Hello" - , TestCase $ assertEqual "Transpile String 2" (transpileString "World") "\x00\x00\x00\x00\x00\x00\x00\x05World" - , TestCase $ assertEqual "Transpile Empty String" (transpileString "") "\x00\x00\x00\x00\x00\x00\x00\x00" + [ TestCase $ assertEqual "Transpile Int" (transpileInt 1 8) "\x00\x00\x00\x00\x00\x00\x00\x01" + , TestCase $ assertEqual "Transpile Int Zero" (transpileInt 0 8) "\x00\x00\x00\x00\x00\x00\x00\x00" + , TestCase $ assertEqual "Transpile Int Negative" (transpileInt (-1) 8) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + , TestCase $ assertEqual "Transpile Float" (transpileInstruction (Push (Float 1.0))) "\x01\DC2Q\x01\a\DLE\NUL\NUL\NUL\NUL\NUL\NUL\255\255\255\255\255\255\255\204" + , TestCase $ assertEqual "Transpile String" (transpileString "Hello") "\x01\x05Hello" + , TestCase $ assertEqual "Transpile Empty String" (transpileString "") "\x01\x00" , TestCase $ assertEqual "Transpile Call Add" (transpileCall (Operator Add)) "\x21\x31" , TestCase $ assertEqual "Transpile Call Print" (transpileCall (Builtin Print)) "\x22\x26" , TestCase $ assertEqual "Transpile Instruction Push" (transpileInstruction (Push (Integer 1))) "\x01\x11\x00\x00\x00\x00\x00\x00\x00\x01" - , TestCase $ assertEqual "Transpile Instruction PushArg" (transpileInstruction (PushArg 1)) "\x02\x00\x00\x00\x00\x00\x00\x00\x01" - , TestCase $ assertEqual "Transpile Instruction PushEnv" (transpileInstruction (PushEnv "test")) "\x03\x00\x00\x00\x00\x00\x00\x00\x04test" + , TestCase $ assertEqual "Transpile Instruction PushArg" (transpileInstruction (PushArg 1)) "\x02\x01\x01" + , TestCase $ assertEqual "Transpile Instruction PushEnv" (transpileInstruction (PushEnv "test")) "\x03\x01\x04test" , TestCase $ assertEqual "Transpile Instruction Call" (transpileInstruction Call) "\x04" - , TestCase $ assertEqual "Transpile Instruction DefineEnv with value" (transpileInstruction (DefineEnv "test" Define (Just (Lambda 0 [])))) "\ENQ\NUL\NUL\NUL\NUL\NUL\NUL\NUL\EOTtestAQ\SYN\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL" - , TestCase $ assertEqual "Transpile Instruction DefineEnv from stack" (transpileInstruction (DefineEnv "test" Define Nothing)) "\x05\x00\x00\x00\x00\x00\x00\x00\x04test\x41\x53" - , TestCase $ assertEqual "Transpile Instruction EraseEnv" (transpileInstruction (EraseEnv "yo")) "\x06\x00\x00\x00\x00\x00\x00\x00\x02yo" + , TestCase $ assertEqual "Transpile Instruction DefineEnv with value" (transpileInstruction (DefineEnv "test" Define (Just (Lambda 0 [])))) "\ENQ\x01\x04testAQ\SYN\x01\x00\x01\x00" + , TestCase $ assertEqual "Transpile Instruction DefineEnv from stack" (transpileInstruction (DefineEnv "test" Define Nothing)) "\x05\x01\x04test\x41\x53" + , TestCase $ assertEqual "Transpile Instruction EraseEnv" (transpileInstruction (EraseEnv "yo")) "\x06\x01\x02yo" , TestCase $ assertEqual "Transpile Instruction Jump" (transpileInstruction (Jump 1 Nothing)) "\x07\x00\x00\x00\x00\x00\x00\x00\x01\x53" , TestCase $ assertEqual "Transpile Instruction Ret" (transpileInstruction Ret) "\x08" ] @@ -48,13 +47,13 @@ testTranspilation :: Test testTranspilation = TestList [ TestCase $ assertEqual "basic bytecode" (transpileIntoBytecode [Push (Integer 1), Ret]) "db4\n\x01\x11\x00\x00\x00\x00\x00\x00\x00\x01\x08\n" - , TestCase $ assertEqual "test equality between floats" (transpileIntoBytecode [Push (Float 2.0), Push (Float 3.4), Push (Symbol (Operator Eq)), Call, Ret]) "db4\n\SOH\DC2Q\NUL\NUL\NUL\NUL\NUL\NUL\NUL\a\DLE\NUL\NUL\NUL\NUL\NUL\NUL\255\255\255\255\255\255\255\205\SOH\DC2Q\NUL\NUL\NUL\NUL\NUL\NUL\NUL\a\ESC333333\255\255\255\255\255\255\255\205\SOH\NAK!7\EOT\b\n" - , TestCase $ assertEqual "abs function" (transpileIntoBytecode [DefineEnv "abs" Define (Just (Lambda 1 [Push (Integer 0), PushArg 0, Push (Symbol (Operator Less)), Call, Jump 5 (Just False), Push (Integer (-1)), PushArg 0, Push (Symbol (Operator Mul)), Call, Ret, PushArg 0, Ret]))]) "db4\n\ENQ\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ETXabsAQ\SYN\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOH\NUL\NUL\NUL\NUL\NUL\NUL\NULE\SOH\DC1\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\STX\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOH\NAK!9\EOT\a\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ENQR\SOH\DC1\255\255\255\255\255\255\255\255\STX\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOH\NAK!3\EOT\b\STX\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\b\n" - , TestCase $ assertEqual "function call" (transpileIntoBytecode [DefineEnv "abs" Define (Just (Lambda 1 [Push (Integer 0), PushArg 0, Push (Symbol (Operator Less)), Call, Jump 5 (Just False), Push (Integer (-1)), PushArg 0, Push (Symbol (Operator Mul)), Call, Ret, PushArg 0, Ret])), Push (Integer (-2)), PushEnv "abs", Call, Ret]) "db4\n\ENQ\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ETXabsAQ\SYN\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOH\NUL\NUL\NUL\NUL\NUL\NUL\NULE\SOH\DC1\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\STX\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOH\NAK!9\EOT\a\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ENQR\SOH\DC1\255\255\255\255\255\255\255\255\STX\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOH\NAK!3\EOT\b\STX\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\b\SOH\DC1\255\255\255\255\255\255\255\254\ETX\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ETXabs\EOT\b\n" - , TestCase $ assertEqual "defines" (transpileIntoBytecode [Push (Float (-5.2)), DefineEnv "a" Define Nothing, DefineEnv "a" Redefine (Just (Lambda 1 [PushArg 0, Push (Bool False), Push (Symbol (Operator Neq)), Call, Ret]))]) "db4\n\SOH\DC2R\NUL\NUL\NUL\NUL\NUL\NUL\NUL\a\DC4\204\204\204\204\204\205\255\255\255\255\255\255\255\206\ENQ\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOHaAS\ENQ\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOHaBQ\SYN\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOH\NUL\NUL\NUL\NUL\NUL\NUL\NUL\DC2\STX\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOH\DC3\NUL\SOH\NAK!8\EOT\b\n" + , TestCase $ assertEqual "test equality between floats" (transpileIntoBytecode [Push (Float 2.0), Push (Float 3.4), Push (Symbol (Operator Eq)), Call, Ret]) "db4\n\SOH\DC2Q\SOH\a\DLE\NUL\NUL\NUL\NUL\NUL\NUL\255\255\255\255\255\255\255\205\SOH\DC2Q\SOH\a\ESC333333\255\255\255\255\255\255\255\205\SOH\NAK!7\EOT\b\n" + , TestCase $ assertEqual "abs function" (transpileIntoBytecode [DefineEnv "abs" Define (Just (Lambda 1 [Push (Integer 0), PushArg 0, Push (Symbol (Operator Less)), Call, Jump 5 (Just False), Push (Integer (-1)), PushArg 0, Push (Symbol (Operator Mul)), Call, Ret, PushArg 0, Ret]))]) "db4\n\ENQ\SOH\ETXabsAQ\SYN\SOH\SOH\SOH3\SOH\DC1\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\STX\SOH\NUL\SOH\NAK!9\EOT\a\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ENQR\SOH\DC1\255\255\255\255\255\255\255\255\STX\SOH\NUL\SOH\NAK!3\EOT\b\STX\SOH\NUL\b\n" + , TestCase $ assertEqual "function call" (transpileIntoBytecode [DefineEnv "abs" Define (Just (Lambda 1 [Push (Integer 0), PushArg 0, Push (Symbol (Operator Less)), Call, Jump 5 (Just False), Push (Integer (-1)), PushArg 0, Push (Symbol (Operator Mul)), Call, Ret, PushArg 0, Ret])), Push (Integer (-2)), PushEnv "abs", Call, Ret]) "db4\n\ENQ\SOH\ETXabsAQ\SYN\SOH\SOH\SOH3\SOH\DC1\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\STX\SOH\NUL\SOH\NAK!9\EOT\a\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ENQR\SOH\DC1\255\255\255\255\255\255\255\255\STX\SOH\NUL\SOH\NAK!3\EOT\b\STX\SOH\NUL\b\SOH\DC1\255\255\255\255\255\255\255\254\ETX\SOH\ETXabs\EOT\b\n" + , TestCase $ assertEqual "defines" (transpileIntoBytecode [Push (Float (-5.2)), DefineEnv "a" Define Nothing, DefineEnv "a" Redefine (Just (Lambda 1 [PushArg 0, Push (Bool False), Push (Symbol (Operator Neq)), Call, Ret]))]) "db4\n\SOH\DC2R\SOH\a\DC4\204\204\204\204\204\205\255\255\255\255\255\255\255\206\ENQ\SOH\SOHaAS\ENQ\SOH\SOHaBQ\SYN\SOH\SOH\SOH\f\STX\SOH\NUL\SOH\DC3\NUL\SOH\NAK!8\EOT\b\n" , TestCase $ assertEqual "jump too long (should not raise)" (transpileIntoBytecode [Push (Bool True), Jump 46 (Just True), Ret]) "db4\n\SOH\DC3\SOH\a\NUL\NUL\NUL\NUL\NUL\NUL\NUL.Q\b\n" - , TestCase $ assertEqual "invalid variables for op (should not raise)" (transpileIntoBytecode [Push Void, Push (String "bonsoir a tous"), Push (Bool True), Push (Symbol (Operator Eq)), Call, Ret]) "db4\n\SOH\ETB\SOH\DC4\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SObonsoir a tous\SOH\DC3\SOH\SOH\NAK!7\EOT\b\n" - , TestCase $ assertEqual "invalid redefine (should not raise)" (transpileIntoBytecode [DefineEnv "b" Define Nothing, DefineEnv "a" Redefine (Just (String "haha")), Ret]) "db4\n\ENQ\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOHbAS\ENQ\NUL\NUL\NUL\NUL\NUL\NUL\NUL\SOHaBQ\DC4\NUL\NUL\NUL\NUL\NUL\NUL\NUL\EOThaha\b\n" + , TestCase $ assertEqual "invalid variables for op (should not raise)" (transpileIntoBytecode [Push Void, Push (String "bonsoir a tous"), Push (Bool True), Push (Symbol (Operator Eq)), Call, Ret]) "db4\n\SOH\ETB\SOH\DC4\SOH\SObonsoir a tous\SOH\DC3\SOH\SOH\NAK!7\EOT\b\n" + , TestCase $ assertEqual "invalid redefine (should not raise)" (transpileIntoBytecode [DefineEnv "b" Define Nothing, DefineEnv "a" Redefine (Just (String "haha")), Ret]) "db4\n\ENQ\SOH\SOHbAS\ENQ\SOH\SOHaBQ\DC4\SOH\EOThaha\b\n" ] testEncodeDecode :: Test @@ -71,9 +70,9 @@ testEncodeDecode = testDecodeErrorHandling :: Test testDecodeErrorHandling = TestList - [ TestCase $ assertEqual "wrong header" (getFromBytecode "db5\n\SOH\DC2Q\NUL\NUL\NUL\NUL\NUL\NUL\NUL\a\FS\NUL\NUL\NUL\NUL\NUL\NUL\255\255\255\255\255\255\255\206\n") (Left "Exec format error") - , TestCase $ assertEqual "wrong integer size (inf)" (getFromBytecode "db4\n\SOH\DC2Q\NUL\NUL\NUL\NUL\NUL\NUL\NUL\a\FS\NUL\NUL\NUL\NUL\NUL\NUL\255\255\255\255\255") (Left "Not enough space for an int") - , TestCase $ assertEqual "wrong integer size (code)" (getFromBytecode "db4\n\SOH\DC2Q\NUL\NUL\NUL\NUL\NUL\NUL\NUL\a\FS\NUL\NUL\NUL\NUL") (Left "Not enough space for an integer") - , TestCase $ assertEqual "wrong int size" (getFromBytecode "db4\n\SOH\DC2Q\NUL") (Left "Not enough space for an int") - , TestCase $ assertEqual "wrong int size" (getFromBytecode "db4\n\SOH\DC4\NUL\NUL\NUL\NUL\NUL\NUL\NUL\ENQHell\n") (Left "Wrong string length") + [ TestCase $ assertEqual "wrong header" (getFromBytecode "db5\n\SOH\DC2Q\x01\a\FS\NUL\NUL\NUL\NUL\NUL\NUL\255\255\255\255\255\255\255\206\n") (Left "Exec format error") + , TestCase $ assertEqual "wrong integer size (inf)" (getFromBytecode "db4\n\SOH\DC2Q\x01\a\FS\NUL\NUL\NUL\NUL\NUL\NUL\255\255\255\255\255") (Left "Not enough space for an int") + , TestCase $ assertEqual "wrong integer size (code)" (getFromBytecode "db4\n\SOH\DC2Q\x01\a\FS\NUL\NUL\NUL\NUL") (Left "Not enough space for an integer") + , TestCase $ assertEqual "wrong size" (getFromBytecode "db4\n\SOH\DC2Q\x02\NUL") (Left "Not enough space for a size") + , TestCase $ assertEqual "wrong int size" (getFromBytecode "db4\n\SOH\DC4\x01\ENQHell\n") (Left "Wrong string length") ]