1.1 --- a/micropython/ast.py Thu May 17 23:37:05 2012 +0200
1.2 +++ b/micropython/ast.py Fri May 18 01:21:20 2012 +0200
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 Translate the AST of a Python program into a more interpretable representation.
1.6
1.7 -Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This program is free software; you can redistribute it and/or modify it under
1.11 the terms of the GNU General Public License as published by the Free Software
1.12 @@ -382,13 +382,84 @@
1.13 self._visitAttr(node, self.attribute_load_instructions)
1.14
1.15 def visitList(self, node):
1.16 + self._generateList(node, node.nodes)
1.17 +
1.18 + def visitListComp(self, node):
1.19 self._generateList(node)
1.20 + temp_list = self.optimiser.optimise_temp_storage()
1.21 +
1.22 + # Get the list's append method.
1.23 +
1.24 + self._generateAttr(node, "append", self.attribute_load_instructions)
1.25 + temp_method = self.optimiser.optimise_temp_storage()
1.26 +
1.27 + self.visitListCompFor(node.quals[0], node.quals[1:], node.expr, temp_list, temp_method)
1.28 +
1.29 + # Generate a reference to the list.
1.30 +
1.31 + self.new_op(temp_list)
1.32
1.33 - def visitListComp(self, node): raise TranslationNotImplementedError("ListComp")
1.34 + self.discard_temp(temp_method)
1.35 + self.discard_temp(temp_list)
1.36 +
1.37 + def visitListCompFor(self, node, following_quals, expr, temp_list, temp_method):
1.38 + temp_iterator, next_block, exit_block, else_block = self._startFor(node)
1.39 +
1.40 + # Explicit dispatch to tests, following loops, expression.
1.41 +
1.42 + if node.ifs:
1.43 + self.visitListCompIf(node.ifs[0], node.ifs[1:], following_quals, expr, temp_list, temp_method)
1.44 +
1.45 + # Explicit dispatch to following loops, expression.
1.46 +
1.47 + elif following_quals:
1.48 + self.visitListCompFor(following_quals[0], following_quals[1:], expr, temp_list, temp_method)
1.49 +
1.50 + # Explicit dispatch to the expression.
1.51 +
1.52 + else:
1.53 + self.dispatch(expr)
1.54
1.55 - def visitListCompFor(self, node): raise TranslationNotImplementedError("ListCompFor")
1.56 + # Append the value to the list.
1.57 +
1.58 + temp_value = self.optimiser.optimise_temp_storage()
1.59 + self._generateInvocation(temp_method, (temp_list, temp_value,))
1.60 +
1.61 + self._endFor(node, temp_iterator, next_block, exit_block, else_block)
1.62 +
1.63 + def visitListCompIf(self, node, following_tests, following_quals, expr, temp_list, temp_method):
1.64 + exit_block = self.new_block()
1.65 +
1.66 + # Evaluate the test and jump beyond the body if it is not satisfied.
1.67 +
1.68 + self.dispatch(node.test)
1.69 +
1.70 + temp = self.optimiser.optimise_temp_storage()
1.71 + self.new_op(temp)
1.72 + self._generateTestBoolean(node, temp)
1.73 + self.new_op(JumpIfFalse(exit_block, working="status"))
1.74
1.75 - def visitListCompIf(self, node): raise TranslationNotImplementedError("ListCompIf")
1.76 + # Explicit dispatch to tests, following loops, expression.
1.77 +
1.78 + if following_tests:
1.79 + self.visitListCompIf(following_tests[0], following_tests[1:], following_quals, expr, temp_list, temp_method)
1.80 +
1.81 + # Explicit dispatch to following loops, expression.
1.82 +
1.83 + elif following_quals:
1.84 + self.visitListCompFor(following_quals[0], following_quals[1:], expr, temp_list, temp_method)
1.85 +
1.86 + # Explicit dispatch to the expression.
1.87 +
1.88 + else:
1.89 + self.dispatch(expr)
1.90 +
1.91 + # Append the value to the list.
1.92 +
1.93 + temp_value = self.optimiser.optimise_temp_storage()
1.94 + self._generateInvocation(temp_method, (temp_list, temp_value,))
1.95 +
1.96 + self.set_block(exit_block)
1.97
1.98 def visitName(self, node):
1.99 self._visitName(node, self.name_load_instructions)
1.100 @@ -638,114 +709,9 @@
1.101 self.optimiser.optimise_unused_results()
1.102
1.103 def visitFor(self, node):
1.104 - next_handler_block = self.new_block()
1.105 - end_handler_block = self.new_block()
1.106 - exit_block = self.new_block()
1.107 - next_block = self.new_block()
1.108 - else_block = self.new_block()
1.109 -
1.110 - # Get the "list" to be iterated over, obtain its iterator.
1.111 -
1.112 - self._startCallFunc()
1.113 - self.dispatch(node.list)
1.114 - self._generateAttr(node, "__iter__", self.attribute_load_instructions)
1.115 - temp_target, target, temp_context = self._generateCallFunc([], node)
1.116 - self._doCallFunc(temp_target, target)
1.117 - self._endCallFunc(temp_target, temp_context)
1.118 -
1.119 - # Use a long-lasting temporary storage slot, since any result from the
1.120 - # __iter__ method will not remain around for long.
1.121 -
1.122 - temp_iterator = self.get_temp()
1.123 -
1.124 - # In the loop...
1.125 -
1.126 - self.set_block(next_block)
1.127 -
1.128 - # Handle exceptions when calling "next"...
1.129 -
1.130 - self.add_exception_blocks(next_handler_block, end_handler_block)
1.131 - self.new_op(PushHandler(next_handler_block))
1.132 -
1.133 - # Use the iterator to get the next value.
1.134 -
1.135 - self._startCallFunc()
1.136 - self.new_op(temp_iterator)
1.137 - self._generateAttr(node, "next", self.attribute_load_instructions)
1.138 - temp_target, target, temp_context = self._generateCallFunc([], node)
1.139 - self._doCallFunc(temp_target, target)
1.140 - self._endCallFunc(temp_target, temp_context)
1.141 -
1.142 - # Record the value to be assigned.
1.143 -
1.144 - self.record_value()
1.145 -
1.146 - # Skip the handler where the call was successful.
1.147 -
1.148 - self.new_op(PopHandler(1))
1.149 - self.new_op(Jump(end_handler_block))
1.150 -
1.151 - # Enter the exception handler.
1.152 -
1.153 - self.set_block(next_handler_block)
1.154 - self.new_op(PopHandler(1))
1.155 -
1.156 - # Disable the handlers.
1.157 -
1.158 - self.drop_exception_blocks()
1.159 -
1.160 - # Test for StopIteration.
1.161 -
1.162 - self.load_builtin("StopIteration", node)
1.163 - self.new_op(CheckException(target="status"))
1.164 - if node.else_ is not None:
1.165 - self.new_op(JumpIfTrue(else_block, working="status"))
1.166 - else:
1.167 - self.new_op(JumpIfTrue(exit_block, working="status"))
1.168 -
1.169 - # Re-raise the exception otherwise.
1.170 -
1.171 - self.new_op(RaiseException())
1.172 -
1.173 - # After the handler, clear the exception.
1.174 -
1.175 - self.set_block(end_handler_block)
1.176 -
1.177 - # Assign to the target.
1.178 -
1.179 - self.dispatch(node.assign)
1.180 - self.discard_value()
1.181 -
1.182 - # Process the body with the current next and exit points.
1.183 -
1.184 - self.add_loop_blocks(next_block, exit_block)
1.185 + temp_iterator, next_block, exit_block, else_block = self._startFor(node, node.else_)
1.186 self.dispatch(node.body)
1.187 - self.drop_loop_blocks()
1.188 -
1.189 - # Repeat the loop.
1.190 -
1.191 - self.new_op(Jump(next_block))
1.192 -
1.193 - # Produce the "else" section.
1.194 -
1.195 - if node.else_ is not None:
1.196 - self.set_block(else_block)
1.197 - self.new_op(ClearException(target="exception"))
1.198 - self.dispatch(node.else_)
1.199 -
1.200 - # After the loop...
1.201 -
1.202 - self.set_block(exit_block)
1.203 -
1.204 - else:
1.205 - # After the loop...
1.206 -
1.207 - self.set_block(exit_block)
1.208 - self.new_op(ClearException(target="exception"))
1.209 -
1.210 - # Compilation duties...
1.211 -
1.212 - self.discard_temp(temp_iterator)
1.213 + self._endFor(node, temp_iterator, next_block, exit_block, else_block, node.else_)
1.214
1.215 def visitIf(self, node):
1.216 first = 1