Ejemplo n.º 1
0
    def __init__(self, python, verbose=False, emit=None):
        self.temp_vars = {}
        self.free_temp_vars = []
        self.byte_var_table = {}
        self.current_var_index = 0
        self.if_depth = 0

        self.python = python
        self.vmap = VariableMap()
        if emit:
            self.emit = emit
        else:
            self.emit = Emitter(verbose=verbose)
Ejemplo n.º 2
0
    def test_difference_in_if(self):
        emit_output = StringIO.StringIO()
        run_output = StringIO.StringIO()
        emitter = Emitter(stdout=emit_output)
        python = """if True != False:\n    print "OK" """
        builder = BFBuild(python, emit=emitter).emit_bf()
        run(emit_output.getvalue(), stdout=run_output)
        self.assertEquals("OK\n", run_output.getvalue())

        emit_output = StringIO.StringIO()
        run_output = StringIO.StringIO()
        emitter = Emitter(stdout=emit_output)
        python = """if True != True:\n    print "OK" """
        builder = BFBuild(python, emit=emitter).emit_bf()
        run(emit_output.getvalue(), stdout=run_output)
        self.assertEquals("", run_output.getvalue())
    def test_single_assignment(self):
        emit_output = StringIO.StringIO()
        run_output = StringIO.StringIO()
        emitter = Emitter(stdout=emit_output)
        python = """v1 = "a" """
        builder = BFBuild(python, emit=emitter).emit_bf()

        run(emit_output.getvalue(), stdout=run_output)
    def test_variable_to_variable(self):
        emit_output = StringIO.StringIO()
        run_output = StringIO.StringIO()
        emitter = Emitter(stdout=emit_output)
        python = """v1 = "a"\nv2 = v1 """
        builder = BFBuild(python, emit=emitter).emit_bf()

        run(emit_output.getvalue(), stdout=run_output)
Ejemplo n.º 5
0
 def test_if_true(self):
     emit_output = StringIO.StringIO()
     run_output = StringIO.StringIO()
     emitter = Emitter(stdout=emit_output)
     python = """if True:\n    print "OK" """
     builder = BFBuild(python, emit=emitter).emit_bf()
     run(emit_output.getvalue(), stdout=run_output)
     self.assertEqual(run_output.getvalue(), "OK\n")
Ejemplo n.º 6
0
 def test_if_else_match_else(self):
     emit_output = StringIO.StringIO()
     run_output = StringIO.StringIO()
     emitter = Emitter(stdout=emit_output)
     python = ("if False:\n    print 'IF'\n" "else:\n    print 'ELSE'\n")
     builder = BFBuild(python, emit=emitter).emit_bf()
     run(emit_output.getvalue(), stdout=run_output)
     self.assertEqual(run_output.getvalue(), "ELSE\n")
    def test_setting_integer(self):
        emit_output = StringIO.StringIO()
        run_output = StringIO.StringIO()
        emitter = Emitter(stdout=emit_output)
        python = """v1 = 57 """
        builder = BFBuild(python, emit=emitter).emit_bf()

        memory_space = []
        run(emit_output.getvalue(), stdout=run_output)
Ejemplo n.º 8
0
    def test_equality_true_false(self):
        emit_output = StringIO.StringIO()
        run_output = StringIO.StringIO()
        emitter = Emitter(stdout=emit_output)
        python = """foo = True == True\nprint foo"""
        builder = BFBuild(python, emit=emitter).emit_bf()
        memory_space = []
        run(emit_output.getvalue(), stdout=run_output, memory=memory_space)
        self.assertEquals(1, ord(run_output.getvalue()[0]))

        emit_output = StringIO.StringIO()
        run_output = StringIO.StringIO()
        emitter = Emitter(stdout=emit_output)
        python = """foo = True == False\nprint foo"""
        builder = BFBuild(python, emit=emitter).emit_bf()
        memory_space = []
        run(emit_output.getvalue(), stdout=run_output, memory=memory_space)
        self.assertEquals(0, ord(run_output.getvalue()[0]))
Ejemplo n.º 9
0
    def test_single_static_output(self):
        emit_output = StringIO.StringIO()
        run_output = StringIO.StringIO()
        emitter = Emitter(stdout=emit_output)
        python = """print "Hello" """
        builder = BFBuild(python, emit=emitter).emit_bf()

        run(emit_output.getvalue(), stdout=run_output)

        self.assertEqual(run_output.getvalue(), "Hello\n")
Ejemplo n.º 10
0
class BFBuild(object):
    def __init__(self, python, verbose=False, emit=None):
        self.temp_vars = {}
        self.free_temp_vars = []
        self.byte_var_table = {}
        self.current_var_index = 0
        self.if_depth = 0

        self.python = python
        self.vmap = VariableMap()
        if emit:
            self.emit = emit
        else:
            self.emit = Emitter(verbose=verbose)

    def error_on_node(self, node, error):
        raise Exception("Error on line %s: %s" % (node.lineno, error))

    def process_print_node(self, print_node):
        if print_node.dest:
            self.error_on_node(node, "Don't know how to do print destinations")

        values = print_node.values
        for value in values:
            if isinstance(value, ast.Str):
                self.emit_print_string(value.s)
            elif isinstance(value, ast.Name):
                if not isinstance(value.ctx, ast.Load):
                    self.error_on_node(
                        node, "Don't know what this variable"
                        "context is")

                self.emit_print_variable(value.id)
        if print_node.nl:
            self.emit_print_string("\n")

    def process_number_assignment(self, target, value, value_node):
        if value != int(value):
            self.error_on_node(value_node, "Can only set integers right now")

        if value > 127 or value < -127:
            self.error_on_node(value_node, "Out of 8-bit (signed) range")

        v_index = self.vmap.get_or_create_variable_index(target)

        self.emit_move_to_var_index(v_index["type"])
        self.emit_set_current_index_value(constants.TYPE_INT)
        self.emit_move_to_var_index(v_index["data"])
        self.emit_zero_current_index()
        self.emit_set_current_index_value(value)

    def process_string_assignment(self, target, value, value_node):
        if len(value) > 1:
            self.error_on_node(value_node,
                               "Can only set single chars right now")

        v_index = self.vmap.get_or_create_variable_index(target)

        self.emit_move_to_var_index(v_index["type"])
        self.emit_set_current_index_value(constants.TYPE_STRING)
        self.emit_move_to_var_index(v_index["data"])
        self.emit_zero_current_index()
        self.emit_set_current_index_value(ord(value))

    def process_if_node(self, node):
        test = node.test

        current_if_var = self.get_temp_target_var()
        current_else_var = self.get_temp_target_var()

        self.if_depth += 1
        if_index = self.vmap.get_variable_index(current_if_var)["data"]
        else_index = self.vmap.get_variable_index(current_else_var)["data"]

        self.emit.debug("At if depth %s" % (self.if_depth - 1))
        self.emit_move_to_var_index(if_index)
        self.emit_zero_current_index()
        self.emit_move_to_var_index(else_index)
        self.emit_zero_current_index()
        self.emit.add("Set the else to true by default")

        self._process_assignment_to_variable(current_if_var, test)

        self.emit_move_to_var_index(if_index)
        self.emit.start_loop("If the value at index %s is true:" % if_index)
        # If true value, zero out the if index to make sure we don't keep
        # looping, and zero out the else index so the else doesn't run.
        self.emit_zero_current_index()
        self.emit_move_to_var_index(else_index)
        self.emit_zero_current_index()

        for if_body_node in node.body:
            self.process_node(if_body_node)

        self.emit_move_to_var_index(if_index)
        self.emit.end_loop()

        self.emit_move_to_var_index(else_index)
        self.emit.start_loop("Else")
        self.emit_zero_current_index()
        orelse_len = len(node.orelse)
        if orelse_len:
            else_node = node.orelse[0]
            if orelse_len == 1 and isinstance(else_node, ast.If):
                self.process_if_node(else_node)
            else:
                for else_node in node.orelse:
                    self.process_node(else_node)
        self.emit_move_to_var_index(else_index)
        self.emit.end_loop()
        self.free_temp_target_var(current_if_var)
        self.free_temp_target_var(current_else_var)

    def get_temp_target_var(self):
        if len(self.free_temp_vars):
            return self.free_temp_vars.pop()
        current_count = len(self.temp_vars)
        var_id = '___tmp_var_%s' % current_count
        self.temp_vars[var_id] = True
        self.vmap.get_or_create_variable_index(var_id)
        return var_id

    def free_temp_target_var(self, variable):
        self.free_temp_vars.append(variable)

    def process_compare(self, target, node):

        if len(node.ops) > 1:
            self.error_on_node(node,
                               "Don't know how to do multiple comparisons")
        if isinstance(node.ops[0], ast.Eq):

            def _indexes_equal(target_index, left_index, comp_index):
                # If we subtract one from each temp var until the first one is
                # empty, if the second temp var is empty then they're equal.

                # We set the target to true initially, so it can fail in a
                # loop on the second variable
                self.emit_move_to_var_index(target_index)
                self.emit_zero_current_index()
                self.emit.add()

                self.emit_move_to_var_index(left_index)
                self.emit.start_loop("Emptying tmp left and comp variables")
                self.emit.subtract()
                self.emit_move_to_var_index(comp_index)
                self.emit.subtract()
                self.emit_move_to_var_index(left_index)
                self.emit.end_loop()

                self.emit_move_to_var_index(comp_index)
                self.emit.start_loop("If there's a value here, the values "
                                     "aren't equal!")
                self.emit_zero_current_index()
                self.emit_move_to_var_index(target_index)
                self.emit_zero_current_index()
                self.emit_move_to_var_index(comp_index)
                self.emit.end_loop()

            left_var = self.get_temp_target_var()
            comp_var = self.get_temp_target_var()
            self._process_assignment_to_variable(left_var, node.left)
            self._process_assignment_to_variable(comp_var, node.comparators[0])

            target_index = self.vmap.get_variable_index(target)

            self.emit_move_to_var_index(target_index["type"])
            self.emit_set_current_index_value(constants.TYPE_INT)

            left_index = self.vmap.get_variable_index(left_var)
            comp_index = self.vmap.get_variable_index(comp_var)

            _indexes_equal(target_index["data"], left_index["type"],
                           comp_index["type"])

            _indexes_equal(target_index["data"], left_index["data"],
                           comp_index["data"])

            self.free_temp_target_var(left_var)
            self.free_temp_target_var(comp_var)
        elif isinstance(node.ops[0], ast.NotEq):
            # If we subtract one from each temp var until the first one is
            # empty, if the second temp var is empty then they're equal.

            # We set the target to false initially, so it can be true in a
            # loop on the second variable
            def _indexes_ne(target_index, left_index, right_index):
                self.emit_move_to_var_index(left_index)
                self.emit.start_loop("Emptying tmp left and comp variables")
                self.emit.subtract()
                self.emit_move_to_var_index(right_index)
                self.emit.subtract()
                self.emit_move_to_var_index(left_index)
                self.emit.end_loop()

                self.emit_move_to_var_index(right_index)
                self.emit.start_loop("If there's a value here, the values "
                                     "aren't equal!")
                self.emit_zero_current_index()
                self.emit_move_to_var_index(target_index)
                self.emit.add()
                self.emit_move_to_var_index(right_index)
                self.emit.end_loop()

            left_var = self.get_temp_target_var()
            comp_var = self.get_temp_target_var()
            self._process_assignment_to_variable(left_var, node.left)
            self._process_assignment_to_variable(comp_var, node.comparators[0])

            target_index = self.vmap.get_variable_index(target)

            self.emit_move_to_var_index(target_index["type"])
            self.emit_set_current_index_value(constants.TYPE_INT)
            self.emit_move_to_var_index(target_index["data"])
            self.emit_zero_current_index()

            left_index = self.vmap.get_variable_index(left_var)
            comp_index = self.vmap.get_variable_index(comp_var)

            _indexes_ne(target_index["data"], left_index["type"],
                        comp_index["type"])
            _indexes_ne(target_index["data"], left_index["data"],
                        comp_index["data"])
            self.free_temp_target_var(left_var)
            self.free_temp_target_var(comp_var)

        else:
            self.error_on_node(node, "Unknown comparison: %s" % node.ops[0])

    def _process_assignment_to_variable(self, target, node):
        if isinstance(node, ast.Str):
            self.process_string_assignment(target, node.s, node)
        elif isinstance(node, ast.Num):
            self.process_number_assignment(target, node.n, node)
        elif isinstance(node, ast.Name):
            self.process_variable_to_variable(target, node.id, node)
        elif isinstance(node, ast.Compare):
            compare_target = self.get_temp_target_var()
            self.process_compare(compare_target, node)
            self.process_variable_to_variable(target, compare_target, node)
            self.free_temp_target_var(compare_target)

        else:
            print ast.dump(node)
            self.error_on_node(node, "Unable to set value type")

    def process_assignment_node(self, assignment_node):
        targets = assignment_node.targets
        value = assignment_node.value

        for target in targets:
            if not isinstance(target, ast.Name):
                self.error_on_node(target, "Unknown syntax :(")

            self._process_assignment_to_variable(target.id, value)

    def _copy_value_to_index_from_index(self, target_index, source_index):
        self.emit.debug("Copying value from %s to %s" %
                        (source_index, target_index))
        # Clear out our scratch space.
        self.emit_move_to_var_index(self.get_scratch_index())
        self.emit_zero_current_index()

        # Clear out the destination space
        self.emit_move_to_var_index(target_index)
        self.emit_zero_current_index()

        # While there's a value at the source, subtract one, and add one to
        # the scratch space and target
        self.emit_move_to_var_index(source_index)
        self.emit.start_loop("Start copying the value into the "
                             "scratch %s and destination %s")

        self.emit.subtract()
        self.emit_move_to_var_index(self.get_scratch_index())
        self.emit.add()
        self.emit_move_to_var_index(target_index)
        self.emit.add()
        self.emit_move_to_var_index(source_index)
        self.emit.end_loop()

        # While there's a value in the scratch space, subtract one, and add
        # one at the source to restore its value
        self.emit_move_to_var_index(self.get_scratch_index())
        self.emit.start_loop("Restore the value to the source index")
        self.emit.subtract()
        self.emit_move_to_var_index(source_index)
        self.emit.add()
        self.emit_move_to_var_index(self.get_scratch_index())
        self.emit.end_loop()

    def process_variable_to_variable(self, target, source, source_node):
        source_index = self.vmap.get_variable_index(source)
        target_index = self.vmap.get_or_create_variable_index(target)

        self._copy_value_to_index_from_index(target_index["type"],
                                             source_index["type"])

        self._copy_value_to_index_from_index(target_index["data"],
                                             source_index["data"])

    def emit_print_variable(self, variable_name):
        v_index = self.vmap.get_variable_index(variable_name)
        self.emit_move_to_var_index(v_index["data"])
        self.emit.print_current_index()

    def emit_print_string(self, value):
        self.emit_move_to_var_index(self.get_scratch_index())

        for char in value:
            next_ord = ord(char)
            self.emit_zero_current_index()
            self.emit_set_current_index_value(next_ord)
            self.emit.print_current_index()

    def emit_zero_current_index(self):
        self.emit.start_loop()
        self.emit.subtract()
        self.emit.end_loop("Set the current index to 0")

    def emit_set_current_index_value(self, value):
        for i in range(value):
            self.emit.add()
        self.emit.debug("Setting value to %s" % value)

    def emit_move_to_var_index(self, index):
        if index > self.current_var_index:
            self.emit.move_index_right_by(index - self.current_var_index,
                                          "Move to variable index %s" % index)

        elif index < self.current_var_index:
            self.emit.move_index_left_by(self.current_var_index - index,
                                         "Move to variable index %s" % index)
        else:
            self.emit.debug("noop: Already at variable index %s" % index)
        self.current_var_index = index

    def process_node(self, node):
        if isinstance(node, ast.Assign):
            self.process_assignment_node(node)
        elif isinstance(node, ast.Print):
            self.process_print_node(node)
        elif isinstance(node, ast.If):
            self.process_if_node(node)
        elif isinstance(node, ast.Pass):
            pass
        else:
            print ast.dump(node)
            self.error_on_node(node, "Syntax not supported yet :(")

    def get_scratch_index(self):
        index = self.vmap.get_or_create_variable_index("___scratch", size=1)
        return index["data"]

    def create_starting_variables(self):
        vmap = self.vmap
        self.get_scratch_index()
        true_index = vmap.get_or_create_variable_index("True", size=1)
        false_index = vmap.get_or_create_variable_index("False", size=1)

        self.emit.debug("Defining True at index %s" % true_index)

        self.emit_move_to_var_index(true_index["type"])
        self.emit_set_current_index_value(constants.TYPE_INT)
        self.emit_move_to_var_index(true_index["data"])
        self.emit_zero_current_index()
        self.emit.add()

        self.emit.debug("Defining False at index %s" % false_index)
        self.emit_move_to_var_index(true_index["type"])
        self.emit_set_current_index_value(constants.TYPE_INT)
        self.emit_move_to_var_index(false_index["data"])
        self.emit_zero_current_index()

    def emit_bf(self):
        self.create_starting_variables()
        top_node = ast.parse(self.python)
        for node in ast.iter_child_nodes(top_node):
            self.process_node(node)