def test_copy_loop_multiple_separate_offsets(self): # 2 offsets self._run_and_check_ir( ',[->+>+<<]', [ir.INPUT(), ir.RMUL(1, 1), ir.RMUL(2, 1), ir.SET(0)]) self._run_and_check_ir( ',[->->-<<]', [ir.INPUT(), ir.RMUL(1, 255), ir.RMUL(2, 255), ir.SET(0)]) self._run_and_check_ir( ',[<+>>-<-]', [ir.INPUT(), ir.LMUL(1, 1), ir.RMUL(1, 255), ir.SET(0)]) # many but less than 127 offsets self._run_and_check_ir(',[-' + '<+' * 126 + '>' * 126 + ']', [ir.INPUT()] + [ir.LMUL(i, 1) for i in range(1, 127)] + [ir.SET(0)]) self._run_and_check_ir(',[<<<+>>>>>-<<<<<<<+>>>>>-<+>]', [ ir.INPUT(), ir.LMUL(3, 1), ir.RMUL(2, 255), ir.LMUL(5, 1), ir.LMUL(1, 1), ir.SET(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)
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])
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)
def test_contraction_set_arithmetic(self): # Arithmetic ops after a SET() are collapsed into the SET() self._run_and_check_ir(',[-]--', [ir.INPUT(), ir.SET(254)]) self._run_and_check_ir(',[-]-', [ir.INPUT(), ir.SET(255)]) self._run_and_check_ir(',[-]', [ir.INPUT(), ir.SET(0)]) self._run_and_check_ir(',[-]+', [ir.INPUT(), ir.SET(1)]) self._run_and_check_ir(',[-]++', [ir.INPUT(), ir.SET(2)]) self._run_and_check_ir(',[+]--', [ir.INPUT(), ir.SET(254)]) self._run_and_check_ir(',[+]-', [ir.INPUT(), ir.SET(255)]) self._run_and_check_ir(',[+]', [ir.INPUT(), ir.SET(0)]) self._run_and_check_ir(',[+]+', [ir.INPUT(), ir.SET(1)]) self._run_and_check_ir(',[+]++', [ir.INPUT(), ir.SET(2)])
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])
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)
def test_clear_loops(self): self._run_and_check_ir( "+[-]+[+]", [ir.ADD(1), ir.SET(1), ir.OPEN(), ir.ADD(1), ir.CLOSE()], maxdepth=2)
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])
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])
def test_copy_loop_multiple_repeated_offsets(self): # repeated offsets result in multiple LMUL/RMUL self._run_and_check_ir(',[->+>++<+++>----<<]', [ ir.INPUT(), ir.RMUL(1, 1), ir.RMUL(2, 2), ir.RMUL(1, 3), ir.RMUL(2, 252), ir.SET(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("[-][+++]", [])
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
def test_cancellation_arithmetic_set(self): # SET() invalidates all immediately preceding arithmetic # operations. self._run_and_check_ir('+[-]', [ir.SET(0)]) self._run_and_check_ir('+[+]', [ir.SET(0)]) self._run_and_check_ir('++++++++++[-]', [ir.SET(0)]) self._run_and_check_ir('++++++++++[+]', [ir.SET(0)]) self._run_and_check_ir('----------[-]++', [ir.SET(2)]) self._run_and_check_ir('++++++++++[+]++', [ir.SET(2)])
def test_copy_loop_wrap_around(self): self._run_and_check_ir( ',[->' + '+' * 255 + '<]', [ir.INPUT(), ir.RMUL(1, 255), ir.SET(0)]) self._run_and_check_ir(',[->' + '+' * 256 + '<]', [ir.INPUT(), ir.SET(0)]) self._run_and_check_ir( ',[->' + '+' * 257 + '<]', [ir.INPUT(), ir.RMUL(1, 1), ir.SET(0)]) self._run_and_check_ir( ',[-<<' + '-' * 255 + '>>]', [ir.INPUT(), ir.LMUL(2, 1), ir.SET(0)]) self._run_and_check_ir(',[-<<' + '-' * 256 + '>>]', [ir.INPUT(), ir.SET(0)]) self._run_and_check_ir( ',[-<<' + '-' * 257 + '>>]', [ir.INPUT(), ir.LMUL(2, 255), ir.SET(0)])
def test_copy_loop_simple(self): # single cell copy loops self._run_and_check_ir( ',[->+<]', [ir.INPUT(), ir.RMUL(1, 1), ir.SET(0)]) self._run_and_check_ir( ',[->-<]', [ir.INPUT(), ir.RMUL(1, 255), ir.SET(0)]) self._run_and_check_ir( ',[-<+>]', [ir.INPUT(), ir.LMUL(1, 1), ir.SET(0)]) self._run_and_check_ir( ',[-<->]', [ir.INPUT(), ir.LMUL(1, 255), ir.SET(0)]) self._run_and_check_ir( ',[<->-]', [ir.INPUT(), ir.LMUL(1, 255), ir.SET(0)]) self._run_and_check_ir( ',[>+<-]', [ir.INPUT(), ir.RMUL(1, 1), ir.SET(0)])
def test_set(self): # simple cases self._run_and_check_ir(',[-]-', [ir.INPUT(), ir.SET(255)]) self._run_and_check_ir(',[-]', [ir.INPUT(), ir.SET(0)]) self._run_and_check_ir(',[-]+', [ir.INPUT(), ir.SET(1)]) self._run_and_check_ir(',[-]++', [ir.INPUT(), ir.SET(2)]) self._run_and_check_ir(',[-]+++', [ir.INPUT(), ir.SET(3)]) self._run_and_check_ir(',[-]-', [ir.INPUT(), ir.SET(255)]) self._run_and_check_ir(',[-]--', [ir.INPUT(), ir.SET(254)]) self._run_and_check_ir(',[-]---', [ir.INPUT(), ir.SET(253)]) # overflow self._run_and_check_ir(',[-]' + '+' * 255, [ir.INPUT(), ir.SET(255)]) self._run_and_check_ir(',[-]' + '+' * 256, [ir.INPUT(), ir.SET(0)]) self._run_and_check_ir(',[-]' + '+' * 257, [ir.INPUT(), ir.SET(1)]) self._run_and_check_ir(',[-]' + '-' * 255, [ir.INPUT(), ir.SET(1)]) self._run_and_check_ir(',[-]' + '-' * 256, [ir.INPUT(), ir.SET(0)]) self._run_and_check_ir(',[-]' + '-' * 257, [ir.INPUT(), ir.SET(255)])