|
@@ -0,0 +1,240 @@
|
|
|
+
|
|
|
+class Instruction(object):
|
|
|
+ """A base class for instructions. An instruction is essentially a syntax
|
|
|
+ node that must first be defined, and can only then be used."""
|
|
|
+
|
|
|
+ def __init__(self):
|
|
|
+ pass
|
|
|
+
|
|
|
+ def has_result(self):
|
|
|
+ """Tells if this instruction computes a result."""
|
|
|
+
|
|
|
+ return True
|
|
|
+
|
|
|
+ def generate_python_def(self, code_generator):
|
|
|
+ """Generates a Python statement that executes this instruction.
|
|
|
+ The statement is appended immediately to the code generator."""
|
|
|
+
|
|
|
+ raise NotImplementedError
|
|
|
+
|
|
|
+ def generate_python_use(self, code_generator):
|
|
|
+ """Generates a Python expression that retrieves this instruction's
|
|
|
+ result. The expression is returned as a string."""
|
|
|
+
|
|
|
+ if self.has_result():
|
|
|
+ return code_generator.get_result_name(self)
|
|
|
+ else:
|
|
|
+ return 'None'
|
|
|
+
|
|
|
+ def simplify(self):
|
|
|
+ """Applies basic simplification to this instruction and its children."""
|
|
|
+
|
|
|
+ return self
|
|
|
+
|
|
|
+ def __str__(self):
|
|
|
+ cg = PythonGenerator()
|
|
|
+ self.generate_python_def(cg)
|
|
|
+ return cg.code
|
|
|
+
|
|
|
+class PythonGenerator(object):
|
|
|
+ """Generates Python code from instructions."""
|
|
|
+
|
|
|
+ def __init__(self):
|
|
|
+ self.code = ''
|
|
|
+ self.indentation_string = ' ' * 4
|
|
|
+ self.indentation = 0
|
|
|
+ self.result_value_dict = {}
|
|
|
+
|
|
|
+ def append(self, text):
|
|
|
+ """Appends the given string to this code generator."""
|
|
|
+
|
|
|
+ self.code += text
|
|
|
+
|
|
|
+ def append_indentation(self):
|
|
|
+ """Appends indentation to the code generator."""
|
|
|
+
|
|
|
+ self.append(self.indentation_string * self.indentation)
|
|
|
+
|
|
|
+ def append_line(self, line = None):
|
|
|
+ """Appends the indentation string followed by the given string (if any)
|
|
|
+ and a newline to the code generator."""
|
|
|
+
|
|
|
+ self.append_indentation()
|
|
|
+ if line is not None:
|
|
|
+ self.append(line)
|
|
|
+ self.append('\n')
|
|
|
+
|
|
|
+ def increase_indentation(self):
|
|
|
+ """Increases the code generator's indentation by one indent."""
|
|
|
+
|
|
|
+ self.indentation += 1
|
|
|
+
|
|
|
+ def decrease_indentation(self):
|
|
|
+ """Decreases the code generator's indentation by one indent."""
|
|
|
+
|
|
|
+ self.indentation -= 1
|
|
|
+
|
|
|
+ def get_result_name(self, instruction):
|
|
|
+ """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))
|
|
|
+
|
|
|
+ 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))
|
|
|
+
|
|
|
+class VoidInstruction(Instruction):
|
|
|
+ """A base class for instructions that do not return a value."""
|
|
|
+
|
|
|
+ def has_result(self):
|
|
|
+ """Tells if this instruction computes a result."""
|
|
|
+
|
|
|
+ return False
|
|
|
+
|
|
|
+class EmptyInstruction(VoidInstruction):
|
|
|
+ """Represents the empty instruction, which does nothing."""
|
|
|
+
|
|
|
+ def generate_python_def(self, code_generator):
|
|
|
+ code_generator.append_line('pass')
|
|
|
+
|
|
|
+class SelectInstruction(Instruction):
|
|
|
+ """Represents a select-instruction: an instruction that defines one of two
|
|
|
+ child instructions, and sets its result to the defined child's result."""
|
|
|
+
|
|
|
+ def __init__(self, condition, if_clause, else_clause):
|
|
|
+ Instruction.__init__(self)
|
|
|
+ self.condition = condition
|
|
|
+ self.if_clause = if_clause
|
|
|
+ self.else_clause = else_clause
|
|
|
+
|
|
|
+ def has_result(self):
|
|
|
+ """Tells if this instruction computes a result."""
|
|
|
+
|
|
|
+ return self.if_clause.has_result() or self.else_clause.has_result()
|
|
|
+
|
|
|
+ def simplify(self):
|
|
|
+ """Applies basic simplification to this instruction and its children."""
|
|
|
+
|
|
|
+ simple_cond = self.condition.simplify()
|
|
|
+ simple_if = self.if_clause.simplify()
|
|
|
+ simple_else = self.else_clause.simplify()
|
|
|
+ return SelectInstruction(simple_cond, simple_if, simple_else)
|
|
|
+
|
|
|
+ def generate_python_def(self, code_generator):
|
|
|
+ """Generates Python code for this instruction."""
|
|
|
+
|
|
|
+ if_has_result = self.has_result()
|
|
|
+ if not isinstance(self.condition, EmptyInstruction):
|
|
|
+ self.condition.generate_python_def(code_generator)
|
|
|
+
|
|
|
+ code_generator.append_line(
|
|
|
+ 'if ' + self.condition.generate_python_use(code_generator) + ':')
|
|
|
+ code_generator.increase_indentation()
|
|
|
+ self.if_clause.generate_python_def(code_generator)
|
|
|
+ if if_has_result:
|
|
|
+ code_generator.append_definition(self, self.if_clause)
|
|
|
+ code_generator.decrease_indentation()
|
|
|
+ if not isinstance(self.else_clause, EmptyInstruction) or if_has_result:
|
|
|
+ code_generator.append_line('else:')
|
|
|
+ code_generator.increase_indentation()
|
|
|
+ self.else_clause.generate_python_def(code_generator)
|
|
|
+ if if_has_result:
|
|
|
+ code_generator.append_definition(self, self.else_clause)
|
|
|
+ code_generator.decrease_indentation()
|
|
|
+
|
|
|
+class ReturnInstruction(VoidInstruction):
|
|
|
+ """Represents a return-instruction."""
|
|
|
+
|
|
|
+ def __init__(self, value):
|
|
|
+ Instruction.__init__(self)
|
|
|
+ self.value = value
|
|
|
+
|
|
|
+ def generate_python_def(self, code_generator):
|
|
|
+ """Generates Python code for this instruction."""
|
|
|
+
|
|
|
+ code_generator.append_line(
|
|
|
+ 'raise PrimitiveFinished(' +
|
|
|
+ self.value.generate_python_use(code_generator) +
|
|
|
+ ')')
|
|
|
+
|
|
|
+class LoopInstruction(VoidInstruction):
|
|
|
+ """Represents a loop-instruction, which loops until broken."""
|
|
|
+
|
|
|
+ def __init__(self, body):
|
|
|
+ Instruction.__init__(self)
|
|
|
+ self.body = body
|
|
|
+
|
|
|
+ def generate_python_def(self, code_generator):
|
|
|
+ """Generates Python code for this instruction."""
|
|
|
+
|
|
|
+ code_generator.append_line('while True:')
|
|
|
+ code_generator.increase_indentation()
|
|
|
+ self.body.generate_python_def(code_generator)
|
|
|
+ code_generator.decrease_indentation()
|
|
|
+
|
|
|
+class BreakInstruction(VoidInstruction):
|
|
|
+ """Represents a break-instruction."""
|
|
|
+
|
|
|
+ def generate_python_def(self, code_generator):
|
|
|
+ """Generates Python code for this instruction."""
|
|
|
+
|
|
|
+ code_generator.append_line('break')
|
|
|
+
|
|
|
+class ContinueInstruction(VoidInstruction):
|
|
|
+ """Represents a continue-instruction."""
|
|
|
+
|
|
|
+ def generate_python_def(self, code_generator):
|
|
|
+ """Generates Python code for this instruction."""
|
|
|
+
|
|
|
+ code_generator.append_line('continue')
|
|
|
+
|
|
|
+class CompoundInstruction(VoidInstruction):
|
|
|
+ """Represents an instruction that evaluates two other instructions
|
|
|
+ in order."""
|
|
|
+
|
|
|
+ def __init__(self, first, second):
|
|
|
+ Instruction.__init__(self)
|
|
|
+ self.first = first
|
|
|
+ self.second = second
|
|
|
+
|
|
|
+ def simplify(self):
|
|
|
+ """Applies basic simplification to this instruction and its children."""
|
|
|
+
|
|
|
+ simple_fst, simple_snd = self.first.simplify(), self.second.simplify()
|
|
|
+ if isinstance(simple_snd, EmptyInstruction):
|
|
|
+ return simple_fst
|
|
|
+ elif isinstance(simple_snd, EmptyInstruction):
|
|
|
+ return simple_snd
|
|
|
+ else:
|
|
|
+ return CompoundInstruction(simple_fst, simple_snd)
|
|
|
+
|
|
|
+ def generate_python_def(self, code_generator):
|
|
|
+ """Generates Python code for this instruction."""
|
|
|
+
|
|
|
+ if isinstance(self.second, EmptyInstruction):
|
|
|
+ self.first.generate_python_def(code_generator)
|
|
|
+ elif isinstance(self.first, EmptyInstruction):
|
|
|
+ self.second.generate_python_def(code_generator)
|
|
|
+ else:
|
|
|
+ self.first.generate_python_def(code_generator)
|
|
|
+ self.second.generate_python_def(code_generator)
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ exampleTree = SelectInstruction(
|
|
|
+ EmptyInstruction(),
|
|
|
+ LoopInstruction(
|
|
|
+ CompoundInstruction(
|
|
|
+ BreakInstruction(),
|
|
|
+ ContinueInstruction()
|
|
|
+ )
|
|
|
+ ),
|
|
|
+ ReturnInstruction(
|
|
|
+ EmptyInstruction()))
|
|
|
+ print(exampleTree)
|