Пример #1
0
    def test_nested_loops(self):
        # ++[->++[->++[->++[->++[->++<]<]<]<]<]>>>>>.[-].
        self.run_ir([ir.ADD(2),
                     ir.OPEN(), ir.SUB(1), ir.RIGHT(1), ir.ADD(2),
                       ir.OPEN(), ir.SUB(1), ir.RIGHT(1), ir.ADD(2),
                         ir.OPEN(), ir.SUB(1), ir.RIGHT(1), ir.ADD(2),
                           ir.OPEN(), ir.SUB(1), ir.RIGHT(1), ir.ADD(2),
                             ir.OPEN(), ir.SUB(1), ir.RIGHT(1), ir.ADD(2),
                             ir.LEFT(1), ir.CLOSE(),
                           ir.LEFT(1), ir.CLOSE(),
                         ir.LEFT(1), ir.CLOSE(),
                       ir.LEFT(1), ir.CLOSE(),
                     ir.LEFT(1), ir.CLOSE(),
                     ir.RIGHT(5), ir.OUTPUT(), ir.SET(0), ir.OUTPUT()],
                    [], [64, 0])

        # ++>+[[[[->]<]>]<].<.
        self.run_ir([ir.ADD(2), ir.RIGHT(1), ir.ADD(1),
                     ir.OPEN(),
                       ir.OPEN(),
                         ir.OPEN(),
                           ir.OPEN(),
                             ir.SUB(1), ir.RIGHT(1),
                           ir.CLOSE(),
                           ir.LEFT(1),
                         ir.CLOSE(),
                         ir.RIGHT(1),
                       ir.CLOSE(),
                       ir.LEFT(1),
                     ir.CLOSE(),
                     ir.OUTPUT(), ir.LEFT(1), ir.OUTPUT()],
                    [], [0, 2])
Пример #2
0
    def test_left_right(self):
        # the 386_linux backend outputs different machine instructions
        # for LEFT and RIGHT depending on the size of the
        # argument. this tests the edge cases.

        ops = []

        # set up memory to 0,1,2,...,255,0,0,0,...
        for i in range(256):
            ops.append(ir.SET(i))
            ops.append(ir.RIGHT(1))

        # jump all the "edgy" distances left and right and output
        edges = [1, 2, 3, 4, 126, 127, 128, 129, 130, 131, 253, 254, 255]
        for i in edges:
            ops.append(ir.LEFT(i))
            ops.append(ir.OUTPUT())
            ops.append(ir.RIGHT(i))
            ops.append(ir.OUTPUT())

        # expected output is 0 alternated with all the edges
        expected = []
        for i in edges:
            expected.append(256 - i)
            expected.append(0)

        self.run_ir(ops, [], expected)
Пример #3
0
    def test_mul(self):
        self.run_ir([ir.ADD(4), ir.RMUL(2, 4), ir.RIGHT(2), ir.OUTPUT()],
                    [], [16])
        self.run_ir([ir.ADD(4), ir.RIGHT(2), ir.ADD(7), ir.LMUL(2, 254),
                     ir.LEFT(2), ir.OUTPUT()],
                    [], [246])

        self.run_ir([ir.RIGHT(127), ir.SUB(2), ir.LMUL(127, 1),
                     ir.LEFT(127), ir.OUTPUT()],
                     [], [254])
        self.run_ir([ir.RIGHT(127), ir.SUB(2), ir.LMUL(127, 12),
                     ir.LEFT(127), ir.OUTPUT()],
                    [], [232])
        self.run_ir([ir.RIGHT(127), ir.SUB(2), ir.LMUL(127, 255),
                     ir.LEFT(127), ir.OUTPUT()],
                    [], [2])

        self.run_ir([ir.SET(3), ir.RMUL(127, 1), ir.RIGHT(127), ir.OUTPUT()],
                    [], [3])
        self.run_ir([ir.SET(3), ir.RMUL(127, 12), ir.RIGHT(127), ir.OUTPUT()],
                    [], [36])
        self.run_ir([ir.SET(3), ir.RMUL(127, 255),
                     ir.RIGHT(127), ir.OUTPUT()],
                    [], [253])

        self.run_ir([ir.ADD(12), ir.RMUL(1, 12), ir.RIGHT(1), ir.OUTPUT()],
                    [], [144])
        self.run_ir([ir.RIGHT(1), ir.ADD(12), ir.LMUL(1, 12), ir.LEFT(1),
                     ir.OUTPUT()],
                    [], [144])
Пример #4
0
 def test_nested_loops(self):
     # Loops can be nested
     # Loop depth is calculated
     self._run_and_check_ir("+[-[+<].]>[[[]+]+]+", [
         ir.ADD(1),
         ir.OPEN(),
         ir.SUB(1),
         ir.OPEN(),
         ir.ADD(1),
         ir.LEFT(1),
         ir.CLOSE(),
         ir.OUTPUT(),
         ir.CLOSE(),
         ir.RIGHT(1),
         ir.OPEN(),
         ir.OPEN(),
         ir.OPEN(),
         ir.CLOSE(),
         ir.ADD(1),
         ir.CLOSE(),
         ir.ADD(1),
         ir.CLOSE(),
         ir.ADD(1)
     ],
                            maxdepth=4)
     self._run_and_check_ir("+[[[[[[[[.]]]]],[[[]]]]]]",
                            [ir.ADD(1)] + [ir.OPEN()] * 8 + [ir.OUTPUT()] +
                            [ir.CLOSE()] * 5 + [ir.INPUT()] +
                            [ir.OPEN()] * 3 + [ir.CLOSE()] * 6,
                            maxdepth=9)
Пример #5
0
 def test_basic_operations(self):
     # ,[->>++++++++<<]>>.[-].[-]+
     self.run_ir([ir.INPUT(),
                  ir.OPEN(),
                    ir.SUB(1), ir.RIGHT(2), ir.ADD(8), ir.LEFT(2),
                  ir.CLOSE(),
                  ir.RIGHT(2), ir.OUTPUT(), ir.SET(0), ir.OUTPUT()],
                 [8],
                 [64, 0])
Пример #6
0
 def test_target_lang_c(self):
     self._run_and_check_target(17, _LANG_C, "@lang_c ")
     self._run_and_check_target(17, _LANG_C, "@lang_c\n")
     self._run_and_check_target(17, _LANG_C, "@lang_c+", ir=[ir.ADD(1)])
     self._run_and_check_target(17,
                                _LANG_C,
                                "@lang_c.+",
                                ir=[ir.OUTPUT(), ir.ADD(1)])
     self._run_and_check_target(17, _LANG_C, "@lang_c[.]")
     self._run_and_check_target(17,
                                _LANG_C,
                                "@lang_c..",
                                ir=[ir.OUTPUT(), ir.OUTPUT()])
Пример #7
0
 def test_nested_loops(self):
     self._run_and_check_ir("+[-[+<].]>[[[]+]+]+[+]", [
         ir.ADD(1),
         ir.OPEN(),
         ir.SUB(1),
         ir.OPEN(),
         ir.ADD(1),
         ir.LEFT(1),
         ir.CLOSE(),
         ir.OUTPUT(),
         ir.CLOSE(),
         ir.RIGHT(1),
         ir.OPEN(),
         ir.OPEN(),
         ir.OPEN(),
         ir.CLOSE(),
         ir.ADD(1),
         ir.CLOSE(),
         ir.ADD(1),
         ir.CLOSE(),
         ir.ADD(1),
         ir.OPEN(),
         ir.ADD(1),
         ir.CLOSE()
     ],
                            maxdepth=4)
Пример #8
0
    def test_loop_elimination(self):
        # Obviously dead loops are skipped entirely

        # Loop open as first op => dead
        self._run_and_check_ir("[+,-.]", [])
        self._run_and_check_ir("[+[[[,]-]-]-.]", [])
        self._run_and_check_ir("[+[[[,]-]-]-.][-]", [])
        self._run_and_check_ir("[+[[[,]-]-]-.][+]", [])
        self._run_and_check_ir("[+[[[,]-]-]-.][>>>]", [])
        self._run_and_check_ir("[+[[[,]-]-]-.][>>>][.]", [])

        # Loop open after loop close => dead
        self._run_and_check_ir(
            "+[>][.]",
            [ir.ADD(1), ir.OPEN(),
             ir.RIGHT(1), ir.CLOSE()],
            maxdepth=2)

        # Loop open after SET(0) => dead
        self._run_and_check_ir(",[-][>>]", [ir.INPUT(), ir.SET(0)])
        self._run_and_check_ir(",[-][>>][..]", [ir.INPUT(), ir.SET(0)])
        self._run_and_check_ir(
            ",[-][>>].",
            [ir.INPUT(), ir.SET(0), ir.OUTPUT()])

        # But open after SET(x) where x > 0 => alive
        self._run_and_check_ir(
            ",[-]+[>>]",
            [ir.INPUT(),
             ir.SET(1),
             ir.OPEN(),
             ir.RIGHT(2),
             ir.CLOSE()],
            maxdepth=2)
Пример #9
0
 def test_single_instruction_with_comment(self):
     # Single instructions with comments can be valid programs
     self._run_and_check_ir("a>", [ir.RIGHT(1)])
     self._run_and_check_ir("<a", [ir.LEFT(1)])
     self._run_and_check_ir("a.a", [ir.OUTPUT()])
     self._run_and_check_ir("aa,", [ir.INPUT()])
     self._run_and_check_ir("+aa", [ir.ADD(1)])
     self._run_and_check_ir("aa-aa", [ir.SUB(1)])
Пример #10
0
 def test_single_instruction(self):
     # Single brainfuck instructions can be valid programs
     self._run_and_check_ir(">", [ir.RIGHT(1)])
     self._run_and_check_ir("<", [ir.LEFT(1)])
     self._run_and_check_ir(",", [ir.INPUT()])
     self._run_and_check_ir(".", [ir.OUTPUT()])
     self._run_and_check_ir("+", [ir.ADD(1)])
     self._run_and_check_ir("-", [ir.SUB(1)])
Пример #11
0
 def test_clear_loops(self):
     # The [-] and [+] constructs become SET(0)
     # These are not included when calculating loop depth
     self._run_and_check_ir(
         ",[-].[+]",
         [ir.INPUT(), ir.SET(0),
          ir.OUTPUT(), ir.SET(0)],
         maxdepth=1)
Пример #12
0
    def test_set(self):
        self.run_ir([ir.SET(0), ir.OUTPUT()], [], [0])
        self.run_ir([ir.SET(1), ir.OUTPUT()], [], [1])
        self.run_ir([ir.SET(2), ir.OUTPUT()], [], [2])
        self.run_ir([ir.SET(255), ir.OUTPUT()], [], [255])

        self.run_ir([ir.ADD(12), ir.SET(0), ir.OUTPUT()], [], [0])
        self.run_ir([ir.ADD(12), ir.SET(1), ir.OUTPUT()], [], [1])
        self.run_ir([ir.ADD(12), ir.SET(2), ir.OUTPUT()], [], [2])
        self.run_ir([ir.ADD(12), ir.SET(255), ir.OUTPUT()], [], [255])
Пример #13
0
 def test_deep_nested_loops(self):
     # +[{many}-(>+.<]){many}
     self.run_ir([ir.ADD(1)] +
                 ([ir.OPEN()] * self.MAX_NESTED_LOOPS) +
                 [ir.SUB(1)] +
                 ([ir.RIGHT(1), ir.ADD(1), ir.OUTPUT(),
                   ir.LEFT(1), ir.CLOSE()] * self.MAX_NESTED_LOOPS),
                 [], [i % 256 for i in range(1, self.MAX_NESTED_LOOPS + 1)],
                 steps=50000000)
Пример #14
0
    def test_target_incomplete(self):
        self._run_and_check_target(17, 17, "@lang_")
        self._run_and_check_target(17, 17, "@lang_ ")
        self._run_and_check_target(17, 17, "@lang_\n")
        self._run_and_check_target(17, 17, "@lang_+", ir=[ir.ADD(1)])

        self._run_and_check_target(17, 17, "@386_linu")
        self._run_and_check_target(17, 17, "@386_linu ")
        self._run_and_check_target(17, 17, "@386_linu\n")
        self._run_and_check_target(17, 17, "@386_linu_.", ir=[ir.OUTPUT()])
Пример #15
0
    def test_cancellation_of_basic_instructions(self):
        # Two pairs of the basic brainfuck instructions are mutually
        # cancelling

        # Pairs of cancelling instructions are reduced
        self._run_and_check_ir("+-", [])
        self._run_and_check_ir("+-", [])
        self._run_and_check_ir("><", [])
        self._run_and_check_ir("<>", [])

        # Longer sequences of cancelling instructions are reduced
        self._run_and_check_ir("-+<>+-><", [])
        self._run_and_check_ir(".<<<<>>>>++++----.",
                               [ir.OUTPUT(), ir.OUTPUT()])

        # The cancelling instructions do not have to be immediately adjacent
        self._run_and_check_ir("+++-->><-+<-,  <>-++-+-<><>.",
                               [ir.INPUT(), ir.OUTPUT()])
        self._run_and_check_ir(",>>+++>+--+<----+<<++>><<--", [ir.INPUT()])
Пример #16
0
        def ops(d):
            ops = []
            # first use only LEFT(1) and RIGHT(1) to set up memory
            ops += ([ir.RIGHT(1)] * (d) + [ir.SET(12)] + [ir.RIGHT(1)] * (d) +
                    [ir.SET(32)] + [ir.RIGHT(1)] * (d) + [ir.SET(17)] +
                    [ir.LEFT(1)] * (d * 2))

            # state:   0(d) *12 0(d - 1) 32 0(d - 1) 17 0

            # run a [.>>>>] construct to move up the pointer. this
            # should output 12, 32 and 17.
            ops += ([ir.OPEN(), ir.OUTPUT(), ir.RIGHT(d), ir.CLOSE()])

            # state:   0(d) 12 0(d - 1) 32 0(d - 1) 17 0(d - 1) *0

            # same thing in other direction. should output 17,32
            ops += [ir.LEFT(d)]
            ops += ([ir.OPEN(), ir.OUTPUT(), ir.LEFT(d), ir.CLOSE()])

            return ops
Пример #17
0
 def test_loop_elimination(self):
     self._run_and_check_ir("[.]", [])
     self._run_and_check_ir(
         "[+++]+[][+++].[-][+++]",
         [ir.ADD(1),
          ir.OPEN(),
          ir.CLOSE(),
          ir.OUTPUT(),
          ir.SET(0)],
         maxdepth=2)
     self._run_and_check_ir("[-][+++]", [])
Пример #18
0
 def test_basic_operations(self):
     self._run_and_check_ir(">+.<-[,]", [
         ir.RIGHT(1),
         ir.ADD(1),
         ir.OUTPUT(),
         ir.LEFT(1),
         ir.SUB(1),
         ir.OPEN(),
         ir.INPUT(),
         ir.CLOSE()
     ],
                            maxdepth=2)
Пример #19
0
    def test_mul_overreaching(self):
        """Backend should handle MUL writing up to 127 cells outside of tape.

        There are perfectly valid programs for which the frontend will
        output multiplication operations that write to a position
        outside of the tape. One example would be '.[-<+>]' for which
        an OUTPUT() followed by LMUL(1,1) will be produced. There are
        other less obvious cases that the frontend cannot catch (and
        my gut says catching them all it's equivalent to the halting
        problem).

        One option is for the backends to always check that the
        current cell is non-zero before writing the product of a
        multiplication operation. Another option is to simply pad the
        tape with 127 cells on each end and to initialize the pointer
        at position 127 instead of 0 (and 127 is magic because it's
        the max offset the frontend emits for the multipication
        operations).
        """

        # offsets on the left
        self.run_ir([ir.LMUL(1, 1), ir.OUTPUT()], [], [0])
        self.run_ir([ir.LMUL(2, 1), ir.OUTPUT()], [], [0])
        self.run_ir([ir.LMUL(3, 1), ir.OUTPUT()], [], [0])
        self.run_ir([ir.LMUL(126, 1), ir.OUTPUT()], [], [0])
        self.run_ir([ir.LMUL(127, 1), ir.OUTPUT()], [], [0])

        # offsets on the right
        movetolastcell = [ir.RIGHT(127) for _ in range(516)] + [ir.RIGHT(2)]
        self.run_ir(movetolastcell + [ir.RMUL(1, 1), ir.OUTPUT()], [], [0],
                    steps=10000000)
        self.run_ir(movetolastcell + [ir.RMUL(2, 1), ir.OUTPUT()], [], [0],
                    steps=10000000)
        self.run_ir(movetolastcell + [ir.RMUL(3, 1), ir.OUTPUT()], [], [0],
                    steps=10000000)
        self.run_ir(movetolastcell + [ir.RMUL(126, 1), ir.OUTPUT()], [], [0],
                    steps=10000000)
        self.run_ir(movetolastcell + [ir.RMUL(127, 1), ir.OUTPUT()], [], [0],
                    steps=10000000)
Пример #20
0
 def test_cells_wrap(self):
     # .-.++.+{254}.+.-.
     self.run_ir([ir.OUTPUT(),
                  ir.SUB(1), ir.OUTPUT(),
                  ir.ADD(2), ir.OUTPUT(),
                  ir.ADD(254), ir.OUTPUT(),
                  ir.ADD(1), ir.OUTPUT(),
                  ir.SUB(1), ir.OUTPUT()],
                 [], [0, 255, 1, 255, 0, 255])
Пример #21
0
 def test_all_instructions(self):
     # All instructions can live in the same program
     self._run_and_check_ir(">+.<-[,]", [
         ir.RIGHT(1),
         ir.ADD(1),
         ir.OUTPUT(),
         ir.LEFT(1),
         ir.SUB(1),
         ir.OPEN(),
         ir.INPUT(),
         ir.CLOSE()
     ],
                            maxdepth=2)
     self._run_and_check_ir("+,[->.]<", [
         ir.ADD(1),
         ir.INPUT(),
         ir.OPEN(),
         ir.SUB(1),
         ir.RIGHT(1),
         ir.OUTPUT(),
         ir.CLOSE(),
         ir.LEFT(1)
     ],
                            maxdepth=2)
Пример #22
0
 def test_cancellation(self):
     self._run_and_check_ir("+++-->><-+<-,  <>-++-+-<><>.",
                            [ir.INPUT(), ir.OUTPUT()])
     self._run_and_check_ir("-+<>+-><", [])
     self._run_and_check_ir(".<<<<>>>>++++----.",
                            [ir.OUTPUT(), ir.OUTPUT()])
Пример #23
0
 def test_eof_behaviour(self):
     # do no-change on EOF
     # ++++++++++,.
     self.run_ir([ir.ADD(10), ir.INPUT(), ir.OUTPUT()], [], [10])