simplify

Changeset

35:52fb7135229b
2006-07-31 paulb raw files shortlog changelog graph 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.
simplified.py (file) simplify.py (file)
     1.1 --- a/simplified.py	Mon Jul 31 01:01:34 2006 +0200
     1.2 +++ b/simplified.py	Mon Jul 31 21:20:33 2006 +0200
     1.3 @@ -62,7 +62,6 @@
     1.4      expr        Any contributing expression.
     1.5      lvalue      Any target expression.
     1.6      test        Any test expression in a conditional instruction.
     1.7 -    handler     Any exception handler selector expression.
     1.8  
     1.9      Invocation and subprogram attributes:
    1.10  
    1.11 @@ -73,6 +72,7 @@
    1.12  
    1.13      body        Any conditional code depending on the success of a test.
    1.14      else_       Any conditional code depending on the failure of a test.
    1.15 +    handler     Any exception handler code.
    1.16      finally_    Any code which will be executed regardless.
    1.17      code        Any unconditional code.
    1.18      choices     Any choices which may be included in the final program.
    1.19 @@ -123,14 +123,12 @@
    1.20              self._pprint(indent + 2, "( ", "structure '%s'" % self.structure.name)
    1.21          if hasattr(self, "test"):
    1.22              self.test.pprint(indent + 2, "? ")
    1.23 -        for attr in "code", "body", "else_", "finally_", "choices":
    1.24 +        for attr in "code", "body", "else_", "handler", "finally_", "choices":
    1.25              if hasattr(self, attr) and getattr(self, attr):
    1.26                  self._pprint(indent, "", "{ (%s)" % attr)
    1.27                  for node in getattr(self, attr):
    1.28                      node.pprint(indent + 2)
    1.29                  self._pprint(indent, "", "}")
    1.30 -        if hasattr(self, "handler"):
    1.31 -            self.handler.pprint(indent + 2, "! ")
    1.32          if hasattr(self, "expr"):
    1.33              self.expr.pprint(indent + 2, "- ")
    1.34          if hasattr(self, "nodes"):
     2.1 --- a/simplify.py	Mon Jul 31 01:01:34 2006 +0200
     2.2 +++ b/simplify.py	Mon Jul 31 21:20:33 2006 +0200
     2.3 @@ -186,83 +186,73 @@
     2.4      def visitIf(self, if_):
     2.5  
     2.6          """
     2.7 -        Convert If(tests=..., else_=...) to:
     2.8 +        Make conditionals for each test from an 'if_' AST node, adding the body
     2.9 +        and putting each subsequent test as part of the conditional's else
    2.10 +        section.
    2.11 +
    2.12 +        Convert...
    2.13  
    2.14 -        Invoke -> Subprogram
    2.15 -                  Conditional (test) -> Invoke -> Subprogram (body)
    2.16 -                                        Return
    2.17 -                  Conditional (test) -> Invoke -> Subprogram (body)
    2.18 -                                        Return
    2.19 -                  ...
    2.20 +        If (test/body)
    2.21 +           (test/body)
    2.22 +           ...
    2.23 +           (else/body)
    2.24 +
    2.25 +        ...to:
    2.26 +
    2.27 +        Conditional (test) -> (body)
    2.28 +                    (else) -> Conditional (test) -> (body)
    2.29 +                                          (else) -> ...
    2.30          """
    2.31  
    2.32 -        # Make a subprogram for the statement and record it outside the main tree.
    2.33 -
    2.34 -        subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None)
    2.35 -        self.current_subprograms.append(subprogram)
    2.36  
    2.37 -        # In the subprogram, make conditionals for each test plus statement,
    2.38 -        # adding a return onto the end of each statement block.
    2.39 +        results = nodes = []
    2.40  
    2.41 -        nodes = []
    2.42          for compare, stmt in if_.tests:
    2.43              # Produce something like...
    2.44              # expr.__true__() ? body
    2.45 -            test = Conditional(else_=[], test=Invoke(
    2.46 -                expr=LoadAttr(expr=self.dispatch(compare), name="__true__"),
    2.47 +            test = Conditional(test=Invoke(expr=LoadAttr(expr=self.dispatch(compare), name="__true__"),
    2.48                  args=[], star=None, dstar=None))
    2.49 -
    2.50 -            body_subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None)
    2.51 -            self.current_subprograms.append(body_subprogram)
    2.52 -
    2.53 -            body_subprogram.code = self.dispatch(stmt) + [Return()]
    2.54 -
    2.55 -            self.current_subprograms.pop()
    2.56 -            self.subprograms.append(body_subprogram)
    2.57 -
    2.58 -            # Always return from conditional sections.
    2.59 -
    2.60 -            test.body = [Invoke(stmt, expr=LoadRef(ref=body_subprogram), same_frame=1, star=None, dstar=None, args=[]), Return()]
    2.61 +            test.body = self.dispatch(stmt)
    2.62              nodes.append(test)
    2.63 +            nodes = test.else_ = []
    2.64  
    2.65          # Add the compound statement from any else clause to the end.
    2.66  
    2.67          if if_.else_ is not None:
    2.68 -            else_subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None)
    2.69 -            self.current_subprograms.append(else_subprogram)
    2.70 -
    2.71 -            else_subprogram.code = self.dispatch(if_.else_) + [Return()]
    2.72 -
    2.73 -            self.current_subprograms.pop()
    2.74 -            self.subprograms.append(else_subprogram)
    2.75 -
    2.76 -            # Always return from conditional subprograms.
    2.77 +            nodes += self.dispatch(if_.else_)
    2.78  
    2.79 -            nodes.append(Invoke(stmt, expr=LoadRef(ref=else_subprogram), same_frame=1, star=None, dstar=None, args=[]))
    2.80 -            nodes.append(Return())
    2.81 -
    2.82 -        subprogram.code = nodes
    2.83 -
    2.84 -        self.current_subprograms.pop()
    2.85 -        self.subprograms.append(subprogram)
    2.86 -
    2.87 -        # Make an invocation of the subprogram.
    2.88 -
    2.89 -        result = Invoke(compare, same_frame=1, star=None, dstar=None, args=[])
    2.90 -        result.expr = LoadRef(ref=subprogram)
    2.91 +        result = results[0]
    2.92          return result
    2.93  
    2.94 -    def _visitTryExcept(self, tryexcept):
    2.95 +    def visitTryExcept(self, tryexcept):
    2.96 +
    2.97 +        """
    2.98 +        Make conditionals for each handler associated with a 'tryexcept' node.
    2.99 +
   2.100 +        Convert...
   2.101  
   2.102 -        # Make a subprogram for the statement and record it outside the main tree.
   2.103 +        TryExcept (body)
   2.104 +                  (else)
   2.105 +                  (spec/assign/stmt)
   2.106 +                  ...
   2.107 +
   2.108 +        ...to:
   2.109  
   2.110 -        subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None)
   2.111 -        self.current_subprograms.append(subprogram)
   2.112 +        Try (body)
   2.113 +            (else)
   2.114 +            (handler) -> Conditional (test) -> (stmt)
   2.115 +                                     (else) -> Conditional (test) -> (stmt)
   2.116 +                                                           (else) -> ...
   2.117 +        """
   2.118 +                  
   2.119 +        result = Try(tryexcept, body=[], else_=[], finally_=[])
   2.120  
   2.121 -        # In the subprogram, make conditionals for each test plus statement,
   2.122 -        # adding a return onto the end of each statement block.
   2.123 +        if tryexcept.body is not None:
   2.124 +            result.body = self.dispatch(tryexcept.body)
   2.125 +        if tryexcept.else_ is not None:
   2.126 +            result.else_ = self.dispatch(tryexcept.else_)
   2.127  
   2.128 -        nodes = []
   2.129 +        results = nodes = []
   2.130          for spec, assign, stmt in tryexcept.handlers:
   2.131  
   2.132              # If no specification exists, produce an unconditional block.
   2.133 @@ -275,7 +265,9 @@
   2.134  
   2.135              else:
   2.136                  new_spec = self.dispatch(spec)
   2.137 -                test = Conditional(body=[], else_=[], test=Invoke(expr=LoadName(name="isinstance"), args=[LoadExc(), new_spec], star=None, dstar=None))
   2.138 +                test = Conditional(test=Invoke(expr=LoadName(name="isinstance"), args=[LoadExc(), new_spec], star=None, dstar=None))
   2.139 +                test.body = []
   2.140 +
   2.141                  if assign is not None:
   2.142                      test.body.append(Assign(code=[StoreTemp(expr=LoadExc()), self.dispatch(assign), ReleaseTemp()]))
   2.143  
   2.144 @@ -283,28 +275,13 @@
   2.145  
   2.146                  test.body += self.dispatch(stmt) + [Return()]
   2.147                  nodes.append(test)
   2.148 +                nodes = test.else_ = []
   2.149  
   2.150          # Add a raise operation to deal with unhandled exceptions.
   2.151  
   2.152          nodes.append(Raise(expr=LoadExc()))
   2.153 -        subprogram.code = nodes
   2.154  
   2.155 -        self.current_subprograms.pop()
   2.156 -        self.subprograms.append(subprogram)
   2.157 -
   2.158 -        # Make an invocation of the subprogram.
   2.159 -
   2.160 -        result = Invoke(same_frame=1, star=None, dstar=None, args=[])
   2.161 -        result.expr = LoadRef(ref=subprogram)
   2.162 -        return result
   2.163 -
   2.164 -    def visitTryExcept(self, tryexcept):
   2.165 -        result = Try(tryexcept, body=[], else_=[], finally_=[])
   2.166 -        if tryexcept.body is not None:
   2.167 -            result.body = self.dispatch(tryexcept.body)
   2.168 -        if tryexcept.else_ is not None:
   2.169 -            result.else_ = self.dispatch(tryexcept.else_)
   2.170 -        result.handler = self._visitTryExcept(tryexcept)
   2.171 +        result.handler = results
   2.172          return result
   2.173  
   2.174      comparison_methods = {
   2.175 @@ -314,7 +291,20 @@
   2.176  
   2.177      def visitCompare(self, compare):
   2.178  
   2.179 -        # Make a subprogram for the expression and record it outside the main tree.
   2.180 +        """
   2.181 +        Make a subprogram for the 'compare' node and record its contents inside
   2.182 +        the subprogram. Convert...
   2.183 +
   2.184 +        Compare (expr)
   2.185 +                (name/node)
   2.186 +                ...
   2.187 +
   2.188 +        ...to:
   2.189 +
   2.190 +        Subprogram -> Conditional (test) -> (body)
   2.191 +                                  (else) -> Conditional (test) -> (body)
   2.192 +                                                        (else) -> ...
   2.193 +        """
   2.194  
   2.195          subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None)
   2.196          self.current_subprograms.append(subprogram)
   2.197 @@ -323,12 +313,16 @@
   2.198          # first operand of each operand pair and, if appropriate, return with
   2.199          # the value from that method.
   2.200  
   2.201 -        nodes = []
   2.202          last = compare.ops[-1]
   2.203          previous = self.dispatch(compare.expr)
   2.204 +        results = nodes = []
   2.205 +
   2.206          for op in compare.ops:
   2.207              op_name, node = op
   2.208              expr = self.dispatch(node)
   2.209 +
   2.210 +            # Identify the operation and produce the appropriate method call.
   2.211 +
   2.212              method_name = self.comparison_methods[op_name]
   2.213              if method_name:
   2.214                  invocation = Invoke(expr=LoadAttr(expr=previous, name=method_name), args=[expr], star=None, dstar=None)
   2.215 @@ -340,15 +334,26 @@
   2.216                  raise NotImplementedError, op_name
   2.217              nodes.append(StoreTemp(expr=invocation))
   2.218  
   2.219 -            # Always return from conditional sections/subprograms.
   2.220 +            # Return from the subprogram where the test is not satisfied.
   2.221  
   2.222              if op is not last:
   2.223 -                nodes.append(Conditional(test=Not(expr=LoadTemp()), body=[Return(expr=LoadTemp())]))
   2.224 -                nodes.append(ReleaseTemp())
   2.225 +                test = Conditional(test=Not(expr=LoadTemp()), body=[Return(expr=LoadTemp())])
   2.226 +                nodes.append(test)
   2.227 +
   2.228 +                # Put subsequent operations in the else section of this conditional.
   2.229 +
   2.230 +                nodes = test.else_ = [ReleaseTemp()]
   2.231 +
   2.232 +            # For the last operation, return the result.
   2.233 +
   2.234              else:
   2.235                  nodes.append(Return(expr=LoadTemp()))
   2.236 +
   2.237              previous = expr
   2.238 -        subprogram.code = nodes
   2.239 +
   2.240 +        # Finish the subprogram definition.
   2.241 +
   2.242 +        subprogram.code = results
   2.243  
   2.244          self.current_subprograms.pop()
   2.245          self.subprograms.append(subprogram)
   2.246 @@ -361,7 +366,20 @@
   2.247  
   2.248      def visitAnd(self, and_):
   2.249  
   2.250 -        # Make a subprogram for the expression and record it outside the main tree.
   2.251 +        """
   2.252 +        Make a subprogram for the 'and_' node and record its contents inside the
   2.253 +        subprogram. Convert...
   2.254 +
   2.255 +        And (test)
   2.256 +            (test)
   2.257 +            ...
   2.258 +
   2.259 +        ...to:
   2.260 +
   2.261 +        Subprogram -> Conditional (test) -> Return ...
   2.262 +                                  (else) -> Conditional (test) -> Return ...
   2.263 +                                                        (else) -> ...
   2.264 +        """
   2.265  
   2.266          subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None)
   2.267          self.current_subprograms.append(subprogram)
   2.268 @@ -370,21 +388,32 @@
   2.269          # for each operand's truth status, and if appropriate return from the
   2.270          # subprogram with the value of the operand.
   2.271  
   2.272 -        nodes = []
   2.273          last = and_.nodes[-1]
   2.274 +        results = nodes = []
   2.275 +
   2.276          for node in and_.nodes:
   2.277              expr = self.dispatch(node)
   2.278  
   2.279 -            # Always return from conditional sections/subprograms.
   2.280 +            # Return from the subprogram where the test is not satisfied.
   2.281  
   2.282              if node is not last:
   2.283                  nodes.append(StoreTemp(expr=expr))
   2.284                  invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), args=[], star=None, dstar=None)
   2.285 -                nodes.append(Conditional(test=Not(expr=invocation), body=[Return(expr=LoadTemp())]))
   2.286 -                nodes.append(ReleaseTemp())
   2.287 +                test = Conditional(test=Not(expr=invocation), body=[Return(expr=LoadTemp())])
   2.288 +                nodes.append(test)
   2.289 +
   2.290 +                # Put subsequent operations in the else section of this conditional.
   2.291 +
   2.292 +                nodes = test.else_ = [ReleaseTemp()]
   2.293 +
   2.294 +            # For the last operation, return the result.
   2.295 +
   2.296              else:
   2.297                  nodes.append(Return(expr=expr))
   2.298 -        subprogram.code = nodes
   2.299 +
   2.300 +        # Finish the subprogram definition.
   2.301 +
   2.302 +        subprogram.code = results
   2.303  
   2.304          self.current_subprograms.pop()
   2.305          self.subprograms.append(subprogram)
   2.306 @@ -397,7 +426,20 @@
   2.307  
   2.308      def visitOr(self, or_):
   2.309  
   2.310 -        # Make a subprogram for the expression and record it outside the main tree.
   2.311 +        """
   2.312 +        Make a subprogram for the 'or_' node and record its contents inside the
   2.313 +        subprogram. Convert...
   2.314 +
   2.315 +        Or (test)
   2.316 +           (test)
   2.317 +           ...
   2.318 +
   2.319 +        ...to:
   2.320 +
   2.321 +        Subprogram -> Conditional (test) -> Return ...
   2.322 +                                  (else) -> Conditional (test) -> Return ...
   2.323 +                                                        (else) -> ...
   2.324 +        """
   2.325  
   2.326          subprogram = Subprogram(name=None, acquire_locals=1, returns_value=1, params=[], star=None, dstar=None)
   2.327          self.current_subprograms.append(subprogram)
   2.328 @@ -406,21 +448,32 @@
   2.329          # for each operand's truth status, and if appropriate return from the
   2.330          # subprogram with the value of the operand.
   2.331  
   2.332 -        nodes = []
   2.333          last = or_.nodes[-1]
   2.334 +        results = nodes = []
   2.335 +
   2.336          for node in or_.nodes:
   2.337              expr = self.dispatch(node)
   2.338  
   2.339 -            # Always return from conditional sections/subprograms.
   2.340 +            # Return from the subprogram where the test is satisfied.
   2.341  
   2.342              if node is not last:
   2.343                  nodes.append(StoreTemp(expr=expr))
   2.344                  invocation = Invoke(expr=LoadAttr(expr=LoadTemp(), name="__true__"), args=[], star=None, dstar=None)
   2.345 -                nodes.append(Conditional(test=invocation, body=[Return(expr=LoadTemp())]))
   2.346 -                nodes.append(ReleaseTemp())
   2.347 +                test = Conditional(test=invocation, body=[Return(expr=LoadTemp())])
   2.348 +                nodes.append(test)
   2.349 +
   2.350 +                # Put subsequent operations in the else section of this conditional.
   2.351 +
   2.352 +                nodes = test.else_ = [ReleaseTemp()]
   2.353 +
   2.354 +            # For the last operation, return the result.
   2.355 +
   2.356              else:
   2.357                  nodes.append(Return(expr=expr))
   2.358 -        subprogram.code = nodes
   2.359 +
   2.360 +        # Finish the subprogram definition.
   2.361 +
   2.362 +        subprogram.code = results
   2.363  
   2.364          self.current_subprograms.pop()
   2.365          self.subprograms.append(subprogram)
   2.366 @@ -738,7 +791,19 @@
   2.367  
   2.368      def visitWhile(self, while_):
   2.369  
   2.370 -        # Make a subprogram for the block and record it outside the main tree.
   2.371 +        """
   2.372 +        Make a subprogram for the 'while' node and record its contents inside the
   2.373 +        subprogram. Convert...
   2.374 +
   2.375 +        While (test) -> (body)
   2.376 +              (else)
   2.377 +
   2.378 +        ...to:
   2.379 +
   2.380 +        Subprogram -> Conditional (test) -> (body) -> Invoke subprogram
   2.381 +                                  (else) -> Conditional (test) -> Return ...
   2.382 +                                                        (else) -> ...
   2.383 +        """
   2.384  
   2.385          subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None)
   2.386          self.current_subprograms.append(subprogram)
   2.387 @@ -755,12 +820,18 @@
   2.388          continuation = Invoke(same_frame=1, star=None, dstar=None, args=[])
   2.389          continuation.expr = LoadRef(ref=subprogram)
   2.390  
   2.391 -        # Always return from conditional sections/subprograms.
   2.392 +        # Return within the main section of the loop.
   2.393  
   2.394          test.body = self.dispatch(while_.body) + [continuation, Return()]
   2.395 +
   2.396 +        # Provide the else section, if present, along with an explicit return.
   2.397 +
   2.398          if while_.else_ is not None:
   2.399 -            test.else_ = self.dispatch(while_.else_)
   2.400 -        subprogram.code = [test, Return()]
   2.401 +            test.else_ = self.dispatch(while_.else_) + [Return()]
   2.402 +
   2.403 +        # Finish the subprogram definition.
   2.404 +
   2.405 +        subprogram.code = test
   2.406  
   2.407          self.current_subprograms.pop()
   2.408          self.subprograms.append(subprogram)
   2.409 @@ -773,7 +844,23 @@
   2.410  
   2.411      def visitFor(self, for_):
   2.412  
   2.413 -        # Make a subprogram for the block and record it outside the main tree.
   2.414 +        """
   2.415 +        Make a subprogram for the 'for_' node and record its contents inside the
   2.416 +        subprogram. Convert...
   2.417 +
   2.418 +        For (assign)
   2.419 +            (body)
   2.420 +            (else)
   2.421 +
   2.422 +        ...to:
   2.423 +
   2.424 +        Assign (assign #1)
   2.425 +        Invoke -> Subprogram -> Try (body) -> (assign #2)
   2.426 +                                              (body)
   2.427 +                                              Invoke subprogram
   2.428 +                                    (handler) -> ...
   2.429 +                                    (else) -> ...
   2.430 +        """
   2.431  
   2.432          subprogram = Subprogram(name=None, acquire_locals=1, returns_value=0, params=[], star=None, dstar=None)
   2.433          self.current_subprograms.append(subprogram)
   2.434 @@ -788,9 +875,13 @@
   2.435          # Wrap the assignment in a try...except statement.
   2.436  
   2.437          try_except = Try(body=[], else_=[], finally_=[])
   2.438 -        try_except.handler = Conditional(test=Invoke(expr=LoadName(name="isinstance"),
   2.439 -            args=[LoadExc(), LoadName(name="StopIteration")], star=None, dstar=None),
   2.440 -            body=else_stmt, else_=[Raise(expr=LoadExc())])
   2.441 +        try_except.handler = Conditional(
   2.442 +            test=Invoke(
   2.443 +                expr=LoadName(name="isinstance"),
   2.444 +                args=[LoadExc(), LoadName(name="StopIteration")], star=None, dstar=None
   2.445 +                ),
   2.446 +            body=else_stmt,
   2.447 +            else_=[Raise(expr=LoadExc())])
   2.448  
   2.449          assign = Assign()
   2.450          assign.code = [
   2.451 @@ -807,6 +898,8 @@
   2.452          try_except.body = [assign] + self.dispatch(for_.body) + [continuation]
   2.453          subprogram.code = [try_except, Return()]
   2.454  
   2.455 +        # Finish the subprogram definition.
   2.456 +
   2.457          self.subprograms.append(subprogram)
   2.458          self.current_subprograms.pop()
   2.459