1.1 --- a/micropython/trans.py Thu May 17 23:37:05 2012 +0200
1.2 +++ b/micropython/trans.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 @@ -1139,20 +1139,22 @@
1.13
1.14 # Store using 0-based index values.
1.15
1.16 - self._populateSequence(temp, node)
1.17 + self._populateSequence(temp, node.nodes)
1.18
1.19 self.new_op(temp)
1.20 self.discard_temp(temp)
1.21
1.22 - def _generateList(self, node):
1.23 + def _generateList(self, node, nodes=None):
1.24
1.25 - "Make a list using the given program 'node'."
1.26 + "Make a list using the given program 'node' and optional 'nodes'."
1.27 +
1.28 + nodes = nodes or []
1.29
1.30 # Make a fragment containing the list elements.
1.31
1.32 - self.new_op(MakeFragment(len(node.nodes) + 1))
1.33 + self.new_op(MakeFragment(len(nodes) + 1))
1.34 temp = self.get_temp()
1.35 - self._populateSequence(temp, node)
1.36 + self._populateSequence(temp, nodes)
1.37 self.new_op(temp)
1.38 self.record_value()
1.39
1.40 @@ -1171,13 +1173,13 @@
1.41 self.discard_temp(temp)
1.42 self.discard_temp(list_temp)
1.43
1.44 - def _populateSequence(self, temp, node, offset=0):
1.45 + def _populateSequence(self, temp, nodes, offset=0):
1.46
1.47 """
1.48 - Populate a sequence using the given 'temp' reference and program 'node'.
1.49 + Populate a sequence using the given 'temp' reference and 'nodes'.
1.50 """
1.51
1.52 - for i, n in enumerate(node.nodes):
1.53 + for i, n in enumerate(nodes):
1.54 self.dispatch(n)
1.55 self.record_value()
1.56 self._storeInSequence(temp, i, offset)
1.57 @@ -1236,6 +1238,144 @@
1.58
1.59 self.set_block(end_block, [false_block, true_block])
1.60
1.61 + # Common AST operations.
1.62 +
1.63 + def _startFor(self, node, else_=None):
1.64 +
1.65 + """
1.66 + Generate the start of a loop using the given 'node' and 'else_' clause,
1.67 + if defined. The iterator and next, exit and else blocks are returned.
1.68 + """
1.69 +
1.70 + next_handler_block = self.new_block()
1.71 + end_handler_block = self.new_block()
1.72 + exit_block = self.new_block()
1.73 + next_block = self.new_block()
1.74 + else_block = self.new_block()
1.75 +
1.76 + temp_iterator = self._visitForList(node)
1.77 +
1.78 + # In the loop...
1.79 +
1.80 + self.set_block(next_block)
1.81 +
1.82 + # Handle exceptions when calling "next"...
1.83 +
1.84 + self.add_exception_blocks(next_handler_block, end_handler_block)
1.85 + self.new_op(PushHandler(next_handler_block))
1.86 +
1.87 + # Invoke the next method.
1.88 +
1.89 + self._visitForNext(node, temp_iterator)
1.90 +
1.91 + # Record the value to be assigned.
1.92 +
1.93 + self.record_value()
1.94 +
1.95 + # Skip the handler where the call was successful.
1.96 +
1.97 + self.new_op(PopHandler(1))
1.98 + self.new_op(Jump(end_handler_block))
1.99 +
1.100 + # Enter the exception handler.
1.101 +
1.102 + self.set_block(next_handler_block)
1.103 + self.new_op(PopHandler(1))
1.104 +
1.105 + # Disable the handlers.
1.106 +
1.107 + self.drop_exception_blocks()
1.108 +
1.109 + # Test for StopIteration.
1.110 +
1.111 + self.load_builtin("StopIteration", node)
1.112 + self.new_op(CheckException(target="status"))
1.113 + if else_ is not None:
1.114 + self.new_op(JumpIfTrue(else_block, working="status"))
1.115 + else:
1.116 + self.new_op(JumpIfTrue(exit_block, working="status"))
1.117 +
1.118 + # Re-raise the exception otherwise.
1.119 +
1.120 + self.new_op(RaiseException())
1.121 +
1.122 + # After the handler, clear the exception.
1.123 +
1.124 + self.set_block(end_handler_block)
1.125 +
1.126 + # Assign to the target.
1.127 +
1.128 + self.dispatch(node.assign)
1.129 + self.discard_value()
1.130 +
1.131 + # Process the body with the current next and exit points.
1.132 +
1.133 + self.add_loop_blocks(next_block, exit_block)
1.134 +
1.135 + return temp_iterator, next_block, exit_block, else_block
1.136 +
1.137 + def _endFor(self, node, temp_iterator, next_block, exit_block, else_block=None, else_=None):
1.138 +
1.139 + """
1.140 + Generate the end of a loop for the given 'node' using the given
1.141 + 'temp_iterator' and 'next_block', 'exit_block' and 'else_block'
1.142 + definitions, together with an 'else_' clause, if defined.
1.143 + """
1.144 +
1.145 + self.drop_loop_blocks()
1.146 +
1.147 + # Repeat the loop.
1.148 +
1.149 + self.new_op(Jump(next_block))
1.150 +
1.151 + # Produce the "else" section.
1.152 +
1.153 + if else_ is not None:
1.154 + self.set_block(else_block)
1.155 + self.new_op(ClearException(target="exception"))
1.156 + self.dispatch(else_)
1.157 +
1.158 + # After the loop...
1.159 +
1.160 + self.set_block(exit_block)
1.161 +
1.162 + else:
1.163 + # After the loop...
1.164 +
1.165 + self.set_block(exit_block)
1.166 + self.new_op(ClearException(target="exception"))
1.167 +
1.168 + # Compilation duties...
1.169 +
1.170 + self.discard_temp(temp_iterator)
1.171 +
1.172 + def _visitForList(self, node):
1.173 +
1.174 + "Get the list to be iterated over, returning its iterator."
1.175 +
1.176 + self._startCallFunc()
1.177 + self.dispatch(node.list)
1.178 + self._generateAttr(node, "__iter__", self.attribute_load_instructions)
1.179 + temp_target, target, temp_context = self._generateCallFunc([], node)
1.180 + self._doCallFunc(temp_target, target)
1.181 + self._endCallFunc(temp_target, temp_context)
1.182 +
1.183 + # Use a long-lasting temporary storage slot, since any result from the
1.184 + # __iter__ method will not remain around for long.
1.185 +
1.186 + return self.get_temp()
1.187 +
1.188 + def _visitForNext(self, node, temp_iterator):
1.189 +
1.190 + "Use the iterator to get the next value."
1.191 +
1.192 + self._startCallFunc()
1.193 + self.new_op(temp_iterator)
1.194 + self._generateAttr(node, "next", self.attribute_load_instructions)
1.195 + temp_target, target, temp_context = self._generateCallFunc([], node)
1.196 + self._doCallFunc(temp_target, target)
1.197 + self._endCallFunc(temp_target, temp_context)
1.198 +
1.199 def _visitPrint(self, node, function_name):
1.200 self._startCallFunc()
1.201 self.load_builtin(function_name, node)