# HG changeset patch # User paulb@localhost.localdomain # Date 1168209879 -3600 # Node ID 79b255e8af48e8efbb191d026caea3551e595008 # Parent b5fad042b4dc2ecb4ec997a9a223be142eab73bf Added some documentation. diff -r b5fad042b4dc -r 79b255e8af48 docs/architecture.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/architecture.txt Sun Jan 07 23:44:39 2007 +0100 @@ -0,0 +1,77 @@ +Architecture Overview +===================== + +The simplify modules take Python source code, obtain an abstract syntax tree +(AST) using the standard library compiler module, produce a simplified node +tree whose nodes correspond to primitive operations, and then perform a number +of processes such as name resolution and type annotation on the simplified +tree. + +The Simplified Nodes +==================== + +Unlike the selection of AST nodes produced by the compiler module which +reflect syntactic constructs in Python source code, the simplified nodes more +closely reflect the underlying operations performed when such constructs are +executed in a running program. Thus, in some respects the simplified nodes +have a certain similarity with CPython interpreter bytecodes. However, unlike +the instruction set encoded in the selection of bytecodes understood by the +CPython interpreter, simplified nodes are more low-level and eliminate the +hidden complexity of certain bytecodes (eg. BINARY_ADD). Consequently, even a +small Python program, producing a small AST, can produce a much larger +simplified node tree. + +The simplify module is responsible for the production of a simplified node +tree, using the full range of nodes defined in the simplified module. In some +cases, the nodes created in this process may be discarded in favour of others +after further analysis of the program. + +Name Resolution +=============== + +The scope of names or identifiers in Python programs can be determined by +relatively simple methods, and the process of name resolution is concerned +with identifying the scope in all name accesses within a program, changing the +simplified node involved where necessary. For example, before the name +resolution process the mention of a name in a program, as represented by a +LoadName simplified node, may be found to refer to a module global instead of +a local name; consequently, the LoadName node would be changed to a LoadAttr +node which references the module. + +The fixnames module is responsible for the transformation of the simplified +node tree and the replacement of nodes in order to indicate particular +namespace operations. + +Type Annotation +=============== + +The principal motivation in developing this system is to discover the nature +of data at each point in a program, and one important aspect of doing so is to +examine the data types employed at certain points (principally the definition +and instantiation of such types), and to propagate such information throughout +the program, in a way simulating the execution of the program but without +actually doing so with concrete values or objects associated with such types. +In order to simulate the semantics of Python, the following concepts have been +employed: + + * Attribute: a bundle containing a data type and its context. + * Namespace: a mapping of names to attributes. + * Accessor: a combination of an attribute and its origin - the owner of the + namespace providing access to the attribute. + +Attributes +---------- + +The main purpose of the notion of an attribute is to support references to +methods. Contrary to initial expectations (perhaps fuelled by experience with +other programming languages [1] or by simple example programs), Python does +not insist that methods be invoked immediately upon dereferencing objects +providing such methods; instead the reference to a method may be stored in a +variable and used in an invocation on a subsequent occasion. In order to +permit this behaviour, the context of a method (typically the object from +which the method was obtained) must be recalled and employed in the +invocation. Thus, it becomes necessary to treat type information as a bundle +containing the type of an attribute and any context information that may +subsequently be useful. + +[1] http://java.sun.com/docs/white/delegates.html diff -r b5fad042b4dc -r 79b255e8af48 viewer.py --- a/viewer.py Sun Jan 07 20:09:39 2007 +0100 +++ b/viewer.py Sun Jan 07 23:44:39 2007 +0100 @@ -3,7 +3,7 @@ """ View annotated sources. -Copyright (C) 2006 Paul Boddie +Copyright (C) 2006, 2007 Paul Boddie This software is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -872,13 +872,25 @@ self._types_list(node.namespace.raises, style_class="raises") def _scopes(self, node): + + "Output the scope information for the given simplified 'node'." + + # Straightforward name loading/storing involves the local scope. + if isinstance(node, StoreName) or isinstance(node, LoadName): self.stream.write("
\n") self.stream.write("
") self.stream.write("(local)") self.stream.write("
\n") self.stream.write("
\n") + + # Other loading/storing involves attributes accessed on modules, classes + # and objects. + else: + + # Loading... + if hasattr(node, "accesses") and node.accesses: self.stream.write("
\n") for ref, accesses in node.accesses.items(): @@ -891,6 +903,9 @@ self.stream.write(" (via " + self._text(access_fn) + ")") self.stream.write("
\n") self.stream.write("\n") + + # Storing... + if hasattr(node, "writes") and node.writes: self.stream.write("
\n") for ref in node.writes.keys(): @@ -899,8 +914,14 @@ self.stream.write(self._text(fn)) self.stream.write("
\n") self.stream.write("\n") + + # Non-loading... + if hasattr(node, "non_accesses") and node.non_accesses: self._types_list(node.non_accesses, style_class="non-accesses") + + # Non-storing... + if hasattr(node, "non_writes") and node.non_writes: self._types_list(node.non_writes, style_class="non-writes")