# HG changeset patch # User paulb@jeremy # Date 1154373633 -7200 # Node ID 52fb7135229b76b90ba5aee273e200b3f64ecf4d # Parent adf464d8a1883d9ed88334f6562209a0663bc2e3 Made usage of Conditional nodes more consistent, employing both the body and else_ attributes instead of relying on Return node usage in subprograms. Added docstrings for various complicated methods. Changed the handler attribute (on Try) to refer to a list of nodes. diff -r adf464d8a188 -r 52fb7135229b simplified.py --- a/simplified.py Mon Jul 31 01:01:34 2006 +0200 +++ b/simplified.py Mon Jul 31 21:20:33 2006 +0200 @@ -62,7 +62,6 @@ expr Any contributing expression. lvalue Any target expression. test Any test expression in a conditional instruction. - handler Any exception handler selector expression. Invocation and subprogram attributes: @@ -73,6 +72,7 @@ body Any conditional code depending on the success of a test. else_ Any conditional code depending on the failure of a test. + handler Any exception handler code. finally_ Any code which will be executed regardless. code Any unconditional code. choices Any choices which may be included in the final program. @@ -123,14 +123,12 @@ self._pprint(indent + 2, "( ", "structure '%s'" % self.structure.name) if hasattr(self, "test"): self.test.pprint(indent + 2, "? ") - for attr in "code", "body", "else_", "finally_", "choices": + for attr in "code", "body", "else_", "handler", "finally_", "choices": if hasattr(self, attr) and getattr(self, attr): self._pprint(indent, "", "{ (%s)" % attr) for node in getattr(self, attr): node.pprint(indent + 2) self._pprint(indent, "", "}") - if hasattr(self, "handler"): - self.handler.pprint(indent + 2, "! ") if hasattr(self, "expr"): self.expr.pprint(indent + 2, "- ") if hasattr(self, "nodes"): diff -r adf464d8a188 -r 52fb7135229b simplify.py --- a/simplify.py Mon Jul 31 01:01:34 2006 +0200 +++ b/simplify.py Mon Jul 31 21:20:33 2006 +0200 @@ -186,83 +186,73 @@ def visitIf(self, if_): """ - Convert If(tests=..., else_=...) to: + Make conditionals for each test from an 'if_' AST node, adding the body + and putting each subsequent test as part of the conditional's else + section. + + Convert... - Invoke -> Subprogram - Conditional (test) -> Invoke -> Subprogram (body) - Return - Conditional (test) -> Invoke -> Subprogram (body) - Return - ... + If (test/body) + (test/body) + ... + (else/body) + + ...to: + + Conditional (test) -> (body) + (else) -> Conditional (test) -> (body) + (else) -> ... """ - # Make a subprogram for the statement and record it outside the main tree. - - subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) - self.current_subprograms.append(subprogram) - # In the subprogram, make conditionals for each test plus statement, - # adding a return onto the end of each statement block. + results = nodes = [] - nodes = [] for compare, stmt in if_.tests: # Produce something like... # expr.__true__() ? body - test = Conditional(else_=[], test=Invoke( - expr=LoadAttr(expr=self.dispatch(compare), name="__true__"), + test = Conditional(test=Invoke(expr=LoadAttr(expr=self.dispatch(compare), name="__true__"), args=[], star=None, dstar=None)) - - body_subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) - self.current_subprograms.append(body_subprogram) - - body_subprogram.code = self.dispatch(stmt) + [Return()] - - self.current_subprograms.pop() - self.subprograms.append(body_subprogram) - - # Always return from conditional sections. - - test.body = [Invoke(stmt, expr=LoadRef(ref=body_subprogram), same_frame=1, star=None, dstar=None, args=[]), Return()] + test.body = self.dispatch(stmt) nodes.append(test) + nodes = test.else_ = [] # Add the compound statement from any else clause to the end. if if_.else_ is not None: - else_subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) - self.current_subprograms.append(else_subprogram) - - else_subprogram.code = self.dispatch(if_.else_) + [Return()] - - self.current_subprograms.pop() - self.subprograms.append(else_subprogram) - - # Always return from conditional subprograms. + nodes += self.dispatch(if_.else_) - nodes.append(Invoke(stmt, expr=LoadRef(ref=else_subprogram), same_frame=1, star=None, dstar=None, args=[])) - nodes.append(Return()) - - subprogram.code = nodes - - self.current_subprograms.pop() - self.subprograms.append(subprogram) - - # Make an invocation of the subprogram. - - result = Invoke(compare, same_frame=1, star=None, dstar=None, args=[]) - result.expr = LoadRef(ref=subprogram) + result = results[0] return result - def _visitTryExcept(self, tryexcept): + def visitTryExcept(self, tryexcept): + + """ + Make conditionals for each handler associated with a 'tryexcept' node. + + Convert... - # Make a subprogram for the statement and record it outside the main tree. + TryExcept (body) + (else) + (spec/assign/stmt) + ... + + ...to: - subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) - self.current_subprograms.append(subprogram) + Try (body) + (else) + (handler) -> Conditional (test) -> (stmt) + (else) -> Conditional (test) -> (stmt) + (else) -> ... + """ + + result = Try(tryexcept, body=[], else_=[], finally_=[]) - # In the subprogram, make conditionals for each test plus statement, - # adding a return onto the end of each statement block. + if tryexcept.body is not None: + result.body = self.dispatch(tryexcept.body) + if tryexcept.else_ is not None: + result.else_ = self.dispatch(tryexcept.else_) - nodes = [] + results = nodes = [] for spec, assign, stmt in tryexcept.handlers: # If no specification exists, produce an unconditional block. @@ -275,7 +265,9 @@ else: new_spec = self.dispatch(spec) - test = Conditional(body=[], else_=[], test=Invoke(expr=LoadName(name="isinstance"), args=[LoadExc(), new_spec], star=None, dstar=None)) + test = Conditional(test=Invoke(expr=LoadName(name="isinstance"), args=[LoadExc(), new_spec], star=None, dstar=None)) + test.body = [] + if assign is not None: test.body.append(Assign(code=[StoreTemp(expr=LoadExc()), self.dispatch(assign), ReleaseTemp()])) @@ -283,28 +275,13 @@ test.body += self.dispatch(stmt) + [Return()] nodes.append(test) + nodes = test.else_ = [] # Add a raise operation to deal with unhandled exceptions. nodes.append(Raise(expr=LoadExc())) - subprogram.code = nodes - self.current_subprograms.pop() - self.subprograms.append(subprogram) - - # Make an invocation of the subprogram. - - result = Invoke(same_frame=1, star=None, dstar=None, args=[]) - result.expr = LoadRef(ref=subprogram) - return result - - def visitTryExcept(self, tryexcept): - result = Try(tryexcept, body=[], else_=[], finally_=[]) - if tryexcept.body is not None: - result.body = self.dispatch(tryexcept.body) - if tryexcept.else_ is not None: - result.else_ = self.dispatch(tryexcept.else_) - result.handler = self._visitTryExcept(tryexcept) + result.handler = results return result comparison_methods = { @@ -314,7 +291,20 @@ def visitCompare(self, compare): - # Make a subprogram for the expression and record it outside the main tree. + """ + Make a subprogram for the 'compare' node and record its contents inside + the subprogram. Convert... + + Compare (expr) + (name/node) + ... + + ...to: + + Subprogram -> Conditional (test) -> (body) + (else) -> Conditional (test) -> (body) + (else) -> ... + """ subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) self.current_subprograms.append(subprogram) @@ -323,12 +313,16 @@ # first operand of each operand pair and, if appropriate, return with # the value from that method. - nodes = [] last = compare.ops[-1] previous = self.dispatch(compare.expr) + results = nodes = [] + for op in compare.ops: op_name, node = op expr = self.dispatch(node) + + # Identify the operation and produce the appropriate method call. + method_name = self.comparison_methods[op_name] if method_name: invocation = Invoke(expr=LoadAttr(expr=previous, name=method_name), args=[expr], star=None, dstar=None) @@ -340,15 +334,26 @@ raise NotImplementedError, op_name nodes.append(StoreTemp(expr=invocation)) - # Always return from conditional sections/subprograms. + # Return from the subprogram where the test is not satisfied. if op is not last: - nodes.append(Conditional(test=Not(expr=LoadTemp()), body=[Return(expr=LoadTemp())])) - nodes.append(ReleaseTemp()) + test = Conditional(test=Not(expr=LoadTemp()), body=[Return(expr=LoadTemp())]) + nodes.append(test) + + # Put subsequent operations in the else section of this conditional. + + nodes = test.else_ = [ReleaseTemp()] + + # For the last operation, return the result. + else: nodes.append(Return(expr=LoadTemp())) + previous = expr - subprogram.code = nodes + + # Finish the subprogram definition. + + subprogram.code = results self.current_subprograms.pop() self.subprograms.append(subprogram) @@ -361,7 +366,20 @@ def visitAnd(self, and_): - # Make a subprogram for the expression and record it outside the main tree. + """ + Make a subprogram for the 'and_' node and record its contents inside the + subprogram. Convert... + + And (test) + (test) + ... + + ...to: + + Subprogram -> Conditional (test) -> Return ... + (else) -> Conditional (test) -> Return ... + (else) -> ... + """ subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) self.current_subprograms.append(subprogram) @@ -370,21 +388,32 @@ # for each operand's truth status, and if appropriate return from the # subprogram with the value of the operand. - nodes = [] last = and_.nodes[-1] + results = nodes = [] + for node in and_.nodes: expr = self.dispatch(node) - # Always return from conditional sections/subprograms. + # Return from the subprogram where the test is not satisfied. if node is not last: nodes.append(StoreTemp(expr=expr)) invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), args=[], star=None, dstar=None) - nodes.append(Conditional(test=Not(expr=invocation), body=[Return(expr=LoadTemp())])) - nodes.append(ReleaseTemp()) + test = Conditional(test=Not(expr=invocation), body=[Return(expr=LoadTemp())]) + nodes.append(test) + + # Put subsequent operations in the else section of this conditional. + + nodes = test.else_ = [ReleaseTemp()] + + # For the last operation, return the result. + else: nodes.append(Return(expr=expr)) - subprogram.code = nodes + + # Finish the subprogram definition. + + subprogram.code = results self.current_subprograms.pop() self.subprograms.append(subprogram) @@ -397,7 +426,20 @@ def visitOr(self, or_): - # Make a subprogram for the expression and record it outside the main tree. + """ + Make a subprogram for the 'or_' node and record its contents inside the + subprogram. Convert... + + Or (test) + (test) + ... + + ...to: + + Subprogram -> Conditional (test) -> Return ... + (else) -> Conditional (test) -> Return ... + (else) -> ... + """ subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None) self.current_subprograms.append(subprogram) @@ -406,21 +448,32 @@ # for each operand's truth status, and if appropriate return from the # subprogram with the value of the operand. - nodes = [] last = or_.nodes[-1] + results = nodes = [] + for node in or_.nodes: expr = self.dispatch(node) - # Always return from conditional sections/subprograms. + # Return from the subprogram where the test is satisfied. if node is not last: nodes.append(StoreTemp(expr=expr)) invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), args=[], star=None, dstar=None) - nodes.append(Conditional(test=invocation, body=[Return(expr=LoadTemp())])) - nodes.append(ReleaseTemp()) + test = Conditional(test=invocation, body=[Return(expr=LoadTemp())]) + nodes.append(test) + + # Put subsequent operations in the else section of this conditional. + + nodes = test.else_ = [ReleaseTemp()] + + # For the last operation, return the result. + else: nodes.append(Return(expr=expr)) - subprogram.code = nodes + + # Finish the subprogram definition. + + subprogram.code = results self.current_subprograms.pop() self.subprograms.append(subprogram) @@ -738,7 +791,19 @@ def visitWhile(self, while_): - # Make a subprogram for the block and record it outside the main tree. + """ + Make a subprogram for the 'while' node and record its contents inside the + subprogram. Convert... + + While (test) -> (body) + (else) + + ...to: + + Subprogram -> Conditional (test) -> (body) -> Invoke subprogram + (else) -> Conditional (test) -> Return ... + (else) -> ... + """ subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) self.current_subprograms.append(subprogram) @@ -755,12 +820,18 @@ continuation = Invoke(same_frame=1, star=None, dstar=None, args=[]) continuation.expr = LoadRef(ref=subprogram) - # Always return from conditional sections/subprograms. + # Return within the main section of the loop. test.body = self.dispatch(while_.body) + [continuation, Return()] + + # Provide the else section, if present, along with an explicit return. + if while_.else_ is not None: - test.else_ = self.dispatch(while_.else_) - subprogram.code = [test, Return()] + test.else_ = self.dispatch(while_.else_) + [Return()] + + # Finish the subprogram definition. + + subprogram.code = test self.current_subprograms.pop() self.subprograms.append(subprogram) @@ -773,7 +844,23 @@ def visitFor(self, for_): - # Make a subprogram for the block and record it outside the main tree. + """ + Make a subprogram for the 'for_' node and record its contents inside the + subprogram. Convert... + + For (assign) + (body) + (else) + + ...to: + + Assign (assign #1) + Invoke -> Subprogram -> Try (body) -> (assign #2) + (body) + Invoke subprogram + (handler) -> ... + (else) -> ... + """ subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None) self.current_subprograms.append(subprogram) @@ -788,9 +875,13 @@ # Wrap the assignment in a try...except statement. try_except = Try(body=[], else_=[], finally_=[]) - try_except.handler = Conditional(test=Invoke(expr=LoadName(name="isinstance"), - args=[LoadExc(), LoadName(name="StopIteration")], star=None, dstar=None), - body=else_stmt, else_=[Raise(expr=LoadExc())]) + try_except.handler = Conditional( + test=Invoke( + expr=LoadName(name="isinstance"), + args=[LoadExc(), LoadName(name="StopIteration")], star=None, dstar=None + ), + body=else_stmt, + else_=[Raise(expr=LoadExc())]) assign = Assign() assign.code = [ @@ -807,6 +898,8 @@ try_except.body = [assign] + self.dispatch(for_.body) + [continuation] subprogram.code = [try_except, Return()] + # Finish the subprogram definition. + self.subprograms.append(subprogram) self.current_subprograms.pop()