Sfoglia il codice sorgente

Change how simplify(), has_result() and has_definition() are implemented

simplify() has been replaced by a more general mechanism. Results for has_result()
and has_definition() are cached now.
jonathanvdc 8 anni fa
parent
commit
7293af1012
1 ha cambiato i file con 284 aggiunte e 150 eliminazioni
  1. 284 150
      kernel/modelverse_jit/tree_ir.py

+ 284 - 150
kernel/modelverse_jit/tree_ir.py

@@ -34,13 +34,26 @@ class Instruction(object):
        node that must first be defined, and can only then be used."""
        node that must first be defined, and can only then be used."""
 
 
     def __init__(self):
     def __init__(self):
-        pass
+        self.has_result_cache = None
+        self.has_definition_cache = None
 
 
     def has_result(self):
     def has_result(self):
         """Tells if this instruction computes a result."""
         """Tells if this instruction computes a result."""
-        return True
+        if self.has_result_cache is None:
+            self.has_result_cache = self.has_result_impl()
+        return self.has_result_cache
 
 
     def has_definition(self):
     def has_definition(self):
+        """Tells if this instruction requires a definition."""
+        if self.has_definition_cache is None:
+            self.has_definition_cache = self.has_definition_impl()
+        return self.has_definition_cache
+
+    def has_result_impl(self):
+        """Tells if this instruction computes a result."""
+        return True
+
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return True
         return True
 
 
@@ -52,7 +65,6 @@ class Instruction(object):
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
         """Generates a Python statement that executes this instruction.
            The statement is appended immediately to the code generator."""
            The statement is appended immediately to the code generator."""
-
         if self.has_definition():
         if self.has_definition():
             raise NotImplementedError()
             raise NotImplementedError()
         else:
         else:
@@ -61,17 +73,30 @@ class Instruction(object):
     def generate_python_use(self, code_generator):
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
         """Generates a Python expression that retrieves this instruction's
            result. The expression is returned as a string."""
            result. The expression is returned as a string."""
-
         if self.has_result():
         if self.has_result():
             return code_generator.get_result_name(self)
             return code_generator.get_result_name(self)
         else:
         else:
             return 'None'
             return 'None'
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        raise NotImplementedError()
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        raise NotImplementedError()
 
 
+    def simplify_node(self):
+        """Applies basic simplification to this instruction only."""
         return self
         return self
 
 
+    def simplify(self):
+        """Applies basic simplification to this instruction and all of its children."""
+        # This fairly convoluted one-liner first simplifies all children, then creates
+        # an instruction from the simplified children, and finally simplifies that top-level
+        # instruction.
+        return self.create([c.simplify() for c in self.get_children()]).simplify_node()
+
     def __str__(self):
     def __str__(self):
         code_generator = PythonGenerator()
         code_generator = PythonGenerator()
         self.generate_python_def(code_generator)
         self.generate_python_def(code_generator)
@@ -92,13 +117,11 @@ class PythonGenerator(object):
 
 
     def append_indentation(self):
     def append_indentation(self):
         """Appends indentation to the code generator."""
         """Appends indentation to the code generator."""
-
         self.append(self.indentation_string * self.indentation)
         self.append(self.indentation_string * self.indentation)
 
 
     def append_line(self, line=None):
     def append_line(self, line=None):
         """Appends the indentation string followed by the given string (if any)
         """Appends the indentation string followed by the given string (if any)
            and a newline to the code generator."""
            and a newline to the code generator."""
-
         self.append_indentation()
         self.append_indentation()
         if line is not None:
         if line is not None:
             self.append(line)
             self.append(line)
@@ -106,12 +129,10 @@ class PythonGenerator(object):
 
 
     def increase_indentation(self):
     def increase_indentation(self):
         """Increases the code generator's indentation by one indent."""
         """Increases the code generator's indentation by one indent."""
-
         self.indentation += 1
         self.indentation += 1
 
 
     def decrease_indentation(self):
     def decrease_indentation(self):
         """Decreases the code generator's indentation by one indent."""
         """Decreases the code generator's indentation by one indent."""
-
         self.indentation -= 1
         self.indentation -= 1
 
 
     def get_result_name(self, instruction, advised_name=None):
     def get_result_name(self, instruction, advised_name=None):
@@ -152,7 +173,6 @@ class PythonGenerator(object):
 
 
     def append_state_definition(self, lhs, opcode, args):
     def append_state_definition(self, lhs, opcode, args):
         """Appends a definition that queries the modelverse state."""
         """Appends a definition that queries the modelverse state."""
-
         self.append_line(
         self.append_line(
             "%s, = yield [('%s', [%s])]" % (
             "%s, = yield [('%s', [%s])]" % (
                 self.get_result_name(lhs),
                 self.get_result_name(lhs),
@@ -165,40 +185,53 @@ class PythonGenerator(object):
 class VoidInstruction(Instruction):
 class VoidInstruction(Instruction):
     """A base class for instructions that do not return a value."""
     """A base class for instructions that do not return a value."""
 
 
-    def has_result(self):
+    def has_result_impl(self):
         """Tells if this instruction computes a result."""
         """Tells if this instruction computes a result."""
         return False
         return False
 
 
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return []
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        return self
+
 class EmptyInstruction(VoidInstruction):
 class EmptyInstruction(VoidInstruction):
     """Represents the empty instruction, which does nothing."""
     """Represents the empty instruction, which does nothing."""
 
 
-    def has_definition(self):
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return False
         return False
 
 
 class SelectInstruction(Instruction):
 class SelectInstruction(Instruction):
     """Represents a select-instruction: an instruction that defines one of two
     """Represents a select-instruction: an instruction that defines one of two
        child instructions, and sets its result to the defined child's result."""
        child instructions, and sets its result to the defined child's result."""
-
     def __init__(self, condition, if_clause, else_clause):
     def __init__(self, condition, if_clause, else_clause):
         Instruction.__init__(self)
         Instruction.__init__(self)
         self.condition = condition
         self.condition = condition
         self.if_clause = if_clause
         self.if_clause = if_clause
         self.else_clause = else_clause
         self.else_clause = else_clause
 
 
-    def has_result(self):
+    def has_result_impl(self):
         """Tells if this instruction computes a result."""
         """Tells if this instruction computes a result."""
         return self.if_clause.has_result() or self.else_clause.has_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()
-        if isinstance(simple_cond, LiteralInstruction):
-            return simple_if if simple_cond.literal else simple_else
+    def simplify_node(self):
+        """Applies basic simplification to this instruction only."""
+        if isinstance(self.condition, LiteralInstruction):
+            return self.if_clause if self.condition.literal else self.else_clause
         else:
         else:
-            return SelectInstruction(simple_cond, simple_if, simple_else)
+            return SelectInstruction(self.condition, self.if_clause, self.else_clause)
+
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.condition, self.if_clause, self.else_clause]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        condition, if_clause, else_clause = new_children
+        return SelectInstruction(condition, if_clause, else_clause)
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
         """Generates Python code for this instruction."""
@@ -226,14 +259,18 @@ class SelectInstruction(Instruction):
 
 
 class ReturnInstruction(VoidInstruction):
 class ReturnInstruction(VoidInstruction):
     """Represents a return-instruction."""
     """Represents a return-instruction."""
-
     def __init__(self, value):
     def __init__(self, value):
         VoidInstruction.__init__(self)
         VoidInstruction.__init__(self)
         self.value = value
         self.value = value
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return ReturnInstruction(self.value.simplify())
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.value]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        value, = new_children
+        return ReturnInstruction(value)
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
         """Generates Python code for this instruction."""
@@ -246,14 +283,18 @@ class ReturnInstruction(VoidInstruction):
 
 
 class RaiseInstruction(VoidInstruction):
 class RaiseInstruction(VoidInstruction):
     """An instruction that raises an error."""
     """An instruction that raises an error."""
-
     def __init__(self, value):
     def __init__(self, value):
         VoidInstruction.__init__(self)
         VoidInstruction.__init__(self)
         self.value = value
         self.value = value
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return RaiseInstruction(self.value.simplify())
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.value]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        value, = new_children
+        return RaiseInstruction(value)
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
         """Generates Python code for this instruction."""
@@ -268,11 +309,13 @@ class CallInstruction(Instruction):
         self.target = target
         self.target = target
         self.argument_list = argument_list
         self.argument_list = argument_list
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return CallInstruction(
-            self.target.simplify(),
-            [arg.simplify() for arg in self.argument_list])
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.target] + self.argument_list
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        return CallInstruction(new_children[0], new_children[1:])
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
         """Generates Python code for this instruction."""
@@ -297,12 +340,15 @@ class JitCallInstruction(Instruction):
         self.named_args = named_args
         self.named_args = named_args
         self.kwarg = kwarg
         self.kwarg = kwarg
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.target] + [arg for _, arg in self.named_args] + [self.kwarg]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        param_names = [name for name, _ in self.named_args]
         return JitCallInstruction(
         return JitCallInstruction(
-            self.target.simplify(),
-            [(param_name, arg.simplify()) for param_name, arg in self.named_args],
-            self.kwarg.simplify())
+            new_children[0], zip(param_names, new_children[1:-1]), new_children[-1])
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
         """Generates Python code for this instruction."""
@@ -349,13 +395,18 @@ class PrintInstruction(Instruction):
         Instruction.__init__(self)
         Instruction.__init__(self)
         self.argument = argument
         self.argument = argument
 
 
-    def has_result(self):
+    def has_result_impl(self):
         """Tells if this instruction has a result."""
         """Tells if this instruction has a result."""
         return False
         return False
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return PrintInstruction(self.argument.simplify())
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.argument]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        arg, = new_children
+        return PrintInstruction(arg)
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
         """Generates Python code for this instruction."""
@@ -374,14 +425,27 @@ class BinaryInstruction(Instruction):
         self.operator = operator
         self.operator = operator
         self.rhs = rhs
         self.rhs = rhs
 
 
-    def has_definition(self):
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return self.lhs.has_definition() or self.rhs.has_definition()
         return self.lhs.has_definition() or self.rhs.has_definition()
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        simple_lhs, simple_rhs = self.lhs.simplify(), self.rhs.simplify()
-        return BinaryInstruction(simple_lhs, self.operator, simple_rhs)
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.lhs, self.rhs]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        lhs, rhs, = new_children
+        return BinaryInstruction(lhs, self.operator, rhs)
+
+    def simplify_node(self):
+        """Applies basic simplification to this instruction only."""
+        if isinstance(self.lhs, LiteralInstruction) and isinstance(self.rhs, LiteralInstruction):
+            # TODO: there's probably a better way to do this than with eval.
+            return LiteralInstruction(
+                eval('%s %s %s' % (repr(self.lhs.literal), self.operator, repr(self.rhs.literal))))
+        else:
+            return self
 
 
     def generate_python_use(self, code_generator):
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
         """Generates a Python expression that retrieves this instruction's
@@ -410,14 +474,27 @@ class UnaryInstruction(Instruction):
         self.operator = operator
         self.operator = operator
         self.operand = operand
         self.operand = operand
 
 
-    def has_definition(self):
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return self.operand.has_definition()
         return self.operand.has_definition()
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        simple_operand = self.operand.simplify()
-        return UnaryInstruction(self.operator, simple_operand)
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.operand]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        operand, = new_children
+        return UnaryInstruction(self.operator, operand)
+
+    def simplify_node(self):
+        """Applies basic simplification to this instruction only."""
+        if isinstance(self.operand, LiteralInstruction):
+            # TODO: there's probably a better way to do this than with eval.
+            return LiteralInstruction(
+                eval('%s %s' % (self.operator, repr(self.operand.literal))))
+        else:
+            return self
 
 
     def generate_python_use(self, code_generator):
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
         """Generates a Python expression that retrieves this instruction's
@@ -441,14 +518,17 @@ class LoopInstruction(VoidInstruction):
         VoidInstruction.__init__(self)
         VoidInstruction.__init__(self)
         self.body = body
         self.body = body
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.body]
 
 
-        return LoopInstruction(self.body.simplify())
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        body, = new_children
+        return LoopInstruction(body)
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
         """Generates Python code for this instruction."""
-
         code_generator.append_line('while 1:')
         code_generator.append_line('while 1:')
         code_generator.increase_indentation()
         code_generator.increase_indentation()
         self.body.generate_python_def(code_generator)
         self.body.generate_python_def(code_generator)
@@ -456,43 +536,46 @@ class LoopInstruction(VoidInstruction):
 
 
 class BreakInstruction(VoidInstruction):
 class BreakInstruction(VoidInstruction):
     """Represents a break-instruction."""
     """Represents a break-instruction."""
-
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
         """Generates Python code for this instruction."""
-
         code_generator.append_line('break')
         code_generator.append_line('break')
 
 
 class ContinueInstruction(VoidInstruction):
 class ContinueInstruction(VoidInstruction):
     """Represents a continue-instruction."""
     """Represents a continue-instruction."""
-
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
         """Generates Python code for this instruction."""
-
         code_generator.append_line('continue')
         code_generator.append_line('continue')
 
 
 class CompoundInstruction(Instruction):
 class CompoundInstruction(Instruction):
     """Represents an instruction that evaluates two other instructions
     """Represents an instruction that evaluates two other instructions
        in order, and returns the second instruction's result."""
        in order, and returns the second instruction's result."""
-
     def __init__(self, first, second):
     def __init__(self, first, second):
         Instruction.__init__(self)
         Instruction.__init__(self)
         self.first = first
         self.first = first
         self.second = second
         self.second = second
 
 
-    def has_result(self):
+    def has_result_impl(self):
         """Tells if this instruction has a result."""
         """Tells if this instruction has a result."""
         return self.second.has_result() or self.first.has_result()
         return self.second.has_result() or self.first.has_result()
 
 
-    def simplify(self):
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.first, self.second]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        first, second = new_children
+        return CompoundInstruction(first, second)
+
+    def simplify_node(self):
         """Applies basic simplification to this instruction and its children."""
         """Applies basic simplification to this instruction and its children."""
-        simple_fst, simple_snd = self.first.simplify(), self.second.simplify()
-        if not simple_fst.has_definition() and (
-                not simple_fst.has_result() or simple_snd.has_result()):
-            return simple_snd
-        elif (not simple_snd.has_definition()) and (not simple_snd.has_result()):
-            return simple_fst
+        if not self.first.has_definition() and (
+                not self.first.has_result() or self.second.has_result()):
+            return self.second
+        elif (not self.second.has_definition()) and (not self.second.has_result()):
+            return self.first
         else:
         else:
-            return CompoundInstruction(simple_fst, simple_snd)
+            return self
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates Python code for this instruction."""
         """Generates Python code for this instruction."""
@@ -512,10 +595,18 @@ class LiteralInstruction(Instruction):
         Instruction.__init__(self)
         Instruction.__init__(self)
         self.literal = literal
         self.literal = literal
 
 
-    def has_definition(self):
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return False
         return False
 
 
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return []
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        return self
+
     def generate_python_use(self, code_generator):
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
         """Generates a Python expression that retrieves this instruction's
            result. The expression is returned as a string."""
            result. The expression is returned as a string."""
@@ -527,6 +618,15 @@ class DictionaryLiteralInstruction(Instruction):
         Instruction.__init__(self)
         Instruction.__init__(self)
         self.key_value_pairs = key_value_pairs
         self.key_value_pairs = key_value_pairs
 
 
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [val for _, val in self.key_value_pairs]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        keys = [k for k, _ in self.key_value_pairs]
+        return DictionaryLiteralInstruction(zip(keys, new_children))
+
     def has_definition(self):
     def has_definition(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return any(
         return any(
@@ -566,6 +666,14 @@ class StateInstruction(Instruction):
         """Gets this state instruction's argument list."""
         """Gets this state instruction's argument list."""
         raise NotImplementedError()
         raise NotImplementedError()
 
 
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return self.get_arguments()
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        return type(self)(*new_children)
+
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
         """Generates a Python statement that executes this instruction.
            The statement is appended immediately to the code generator."""
            The statement is appended immediately to the code generator."""
@@ -597,6 +705,14 @@ class VariableInstruction(Instruction):
         else:
         else:
             self.name = name
             self.name = name
 
 
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        raise NotImplementedError()
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        raise NotImplementedError()
+
     def get_result_name_override(self, code_generator):
     def get_result_name_override(self, code_generator):
         """Gets a value that overrides the code generator's result name for this
         """Gets a value that overrides the code generator's result name for this
            instruction if it is not None."""
            instruction if it is not None."""
@@ -604,6 +720,14 @@ class VariableInstruction(Instruction):
 
 
 class LocalInstruction(VariableInstruction):
 class LocalInstruction(VariableInstruction):
     """A base class for instructions that access local variables."""
     """A base class for instructions that access local variables."""
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        raise NotImplementedError()
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        raise NotImplementedError()
+
     def create_load(self):
     def create_load(self):
         """Creates an instruction that loads the variable referenced by this instruction."""
         """Creates an instruction that loads the variable referenced by this instruction."""
         return LoadLocalInstruction(self.name)
         return LoadLocalInstruction(self.name)
@@ -619,9 +743,14 @@ class StoreLocalInstruction(LocalInstruction):
         LocalInstruction.__init__(self, name)
         LocalInstruction.__init__(self, name)
         self.value = value
         self.value = value
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return StoreLocalInstruction(self.name, self.value.simplify())
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.value]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        val, = new_children
+        return StoreLocalInstruction(self.name, val)
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
         """Generates a Python statement that executes this instruction.
@@ -630,10 +759,18 @@ class StoreLocalInstruction(LocalInstruction):
 
 
 class LoadLocalInstruction(LocalInstruction):
 class LoadLocalInstruction(LocalInstruction):
     """An instruction that loads a value from a local variable."""
     """An instruction that loads a value from a local variable."""
-    def has_definition(self):
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return False
         return False
 
 
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return []
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        return self
+
 class DefineFunctionInstruction(VariableInstruction):
 class DefineFunctionInstruction(VariableInstruction):
     """An instruction that defines a function."""
     """An instruction that defines a function."""
     def __init__(self, name, parameter_list, body):
     def __init__(self, name, parameter_list, body):
@@ -641,6 +778,15 @@ class DefineFunctionInstruction(VariableInstruction):
         self.parameter_list = parameter_list
         self.parameter_list = parameter_list
         self.body = body
         self.body = body
 
 
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.body]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        body, = new_children
+        return DefineFunctionInstruction(self.name, self.parameter_list, body)
+
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
         """Generates a Python statement that executes this instruction.
            The statement is appended immediately to the code generator."""
            The statement is appended immediately to the code generator."""
@@ -652,11 +798,18 @@ class DefineFunctionInstruction(VariableInstruction):
 
 
 class LocalExistsInstruction(LocalInstruction):
 class LocalExistsInstruction(LocalInstruction):
     """An instruction that checks if a local variable exists."""
     """An instruction that checks if a local variable exists."""
-
-    def has_definition(self):
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return False
         return False
 
 
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return []
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        return self
+
     def generate_python_use(self, code_generator):
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
         """Generates a Python expression that retrieves this instruction's
            result. The expression is returned as a string."""
            result. The expression is returned as a string."""
@@ -664,10 +817,18 @@ class LocalExistsInstruction(LocalInstruction):
 
 
 class LoadGlobalInstruction(VariableInstruction):
 class LoadGlobalInstruction(VariableInstruction):
     """An instruction that loads a value from a global variable."""
     """An instruction that loads a value from a global variable."""
-    def has_definition(self):
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return False
         return False
 
 
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return []
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        return self
+
 class LoadIndexInstruction(Instruction):
 class LoadIndexInstruction(Instruction):
     """An instruction that produces a value by indexing a specified expression with
     """An instruction that produces a value by indexing a specified expression with
        a given key."""
        a given key."""
@@ -676,13 +837,18 @@ class LoadIndexInstruction(Instruction):
         self.indexed = indexed
         self.indexed = indexed
         self.key = key
         self.key = key
 
 
-    def has_definition(self):
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return False
         return False
 
 
-    def simplify(self):
-        return LoadIndexInstruction(
-            self.indexed.simplify(), self.key.simplify())
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.indexed, self.key]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        indexed, key = new_children
+        return LoadIndexInstruction(indexed, key)
 
 
     def generate_python_use(self, code_generator):
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
         """Generates a Python expression that retrieves this instruction's
@@ -704,13 +870,18 @@ class LoadMemberInstruction(Instruction):
         self.container = container
         self.container = container
         self.member_name = member_name
         self.member_name = member_name
 
 
-    def has_definition(self):
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return self.container.has_definition()
         return self.container.has_definition()
 
 
-    def simplify(self):
-        return LoadMemberInstruction(
-            self.container.simplify(), self.member_name)
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.container]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        container, = new_children
+        return LoadMemberInstruction(container, self.member_name)
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
         """Generates a Python statement that executes this instruction.
@@ -732,18 +903,22 @@ class StoreMemberInstruction(Instruction):
         self.member_name = member_name
         self.member_name = member_name
         self.value = value
         self.value = value
 
 
-    def has_definition(self):
+    def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return True
         return True
 
 
-    def has_result(self):
+    def has_result_impl(self):
         """Tells if this instruction computes a result."""
         """Tells if this instruction computes a result."""
         return False
         return False
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return StoreMemberInstruction(
-            self.container.simplify(), self.member_name, self.value.simplify())
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return [self.container, self.value]
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        container, value = new_children
+        return StoreMemberInstruction(container, self.member_name, value)
 
 
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
         """Generates a Python statement that executes this instruction.
@@ -757,11 +932,18 @@ class StoreMemberInstruction(Instruction):
 
 
 class NopInstruction(Instruction):
 class NopInstruction(Instruction):
     """A nop instruction, which allows for the kernel's thread of execution to be interrupted."""
     """A nop instruction, which allows for the kernel's thread of execution to be interrupted."""
-
-    def has_result(self):
+    def has_result_impl(self):
         """Tells if this instruction computes a result."""
         """Tells if this instruction computes a result."""
         return False
         return False
 
 
+    def get_children(self):
+        """Gets this instruction's sequence of child instructions."""
+        return []
+
+    def create(self, new_children):
+        """Creates a new instruction of this type from the given sequence of child instructions."""
+        return self
+
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
         """Generates a Python statement that executes this instruction.
            The statement is appended immediately to the code generator."""
            The statement is appended immediately to the code generator."""
@@ -769,18 +951,16 @@ class NopInstruction(Instruction):
 
 
 class ReadValueInstruction(StateInstruction):
 class ReadValueInstruction(StateInstruction):
     """An instruction that reads a value from a node."""
     """An instruction that reads a value from a node."""
-
     def __init__(self, node_id):
     def __init__(self, node_id):
         StateInstruction.__init__(self)
         StateInstruction.__init__(self)
         self.node_id = node_id
         self.node_id = node_id
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        simplified_node_id = self.node_id.simplify()
-        if isinstance(simplified_node_id, CreateNodeWithValueInstruction):
-            return simplified_node_id.value
+    def simplify_node(self):
+        """Applies basic simplification to this instruction only."""
+        if isinstance(self.node_id, CreateNodeWithValueInstruction):
+            return self.node_id.value
         else:
         else:
-            return ReadValueInstruction(simplified_node_id)
+            return self
 
 
     def get_opcode(self):
     def get_opcode(self):
         """Gets the opcode for this state instruction."""
         """Gets the opcode for this state instruction."""
@@ -792,18 +972,11 @@ class ReadValueInstruction(StateInstruction):
 
 
 class ReadDictionaryValueInstruction(StateInstruction):
 class ReadDictionaryValueInstruction(StateInstruction):
     """An instruction that reads a dictionary value."""
     """An instruction that reads a dictionary value."""
-
     def __init__(self, node_id, key):
     def __init__(self, node_id, key):
         StateInstruction.__init__(self)
         StateInstruction.__init__(self)
         self.node_id = node_id
         self.node_id = node_id
         self.key = key
         self.key = key
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return ReadDictionaryValueInstruction(
-            self.node_id.simplify(),
-            self.key.simplify())
-
     def get_opcode(self):
     def get_opcode(self):
         """Gets the opcode for this state instruction."""
         """Gets the opcode for this state instruction."""
         return "RD"
         return "RD"
@@ -814,18 +987,11 @@ class ReadDictionaryValueInstruction(StateInstruction):
 
 
 class ReadDictionaryEdgeInstruction(StateInstruction):
 class ReadDictionaryEdgeInstruction(StateInstruction):
     """An instruction that reads a dictionary edge."""
     """An instruction that reads a dictionary edge."""
-
     def __init__(self, node_id, key):
     def __init__(self, node_id, key):
         StateInstruction.__init__(self)
         StateInstruction.__init__(self)
         self.node_id = node_id
         self.node_id = node_id
         self.key = key
         self.key = key
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return ReadDictionaryEdgeInstruction(
-            self.node_id.simplify(),
-            self.key.simplify())
-
     def get_opcode(self):
     def get_opcode(self):
         """Gets the opcode for this state instruction."""
         """Gets the opcode for this state instruction."""
         return "RDE"
         return "RDE"
@@ -840,11 +1006,6 @@ class ReadEdgeInstruction(StateInstruction):
         StateInstruction.__init__(self)
         StateInstruction.__init__(self)
         self.node_id = node_id
         self.node_id = node_id
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return ReadEdgeInstruction(
-            self.node_id.simplify())
-
     def get_opcode(self):
     def get_opcode(self):
         """Gets the opcode for this state instruction."""
         """Gets the opcode for this state instruction."""
         return "RE"
         return "RE"
@@ -870,10 +1031,6 @@ class CreateNodeWithValueInstruction(StateInstruction):
         StateInstruction.__init__(self)
         StateInstruction.__init__(self)
         self.value = value
         self.value = value
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return CreateNodeWithValueInstruction(self.value.simplify())
-
     def get_opcode(self):
     def get_opcode(self):
         """Gets the opcode for this state instruction."""
         """Gets the opcode for this state instruction."""
         return "CNV"
         return "CNV"
@@ -889,12 +1046,6 @@ class CreateEdgeInstruction(StateInstruction):
         self.source_id = source_id
         self.source_id = source_id
         self.target_id = target_id
         self.target_id = target_id
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return CreateEdgeInstruction(
-            self.source_id.simplify(),
-            self.target_id.simplify())
-
     def get_opcode(self):
     def get_opcode(self):
         """Gets the opcode for this state instruction."""
         """Gets the opcode for this state instruction."""
         return "CE"
         return "CE"
@@ -911,13 +1062,6 @@ class CreateDictionaryEdgeInstruction(StateInstruction):
         self.key = key
         self.key = key
         self.target_id = target_id
         self.target_id = target_id
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return CreateDictionaryEdgeInstruction(
-            self.source_id.simplify(),
-            self.key.simplify(),
-            self.target_id.simplify())
-
     def get_opcode(self):
     def get_opcode(self):
         """Gets the opcode for this state instruction."""
         """Gets the opcode for this state instruction."""
         return "CD"
         return "CD"
@@ -928,15 +1072,10 @@ class CreateDictionaryEdgeInstruction(StateInstruction):
 
 
 class DeleteNodeInstruction(StateInstruction):
 class DeleteNodeInstruction(StateInstruction):
     """An instruction that deletes a node."""
     """An instruction that deletes a node."""
-
     def __init__(self, node_id):
     def __init__(self, node_id):
         StateInstruction.__init__(self)
         StateInstruction.__init__(self)
         self.node_id = node_id
         self.node_id = node_id
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return DeleteNodeInstruction(self.node_id.simplify())
-
     def has_result(self):
     def has_result(self):
         """Tells if this instruction computes a result."""
         """Tells if this instruction computes a result."""
         return False
         return False
@@ -951,15 +1090,10 @@ class DeleteNodeInstruction(StateInstruction):
 
 
 class DeleteEdgeInstruction(StateInstruction):
 class DeleteEdgeInstruction(StateInstruction):
     """An instruction that deletes an edge."""
     """An instruction that deletes an edge."""
-
     def __init__(self, edge_id):
     def __init__(self, edge_id):
         StateInstruction.__init__(self)
         StateInstruction.__init__(self)
         self.edge_id = edge_id
         self.edge_id = edge_id
 
 
-    def simplify(self):
-        """Applies basic simplification to this instruction and its children."""
-        return DeleteEdgeInstruction(self.edge_id.simplify())
-
     def has_result(self):
     def has_result(self):
         """Tells if this instruction computes a result."""
         """Tells if this instruction computes a result."""
         return False
         return False