Exemple #1
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)
Exemple #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)
Exemple #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])
Exemple #4
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])
Exemple #5
0
 def test_contraction_overflow_movement(self):
     # Argument overflow on movement operations only add more
     # operations
     self._run_and_check_ir(['>'] * 255, [ir.RIGHT(255)])
     self._run_and_check_ir(['>'] * 256, [ir.RIGHT(255), ir.RIGHT(1)])
     self._run_and_check_ir(['>'] * 257, [ir.RIGHT(255), ir.RIGHT(2)])
     self._run_and_check_ir(['<'] * 255, [ir.LEFT(255)])
     self._run_and_check_ir(['<'] * 256, [ir.LEFT(255), ir.LEFT(1)])
     self._run_and_check_ir(['<'] * 257, [ir.LEFT(255), ir.LEFT(2)])
Exemple #6
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])
Exemple #7
0
 def test_contraction(self):
     self._run_and_check_ir("+++", [ir.ADD(3)])
     self._run_and_check_ir(['+'] * 255, [ir.ADD(255)])
     self._run_and_check_ir(['+'] * 256, [])
     self._run_and_check_ir("---", [ir.SUB(3)])
     self._run_and_check_ir(['-'] * 255, [ir.SUB(255)])
     self._run_and_check_ir(['-'] * 256, [])
     self._run_and_check_ir("<<<", [ir.LEFT(3)])
     self._run_and_check_ir(['<'] * 128, [ir.LEFT(127), ir.LEFT(1)])
     self._run_and_check_ir(">>>", [ir.RIGHT(3)])
     self._run_and_check_ir(['>'] * 128, [ir.RIGHT(127), ir.RIGHT(1)])
Exemple #8
0
 def test_contraction_simple_cases(self):
     # Sequences of multiple brainfuck instructions can be
     # contracted into single bytecode operations
     self._run_and_check_ir("++", [ir.ADD(2)])
     self._run_and_check_ir("+++", [ir.ADD(3)])
     self._run_and_check_ir("+" * 128, [ir.ADD(128)])
     self._run_and_check_ir("--", [ir.SUB(2)])
     self._run_and_check_ir("---", [ir.SUB(3)])
     self._run_and_check_ir("-" * 128, [ir.SUB(128)])
     self._run_and_check_ir("<<", [ir.LEFT(2)])
     self._run_and_check_ir("<<<", [ir.LEFT(3)])
     self._run_and_check_ir("<" * 128, [ir.LEFT(128)])
     self._run_and_check_ir(">>", [ir.RIGHT(2)])
     self._run_and_check_ir(">>>", [ir.RIGHT(3)])
     self._run_and_check_ir(">" * 128, [ir.RIGHT(128)])
Exemple #9
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)
Exemple #10
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)
Exemple #11
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)])
Exemple #12
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)])
Exemple #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)
Exemple #14
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
Exemple #15
0
 def test_target_386_linux(self):
     self._run_and_check_target(17, _386_LINUX, "@386_linux ")
     self._run_and_check_target(17,
                                _386_LINUX,
                                "@386_linux,,",
                                ir=[ir.INPUT(), ir.INPUT()])
     self._run_and_check_target(17,
                                _386_LINUX,
                                "@386_linux->",
                                ir=[ir.SUB(1), ir.RIGHT(1)])
     self._run_and_check_target(17, _386_LINUX, "@386_linux[foobar]")
     self._run_and_check_target(17, _386_LINUX, "@386_linux foobar")
Exemple #16
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)
Exemple #17
0
    def test_cancellation_partial(self):
        # Cancellation can be partial, leaving part of the cancelling
        # instructions behind.

        # The basic brainfuck instructions
        self._run_and_check_ir("++++--", [ir.ADD(2)])
        self._run_and_check_ir("--++++", [ir.ADD(2)])
        self._run_and_check_ir("++----", [ir.SUB(2)])
        self._run_and_check_ir("----++", [ir.SUB(2)])
        self._run_and_check_ir(">>>><<", [ir.RIGHT(2)])
        self._run_and_check_ir("<<>>>>", [ir.RIGHT(2)])
        self._run_and_check_ir(">><<<<", [ir.LEFT(2)])
        self._run_and_check_ir("<<<<>>", [ir.LEFT(2)])

        # Cases with argument overflow, i.e. >255 of the same
        # instructions in a row, are also cancelled correctly.
        self._run_and_check_ir(['>'] * 258 + ['<', '<'],
                               [ir.RIGHT(255), ir.RIGHT(1)])
        self._run_and_check_ir(['>'] * 258 + ['<', '<', '<'], [ir.RIGHT(255)])
        self._run_and_check_ir(['>'] * 258 + ['<', '<', '<', '<'],
                               [ir.RIGHT(254)])

        self._run_and_check_ir(['<'] * 258 + ['>', '>'],
                               [ir.LEFT(255), ir.LEFT(1)])
        self._run_and_check_ir(['<'] * 258 + ['>', '>', '>'], [ir.LEFT(255)])
        self._run_and_check_ir(['<'] * 258 + ['>', '>', '>', '>'],
                               [ir.LEFT(254)])
Exemple #18
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)
Exemple #19
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)
Exemple #20
0
    def test_contraction_and_cancellation(self):
        # basic cases
        self._run_and_check_ir("++++--", [ir.ADD(2)])
        self._run_and_check_ir("--++++", [ir.ADD(2)])
        self._run_and_check_ir("++----", [ir.SUB(2)])
        self._run_and_check_ir("----++", [ir.SUB(2)])
        self._run_and_check_ir(">>>><<", [ir.RIGHT(2)])
        self._run_and_check_ir("<<>>>>", [ir.RIGHT(2)])
        self._run_and_check_ir(">><<<<", [ir.LEFT(2)])
        self._run_and_check_ir("<<<<>>", [ir.LEFT(2)])

        # cases triggering argument overflow
        self._run_and_check_ir(['>'] * 130 + ['<', '<'],
                               [ir.RIGHT(127), ir.RIGHT(1)])
        self._run_and_check_ir(['>'] * 130 + ['<', '<', '<'], [ir.RIGHT(127)])
        self._run_and_check_ir(['>'] * 130 + ['<', '<', '<', '<'],
                               [ir.RIGHT(126)])

        self._run_and_check_ir(['<'] * 130 + ['>', '>'],
                               [ir.LEFT(127), ir.LEFT(1)])
        self._run_and_check_ir(['<'] * 130 + ['>', '>', '>'], [ir.LEFT(127)])
        self._run_and_check_ir(['<'] * 130 + ['>', '>', '>', '>'],
                               [ir.LEFT(126)])
Exemple #21
0
    def test_copy_loop_not_optimizeable(self):
        # loop must end where it started
        self._run_and_check_ir(',[->+]', [
            ir.INPUT(),
            ir.OPEN(),
            ir.SUB(1),
            ir.RIGHT(1),
            ir.ADD(1),
            ir.CLOSE()
        ],
                               maxdepth=2)
        self._run_and_check_ir(',[->+<<]', [
            ir.INPUT(),
            ir.OPEN(),
            ir.SUB(1),
            ir.RIGHT(1),
            ir.ADD(1),
            ir.LEFT(2),
            ir.CLOSE()
        ],
                               maxdepth=2)

        # must subtract 1 from cell 0 exactly once
        self._run_and_check_ir(',[->+<-]', [
            ir.INPUT(),
            ir.OPEN(),
            ir.SUB(1),
            ir.RIGHT(1),
            ir.ADD(1),
            ir.LEFT(1),
            ir.SUB(1),
            ir.CLOSE()
        ],
                               maxdepth=2)
        self._run_and_check_ir(',[+>+<--]', [
            ir.INPUT(),
            ir.OPEN(),
            ir.ADD(1),
            ir.RIGHT(1),
            ir.ADD(1),
            ir.LEFT(1),
            ir.SUB(2),
            ir.CLOSE()
        ],
                               maxdepth=2)
        self._run_and_check_ir(',[->+<+<->-]', [
            ir.INPUT(),
            ir.OPEN(),
            ir.SUB(1),
            ir.RIGHT(1),
            ir.ADD(1),
            ir.LEFT(1),
            ir.ADD(1),
            ir.LEFT(1),
            ir.SUB(1),
            ir.RIGHT(1),
            ir.SUB(1),
            ir.CLOSE()
        ],
                               maxdepth=2)

        # must be fewer than 127 < and 127 >
        self._run_and_check_ir(',[-' + '>' * 127 + '+' + '<' * 127 + ']', [
            ir.INPUT(),
            ir.OPEN(),
            ir.SUB(1),
            ir.RIGHT(127),
            ir.ADD(1),
            ir.LEFT(127),
            ir.CLOSE()
        ],
                               maxdepth=2)
        self._run_and_check_ir(',[-' + '<' * 127 + '+' + '>' * 127 + ']', [
            ir.INPUT(),
            ir.OPEN(),
            ir.SUB(1),
            ir.LEFT(127),
            ir.ADD(1),
            ir.RIGHT(127),
            ir.CLOSE()
        ],
                               maxdepth=2)