# HG changeset patch # User Paul Boddie # Date 1243890415 -7200 # Node ID 2197662b8603c6567e9a3898719395d88e5403ae # Parent 77038806cb4024f974353e8c3ecacf7c268843c2 Fixed the inspect module to visit the module and class code sections before the function code bodies, adding also some handling of forward/advance referencing (where a name may accumulate objects after being marked as referenced). Added a flag to Translation instances in order to generate ClearException instructions before Return instructions in exception handlers. Fixed class inspection to correctly collect all instance attributes (including those mentioned in base classes). Added elementary support for generic exceptions. diff -r 77038806cb40 -r 2197662b8603 lib/builtins.py --- a/lib/builtins.py Mon Jun 01 21:10:47 2009 +0200 +++ b/lib/builtins.py Mon Jun 01 23:06:55 2009 +0200 @@ -214,7 +214,8 @@ # Exceptions and warnings. class BaseException(object): - def __init__(self, *args): pass + def __init__(self, *args): + self.args = args class Exception(BaseException): pass class Warning(object): pass diff -r 77038806cb40 -r 2197662b8603 micropython/ast.py --- a/micropython/ast.py Mon Jun 01 21:10:47 2009 +0200 +++ b/micropython/ast.py Mon Jun 01 23:06:55 2009 +0200 @@ -86,6 +86,7 @@ self.label_number = 0 self.loop_blocks = [] self.exception_blocks = [] + self.in_exception_handler = 0 self.reset() @@ -906,6 +907,10 @@ self.dispatch(compiler.ast.Name("None")) self.new_op(StoreResult()) + + if self.in_exception_handler: + self.new_op(ClearException()) + self.new_op(Return()) def visitTryExcept(self, node): @@ -956,7 +961,10 @@ # Produce the handler code, then jump to the exit. + self.in_exception_handler = 1 self.dispatch(handler) + self.in_exception_handler = 0 + self.new_op(Jump(exit_block)) self.set_block(next_block) @@ -969,7 +977,6 @@ if node.else_ is not None: self.set_block(else_block) - self.dispatch(node.else_) # Clear the exception. diff -r 77038806cb40 -r 2197662b8603 micropython/data.py --- a/micropython/data.py Mon Jun 01 21:10:47 2009 +0200 +++ b/micropython/data.py Mon Jun 01 23:06:55 2009 +0200 @@ -274,11 +274,14 @@ # Number of assignments per name. self.assignments = None + self.referenced = 0 def set_referenced(self): "Indicate that the contents are referenced via a namespace." + self.referenced = 1 + for value in self.get_values(): if value is not None: value.set_referenced() @@ -317,6 +320,13 @@ else: self.assignments += AtLeast(1) + # Communicate referencing information. + + if self.referenced: + for context, value in context_values: + if value is not None: + value.set_referenced() + self.context_values.update(context_values) def is_class_attribute(self): @@ -787,6 +797,8 @@ if instattr.has_key(name): instattr[name].add(attr.position) + else: + instattr[name] = set([attr.position]) # Build the dictionary of attributes using the existing positions known # for each name. diff -r 77038806cb40 -r 2197662b8603 micropython/inspect.py --- a/micropython/inspect.py Mon Jun 01 21:10:47 2009 +0200 +++ b/micropython/inspect.py Mon Jun 01 23:06:55 2009 +0200 @@ -114,6 +114,7 @@ self.in_loop = 0 # Note loop "membership", affecting assignments. self.namespaces = [] self.module = None + self.functions = [] def parse(self, filename): @@ -128,11 +129,16 @@ self.astnode = self.module = module processed = self.dispatch(module) + + for node, namespaces in self.functions: + self._visitFunctionBody(node, namespaces) + if self.has_key("__all__"): all = self["__all__"] if isinstance(all, compiler.ast.List): for n in all.nodes: self.store(n.value, self.importer.add_module(self.name + "." + n.value)) + return processed def vacuum(self): @@ -346,22 +352,7 @@ self.expr = self.dispatch(n) function.store_default(self.expr) - # Enter the function. - - self.namespaces.append(function) - - # Current namespace is the function. - # Previous namespace is the class. - - if len(self.namespaces) > 1 and isinstance(self.namespaces[-2], Class): - if name == "__init__": - self.in_init = 1 - self.in_method = 1 - - self.dispatch(node.code) - self.in_init = 0 - self.in_method = 0 - self.namespaces.pop() + self.functions.append((node, self.namespaces + [function])) if name is not None: self.store(name, function) @@ -383,6 +374,24 @@ return function + def _visitFunctionBody(self, node, namespaces): + + "Enter the function." + + # Current namespace is the function. + # Previous namespace is the class. + + if len(namespaces) > 1 and isinstance(namespaces[-2], Class): + if namespaces[-1].name == "__init__": + self.in_init = 1 + self.in_method = 1 + + self.namespaces = namespaces + self.dispatch(node.code) + + self.in_init = 0 + self.in_method = 0 + # Specific handler methods. visitAdd = _visitBinary diff -r 77038806cb40 -r 2197662b8603 rsvp.py --- a/rsvp.py Mon Jun 01 21:10:47 2009 +0200 +++ b/rsvp.py Mon Jun 01 23:06:55 2009 +0200 @@ -925,6 +925,7 @@ "__builtins__.list" : builtins_list_new, "__builtins__.list.__getitem__" : builtins_list_getitem, "__builtins__.object.__init__" : builtins_object_init, + "__builtins__.BaseException.__init__" : builtins_object_init, # NOTE: To be made distinct. } # Convenience functions. diff -r 77038806cb40 -r 2197662b8603 tests/exception.py --- a/tests/exception.py Mon Jun 01 21:10:47 2009 +0200 +++ b/tests/exception.py Mon Jun 01 23:06:55 2009 +0200 @@ -1,6 +1,6 @@ #!/usr/bin/env python -class E: +class E(Exception): pass def f(x, y): @@ -13,6 +13,6 @@ def g(x): raise E, x -f(1, 2) +result_2 = f(1, 2) # vim: tabstop=4 expandtab shiftwidth=4