示例#1
0
 def test_duplicate_definition_of_label_is_not_compilable(self):
     with self.assertRaises(DuplicateLabelError):
         self.program([
             RETURN_TRUE,
             DEF('label'), Noop, RETURN_TRUE,
             DEF('label'), Noop
         ])
示例#2
0
 def test_string_as_call_symbol(self):
     prog = self.program([
         '+1', '+2', RETURN_TRUE,
         DEF('+2'), '+1', '+1', RETURN_TRUE,
         DEF('+1'), Add1, RETURN_TRUE
     ])
     self.assertEqual(3, prog.run(0))
示例#3
0
 def test_branch_on_no(self):
     prog = self.program([
         IF(IsOdd), Add1, Add1, ELSE, 'add1', ENDIF, RETURN_TRUE,
         DEF('add1'), Add1, RETURN_TRUE
     ])
     self.assertEqual(5, prog.run(4))
     self.assertEqual(5, prog.run(3))
示例#4
0
    def test_macro_return_no(self):
        prog = self.program([
            IF('odd?'), Add1, ENDIF, RETURN_TRUE,
            DEF('odd?'),
            IF(IsOdd), RETURN_TRUE, ELSE, RETURN_FALSE, ENDIF
        ])

        self.assertEqual(2, prog.run(2))
        self.assertEqual(4, prog.run(4))
示例#5
0
 def test_backward_reference_is_not_compilable(self):
     with self.assertRaises(BackwardReferenceError):
         self.program([RETURN_TRUE, DEF('label'), Noop, 'label'])
示例#6
0
 def test_label_definition_within_label_def_is_not_compilable(self):
     with self.assertRaises(FallOverOnDefineError):
         self.program(
             [RETURN_TRUE,
              DEF('label'),
              DEF('label2'), RETURN_TRUE])
示例#7
0
 def test_incomplete_before_label_is_not_compilable(self):
     with self.assertRaises(FallOverOnDefineError):
         self.program([Noop, DEF('label'), Noop, RETURN_TRUE])
示例#8
0
class Test_Program(unittest.TestCase):

    PROGRAM_CLASS = m.Program

    def program(self, program_spec):
        return self.PROGRAM_CLASS(program_spec)

    def test_instruction_sequence(self):
        prog = self.program([Add1, Div2, RETURN_TRUE])
        self.assertEqual(2, prog.run(3))

    def test_duplicate_definition_of_label_is_not_compilable(self):
        with self.assertRaises(DuplicateLabelError):
            self.program([
                RETURN_TRUE,
                DEF('label'), Noop, RETURN_TRUE,
                DEF('label'), Noop
            ])

    def test_incomplete_program_is_not_compilable(self):
        with self.assertRaises(UndefinedLabelError):
            self.program(['label', RETURN_TRUE])

    def test_incomplete_before_label_is_not_compilable(self):
        with self.assertRaises(FallOverOnDefineError):
            self.program([Noop, DEF('label'), Noop, RETURN_TRUE])

    def test_label_definition_within_label_def_is_not_compilable(self):
        with self.assertRaises(FallOverOnDefineError):
            self.program(
                [RETURN_TRUE,
                 DEF('label'),
                 DEF('label2'), RETURN_TRUE])

    def test_program_without_closing_return_is_not_compilable(self):
        with self.assertRaises(UnclosedProgramError):
            self.program([Noop])

    def test_backward_reference_is_not_compilable(self):
        with self.assertRaises(BackwardReferenceError):
            self.program([RETURN_TRUE, DEF('label'), Noop, 'label'])

    def test_branch_on_yes(self):
        prog = self.program([
            IF(IsOdd), Add1, ELSE, 'add2', ENDIF, RETURN_TRUE,
            DEF('add2'), Add1, Add1, RETURN_TRUE
        ])
        self.assertEqual(4, prog.run(3))
        self.assertEqual(6, prog.run(4))

    def test_branch_on_no(self):
        prog = self.program([
            IF(IsOdd), Add1, Add1, ELSE, 'add1', ENDIF, RETURN_TRUE,
            DEF('add1'), Add1, RETURN_TRUE
        ])
        self.assertEqual(5, prog.run(4))
        self.assertEqual(5, prog.run(3))

    def test_string_as_call_symbol(self):
        prog = self.program([
            '+1', '+2', RETURN_TRUE,
            DEF('+2'), '+1', '+1', RETURN_TRUE,
            DEF('+1'), Add1, RETURN_TRUE
        ])
        self.assertEqual(3, prog.run(0))

    def test_compilation_with_missing_ENDIF_is_not_possible(self):
        with self.assertRaises(MissingEndIfError):
            self.program([IF(IsOdd), RETURN_TRUE])

    def test_compilation_with_multiple_ELSE_is_not_possible(self):
        with self.assertRaises(MultipleElseError):
            self.program([IF(IsOdd), ELSE, ELSE, ENDIF, RETURN_TRUE])

    def test_IF(self):
        prog = self.program([IF(IsOdd), Add1, ENDIF, Add1, RETURN_TRUE])

        self.assertEqual(1, prog.run(0))
        self.assertEqual(3, prog.run(1))
        self.assertEqual(3, prog.run(2))

    def test_IF_NOT(self):
        prog = self.program([
            IF_NOT(Eq('value')),
            Const('IF_NOT'),
            IF_NOT(Eq('value')),
            Const('IF_NOT'),
            # here we have the bug: this path is merged to here,
            # but outside this path is *ignored*,
            # its ELSE path is merged
            ENDIF,
            ENDIF,
            Add('.'),
            RETURN_TRUE
        ])

        self.assertEqual('value.', prog.run('value'))
        self.assertEqual('IF_NOT.', prog.run('?'))

    def test_ELSE(self):
        prog = self.program([IF(IsOdd), ELSE, Add1, ENDIF, Add1, RETURN_TRUE])

        self.assertEqual(2, prog.run(0))
        self.assertEqual(2, prog.run(1))
        self.assertEqual(4, prog.run(2))

    def test_IF_ELSE(self):
        prog = self.program(
            [IF(IsOdd), Add1, ELSE, Add1, Add1, ENDIF, Add1, RETURN_TRUE])

        self.assertEqual(3, prog.run(0))
        self.assertEqual(3, prog.run(1))
        self.assertEqual(5, prog.run(2))

    def test_IF_ELIF_ELSE(self):
        prog = self.program([
            IF(Eq('value')),
            Const('IF'),
            ELIF(Eq('variant1')),
            Const('ELIF1'),
            ELIF(Eq('variant2')),
            Const('ELIF2'), ELSE,
            Const('ELSE'), ENDIF,
            Add('.'), RETURN_TRUE
        ])

        self.assertEqual('IF.', prog.run('value'))
        self.assertEqual('ELIF1.', prog.run('variant1'))
        self.assertEqual('ELIF2.', prog.run('variant2'))
        self.assertEqual('ELSE.', prog.run('unknown'))

    def test_IF_ELIF_NOT_ELSE(self):
        prog = self.program([
            IF(Eq('value')),
            Const('IF'),
            ELIF_NOT(Eq('variant')),
            # not variant
            Const('ELIF_NOT'),
            ELSE,
            # variant
            Const('ELSE'),
            ENDIF,
            Add('.'),
            RETURN_TRUE
        ])

        self.assertEqual('IF.', prog.run('value'))
        self.assertEqual('ELIF_NOT.', prog.run('not_variant'))
        self.assertEqual('ELSE.', prog.run('variant'))

    def test_IF_NOT_ELSE(self):
        prog = self.program([
            IF_NOT(Eq('value')),
            # not value
            Const('IF_NOT'),
            ELSE,
            # value
            Const('ELSE'),
            ENDIF,
            Add('.'),
            RETURN_TRUE
        ])

        self.assertEqual('IF_NOT.', prog.run('unkown'))
        self.assertEqual('ELSE.', prog.run('value'))

    def test_compilation_with_ELIF_after_ELSE_is_not_possible(self):
        with self.assertRaises(ElIfAfterElseError):
            self.program([IF(IsOdd), ELSE, ELIF(IsOdd), ENDIF, RETURN_TRUE])

    def test_embedded_IFs(self):
        prog = self.program([
            IF(IsOdd), Add1, Div2,
            IF(IsOdd), Add1, ENDIF, ELSE, Add1, Add1, ENDIF, Div2, RETURN_TRUE
        ])

        self.assertEqual(1, prog.run(0))
        self.assertEqual(1, prog.run(1))
        self.assertEqual(2, prog.run(2))
        self.assertEqual(1, prog.run(3))
        self.assertEqual(3, prog.run(4))
        self.assertEqual(2, prog.run(5))

    def test_macro_return_yes(self):
        prog = self.program([
            IF('odd?'), Add1, ENDIF, RETURN_TRUE,
            DEF('odd?'),
            IF(IsOdd), RETURN_TRUE, ELSE, RETURN_FALSE, ENDIF
        ])

        self.assertEqual(2, prog.run(1))
        self.assertEqual(4, prog.run(3))

    def test_macro_return_no(self):
        prog = self.program([
            IF('odd?'), Add1, ENDIF, RETURN_TRUE,
            DEF('odd?'),
            IF(IsOdd), RETURN_TRUE, ELSE, RETURN_FALSE, ENDIF
        ])

        self.assertEqual(2, prog.run(2))
        self.assertEqual(4, prog.run(4))

    # used in the next 2 tests
    complex_prog_spec = [
        IF('even?'),
        RETURN_TRUE,
        ELSE,
        Add1,
        ENDIF,
        RETURN_TRUE,
        DEF('even?'),
        IF(IsOdd),
        RETURN_FALSE,
        ELSE,
        RETURN_TRUE,
        ENDIF,
    ]

    def test_macro_return(self):
        prog = self.program(self.complex_prog_spec)

        self.assertEqual(2, prog.run(1))
        self.assertEqual(2, prog.run(2))
        self.assertEqual(4, prog.run(3))
        self.assertEqual(4, prog.run(4))

    def test_instruction_index(self):
        prog = self.program(self.complex_prog_spec)

        indices = [i.index for i in prog.instructions]
        self.assertEqual(range(len(prog.instructions)), indices)

    def test_joining_into_a_closed_path_reopens_it(self):
        with self.assertRaises(UnclosedProgramError):
            self.program([
                IF(IsOdd),
                RETURN_TRUE,
                ENDIF,
            ])

    def test_sub_programs(self):
        prog = self.program([
            Add1,
            m.RETURN_TRUE,
            m.DEF('x1'),
            m.RETURN_TRUE,
            m.DEF('x2'),
            m.RETURN_TRUE,
            m.DEF('x3'),
            Add1,
            Add1,
            m.RETURN_TRUE,
        ])

        sub_programs = iter(prog.sub_programs())
        sub_program = sub_programs.next()
        self.assertEqual(None, sub_program[0])
        self.assertEqual(2, len(sub_program[1]))  # Add1, RETURN

        sub_program = sub_programs.next()
        self.assertEqual('x1', sub_program[0])
        self.assertEqual(1, len(sub_program[1]))  # RETURN

        sub_program = sub_programs.next()
        self.assertEqual('x2', sub_program[0])
        self.assertEqual(1, len(sub_program[1]))  # RETURN

        sub_program = sub_programs.next()
        self.assertEqual('x3', sub_program[0])
        self.assertEqual(3, len(sub_program[1]))  # Add1, Add1, RETURN

        with self.assertRaises(StopIteration):
            sub_programs.next()

    def program_for_visiting_with_all_features(self):
        return self.program([
            'x', m.RETURN_TRUE,
            m.DEF('x'),
            m.IF(IsOdd), Add1, m.ENDIF, m.RETURN_TRUE
        ])

    def check_visitor(self, visitor):
        prog = self.program_for_visiting_with_all_features()
        prog.accept(visitor)

    def test_remembering_visitor_is_an_accepted_visitor(self):
        self.check_visitor(RememberingVisitor())

    def test_visit(self):
        prog = self.program_for_visiting_with_all_features()

        remembering_visitor = RememberingVisitor()

        prog.accept(remembering_visitor)

        i = prog.instructions
        self.assertEqual([('subprogram', None), ('call', i[0]),
                          ('return', i[1]), ('end', None), ('subprogram', 'x'),
                          ('branch', i[2]), ('instruction', i[3]),
                          ('return', i[4]), ('end', 'x')],
                         remembering_visitor.calls)