1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/simplify/fixinstances.py Mon Jun 18 01:47:51 2007 +0200
1.3 @@ -0,0 +1,197 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Fix instances, removing those which are not part of the distinct set for a given
1.8 +class.
1.9 +
1.10 +Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
1.11 +
1.12 +This software is free software; you can redistribute it and/or
1.13 +modify it under the terms of the GNU General Public License as
1.14 +published by the Free Software Foundation; either version 2 of
1.15 +the License, or (at your option) any later version.
1.16 +
1.17 +This software is distributed in the hope that it will be useful,
1.18 +but WITHOUT ANY WARRANTY; without even the implied warranty of
1.19 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.20 +GNU General Public License for more details.
1.21 +
1.22 +You should have received a copy of the GNU General Public
1.23 +License along with this library; see the file LICENCE.txt
1.24 +If not, write to the Free Software Foundation, Inc.,
1.25 +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
1.26 +
1.27 +--------
1.28 +
1.29 +To use this module, the easiest approach is to use the fix function:
1.30 +
1.31 +fix(module)
1.32 +
1.33 +The more complicated approach involves instantiating a Fixer object:
1.34 +
1.35 +fixer = Fixer()
1.36 +
1.37 +Then, applying the fixer to an existing module:
1.38 +
1.39 +fixer.process(module)
1.40 +"""
1.41 +
1.42 +from simplify.simplified import *
1.43 +
1.44 +# Fixing of instance information.
1.45 +
1.46 +class Fixer(Visitor):
1.47 +
1.48 + """
1.49 + The name fixer which traverses the program nodes in a module, typically
1.50 + depth-first, and eliminates references to superfluous instances, replacing
1.51 + them with those from each class's distinct list, if necessary.
1.52 +
1.53 + See the simplify.fixnames.Fixer class for a description of the
1.54 + """
1.55 +
1.56 + def __init__(self):
1.57 +
1.58 + "Initialise the name fixer."
1.59 +
1.60 + Visitor.__init__(self)
1.61 +
1.62 + # Satisfy visitor issues.
1.63 +
1.64 + self.visitor = self
1.65 +
1.66 + def process(self, module):
1.67 +
1.68 + "Process the given 'module'."
1.69 +
1.70 + # The fixer maintains a list of transformed subprograms (added for each
1.71 + # of the processing "roots" and also for each invoked internal
1.72 + # subprogram), along with a list of current subprograms (used to avoid
1.73 + # recursion issues) and a list of current namespaces (used to recall
1.74 + # namespaces upon invoking internal subprograms).
1.75 +
1.76 + self.subprograms = []
1.77 + self.current_subprograms = []
1.78 +
1.79 + self.module = module
1.80 + self.process_node(self.module)
1.81 +
1.82 + # Then, process all functions and methods.
1.83 +
1.84 + for subprogram in self.module.simplifier.subprograms:
1.85 +
1.86 + # Internal subprograms are skipped here and processed specially via
1.87 + # Invoke nodes.
1.88 +
1.89 + if not getattr(subprogram, "internal", 0):
1.90 + for specialised in subprogram.active():
1.91 + self.subprograms.append(self.process_node(specialised))
1.92 +
1.93 + def process_node(self, node, namespace=None):
1.94 +
1.95 + """
1.96 + Process a subprogram or module 'node', discovering from attributes on
1.97 + 'node' any initial locals. Return a modified subprogram or module.
1.98 + """
1.99 +
1.100 + # Do not process subprograms already being processed.
1.101 +
1.102 + if node in self.current_subprograms:
1.103 + return None
1.104 +
1.105 + # Record the current subprogram.
1.106 +
1.107 + self.current_subprograms.append(node)
1.108 +
1.109 + # Dispatch to the code itself.
1.110 +
1.111 + result = self.dispatch(node)
1.112 +
1.113 + # Restore the previous subprogram and namespace.
1.114 +
1.115 + self.current_subprograms.pop()
1.116 +
1.117 + return node
1.118 +
1.119 + # Visitor methods.
1.120 +
1.121 + def default(self, node):
1.122 +
1.123 + """
1.124 + Process the given 'node', given that it does not have a specific
1.125 + handler.
1.126 + """
1.127 +
1.128 + for name in ("non_accesses", "non_writes", "raises", "returns", "types"):
1.129 + if hasattr(node, name):
1.130 + attrs = getattr(node, name)
1.131 + self._replace(attrs)
1.132 + for name in ("accesses", "writes"):
1.133 + if hasattr(node, name):
1.134 + d = getattr(node, name)
1.135 + for expr, attrs in d.items():
1.136 + self._replace(attrs, name)
1.137 +
1.138 + for attr in ("pos_args",):
1.139 + if hasattr(node, attr):
1.140 + self.dispatches(getattr(node, attr))
1.141 + for attr in ("kw_args",):
1.142 + if hasattr(node, attr):
1.143 + self.dispatch_dict(getattr(node, attr))
1.144 + for attr in ("expr", "lvalue", "test", "star", "dstar"):
1.145 + if hasattr(node, attr):
1.146 + self.dispatch(getattr(node, attr))
1.147 + for attr in ("body", "else_", "handler", "finally_", "code", "choices", "nodes"):
1.148 + if hasattr(node, attr):
1.149 + self.dispatches(getattr(node, attr))
1.150 +
1.151 + return node
1.152 +
1.153 + def _replace(self, attrs, name=None):
1.154 + to_replace = {}
1.155 + for attr in attrs:
1.156 + if name == "accesses":
1.157 + _attr, accessor = attr
1.158 + value = _attr.type
1.159 + else:
1.160 + value = attr.type
1.161 + if isinstance(value, Instance) and not to_replace.has_key(value):
1.162 + distinct_instances = value.get_class().get_distinct_instances()
1.163 + if distinct_instances.has_key(value):
1.164 + attr.type = distinct_instances[value]
1.165 +
1.166 + def dispatch(self, node, *args):
1.167 + return Visitor.dispatch(self, node, *args)
1.168 +
1.169 + def visitInvokeFunction(self, invoke):
1.170 +
1.171 + "Transform the 'invoke' node, performing processing on subprograms."
1.172 +
1.173 + return self.default(invoke)
1.174 +
1.175 + def visitInvokeRef(self, invoke):
1.176 +
1.177 + "Transform the 'invoke' node, performing processing on subprograms."
1.178 +
1.179 + # The special case of internal subprogram invocation is addressed by
1.180 + # propagating namespace information to the subprogram and processing it.
1.181 +
1.182 + if invoke.share_locals:
1.183 + subprogram = self.process_node(invoke.ref, self.namespace)
1.184 + else:
1.185 + subprogram = self.process_node(invoke.ref)
1.186 +
1.187 + if subprogram is not None:
1.188 + self.subprograms.append(subprogram)
1.189 + return invoke
1.190 +
1.191 +# Convenience functions.
1.192 +
1.193 +def fix(module):
1.194 +
1.195 + "Fix the instances in the given 'module'."
1.196 +
1.197 + fixer = Fixer()
1.198 + fixer.process(module)
1.199 +
1.200 +# vim: tabstop=4 expandtab shiftwidth=4
2.1 --- a/simplify/simplified/data.py Mon Jun 18 00:35:46 2007 +0200
2.2 +++ b/simplify/simplified/data.py Mon Jun 18 01:47:51 2007 +0200
2.3 @@ -52,7 +52,7 @@
2.4 names.add(name)
2.5 return names
2.6
2.7 - def get_names_to_instances(self):
2.8 + def get_names_to_instances(self, distinct=0):
2.9
2.10 """
2.11 Return a tuple containing a mapping from names to instances, and a list
2.12 @@ -61,21 +61,29 @@
2.13
2.14 d = {}
2.15 names = []
2.16 - for instance in self.instances.values():
2.17 + if distinct:
2.18 + instances = set(self.get_distinct_instances().values())
2.19 + else:
2.20 + instances = self.instances.values()
2.21 +
2.22 + for instance in instances:
2.23 name = instance.full_name()
2.24 names.append(name)
2.25 d[name] = instance
2.26 +
2.27 names.sort()
2.28 return d, names
2.29
2.30 def get_distinct_instances(self):
2.31
2.32 """
2.33 - Return a list of instances whose instance attribute types are distinct.
2.34 + Return a dictionary mapping instances to a set of instances whose
2.35 + attribute types are distinct.
2.36 """
2.37
2.38 - instances = []
2.39 + instances = {}
2.40 names_found = []
2.41 + instances_found = []
2.42
2.43 # Rather than use the instances directly, get them in name order in
2.44 # order to favour those earlier according to the sorting.
2.45 @@ -85,10 +93,13 @@
2.46 for instance_name in instance_names:
2.47 instance = names_to_instances[instance_name]
2.48 names = instance.namespace.names
2.49 - if not names in names_found:
2.50 - instances.append(instance)
2.51 + try:
2.52 + i = names_found.index(names)
2.53 + instances[instance] = instances_found[i]
2.54 + except ValueError:
2.55 names_found.append(names)
2.56 -
2.57 + instances_found.append(instance)
2.58 +
2.59 return instances
2.60
2.61 class SingleInstanceClass(_Class):
3.1 --- a/simplify/viewer.py Mon Jun 18 00:35:46 2007 +0200
3.2 +++ b/simplify/viewer.py Mon Jun 18 01:47:51 2007 +0200
3.3 @@ -185,8 +185,9 @@
3.4
3.5 class Summariser(Writer):
3.6
3.7 - def __init__(self, stream):
3.8 + def __init__(self, stream, distinct):
3.9 self.stream = stream
3.10 + self.distinct = distinct
3.11
3.12 def process(self, module):
3.13 self.module = module
3.14 @@ -225,7 +226,7 @@
3.15
3.16 # Write instances for the class, along with type details for each attribute.
3.17
3.18 - names_to_instances, instance_names = structure.get_names_to_instances()
3.19 + names_to_instances, instance_names = structure.get_names_to_instances(self.distinct)
3.20
3.21 for instance_name in instance_names:
3.22 instance = names_to_instances[instance_name]
3.23 @@ -1285,10 +1286,10 @@
3.24 browser = Browser(stream or sys.stdout)
3.25 browser.process(module.original)
3.26
3.27 -def makesummary(module, filename):
3.28 +def makesummary(module, filename, distinct=0):
3.29 stream = open(filename, "wb")
3.30 try:
3.31 - summariser = Summariser(stream)
3.32 + summariser = Summariser(stream, distinct=distinct)
3.33 summariser.process(module)
3.34 finally:
3.35 stream.close()
3.36 @@ -1301,12 +1302,12 @@
3.37 finally:
3.38 stream.close()
3.39
3.40 -def makedocs(module, modules, builtins):
3.41 +def makedocs(module, modules, builtins, distinct=0):
3.42 dirname = "%s-docs" % module.name
3.43 if not os.path.exists(dirname):
3.44 os.mkdir(dirname)
3.45 for m in [module, builtins] + modules:
3.46 makedoc(m, os.path.join(dirname, "%s%sxhtml" % (m.name, os.path.extsep)))
3.47 - makesummary(m, os.path.join(dirname, "%s%s%sxhtml" % (m.name, "-summary", os.path.extsep)))
3.48 + makesummary(m, os.path.join(dirname, "%s%s%sxhtml" % (m.name, "-summary", os.path.extsep)), distinct=distinct)
3.49
3.50 # vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/test.py Mon Jun 18 00:35:46 2007 +0200
4.2 +++ b/test.py Mon Jun 18 01:47:51 2007 +0200
4.3 @@ -16,6 +16,7 @@
4.4 simplified.set_prolific_multiple_instance_mode()
4.5
4.6 import simplify.viewer
4.7 + import simplify.fixinstances
4.8 from simplify.annotate import AnnotationError, Importer, load
4.9
4.10 importer = Importer(sys.path)
4.11 @@ -25,7 +26,9 @@
4.12 except simplified.SimplifiedError, exc:
4.13 raise
4.14 else:
4.15 + if "-i" in sys.argv:
4.16 + simplify.fixinstances.fix(module)
4.17 if "-d" in sys.argv:
4.18 - simplify.viewer.makedocs(module, importer.modules.values(), builtins)
4.19 + simplify.viewer.makedocs(module, importer.modules.values(), builtins, distinct=("-i" in sys.argv))
4.20
4.21 # vim: tabstop=4 expandtab shiftwidth=4