# HG changeset patch # User Paul Boddie # Date 1281477851 -7200 # Node ID 33faeaf83f57b56cbbb93814a7f610272bc746ec # Parent 2903ee29db242569ecf6de5f03b388b5fa85bef1 Moved accessor type detection using the attribute usage annotations to the ASTVisitor superclass provided by the common module, changing the report visitors so that they are now initialised with the current program, complete with object table, thus permitting the activity of determining types providing a particular set of attributes. diff -r 2903ee29db24 -r 33faeaf83f57 micropython/common.py --- a/micropython/common.py Tue Aug 10 23:18:42 2010 +0200 +++ b/micropython/common.py Wed Aug 11 00:04:11 2010 +0200 @@ -26,13 +26,16 @@ except NameError: from sets import Set as set -# Visitors. +# Visitors and activities related to node annotations. class ASTVisitor(compiler.visitor.ASTVisitor): "A base class for visitors." def dispatch(self, node, *args): + + "Dispatch using 'node', annotating any raised exceptions." + try: return compiler.visitor.ASTVisitor.dispatch(self, node, *args) except NodeProcessingError, exc: @@ -47,6 +50,25 @@ exc.unit_name = self.full_name() raise + def possible_accessor_types(self, node): + + """ + Given annotations made during the inspection process, return all possible + types for a 'node' involved in attribute access, or return None if no + annotations are available. + """ + + if hasattr(node, "_attrusers"): + target_names = set() + + for user in node._attrusers: + target_names.update(self.objtable.all_possible_objects(user._attrnames[node._username])) + + return target_names + + else: + return None + def used_by_unit(node): """ diff -r 2903ee29db24 -r 33faeaf83f57 micropython/report.py --- a/micropython/report.py Tue Aug 10 23:18:42 2010 +0200 +++ b/micropython/report.py Wed Aug 11 00:04:11 2010 +0200 @@ -73,12 +73,24 @@ z-index: 3; } + .types-popup { + display: none; + position: absolute; + bottom: 3ex; left: 0; + color: white; + border-bottom: 0.5ex solid #000; + border-right: 0.5ex solid #000; + z-index: 3; + } + + .accessor, .name { position: relative; background-color: #300; color: white; } + .accessor:hover, .name:hover { background-color: #500; padding-top: 0.5ex; @@ -86,11 +98,13 @@ z-index: 2; } + .accessor:hover .types-popup, .name:hover .popup { display: block; } .attrnames, + .typenames, .scope { padding: 0.5em; background-color: #700; @@ -157,8 +171,8 @@ self.stream.write(self._text(name)) self._name_end() - def _popup_start(self): - self._span_start("popup") + def _popup_start(self, classes=None): + self._span_start(classes or "popup") _popup_end = _span_end @@ -222,27 +236,47 @@ self._span(name) self._span_end() - def _attrnames(self, attrnames): - if not attrnames: + def _names_list(self, names, label, classes): + if not names: return + names = list(names) + names.sort() - self.stream.write("
attributes
") + self.stream.write("
%s
" % (classes, label)) first = 1 - for attrname in attrnames: + for name in names: if not first: self.stream.write("
") - self.stream.write(attrname) + self.stream.write(name) first = 0 self.stream.write("
\n") + def _attrnames(self, attrnames): + self._names_list(attrnames, "attributes", "attrnames") + + def _typenames(self, typenames): + self._names_list(typenames, "types", "typenames") + + def _accessor_start(self, target_names): + if target_names is not None: + self._span_start("accessor") + self._popup_start("types-popup") + self._typenames(target_names) + self._popup_end() + + def _accessor_end(self, target_names): + if target_names is not None: + self._span_end() + # Summary classes. class Summary(Writer): "Summarise classes and attributes in modules." - def __init__(self, module): + def __init__(self, module, program): self.module = module + self.program = program def to_stream(self, stream): @@ -313,10 +347,13 @@ "A module source code browser." - def __init__(self, module): + def __init__(self, module, program): ASTVisitor.__init__(self) self.visitor = self self.module = module + self.program = program + self.objtable = self.program.get_object_table() + self.paramtable = self.program.get_parameter_table() def to_stream(self, stream): @@ -780,8 +817,11 @@ self._visitBinary(node, "floordiv", "//") def visitGetattr(self, node): + target_names = self.possible_accessor_types(node) self._span_start("getattr") + self._accessor_start(target_names) self.dispatch(node.expr) + self._accessor_end(target_names) self._span_start("attr") self.stream.write(".") self._span(node.attrname, "attrname") @@ -913,28 +953,28 @@ # Convenience functions. -def summarise(module, filename): +def summarise(module, program, filename): stream = open(filename, "wb") try: - summary = Summary(module) + summary = Summary(module, program) summary.to_stream(stream) finally: stream.close() -def annotate(module, filename): +def annotate(module, program, filename): stream = open(filename, "wb") try: - source = AnnotatedSource(module) + source = AnnotatedSource(module, program) source.to_stream(stream) finally: stream.close() -def report(importer, directory): +def report(program, directory): if not exists(directory): os.mkdir(directory) - for module in importer.get_modules(): - annotate(module, join(directory, "%s%sxhtml" % (module.full_name(), extsep))) - summarise(module, join(directory, "%s-summary%sxhtml" % (module.full_name(), extsep))) + for module in program.get_importer().get_modules(): + annotate(module, program, join(directory, "%s%sxhtml" % (module.full_name(), extsep))) + summarise(module, program, join(directory, "%s-summary%sxhtml" % (module.full_name(), extsep))) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 2903ee29db24 -r 33faeaf83f57 micropython/trans.py --- a/micropython/trans.py Tue Aug 10 23:18:42 2010 +0200 +++ b/micropython/trans.py Wed Aug 11 00:04:11 2010 +0200 @@ -511,36 +511,32 @@ elif self.optimiser.should_optimise_accesses_by_attribute_usage(): - if hasattr(node, "_attrusers"): - target_names = set() + target_names = self.possible_accessor_types(node) - for user in node._attrusers: - target_names.update(self.objtable.all_possible_objects(user._attrnames[node._username])) + if target_names is not None and len(target_names) == 1: + target_name = list(target_names)[0] - if len(target_names) == 1: - target_name = list(target_names)[0] + # Access the object table to get the attribute. - # Access the object table to get the attribute. + try: + attr = self.objtable.access(target_name, attrname) - try: - attr = self.objtable.access(target_name, attrname) + # Disallow non-class/instance optimisations. - # Disallow non-class/instance optimisations. + except TableError, exc: + print "Possible optimisation for", target_name, "not permissable." + + # Produce a suitable instruction. - except TableError, exc: - print "Possible optimisation for", target_name, "not permissable." - - # Produce a suitable instruction. - + else: + if AddressContextCondInstruction is not None and attr.is_static_attribute(): + self.new_op(AddressContextCondInstruction(attr)) + elif AttrInstruction is not None and not attr.is_static_attribute(): + self.new_op(AttrInstruction(attr)) else: - if AddressContextCondInstruction is not None and attr.is_static_attribute(): - self.new_op(AddressContextCondInstruction(attr)) - elif AttrInstruction is not None and not attr.is_static_attribute(): - self.new_op(AttrInstruction(attr)) - else: - raise TranslateError("Storing of class or module attribute %r via an object is not permitted." % attrname) + raise TranslateError("Storing of class or module attribute %r via an object is not permitted." % attrname) - return + return # Otherwise, perform a normal operation. diff -r 2903ee29db24 -r 33faeaf83f57 test.py --- a/test.py Tue Aug 10 23:18:42 2010 +0200 +++ b/test.py Wed Aug 11 00:04:11 2010 +0200 @@ -67,7 +67,7 @@ print "No directory specified. Not generating report." else: print "Generating report in", directory - micropython.report.report(i, directory) + micropython.report.report(p, directory) # Build the program.