From 6c5025922806902be4e6015f30d3a17718755e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Sun, 14 Nov 2021 11:06:56 +0100 Subject: [PATCH] Disable stack modification by branching (j*) instructions --- app/VirtualMachine/Instruction.hs | 1 + app/VirtualMachine/VM.hs | 2 +- test/VirtualMachineSpec.hs | 67 ++++++++++++++++++++++--------- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/app/VirtualMachine/Instruction.hs b/app/VirtualMachine/Instruction.hs index 3acb38f..054cf79 100644 --- a/app/VirtualMachine/Instruction.hs +++ b/app/VirtualMachine/Instruction.hs @@ -110,6 +110,7 @@ jump [] _ = throwError "Address expected" jumpIf :: (Int -> Int -> Bool) -> Params -> Pops -> ExceptT String Machine () jumpIf p (addr:_) (top:_) = lift $ do pc <- getPc + push [top] setPc $ if top `p` 0 then addr else pc + 2 return () jumpIf _ [] _ = throwError "Address expected" diff --git a/app/VirtualMachine/VM.hs b/app/VirtualMachine/VM.hs index 8cd9791..2d0480c 100644 --- a/app/VirtualMachine/VM.hs +++ b/app/VirtualMachine/VM.hs @@ -42,7 +42,7 @@ data Op = Nop -- 0x00 | Out -- 0x17 | Clr -- 0x18 | Roll -- 0x19 - | Over -- 0x20 + | Over -- 0x1A deriving (Eq, Ord, Enum, Show, Read, Bounded) type Machine = StateT VM IO diff --git a/test/VirtualMachineSpec.hs b/test/VirtualMachineSpec.hs index 5eee52b..effaddf 100644 --- a/test/VirtualMachineSpec.hs +++ b/test/VirtualMachineSpec.hs @@ -389,23 +389,27 @@ spec = do it "jumps if top stack value == 0" $ do let input = " push 0 \n\ \ je &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [1] 9 (-1) + let expected = done [1] 11 (-1) actual <- run input actual `shouldBe` expected it "proceeds if top stack value != 0" $ do let input = " push 1 \n\ \ je &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [0] 6 (-1) + let expected = done [0] 7 (-1) actual <- run input actual `shouldBe` expected it "raises error if empty stack" $ do @@ -419,23 +423,27 @@ spec = do it "jumps if top stack value != 0" $ do let input = " push 4 \n\ \ jne &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [1] 9 (-1) + let expected = done [1] 11 (-1) actual <- run input actual `shouldBe` expected it "proceeds if top stack value == 0" $ do let input = " push 0 \n\ \ jne &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [0] 6 (-1) + let expected = done [0] 7 (-1) actual <- run input actual `shouldBe` expected it "raises error if empty stack" $ do @@ -449,35 +457,41 @@ spec = do it "jumps if top stack value > 0" $ do let input = " push 1 \n\ \ jg &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [1] 9 (-1) + let expected = done [1] 11 (-1) actual <- run input actual `shouldBe` expected it "proceeds if top stack value == 0" $ do let input = " push 0 \n\ \ jg &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [0] 6 (-1) + let expected = done [0] 7 (-1) actual <- run input actual `shouldBe` expected it "proceeds if top stack value < 0" $ do let input = " push 1 \n\ \ neg \n\ \ jg &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [0] 7 (-1) + let expected = done [0] 8 (-1) actual <- run input actual `shouldBe` expected it "raises error if empty stack" $ do @@ -491,35 +505,41 @@ spec = do it "proceeds if top stack value > 0" $ do let input = " push 1 \n\ \ jl &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [0] 6 (-1) + let expected = done [0] 7 (-1) actual <- run input actual `shouldBe` expected it "proceeds if top stack value == 0" $ do let input = " push 0 \n\ \ jl &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [0] 6 (-1) + let expected = done [0] 7 (-1) actual <- run input actual `shouldBe` expected it "jumps if top stack value < 0" $ do let input = " push 1 \n\ \ neg \n\ \ jl &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [1] 10 (-1) + let expected = done [1] 12 (-1) actual <- run input actual `shouldBe` expected it "raises error if empty stack" $ do @@ -533,35 +553,41 @@ spec = do it "jumps if top stack value > 0" $ do let input = " push 1 \n\ \ jge &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [1] 9 (-1) + let expected = done [1] 11 (-1) actual <- run input actual `shouldBe` expected it "jumps if top stack value == 0" $ do let input = " push 0 \n\ \ jge &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [1] 9 (-1) + let expected = done [1] 11 (-1) actual <- run input actual `shouldBe` expected it "proceeds if top stack value < 0" $ do let input = " push 1 \n\ \ neg \n\ \ jge &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [0] 7 (-1) + let expected = done [0] 8 (-1) actual <- run input actual `shouldBe` expected it "raises error if empty stack" $ do @@ -575,35 +601,41 @@ spec = do it "proceeds if top stack value > 0" $ do let input = " push 1 \n\ \ jle &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [0] 6 (-1) + let expected = done [0] 7 (-1) actual <- run input actual `shouldBe` expected it "jumps if top stack value == 0" $ do let input = " push 0 \n\ \ jle &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [1] 9 (-1) + let expected = done [1] 11 (-1) actual <- run input actual `shouldBe` expected it "jumps if top stack value < 0" $ do let input = " push 1 \n\ \ neg \n\ \ jle &jumped \n\ + \ pop \n\ \ push 0 \n\ \ halt \n\ \ jumped: \n\ + \ pop \n\ \ push 1 \n\ \ halt " - let expected = done [1] 10 (-1) + let expected = done [1] 12 (-1) actual <- run input actual `shouldBe` expected it "raises error if empty stack" $ do @@ -989,9 +1021,8 @@ spec = do let input = " main: push 100 \n\ \ loop: push 1 \n\ \ sub \n\ - \ dup \n\ \ jne &loop \n\ \ halt " - let expected = done [0] 8 (-1) + let expected = done [0] 7 (-1) actual <- run input actual `shouldBe` expected \ No newline at end of file