# HG changeset patch # User Paul Boddie # Date 1205956658 -3600 # Node ID a7cbfb7bb92b4931bfdd6c560ad75aba978c4a74 # Parent 47656b7fd26725cf9de821c0efc6398e20827b52 Added tentative exception handling and binary operator support. Added specific methods for managing loop and exception labels. Added temporary value instructions. diff -r 47656b7fd267 -r a7cbfb7bb92b docs/exceptions.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/exceptions.txt Wed Mar 19 20:57:38 2008 +0100 @@ -0,0 +1,13 @@ +Exception Handling +------------------ + +Where exceptions may be raised, the following rules are applied: + + 1. If exception labels exist, any raised exception causes a jump to the + handler label. + + 2. If no exception labels exist, any raised exception causes the current + function to be terminated with an exception condition. + + 3. Where an invocation returns with an exception condition set, rules #1 and + #2 are applied. diff -r 47656b7fd267 -r a7cbfb7bb92b micropython/ast.py --- a/micropython/ast.py Mon Mar 10 00:37:37 2008 +0100 +++ b/micropython/ast.py Wed Mar 19 20:57:38 2008 +0100 @@ -67,6 +67,7 @@ self.labels = {} self.label_number = 0 self.loop_labels = [] + self.exception_labels = [] # The code itself. @@ -124,6 +125,24 @@ label.location = len(self.code) + self.unit.code_location + def get_loop_labels(self): + return self.loop_labels[-1] + + def add_loop_labels(self, next_label, exit_label): + self.loop_labels.append((next_label, exit_label)) + + def drop_loop_labels(self): + self.loop_labels.pop() + + def get_exception_labels(self): + return self.exception_labels[-1] + + def add_exception_labels(self, handler_label, exit_label): + self.exception_labels.append((handler_label, exit_label)) + + def drop_exception_labels(self): + self.exception_labels.pop() + def new_op(self, op): "Add 'op' to the generated code." @@ -236,7 +255,7 @@ self.new_op(LoadContext()) self.new_op(CheckContext()) self.new_op(JumpIfTrue(continue_label)) - self.new_op(LoadAttr(self._get_builtin("TypeError"))) + self.dispatch(compiler.ast.Name("TypeError")) self.new_op(RaiseException()) self.set_label(continue_label) @@ -299,6 +318,10 @@ else: self.dispatch(arg) + def _endCallFunc(self): + + "Make the invocation and tidy up afterwards." + self.new_op(LoadCallable()) # uses the start of the frame to get the callable self.new_op(Jump()) @@ -383,7 +406,7 @@ def dispatch(self, node, *args): return ASTVisitor.dispatch(self, node, *args) - def visitAdd(self, node): + def _visitBinary(self, node, left_method, right_method): """ _t1 = node.left @@ -394,6 +417,44 @@ _t2.__radd__(_t1) """ + right_label = self.new_label() + end_label = self.new_label() + + # NOTE: Decide on temporary storage access. + + self.dispatch(node.left) + self.new_op(StoreTemp(1)) + self.dispatch(node.right) + self.new_op(StoreTemp(2)) + + # Left method. + + self._startCallFunc() + self.new_op(LoadTemp(1)) + self._generateAttr(left_method, (LoadAttr, LoadAttrIndex)) + self.new_op(LoadTemp(1)) # Explicit context as first argument. + self.new_op(LoadTemp(2)) + self._endCallFunc() + + self.dispatch(compiler.ast.Name("AttributeError")) + self.new_op(CheckException()) + self.new_op(JumpIfFalse(end_label)) + + # Right method. + + self.set_label(right_label) + self._startCallFunc() + self.new_op(LoadTemp(2)) + self._generateAttr(right_method, (LoadAttr, LoadAttrIndex)) + self.new_op(LoadTemp(2)) # Explicit context as first argument. + self.new_op(LoadTemp(1)) + self._endCallFunc() + + self.set_label(end_label) + + def visitAdd(self, node): + self._visitBinary(node, "__add__", "__radd__") + def visitAnd(self, node): pass def visitAssert(self, node): pass @@ -424,7 +485,7 @@ def visitBitxor(self, node): pass def visitBreak(self, node): - next_label, exit_label = self.loop_labels[-1] + next_label, exit_label = self.get_loop_labels() self.new_op(Jump(exit_label)) def visitCallFunc(self, node): @@ -439,6 +500,7 @@ self._startCallFunc() self.dispatch(node.node) self._generateCallFunc(node.args, node) + self._endCallFunc() def visitClass(self, node): unit = self.unit @@ -465,7 +527,7 @@ self.new_op(LoadConst(const)) def visitContinue(self, node): - next_label, exit_label = self.loop_labels[-1] + next_label, exit_label = self.get_loop_labels() self.new_op(Jump(next_label)) def visitDecorators(self, node): pass @@ -475,7 +537,8 @@ def visitDiscard(self, node): self.dispatch(node.expr) - def visitDiv(self, node): pass + def visitDiv(self, node): + self._visitBinary(node, "__div__", "__rdiv__") def visitEllipsis(self, node): pass @@ -483,7 +546,8 @@ def visitExpression(self, node): pass - def visitFloorDiv(self, node): pass + def visitFloorDiv(self, node): + self._visitBinary(node, "__floordiv__", "__rfloordiv__") def visitFor(self, node): exit_label = self.new_label() @@ -496,6 +560,8 @@ self.dispatch(node.list) self._generateAttr("__iter__", (LoadAttr, LoadAttrIndex)) self._generateCallFunc([], node) + self._endCallFunc() + # Iterator on stack. # In the loop... @@ -508,10 +574,12 @@ self.new_op(Duplicate()) self._generateAttr("next", (LoadAttr, LoadAttrIndex)) self._generateCallFunc([], node) + self._endCallFunc() # Test for StopIteration. - self.new_op(CheckException("StopIteration")) # NOTE: To be done properly. + self.dispatch(compiler.ast.Name("StopIteration")) + self.new_op(CheckException()) if node.else_ is not None: self.new_op(JumpIfTrue(else_label)) else: @@ -523,9 +591,9 @@ # Process the body with the current next and exit points. - self.loop_labels.append((next_label, exit_label)) + self.add_loop_labels(next_label, exit_label) self.dispatch(node.body) - self.loop_labels.pop() + self.drop_loop_labels() # Repeat the loop. @@ -608,12 +676,14 @@ def visitListCompIf(self, node): pass - def visitMod(self, node): pass + def visitMod(self, node): + self._visitBinary(node, "__mod__", "__rmod__") def visitModule(self, node): self.dispatch(node.node) - def visitMul(self, node): pass + def visitMul(self, node): + self._visitBinary(node, "__mul__", "__rmul__") def visitName(self, node): self._visitName(node, (LoadName, LoadAttr)) @@ -645,11 +715,58 @@ for n in node.nodes: self.dispatch(n) - def visitSub(self, node): pass + def visitSub(self, node): + self._visitBinary(node, "__sub__", "__rsub__") def visitSubscript(self, node): pass - def visitTryExcept(self, node): pass + def visitTryExcept(self, node): + + """ + Enter try block. + Dispatch to code. + + """ + + exit_label = self.new_label() + handler_label = self.new_label() + + self.add_exception_labels(handler_label, exit_label) + + self.dispatch(node.body) + self.new_op(Jump(exit_label)) + + self.set_label(handler_label) + for name, assignment, handler in node.handlers: + next_label = self.new_label() + + if name is not None: + self.dispatch(name) + self.new_op(CheckException()) + self.new_op(JumpIfFalse(next_label)) + + if assignment is not None: + self.dispatch(assignment) + + self.dispatch(handler) + self.new_op(Jump(exit_label)) + + self.set_label(next_label) + + # Unhandled exceptions. + + self.new_op(RaiseException()) + + # After exception + + self.set_label(exit_label) + + # Optional else clause. + + if node.else_ is not None: + self.dispatch(node.else_) + + self.drop_exception_labels() def visitTryFinally(self, node): pass @@ -671,7 +788,7 @@ else: self.new_op(JumpIfFalse(exit_label)) - self.loop_labels.append((next_label, exit_label)) + self.add_loop_labels(next_label, exit_label) self.dispatch(node.body) self.new_op(Jump(next_label)) @@ -681,7 +798,7 @@ self.dispatch(node.else_) self.set_label(exit_label) - self.loop_labels.pop() + self.drop_loop_labels() def visitWith(self, node): pass diff -r 47656b7fd267 -r a7cbfb7bb92b micropython/rsvp.py --- a/micropython/rsvp.py Mon Mar 10 00:37:37 2008 +0100 +++ b/micropython/rsvp.py Wed Mar 19 20:57:38 2008 +0100 @@ -86,6 +86,8 @@ class LoadName(SR): "Load the object from the given local attribute/variable." class StoreName(SR): "Store the object in the given local attribute/variable." +class LoadTemp(SR): "Load the object from the given temporary location." +class StoreTemp(SR): "Store the object in the given temporary location." # Access to address-relative data.