1.1 --- a/docs/exceptions.txt Sun Feb 20 01:35:15 2011 +0100
1.2 +++ b/docs/exceptions.txt Sun Feb 20 19:31:50 2011 +0100
1.3 @@ -47,5 +47,6 @@
1.4 PushHandler(block) defines an active handler at the location indicated by the
1.5 given block.
1.6
1.7 -PopHandler removes the active handler at or after the location indicated by
1.8 -the previously given block.
1.9 +PopHandler(n) removes the n topmost active handlers. A single handler is
1.10 +typically removed when leaving a try block, but potentially more handlers are
1.11 +removed when such a block is exited using a return statement.
2.1 --- a/micropython/ast.py Sun Feb 20 01:35:15 2011 +0100
2.2 +++ b/micropython/ast.py Sun Feb 20 19:31:50 2011 +0100
2.3 @@ -3,7 +3,7 @@
2.4 """
2.5 Translate the AST of a Python program into a more interpretable representation.
2.6
2.7 -Copyright (C) 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk>
2.8 +Copyright (C) 2007, 2008, 2009, 2010, 2011 Paul Boddie <paul@boddie.org.uk>
2.9
2.10 This program is free software; you can redistribute it and/or modify it under
2.11 the terms of the GNU General Public License as published by the Free Software
2.12 @@ -123,6 +123,7 @@
2.13
2.14 self.unit = self.module
2.15 self.reset()
2.16 + self.add_exception_unit()
2.17
2.18 block = self.new_block()
2.19 self.set_block(block)
2.20 @@ -142,9 +143,10 @@
2.21
2.22 if self.module.name == "__main__":
2.23 self.set_block(handler_block)
2.24 - self.new_op(PopHandler())
2.25 + self.new_op(PopHandler(1))
2.26 self.new_op(Return())
2.27
2.28 + self.drop_exception_unit()
2.29 self.unit.temp_usage = self.max_temp_position + 1
2.30 self.unit.blocks = self.blocks
2.31 return self.blocks
2.32 @@ -155,6 +157,7 @@
2.33
2.34 self.unit = unit
2.35 self.reset()
2.36 + self.add_exception_unit()
2.37
2.38 block = self.new_block()
2.39 self.set_block(block)
2.40 @@ -162,6 +165,7 @@
2.41 if unit.astnode is not None:
2.42 self.dispatch(unit.astnode)
2.43
2.44 + self.drop_exception_unit()
2.45 self.unit.temp_usage = self.max_temp_position + 2 # include space for instantiators to expand backwards
2.46 self.unit.blocks = self.blocks
2.47 return self.blocks
2.48 @@ -698,6 +702,7 @@
2.49
2.50 # Handle exceptions when calling "next"...
2.51
2.52 + self.add_exception_blocks(next_handler_block, end_handler_block)
2.53 self.new_op(PushHandler(next_handler_block))
2.54
2.55 # Use the iterator to get the next value.
2.56 @@ -715,13 +720,17 @@
2.57
2.58 # Skip the handler where the call was successful.
2.59
2.60 - self.new_op(PopHandler())
2.61 + self.new_op(PopHandler(1))
2.62 self.new_op(Jump(end_handler_block))
2.63
2.64 # Enter the exception handler.
2.65
2.66 self.set_block(next_handler_block)
2.67 - self.new_op(PopHandler())
2.68 + self.new_op(PopHandler(1))
2.69 +
2.70 + # Disable the handlers.
2.71 +
2.72 + self.drop_exception_blocks()
2.73
2.74 # Test for StopIteration.
2.75
2.76 @@ -846,6 +855,11 @@
2.77 if self.in_exception_handler:
2.78 self.new_op(ClearException())
2.79
2.80 + # NOTE: Support finally blocks here.
2.81 +
2.82 + if self.exception_blocks[-1]:
2.83 + self.new_op(PopHandler(len(self.exception_blocks[-1])))
2.84 +
2.85 self.new_op(Return())
2.86
2.87 def visitTryExcept(self, node):
2.88 @@ -860,7 +874,7 @@
2.89
2.90 self.new_op(PushHandler(handler_block))
2.91 self.dispatch(node.body)
2.92 - self.new_op(PopHandler())
2.93 + self.new_op(PopHandler(1))
2.94
2.95 if node.else_ is not None:
2.96 self.new_op(Jump(else_block))
2.97 @@ -870,7 +884,11 @@
2.98 # Start of handlers.
2.99
2.100 self.set_block(handler_block)
2.101 - self.new_op(PopHandler())
2.102 + self.new_op(PopHandler(1))
2.103 +
2.104 + # Disable the handlers.
2.105 +
2.106 + self.drop_exception_blocks()
2.107
2.108 for name, assignment, handler in node.handlers:
2.109 next_block = self.new_block()
2.110 @@ -918,7 +936,6 @@
2.111
2.112 self.set_block(exit_block)
2.113 self.new_op(ClearException())
2.114 - self.drop_exception_blocks()
2.115
2.116 def visitTryFinally(self, node):
2.117
3.1 --- a/micropython/rsvp.py Sun Feb 20 01:35:15 2011 +0100
3.2 +++ b/micropython/rsvp.py Sun Feb 20 19:31:50 2011 +0100
3.3 @@ -625,8 +625,8 @@
3.4 "Push an exception handler onto the handler stack."
3.5 cost = 3
3.6
3.7 -class PopHandler(Instruction):
3.8 - "Pop an exception handler from the handler stack."
3.9 +class PopHandler(Immediate):
3.10 + "Pop exception handlers from the handler stack."
3.11 cost = 3
3.12
3.13 class CheckException(Instruction):
4.1 --- a/micropython/trans.py Sun Feb 20 01:35:15 2011 +0100
4.2 +++ b/micropython/trans.py Sun Feb 20 19:31:50 2011 +0100
4.3 @@ -113,13 +113,19 @@
4.4 def drop_loop_blocks(self):
4.5 self.loop_blocks.pop()
4.6
4.7 + def add_exception_unit(self):
4.8 + self.exception_blocks.append([])
4.9 +
4.10 def get_exception_blocks(self):
4.11 - return self.exception_blocks[-1]
4.12 + return self.exception_blocks[-1][-1]
4.13
4.14 def add_exception_blocks(self, handler_block, exit_block):
4.15 - self.exception_blocks.append((handler_block, exit_block))
4.16 + self.exception_blocks[-1].append((handler_block, exit_block))
4.17
4.18 def drop_exception_blocks(self):
4.19 + self.exception_blocks[-1].pop()
4.20 +
4.21 + def drop_exception_unit(self):
4.22 self.exception_blocks.pop()
4.23
4.24 # Assignment expression values.
5.1 --- a/rsvp.py Sun Feb 20 01:35:15 2011 +0100
5.2 +++ b/rsvp.py Sun Feb 20 19:31:50 2011 +0100
5.3 @@ -110,8 +110,13 @@
5.4 self.frame_stack = []
5.5 self.local_sp_stack = [0]
5.6 self.invocation_sp_stack = []
5.7 +
5.8 + # Exception handler stacks are used to reset the state of the main
5.9 + # stacks.
5.10 +
5.11 self.handler_stack = [len(self.memory) - 1] # final handler is the end of the code
5.12 self.handler_local_sp_stack = []
5.13 + self.handler_invocation_sp_stack = []
5.14 self.handler_pc_stack = []
5.15
5.16 # Registers.
5.17 @@ -747,14 +752,26 @@
5.18 def PushHandler(self):
5.19 self.handler_stack.append(self.operand)
5.20 self.handler_local_sp_stack.append(len(self.local_sp_stack))
5.21 + self.handler_invocation_sp_stack.append(len(self.invocation_sp_stack))
5.22 self.handler_pc_stack.append(len(self.pc_stack))
5.23
5.24 def PopHandler(self):
5.25 + nframes = self.operand
5.26 + # Get the new local frame pointer and PC stack references.
5.27 + local_sp_top = self.handler_local_sp_stack[-nframes]
5.28 + invocation_sp_top = self.handler_invocation_sp_stack[-nframes]
5.29 + pc_top = self.handler_pc_stack[-nframes]
5.30 # Reduce the local frame pointer stack to refer to the handler's frame.
5.31 - del self.local_sp_stack[self.handler_local_sp_stack.pop():]
5.32 + del self.local_sp_stack[local_sp_top:]
5.33 + # Reduce the invocation frame pointer stack to refer to an outer frame.
5.34 + del self.invocation_sp_stack[invocation_sp_top:]
5.35 # Reduce the PC stack to discard all superfluous return addresses.
5.36 - self.pc_stack = self.pc_stack[:self.handler_pc_stack.pop()]
5.37 - self.handler_stack.pop()
5.38 + del self.pc_stack[pc_top:]
5.39 + # Remove elements from the handler stacks.
5.40 + del self.handler_pc_stack[-nframes:]
5.41 + del self.handler_local_sp_stack[-nframes:]
5.42 + del self.handler_invocation_sp_stack[-nframes:]
5.43 + del self.handler_stack[-nframes:]
5.44
5.45 def CheckException(self):
5.46 self.status = self.exception is not None and self._CheckInstance(self.exception, self.value.ref)