2.1 --- a/micropython/common.py Sat Apr 20 00:59:58 2013 +0200
2.2 +++ b/micropython/common.py Thu Apr 25 18:08:32 2013 +0200
2.3 @@ -76,6 +76,42 @@
2.4
2.5 # Deduction-related methods.
2.6
2.7 + def get_attributes(self, targets, attrname):
2.8 +
2.9 + "Return a list of attributes for 'targets' supporting 'attrname'."
2.10 +
2.11 + attributes = set()
2.12 +
2.13 + for target in targets:
2.14 + try:
2.15 + attributes.add(self.objtable.access(target.full_name(), attrname))
2.16 + except TableError:
2.17 + return None
2.18 +
2.19 + return attributes
2.20 +
2.21 + def get_attribute_and_value(self, obj):
2.22 +
2.23 + """
2.24 + Return (attribute, value) details for the given 'obj', where an
2.25 + attribute of None can be returned for constant objects, and where None
2.26 + can be returned as the result where no concrete details can be provided.
2.27 + """
2.28 +
2.29 + if isinstance(obj, Constant):
2.30 + return None, obj
2.31 +
2.32 + if isinstance(obj, Attr):
2.33 + return obj, obj.get_value()
2.34 +
2.35 + return None
2.36 +
2.37 + def provides_constant_result(self, value):
2.38 +
2.39 + "Return whether 'value' provides a constant result."
2.40 +
2.41 + return isinstance(value, (Const, Constant))
2.42 +
2.43 def provides_self_access(self, node, unit):
2.44
2.45 """
2.46 @@ -134,22 +170,6 @@
2.47
2.48 return all_target_names and all_target_names[0]
2.49
2.50 - def get_attribute_and_value(self, obj):
2.51 -
2.52 - """
2.53 - Return (attribute, value) details for the given 'obj', where an
2.54 - attribute of None can be returned for constant objects, and where None
2.55 - can be returned as the result where no concrete details can be provided.
2.56 - """
2.57 -
2.58 - if isinstance(obj, Constant):
2.59 - return None, obj
2.60 -
2.61 - if isinstance(obj, Attr):
2.62 - return obj, obj.get_value()
2.63 -
2.64 - return None
2.65 -
2.66 def possible_attributes_from_annotation(self, node):
2.67
2.68 """
2.69 @@ -240,6 +260,17 @@
2.70
2.71 return targets
2.72
2.73 + def possible_accessors_for_attribute(self, attrname):
2.74 +
2.75 + "Return possible accessors given the single 'attrname'."
2.76 +
2.77 + targets = set()
2.78 +
2.79 + for target_name in self.objtable.any_possible_objects([attrname]):
2.80 + targets.add(self.objtable.get_object(target_name))
2.81 +
2.82 + return targets
2.83 +
2.84 def used_by_unit(node):
2.85
2.86 """
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/micropython/deduce.py Thu Apr 25 18:08:32 2013 +0200
3.3 @@ -0,0 +1,242 @@
3.4 +#!/usr/bin/env python
3.5 +
3.6 +"""
3.7 +Perform deductions on an inspected program.
3.8 +
3.9 +Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 Paul Boddie <paul@boddie.org.uk>
3.10 +
3.11 +This program is free software; you can redistribute it and/or modify it under
3.12 +the terms of the GNU General Public License as published by the Free Software
3.13 +Foundation; either version 3 of the License, or (at your option) any later
3.14 +version.
3.15 +
3.16 +This program is distributed in the hope that it will be useful, but WITHOUT
3.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
3.19 +details.
3.20 +
3.21 +You should have received a copy of the GNU General Public License along with
3.22 +this program. If not, see <http://www.gnu.org/licenses/>.
3.23 +"""
3.24 +
3.25 +from micropython.common import *
3.26 +from micropython.data import *
3.27 +from micropython.errors import *
3.28 +import compiler.ast
3.29 +
3.30 +# Source code classes.
3.31 +
3.32 +class DeducedSource(ASTVisitor):
3.33 +
3.34 + "A module upon which deductions of code behaviour are made."
3.35 +
3.36 + def __init__(self, module, program):
3.37 + self.visitor = self
3.38 + self.module = module
3.39 + self.program = program
3.40 + self.objtable = program.get_object_table()
3.41 + self.units = []
3.42 +
3.43 + def get_unit(self):
3.44 + return self.units[-1]
3.45 +
3.46 + def get_module(self):
3.47 + return self.units[0]
3.48 +
3.49 + def deduce(self):
3.50 +
3.51 + "Process the module, making deductions."
3.52 +
3.53 + self.dispatch(self.module.astnode)
3.54 +
3.55 + def dispatch(self, node, *args):
3.56 +
3.57 + "NOTE: From compiler.visitor.ASTVisitor."
3.58 +
3.59 + try:
3.60 + return node.visit(self.visitor, *args)
3.61 + except AttributeError:
3.62 + # NOTE: Obligatory hack to find real attribute errors.
3.63 + if isinstance(node, (Getattr, AssAttr)):
3.64 + raise
3.65 + return self.visitor.default(node, *args)
3.66 +
3.67 + def _visitUnit(self, node):
3.68 +
3.69 + """
3.70 + Track entry into program units in order to support various attribute
3.71 + access operations.
3.72 + """
3.73 +
3.74 + if not used_by_unit(node):
3.75 + return
3.76 +
3.77 + self.units.append(node.unit)
3.78 + self.dispatch(node.node)
3.79 + self.units.pop()
3.80 +
3.81 + visitModule = visitClass = visitFunction = _visitUnit
3.82 +
3.83 + def _visitAttr(self, node):
3.84 +
3.85 + """
3.86 + Perform deductions on attribute accesses, adding annotations to the node
3.87 + that can be used by subsequent activities.
3.88 + """
3.89 +
3.90 + unit = self.get_unit()
3.91 +
3.92 + # The target, on which the access is performed, may influence the effect
3.93 + # on the context. We can only reliably assume that a literal constant is
3.94 + # an instance: all other "instances" may actually be classes in certain
3.95 + # cases.
3.96 +
3.97 + target = node._expr
3.98 + instance_target = isinstance(target, Const)
3.99 +
3.100 + # Attempt to deduce attributes from explicit annotations.
3.101 +
3.102 + node._attrs_deduced = attrs = self.possible_attributes_from_annotation(node)
3.103 +
3.104 + if len(attrs) == 1:
3.105 + for attr, value in attrs:
3.106 +
3.107 + # Constant values can be obtained directly.
3.108 +
3.109 + if self.provides_constant_result(value):
3.110 + node._access_type = "constant"
3.111 + node._value_deduced = value
3.112 + return
3.113 +
3.114 + # Static attributes can be obtained via their parent.
3.115 +
3.116 + if attr.is_static_attribute():
3.117 + node._access_type = "static"
3.118 + node._attr_deduced = attr
3.119 + node._set_context = instance_target and "set" or None
3.120 + return
3.121 +
3.122 + # Attributes of self, which is by definition an instance.
3.123 +
3.124 + if self.provides_self_access(node, unit):
3.125 +
3.126 + # Find instance attributes.
3.127 +
3.128 + attr = unit.parent.instance_attributes().get(node.attrname)
3.129 +
3.130 + if attr:
3.131 + node._access_type = "instance"
3.132 + node._attr_deduced = attr
3.133 + return
3.134 +
3.135 + # Find class attributes.
3.136 + # The context will be overridden for compatible class attributes
3.137 + # only.
3.138 +
3.139 + attr = unit.parent.get(node.attrname)
3.140 +
3.141 + if attr:
3.142 +
3.143 + # Constant attributes.
3.144 +
3.145 + if attr.is_strict_constant():
3.146 + if self.provides_constant_result(attr.get_value()):
3.147 + node._access_type = "constant"
3.148 + node._value_deduced = attr.get_value()
3.149 + return
3.150 +
3.151 + # Compatible class attributes.
3.152 +
3.153 + if attr.defined_within_hierarchy():
3.154 + node._access_type = "static"
3.155 + node._attr_deduced = attr
3.156 + node._set_context = "set"
3.157 + return
3.158 +
3.159 + # Incompatible class attributes.
3.160 +
3.161 + elif attr.defined_outside_hierarchy():
3.162 + node._access_type = "static"
3.163 + node._attr_deduced = attr
3.164 + return
3.165 +
3.166 + # Unknown or mixed compatibility.
3.167 +
3.168 + node._access_type = "static"
3.169 + node._attr_deduced = attr
3.170 + node._set_context = "cond"
3.171 + return
3.172 +
3.173 + # Usage observations, both specific to this node's region of the program
3.174 + # and also applicable to the lifespan of the affected name.
3.175 +
3.176 + specific_targets = self.possible_accessors_from_usage(node, defining_users=0)
3.177 + targets = self.possible_accessors_from_usage(node, defining_users=1)
3.178 +
3.179 + # Record whether types were already deduced. If not, get types using
3.180 + # only this attribute.
3.181 +
3.182 + if not specific_targets or not targets:
3.183 + attribute_targets = self.possible_accessors_for_attribute(node.attrname)
3.184 + if not specific_targets:
3.185 + specific_targets = attribute_targets
3.186 + if not targets:
3.187 + targets = attribute_targets
3.188 +
3.189 + node._attrs_deduced_from_specific_usage = self.get_attributes(specific_targets, node.attrname)
3.190 + node._attrs_deduced_from_usage = attrs = self.get_attributes(targets, node.attrname)
3.191 +
3.192 + # Generate optimisations where only a single attribute applies.
3.193 +
3.194 + if attrs and len(attrs) == 1:
3.195 + for attr in attrs:
3.196 +
3.197 + # Static attributes, but potentially non-static targets.
3.198 +
3.199 + if attr.is_static_attribute():
3.200 +
3.201 + # Static attributes may be accompanied by a different context
3.202 + # depending on the accessor.
3.203 + # NOTE: Should determine whether the context is always replaced.
3.204 +
3.205 + node._access_type = "static"
3.206 + node._attr_deduced = attr
3.207 + node._set_context = instance_target and "set" or "cond"
3.208 + return
3.209 +
3.210 + # Non-static attributes.
3.211 +
3.212 + node._access_type = "instance"
3.213 + node._attr_deduced = attr
3.214 + return
3.215 +
3.216 + # Test for compatible attribute positioning.
3.217 +
3.218 + elif attrs:
3.219 + positions = set([(attr.is_static_attribute(), attr.position) for attr in attrs])
3.220 +
3.221 + # Permit a position-based access only on non-static attributes since
3.222 + # access to static attributes may happen via instances and thus not
3.223 + # be relative to the accessor but to its parent.
3.224 +
3.225 + if len(positions) == 1:
3.226 + for position in positions:
3.227 + if not position[0]:
3.228 + node._access_type = "positioned"
3.229 + node._position_deduced = position[0]
3.230 + return
3.231 +
3.232 + # With no usable deductions, generate a table-based access.
3.233 +
3.234 + node._access_type = "unknown"
3.235 + node._set_context = "cond"
3.236 +
3.237 + visitAssAttr = visitGetattr = _visitAttr
3.238 +
3.239 +# Convenience functions.
3.240 +
3.241 +def deduce(program):
3.242 + for module in program.get_importer().get_modules():
3.243 + DeducedSource(module, program).deduce()
3.244 +
3.245 +# vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/micropython/syspython.py Sat Apr 20 00:59:58 2013 +0200
4.2 +++ b/micropython/syspython.py Thu Apr 25 18:08:32 2013 +0200
4.3 @@ -43,6 +43,15 @@
4.4 def quoted_name(s):
4.5 return compiler.ast.Const(s)
4.6
4.7 +# Special function names.
4.8 +# NOTE: Some of the assignment operations should not be supported unless
4.9 +# NOTE: attribute usage observations are being made.
4.10 +
4.11 +assattr_functions = ("__storeattrcontext__", "__storeattrcontext__", "__storeattr__",
4.12 + "__storeattrindex__", None)
4.13 +getattr_functions = ("__loadattrcontext__", "__loadattrcontextcond__", "__loadattr__",
4.14 + "__loadattrindex__", "__loadattrindexcontextcond__")
4.15 +
4.16 # Source code classes.
4.17
4.18 class ConvertedSource(ASTVisitor):
4.19 @@ -475,6 +484,96 @@
4.20
4.21 return None
4.22
4.23 + def _visitAttr(self, node, expr=None):
4.24 + unit = self.get_unit()
4.25 +
4.26 + # Choose the appropriate special functions.
4.27 +
4.28 + (opattrcontext, opattrcontextcond, opattr,
4.29 + opattrindex, opattrindexcontextcond) = expr and assattr_functions or getattr_functions
4.30 +
4.31 + accessor = self.dispatch(node.expr)
4.32 +
4.33 + # Generate already-deduced accesses.
4.34 +
4.35 + if node._access_type == "constant":
4.36 + return self._generateValue(node._value_deduced)
4.37 +
4.38 + # Generate accesses via static objects and instances.
4.39 +
4.40 + if node._attr_deduced:
4.41 + if node._set_context == "set":
4.42 + op = opattrcontext
4.43 + elif node._set_context == "cond":
4.44 + op = opattrcontextcond
4.45 + else:
4.46 + op = opattr
4.47 +
4.48 + # Handle unsupported operations.
4.49 +
4.50 + if not op:
4.51 + raise TranslateError("Storing of class attribute %r via self not permitted." % node.attrname)
4.52 +
4.53 + # Define the arguments: accessor, attribute name and optional value.
4.54 +
4.55 + args = [
4.56 + node._access_type == "static" and \
4.57 + self._generateValue(node._attr_deduced.parent) or accessor,
4.58 + special_name(node.attrname)
4.59 + ]
4.60 +
4.61 + if expr:
4.62 + args.append(expr)
4.63 +
4.64 + return compiler.ast.CallFunc(special_name(op), args)
4.65 +
4.66 + # Positioned accesses are normal accesses via instances.
4.67 +
4.68 + if node._access_type == "positioned":
4.69 + args = [accessor, special_name(node.attrname)]
4.70 + if expr:
4.71 + args.append(expr)
4.72 + return compiler.ast.CallFunc(special_name(opattr), args)
4.73 +
4.74 + # With no usable deductions, generate a table-based access.
4.75 +
4.76 + args = [accessor, special_name(node.attrname)]
4.77 + if expr:
4.78 + args.append(expr)
4.79 + access = compiler.ast.CallFunc(special_name(opattrindexcontextcond), args)
4.80 +
4.81 + # class.__class__ => __builtins__.type
4.82 +
4.83 + if node.attrname == "__class__":
4.84 +
4.85 + # __storetemp__(n, <accessor>)
4.86 + # __isclass__(n) and __loadattr__(__builtins__, type) or <access>
4.87 +
4.88 + temp = quoted_name(unit.temp_usage)
4.89 + unit.temp_usage += 1
4.90 +
4.91 + return compiler.ast.Stmt([
4.92 + compiler.ast.CallFunc(special_name("__storetemp__"), [temp, access]),
4.93 + compiler.ast.Or([
4.94 + compiler.ast.And([
4.95 + compiler.ast.CallFunc(
4.96 + special_name("__isclass__"),
4.97 + [compiler.ast.CallFunc(special_name("__loadtemp__"), [temp])]
4.98 + ),
4.99 + compiler.ast.CallFunc(
4.100 + special_name("__loadattr__"),
4.101 + [special_name("__builtins__"), special_name("type")]
4.102 + )
4.103 + ]),
4.104 + access
4.105 + ])
4.106 + ])
4.107 +
4.108 + # General accesses.
4.109 +
4.110 + else:
4.111 + return access
4.112 +
4.113 # Expressions.
4.114
4.115 def visitAdd(self, node):
4.116 @@ -484,63 +583,7 @@
4.117 return compiler.ast.And([self.dispatch(n) for n in node.nodes])
4.118
4.119 def visitAssAttr(self, node, expr):
4.120 -
4.121 - # NOTE: Derived from Getattr support.
4.122 -
4.123 - accessor = self.dispatch(node.expr)
4.124 -
4.125 - # NOTE: Replicate the _generateAttr logic.
4.126 - # NOTE: Should be able to store concrete value details on generated
4.127 - # NOTE: nodes, such as whether an expression yields a constant.
4.128 -
4.129 - # NOTE: Known targets:
4.130 - # NOTE: __storeattr__ and __storeattrcontext__
4.131 -
4.132 - # NOTE: Attributes of self.
4.133 -
4.134 - # Usage observations.
4.135 -
4.136 - targets = self.possible_accessors_from_usage(node, defining_users=0)
4.137 -
4.138 - # Record whether types were already deduced. If not, get types using
4.139 - # only this attribute.
4.140 -
4.141 - if not targets:
4.142 - targets = self.possible_accessors_for_attribute(node.attrname)
4.143 -
4.144 - attrs = self.get_attributes(targets, node.attrname)
4.145 -
4.146 - # Generate optimisations where only a single attribute applies.
4.147 -
4.148 - if len(attrs) == 1:
4.149 - attr = attrs[0]
4.150 -
4.151 - # Static attributes.
4.152 -
4.153 - if attr.is_static_attribute():
4.154 -
4.155 - # Static attributes may be accompanied by a different context
4.156 - # depending on the accessor.
4.157 - # NOTE: Should determine whether the context is always replaced.
4.158 -
4.159 - return compiler.ast.CallFunc(
4.160 - special_name("__storeattrcontextcond__"),
4.161 - [accessor, special_name(node.attrname), expr]
4.162 - )
4.163 -
4.164 - # Non-static attributes.
4.165 -
4.166 - return compiler.ast.CallFunc(
4.167 - special_name("__storeattr__"),
4.168 - [accessor, special_name(node.attrname), expr]
4.169 - )
4.170 -
4.171 - # With no usable deductions, generate a table-based access.
4.172 -
4.173 - return compiler.ast.CallFunc(
4.174 - special_name("__storeattrindex__"),
4.175 - [accessor, special_name(node.attrname), expr]
4.176 - )
4.177 + return self._visitAttr(node, expr)
4.178
4.179 def visitAssList(self, node, expr):
4.180 return compiler.ast.Stmt([
4.181 @@ -660,169 +703,7 @@
4.182 return self._visitBinary(node)
4.183
4.184 def visitGetattr(self, node, expr=None):
4.185 - if expr:
4.186 - return self.visitAssAttr(node, expr)
4.187 -
4.188 - unit = self.get_unit()
4.189 -
4.190 - accessor = self.dispatch(node.expr)
4.191 -
4.192 - # The target, on which the access is performed, may influence the effect
4.193 - # on the context. We can only reliably assume that a literal constant is
4.194 - # an instance: all other "instances" may actually be classes in certain
4.195 - # cases.
4.196 -
4.197 - target = node._expr
4.198 - instance_target = isinstance(target, Const)
4.199 -
4.200 - # Attempt to deduce attributes from explicit annotations.
4.201 -
4.202 - attrs = self.possible_attributes_from_annotation(node)
4.203 -
4.204 - if len(attrs) == 1:
4.205 - attr, value = attrs[0]
4.206 -
4.207 - # Constant values can be obtained directly.
4.208 -
4.209 - v = self._generateValue(value)
4.210 - if v: return v
4.211 -
4.212 - # Static attributes can be obtained via their parent.
4.213 -
4.214 - if attr.is_static_attribute():
4.215 - return compiler.ast.CallFunc(
4.216 - special_name(instance_target and "__loadattrcontext__" or "__loadattr__"),
4.217 - [self._generateValue(attr.parent), special_name(node.attrname)])
4.218 -
4.219 - # Attributes of self, which is by definition an instance.
4.220 -
4.221 - if self.provides_self_access(node, unit):
4.222 -
4.223 - # Find instance attributes.
4.224 -
4.225 - attr = unit.parent.instance_attributes().get(node.attrname)
4.226 -
4.227 - if attr:
4.228 -
4.229 - # Emit self.attrname without context overriding.
4.230 -
4.231 - return compiler.ast.CallFunc(
4.232 - special_name("__loadattr__"), [
4.233 - accessor, special_name(node.attrname)
4.234 - ])
4.235 -
4.236 - # Find class attributes.
4.237 - # The context will be overridden for compatible class attributes
4.238 - # only.
4.239 -
4.240 - attr = unit.parent.get(node.attrname)
4.241 -
4.242 - if attr:
4.243 -
4.244 - # Constant attributes.
4.245 -
4.246 - if attr.is_strict_constant():
4.247 - v = self._generateValue(attr.get_value())
4.248 - if v: return v
4.249 -
4.250 - # Compatible class attributes.
4.251 -
4.252 - if attr.defined_within_hierarchy():
4.253 - return compiler.ast.CallFunc(
4.254 - special_name("__loadattrcontext__"), [
4.255 - self._generateValue(attr.parent), special_name(node.attrname)
4.256 - ])
4.257 -
4.258 - # Incompatible class attributes.
4.259 -
4.260 - elif attr.defined_outside_hierarchy():
4.261 - return compiler.ast.CallFunc(
4.262 - special_name("__loadattr__"), [
4.263 - self._generateValue(attr.parent), special_name(node.attrname)
4.264 - ])
4.265 -
4.266 - # Unknown or mixed compatibility.
4.267 -
4.268 - return compiler.ast.CallFunc(
4.269 - special_name("__loadattrcontextcond__"), [
4.270 - self._generateValue(attr.parent), special_name(node.attrname)
4.271 - ])
4.272 -
4.273 - # Usage observations.
4.274 -
4.275 - targets = self.possible_accessors_from_usage(node, defining_users=0)
4.276 -
4.277 - # Record whether types were already deduced. If not, get types using
4.278 - # only this attribute.
4.279 -
4.280 - if not targets:
4.281 - targets = self.possible_accessors_for_attribute(node.attrname)
4.282 -
4.283 - attrs = self.get_attributes(targets, node.attrname)
4.284 -
4.285 - # Generate optimisations where only a single attribute applies.
4.286 -
4.287 - if len(attrs) == 1:
4.288 - attr = attrs[0]
4.289 -
4.290 - # Static attributes, but potentially non-static targets.
4.291 -
4.292 - if attr.is_static_attribute():
4.293 -
4.294 - # Static attributes may be accompanied by a different context
4.295 - # depending on the accessor.
4.296 - # NOTE: Should determine whether the context is always replaced.
4.297 -
4.298 - return compiler.ast.CallFunc(
4.299 - special_name(instance_target and "__loadattrcontext__" or "__loadattrcontextcond__"),
4.300 - [accessor, special_name(node.attrname)]
4.301 - )
4.302 -
4.303 - # Non-static attributes.
4.304 -
4.305 - return compiler.ast.CallFunc(
4.306 - special_name("__loadattr__"),
4.307 - [accessor, special_name(node.attrname)]
4.308 - )
4.309 -
4.310 - # With no usable deductions, generate a table-based access.
4.311 -
4.312 - access = compiler.ast.CallFunc(
4.313 - special_name("__loadattrindexcontextcond__"),
4.314 - [accessor, special_name(node.attrname)]
4.315 - )
4.316 -
4.317 - # class.__class__ => __builtins__.type
4.318 -
4.319 - if node.attrname == "__class__":
4.320 -
4.321 - # __storetemp__(n, <accessor>)
4.322 - # __isclass__(n) and __loadattr__(__builtins__, type) or <access>
4.323 -
4.324 - temp = quoted_name(unit.temp_usage)
4.325 - unit.temp_usage += 1
4.326 -
4.327 - return compiler.ast.Stmt([
4.328 - compiler.ast.CallFunc(special_name("__storetemp__"), [temp, access]),
4.329 - compiler.ast.Or([
4.330 - compiler.ast.And([
4.331 - compiler.ast.CallFunc(
4.332 - special_name("__isclass__"),
4.333 - [compiler.ast.CallFunc(special_name("__loadtemp__"), [temp])]
4.334 - ),
4.335 - compiler.ast.CallFunc(
4.336 - special_name("__loadattr__"),
4.337 - [special_name("__builtins__"), special_name("type")]
4.338 - )
4.339 - ]),
4.340 - access
4.341 - ])
4.342 - ])
4.343 -
4.344 - # General accesses.
4.345 -
4.346 - else:
4.347 - return access
4.348 + return self._visitAttr(node, expr)
4.349
4.350 def visitGenExpr(self, node):
4.351 return compiler.ast.GenExpr(self.dispatch(node.code))
4.352 @@ -982,33 +863,6 @@
4.353 def visitUnarySub(self, node):
4.354 return self._visitUnary(node)
4.355
4.356 - # Type-related methods.
4.357 -
4.358 - def possible_accessor_types(self, node, defining_users=1):
4.359 - return set([tn for (tn, st) in ASTVisitor.possible_accessor_types(self, node, defining_users)])
4.360 -
4.361 - def get_possible_accessors(self, attrname):
4.362 -
4.363 - "Return a list of accessors supporting 'attrname'."
4.364 -
4.365 - targets = []
4.366 -
4.367 - for target_name in self.objtable.any_possible_objects([attrname]):
4.368 - targets.append(self.objtable.get_object(target_name))
4.369 -
4.370 - return targets
4.371 -
4.372 - def get_attributes(self, targets, attrname):
4.373 -
4.374 - "Return a list of attributes for 'targets' supporting 'attrname'."
4.375 -
4.376 - attributes = []
4.377 -
4.378 - for target in targets:
4.379 - attributes.append(self.objtable.access(target.full_name(), attrname))
4.380 -
4.381 - return attributes
4.382 -
4.383 # Convenience functions.
4.384
4.385 def convert(module, program, filename):