Esempio n. 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])
Esempio n. 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))
Esempio n. 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))
Esempio n. 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))
Esempio n. 5
0
 def test_backward_reference_is_not_compilable(self):
     with self.assertRaises(BackwardReferenceError):
         self.program([RETURN_TRUE, DEF('label'), Noop, 'label'])
Esempio n. 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])
Esempio n. 7
0
 def test_incomplete_before_label_is_not_compilable(self):
     with self.assertRaises(FallOverOnDefineError):
         self.program([Noop, DEF('label'), Noop, RETURN_TRUE])
Esempio n. 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)