|
@@ -44,6 +44,11 @@ class Instruction(object):
|
|
|
"""Tells if this instruction requires a definition."""
|
|
|
return True
|
|
|
|
|
|
+ def get_result_name_override(self):
|
|
|
+ """Gets a value that overrides the code generator's result name for this
|
|
|
+ instruction if it is not None."""
|
|
|
+ return None
|
|
|
+
|
|
|
def generate_python_def(self, code_generator):
|
|
|
"""Generates a Python statement that executes this instruction.
|
|
|
The statement is appended immediately to the code generator."""
|
|
@@ -110,22 +115,42 @@ class PythonGenerator(object):
|
|
|
|
|
|
self.indentation -= 1
|
|
|
|
|
|
- def get_result_name(self, instruction):
|
|
|
+ def get_result_name(self, instruction, advised_name=None):
|
|
|
"""Gets the name of the given instruction's result variable."""
|
|
|
-
|
|
|
if instruction not in self.result_value_dict:
|
|
|
- self.result_value_dict[instruction] = \
|
|
|
- 'tmp' + str(len(self.result_value_dict))
|
|
|
+ override_name = instruction.get_result_name_override()
|
|
|
+ if override_name is not None:
|
|
|
+ self.result_value_dict[instruction] = override_name
|
|
|
+ elif advised_name is not None:
|
|
|
+ self.result_value_dict[instruction] = advised_name
|
|
|
+ else:
|
|
|
+ self.result_value_dict[instruction] = \
|
|
|
+ 'tmp' + str(len(self.result_value_dict))
|
|
|
|
|
|
return self.result_value_dict[instruction]
|
|
|
|
|
|
def append_definition(self, lhs, rhs):
|
|
|
"""Defines the first instruction's result variable as the second
|
|
|
instruction's result."""
|
|
|
-
|
|
|
self.append_line(
|
|
|
self.get_result_name(lhs) + ' = ' + rhs.generate_python_use(self))
|
|
|
|
|
|
+ def append_move_definition(self, lhs, rhs):
|
|
|
+ """First defines the second instruction, then defines the first
|
|
|
+ instruction as the result of the second."""
|
|
|
+ if rhs.has_definition():
|
|
|
+ # Retrieve the result name for the lhs.
|
|
|
+ lhs_result_name = self.get_result_name(lhs)
|
|
|
+ # Encourage the rhs to take on the same result name as the lhs.
|
|
|
+ rhs_result_name = self.get_result_name(rhs, lhs_result_name)
|
|
|
+ # Generate the rhs' definition.
|
|
|
+ rhs.generate_python_def(self)
|
|
|
+ # Only perform an assignment if it's truly necessary.
|
|
|
+ if lhs_result_name != rhs_result_name:
|
|
|
+ self.append_definition(lhs, rhs)
|
|
|
+ else:
|
|
|
+ self.append_definition(lhs, rhs)
|
|
|
+
|
|
|
def append_state_definition(self, lhs, opcode, args):
|
|
|
"""Appends a definition that queries the modelverse state."""
|
|
|
|
|
@@ -182,19 +207,19 @@ class SelectInstruction(Instruction):
|
|
|
code_generator.append_line(
|
|
|
'if ' + self.condition.generate_python_use(code_generator) + ':')
|
|
|
code_generator.increase_indentation()
|
|
|
- if self.if_clause.has_definition() or (not if_has_result):
|
|
|
- self.if_clause.generate_python_def(code_generator)
|
|
|
if if_has_result:
|
|
|
- code_generator.append_definition(self, self.if_clause)
|
|
|
+ code_generator.append_move_definition(self, self.if_clause)
|
|
|
+ else:
|
|
|
+ self.if_clause.generate_python_def(code_generator)
|
|
|
code_generator.decrease_indentation()
|
|
|
else_has_def = self.else_clause.has_definition()
|
|
|
if else_has_def or if_has_result:
|
|
|
code_generator.append_line('else:')
|
|
|
code_generator.increase_indentation()
|
|
|
- if else_has_def:
|
|
|
- self.else_clause.generate_python_def(code_generator)
|
|
|
if if_has_result:
|
|
|
- code_generator.append_definition(self, self.else_clause)
|
|
|
+ code_generator.append_move_definition(self, self.else_clause)
|
|
|
+ else:
|
|
|
+ self.else_clause.generate_python_def(code_generator)
|
|
|
code_generator.decrease_indentation()
|
|
|
|
|
|
class ReturnInstruction(VoidInstruction):
|
|
@@ -361,9 +386,7 @@ class CompoundInstruction(Instruction):
|
|
|
def generate_python_def(self, code_generator):
|
|
|
"""Generates Python code for this instruction."""
|
|
|
self.first.generate_python_def(code_generator)
|
|
|
- self.second.generate_python_def(code_generator)
|
|
|
- if self.has_result():
|
|
|
- code_generator.append_definition(self, self.second)
|
|
|
+ code_generator.append_move_definition(self, self.second)
|
|
|
|
|
|
class LiteralInstruction(Instruction):
|
|
|
"""Represents an integer, floating-point, string or Boolean literal."""
|
|
@@ -408,6 +431,11 @@ class LocalInstruction(Instruction):
|
|
|
Instruction.__init__(self)
|
|
|
self.name = name
|
|
|
|
|
|
+ def get_result_name_override(self):
|
|
|
+ """Gets a value that overrides the code generator's result name for this
|
|
|
+ instruction if it is not None."""
|
|
|
+ return self.name
|
|
|
+
|
|
|
def create_load(self):
|
|
|
"""Creates an instruction that loads the variable referenced by this instruction."""
|
|
|
return LoadLocalInstruction(self.name)
|
|
@@ -435,11 +463,7 @@ class StoreLocalInstruction(LocalInstruction):
|
|
|
def generate_python_def(self, code_generator):
|
|
|
"""Generates a Python statement that executes this instruction.
|
|
|
The statement is appended immediately to the code generator."""
|
|
|
-
|
|
|
- if self.value.has_definition():
|
|
|
- self.value.generate_python_def(code_generator)
|
|
|
- code_generator.append_line(
|
|
|
- '%s = %s' % (self.name, self.value.generate_python_use(code_generator)))
|
|
|
+ code_generator.append_move_definition(self, self.value)
|
|
|
|
|
|
class LoadLocalInstruction(LocalInstruction):
|
|
|
"""An instruction that loads a value from a local variable."""
|
|
@@ -642,8 +666,8 @@ def create_block(*statements):
|
|
|
return statements[0]
|
|
|
else:
|
|
|
return CompoundInstruction(
|
|
|
- create_block(*statements[:-1]),
|
|
|
- statements[-1])
|
|
|
+ statements[0],
|
|
|
+ create_block(*statements[1:]))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
example_tree = SelectInstruction(
|