1.1 --- a/micropython/common.py Fri Apr 19 23:38:12 2013 +0200
1.2 +++ b/micropython/common.py Sat Apr 20 00:59:58 2013 +0200
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 Common classes.
1.6
1.7 -Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This program is free software; you can redistribute it and/or modify it under
1.11 the terms of the GNU General Public License as published by the Free Software
1.12 @@ -21,6 +21,7 @@
1.13
1.14 from compiler.ast import AssAttr, Getattr, Name
1.15 import compiler.ast
1.16 +from micropython.basicdata import Const, Constant
1.17 from micropython.data import Attr, Class, Module
1.18 from micropython.errors import *
1.19
1.20 @@ -35,6 +36,23 @@
1.21
1.22 "A base class for visitors."
1.23
1.24 + def process_definitions(self, node):
1.25 +
1.26 + """
1.27 + Process and return all definitions beneath 'node', but not definitions
1.28 + within definitions.
1.29 + """
1.30 +
1.31 + definitions = []
1.32 + for n in node.getChildNodes():
1.33 + if isinstance(n, (compiler.ast.Class, compiler.ast.Function)):
1.34 + definitions.append(self.dispatch(n))
1.35 + else:
1.36 + definitions += self.process_definitions(n)
1.37 + return definitions
1.38 +
1.39 + # Visitor support methods.
1.40 +
1.41 def default(self, node, *args):
1.42 for n in node.getChildNodes():
1.43 self.dispatch(n)
1.44 @@ -56,6 +74,25 @@
1.45 exc.unit_name = self.get_unit().full_name()
1.46 raise
1.47
1.48 + # Deduction-related methods.
1.49 +
1.50 + def provides_self_access(self, node, unit):
1.51 +
1.52 + """
1.53 + Return whether the 'node' in the given 'unit' provides a self-based
1.54 + attribute access.
1.55 + """
1.56 +
1.57 + attr_value = self.get_attribute_and_value(node._expr)
1.58 +
1.59 + if attr_value:
1.60 + target, value = attr_value
1.61 +
1.62 + return target and target.name == "self" and target.parent is unit and \
1.63 + unit.is_method()
1.64 +
1.65 + return False
1.66 +
1.67 def possible_accessor_types(self, node, defining_users=1):
1.68
1.69 """
1.70 @@ -74,69 +111,22 @@
1.71 # not that of a general instance or an unresolved name, attempt to
1.72 # identify it.
1.73
1.74 - if isinstance(node, (AssAttr, Getattr, Name)):
1.75 -
1.76 - # Use any explicit attribute annotation.
1.77 -
1.78 - if isinstance(node._attr, Attr):
1.79 - attr = node._attr
1.80 - all_target_names.append(set([(attr.parent.full_name(), attr.is_static_attribute())]))
1.81 -
1.82 - # Otherwise, try and use an expression annotation.
1.83 -
1.84 - if isinstance(node, (AssAttr, Getattr)):
1.85 - expr = node._expr
1.86 -
1.87 - # Permitting multiple expression types if they provide the
1.88 - # attribute.
1.89 -
1.90 - if isinstance(expr, Attr):
1.91 - exprs = expr.get_values()
1.92 - elif expr:
1.93 - exprs = [expr]
1.94 - else:
1.95 - exprs = None
1.96 -
1.97 - if exprs:
1.98 - target_names = set()
1.99 -
1.100 - # For each expression value try and get a concrete
1.101 - # attribute.
1.102 -
1.103 - for expr in exprs:
1.104 - attr = expr.all_attributes().get(node.attrname)
1.105 + # Use explicit annotations on the node.
1.106
1.107 - # Where an attribute can be obtained, record its
1.108 - # details.
1.109 -
1.110 - if attr:
1.111 - target_names.add((attr.parent.full_name(), attr.is_static_attribute()))
1.112 -
1.113 - if target_names:
1.114 - all_target_names.append(target_names)
1.115 -
1.116 - # Otherwise, attempt to employ the attribute usage observations.
1.117 -
1.118 - if node._attrusers:
1.119 - target_names = set()
1.120 -
1.121 - # Visit each attribute user.
1.122 + attrs = self.possible_attributes_from_annotation(node)
1.123 + if attrs:
1.124 + target_names = set()
1.125 + for (attr, value) in attrs:
1.126 + # NOTE: Ignoring constant objects.
1.127 + if attr:
1.128 + target_names.add((attr.parent.full_name(), attr.is_static_attribute()))
1.129 + all_target_names.append(target_names)
1.130
1.131 - for user in node._attrusers:
1.132 -
1.133 - # Since users such as branches may not provide type information,
1.134 - # attempt to find defining users.
1.135 + # Use attribute usage observations.
1.136
1.137 - if defining_users:
1.138 - for def_user in user._attrdefs or [user]:
1.139 - for target_name, is_static in def_user._attrtypes.get(node._username, []):
1.140 - target_names.add((target_name, is_static))
1.141 - else:
1.142 - for target_name, is_static in user._attrspecifictypes.get(node._username, []):
1.143 - target_names.add((target_name, is_static))
1.144 -
1.145 - if target_names:
1.146 - all_target_names.append(target_names)
1.147 + target_names = self.possible_accessor_types_from_usage(node, defining_users)
1.148 + if target_names:
1.149 + all_target_names.append(target_names)
1.150
1.151 # Return the smallest set of target names.
1.152
1.153 @@ -144,6 +134,112 @@
1.154
1.155 return all_target_names and all_target_names[0]
1.156
1.157 + def get_attribute_and_value(self, obj):
1.158 +
1.159 + """
1.160 + Return (attribute, value) details for the given 'obj', where an
1.161 + attribute of None can be returned for constant objects, and where None
1.162 + can be returned as the result where no concrete details can be provided.
1.163 + """
1.164 +
1.165 + if isinstance(obj, Constant):
1.166 + return None, obj
1.167 +
1.168 + if isinstance(obj, Attr):
1.169 + return obj, obj.get_value()
1.170 +
1.171 + return None
1.172 +
1.173 + def possible_attributes_from_annotation(self, node):
1.174 +
1.175 + """
1.176 + Return (attribute, value) details provided by any _expr or _attr
1.177 + annotations on 'node'.
1.178 + """
1.179 +
1.180 + attr_value = self.get_attribute_and_value(node._attr)
1.181 +
1.182 + if attr_value:
1.183 + return [attr_value]
1.184 +
1.185 + attrs = set()
1.186 + expr = node._expr
1.187 +
1.188 + if expr:
1.189 +
1.190 + # Permitting multiple expression types if they provide the
1.191 + # attribute.
1.192 +
1.193 + if isinstance(expr, Attr):
1.194 + exprs = expr.get_values()
1.195 + else:
1.196 + exprs = [expr]
1.197 +
1.198 + # For each expression value try and get a concrete
1.199 + # attribute.
1.200 +
1.201 + for expr in exprs:
1.202 + attr = expr.all_attributes().get(node.attrname)
1.203 +
1.204 + # Where an attribute can be obtained, record its
1.205 + # details.
1.206 +
1.207 + if attr:
1.208 + attrs.add((attr, attr.get_value()))
1.209 +
1.210 + return attrs
1.211 +
1.212 + def possible_accessor_types_from_usage(self, node, defining_users=1):
1.213 +
1.214 + """
1.215 + Return a set of (target name, static) tuples from an investigation of
1.216 + attribute usage observations stored on the given 'node'.
1.217 +
1.218 + If 'defining_users' is set to a false value, attempt to get the type
1.219 + names specifically applicable to the node, rather than retrieving more
1.220 + general definition-based type observations.
1.221 + """
1.222 +
1.223 + target_names = set()
1.224 +
1.225 + if node._attrusers:
1.226 +
1.227 + # Visit each attribute user.
1.228 +
1.229 + for user in node._attrusers:
1.230 +
1.231 + # Since users such as branches may not provide type information,
1.232 + # attempt to find defining users.
1.233 +
1.234 + if defining_users:
1.235 + for def_user in user._attrdefs or [user]:
1.236 + for target_name, is_static in def_user._attrtypes.get(node._username, []):
1.237 + target_names.add((target_name, is_static))
1.238 + else:
1.239 + for target_name, is_static in user._attrspecifictypes.get(node._username, []):
1.240 + target_names.add((target_name, is_static))
1.241 +
1.242 + return target_names
1.243 +
1.244 + def possible_accessors_from_usage(self, node, defining_users=1):
1.245 +
1.246 + """
1.247 + Return possible accessors from the usage recorded on the given 'node'.
1.248 +
1.249 + If 'defining_users' is set to a false value, attempt to get the type
1.250 + names specifically applicable to the node, rather than retrieving more
1.251 + general definition-based type observations.
1.252 + """
1.253 +
1.254 + targets = set()
1.255 + target_names = self.possible_accessor_types_from_usage(node, defining_users)
1.256 +
1.257 + if target_names:
1.258 + for target_name, is_static in target_names:
1.259 + targets.add(self.objtable.get_object(target_name))
1.260 +
1.261 + return targets
1.262 +
1.263 def used_by_unit(node):
1.264
1.265 """
2.1 --- a/micropython/syspython.py Fri Apr 19 23:38:12 2013 +0200
2.2 +++ b/micropython/syspython.py Sat Apr 20 00:59:58 2013 +0200
2.3 @@ -36,7 +36,12 @@
2.4
2.5 module_attribute = compiler.ast.Getattr
2.6 special_name = compiler.ast.Name
2.7 -quoted_name = compiler.ast.Const
2.8 +
2.9 +def quoted_ref(obj):
2.10 + return compiler.ast.CallFunc("__static__", [compiler.ast.Const(obj.full_name())])
2.11 +
2.12 +def quoted_name(s):
2.13 + return compiler.ast.Const(s)
2.14
2.15 # Source code classes.
2.16
2.17 @@ -48,6 +53,7 @@
2.18 self.visitor = self
2.19 self.module = module
2.20 self.program = program
2.21 + self.objtable = program.get_object_table()
2.22 self.in_main = False
2.23 self.units = []
2.24
2.25 @@ -71,7 +77,7 @@
2.26 module = node.unit
2.27 self.units.append(module)
2.28
2.29 - definitions = self._findDefinitions(node)
2.30 + definitions = self.process_definitions(node)
2.31
2.32 # __globalnames__(name, ...)
2.33
2.34 @@ -97,15 +103,6 @@
2.35
2.36 return compiler.ast.Module(node.doc, compiler.ast.Stmt(definitions + [main]))
2.37
2.38 - def _findDefinitions(self, node):
2.39 - definitions = []
2.40 - for n in node.getChildNodes():
2.41 - if isinstance(n, (compiler.ast.Class, compiler.ast.Function)):
2.42 - definitions.append(self.dispatch(n))
2.43 - else:
2.44 - definitions += self._findDefinitions(n)
2.45 - return definitions
2.46 -
2.47 # Statements.
2.48
2.49 def visitAssert(self, node):
2.50 @@ -183,7 +180,7 @@
2.51 inherited.append(
2.52 compiler.ast.CallFunc(
2.53 special_name("__inherited__"),
2.54 - [special_name(supercls.full_name())] + [special_name(name) for name in attrnames]
2.55 + [quoted_ref(supercls)] + [special_name(name) for name in attrnames]
2.56 ))
2.57
2.58 # __descendants__(name, ...)
2.59 @@ -197,7 +194,7 @@
2.60
2.61 # Process all the definitions defined inside the class.
2.62
2.63 - definitions = self._findDefinitions(node)
2.64 + definitions = self.process_definitions(node)
2.65
2.66 return compiler.ast.Class(node.name, [], node.doc,
2.67 compiler.ast.Stmt(instattrs + clsattrs + inherited + descendants + definitions)
2.68 @@ -238,11 +235,11 @@
2.69 else_nodes = node.else_ and self.dispatch(node.else_).nodes or []
2.70
2.71 return compiler.ast.Stmt([
2.72 - # __storetemp__(_it, __loadaddress__(__builtins__, iter)(<list>))
2.73 + # __storetemp__(_it, __loadattr__(__builtins__, iter)(<list>))
2.74 compiler.ast.CallFunc(special_name("__storetemp__"), [
2.75 temp,
2.76 compiler.ast.CallFunc(
2.77 - compiler.ast.CallFunc(special_name("__loadaddress__"),
2.78 + compiler.ast.CallFunc(special_name("__loadattr__"),
2.79 [special_name("__builtins__"), special_name("iter")]
2.80 ),
2.81 [self.dispatch(node.list)]
2.82 @@ -322,10 +319,10 @@
2.83 # __localnames__(name, ...)
2.84 # __globalnames__(name, ...)
2.85
2.86 - localnames = fn.locals() and [
2.87 + localnames = fn.all_locals() and [
2.88 compiler.ast.CallFunc(
2.89 special_name("__localnames__"),
2.90 - [special_name(name) for name in fn.locals().keys()]
2.91 + [special_name(name) for name in fn.all_locals().keys()]
2.92 )
2.93 ] or []
2.94
2.95 @@ -338,6 +335,8 @@
2.96
2.97 defaults = [self.dispatch(n) for n in node.defaults]
2.98
2.99 + # NOTE: Should generate guards for attribute usage operations.
2.100 +
2.101 code = self.dispatch(node.code)
2.102
2.103 return compiler.ast.Function(node.decorators, node.name, node.argnames, defaults, node.flags, node.doc,
2.104 @@ -376,7 +375,11 @@
2.105
2.106 return compiler.ast.Stmt(statements)
2.107
2.108 - visitPass = NOP
2.109 + def visitPass(self, node):
2.110 + if not isinstance(self.get_unit(), Class):
2.111 + return compiler.ast.Pass()
2.112 + else:
2.113 + return compiler.ast.Stmt([])
2.114
2.115 def visitPrint(self, node):
2.116 return compiler.ast.Print(
2.117 @@ -458,6 +461,20 @@
2.118 [self.dispatch(node.expr)]
2.119 )
2.120
2.121 + def _generateValue(self, value):
2.122 +
2.123 + # Literal constants.
2.124 +
2.125 + if isinstance(value, Const):
2.126 + return compiler.ast.Const(value.get_value())
2.127 +
2.128 + # Other constant structures.
2.129 +
2.130 + if isinstance(value, Constant):
2.131 + return quoted_ref(value)
2.132 +
2.133 + return None
2.134 +
2.135 # Expressions.
2.136
2.137 def visitAdd(self, node):
2.138 @@ -467,7 +484,6 @@
2.139 return compiler.ast.And([self.dispatch(n) for n in node.nodes])
2.140
2.141 def visitAssAttr(self, node, expr):
2.142 - possible_types = self.possible_accessor_types(node, defining_users=0)
2.143
2.144 # NOTE: Derived from Getattr support.
2.145
2.146 @@ -478,37 +494,37 @@
2.147 # NOTE: nodes, such as whether an expression yields a constant.
2.148
2.149 # NOTE: Known targets:
2.150 - # NOTE: __storeaddress__ and __storeaddresscontext__
2.151 + # NOTE: __storeattr__ and __storeattrcontext__
2.152
2.153 # NOTE: Attributes of self.
2.154
2.155 # Usage observations.
2.156
2.157 - possible_types = self.possible_accessor_types(node, defining_users=0)
2.158 + targets = self.possible_accessors_from_usage(node, defining_users=0)
2.159
2.160 # Record whether types were already deduced. If not, get types using
2.161 # only this attribute.
2.162
2.163 - if not possible_types:
2.164 - possible_types = self.get_possible_types(node.attrname)
2.165 + if not targets:
2.166 + targets = self.possible_accessors_for_attribute(node.attrname)
2.167
2.168 - attributes = self.get_attributes(possible_types, node.attrname)
2.169 + attrs = self.get_attributes(targets, node.attrname)
2.170
2.171 # Generate optimisations where only a single attribute applies.
2.172
2.173 - if len(attributes) == 1:
2.174 - value, target, target_name = attributes[0]
2.175 + if len(attrs) == 1:
2.176 + attr = attrs[0]
2.177
2.178 # Static attributes.
2.179
2.180 - if value is not None:
2.181 + if attr.is_static_attribute():
2.182
2.183 # Static attributes may be accompanied by a different context
2.184 # depending on the accessor.
2.185 # NOTE: Should determine whether the context is always replaced.
2.186
2.187 return compiler.ast.CallFunc(
2.188 - special_name("__storeaddresscontextcond__"),
2.189 + special_name("__storeattrcontextcond__"),
2.190 [accessor, special_name(node.attrname), expr]
2.191 )
2.192
2.193 @@ -539,6 +555,7 @@
2.194 unit = self.get_unit()
2.195
2.196 # Generate appropriate name access operation.
2.197 + # NOTE: Should generate guards for attribute usage operations.
2.198
2.199 scope = getattr(node, "_scope", None)
2.200 if not scope:
2.201 @@ -560,16 +577,16 @@
2.202
2.203 elif isinstance(unit, Class):
2.204 return compiler.ast.CallFunc(
2.205 - special_name("__storeaddresscontext__"),
2.206 - [quoted_name(unit.full_name()), special_name(node.name), expr]
2.207 + special_name("__storeattrcontext__"),
2.208 + [quoted_ref(unit), special_name(node.name), expr]
2.209 )
2.210
2.211 # Module locals are module attribute references.
2.212
2.213 elif isinstance(unit, Module):
2.214 return compiler.ast.CallFunc(
2.215 - special_name("__storeaddress__"),
2.216 - [quoted_name(unit.full_name()), special_name(node.name), expr]
2.217 + special_name("__storeattr__"),
2.218 + [quoted_ref(unit), special_name(node.name), expr]
2.219 )
2.220 else:
2.221 raise TranslateError("Program unit has no local %r." % name)
2.222 @@ -579,8 +596,8 @@
2.223 # Globals are references to module attributes.
2.224
2.225 return compiler.ast.CallFunc(
2.226 - special_name("__storeaddress__"),
2.227 - [quoted_name(self.get_module().full_name()), special_name(node.name), expr]
2.228 + special_name("__storeattr__"),
2.229 + [quoted_ref(self.get_module()), special_name(node.name), expr]
2.230 )
2.231
2.232 elif scope == "builtin":
2.233 @@ -588,7 +605,7 @@
2.234 # Builtins are accessed via the __builtins__ module.
2.235
2.236 return compiler.ast.CallFunc(
2.237 - special_name("__storeaddress__"),
2.238 + special_name("__storeattr__"),
2.239 [special_name("__builtins__"), special_name(node.name), expr]
2.240 )
2.241
2.242 @@ -646,53 +663,118 @@
2.243 if expr:
2.244 return self.visitAssAttr(node, expr)
2.245
2.246 + unit = self.get_unit()
2.247 +
2.248 accessor = self.dispatch(node.expr)
2.249
2.250 - # NOTE: Replicate the _generateAttr logic.
2.251 - # NOTE: Should be able to store concrete value details on generated
2.252 - # NOTE: nodes, such as whether an expression yields a constant.
2.253 + # The target, on which the access is performed, may influence the effect
2.254 + # on the context. We can only reliably assume that a literal constant is
2.255 + # an instance: all other "instances" may actually be classes in certain
2.256 + # cases.
2.257 +
2.258 + target = node._expr
2.259 + instance_target = isinstance(target, Const)
2.260 +
2.261 + # Attempt to deduce attributes from explicit annotations.
2.262 +
2.263 + attrs = self.possible_attributes_from_annotation(node)
2.264 +
2.265 + if len(attrs) == 1:
2.266 + attr, value = attrs[0]
2.267 +
2.268 + # Constant values can be obtained directly.
2.269 +
2.270 + v = self._generateValue(value)
2.271 + if v: return v
2.272 +
2.273 + # Static attributes can be obtained via their parent.
2.274 +
2.275 + if attr.is_static_attribute():
2.276 + return compiler.ast.CallFunc(
2.277 + special_name(instance_target and "__loadattrcontext__" or "__loadattr__"),
2.278 + [self._generateValue(attr.parent), special_name(node.attrname)])
2.279 +
2.280 + # Attributes of self, which is by definition an instance.
2.281 +
2.282 + if self.provides_self_access(node, unit):
2.283 +
2.284 + # Find instance attributes.
2.285 +
2.286 + attr = unit.parent.instance_attributes().get(node.attrname)
2.287 +
2.288 + if attr:
2.289 +
2.290 + # Emit self.attrname without context overriding.
2.291
2.292 - # NOTE: Known targets:
2.293 - # NOTE: class.__class__ => __builtins__.type
2.294 - # NOTE: __loadaddress__ and __loadaddresscontext__
2.295 + return compiler.ast.CallFunc(
2.296 + special_name("__loadattr__"), [
2.297 + accessor, special_name(node.attrname)
2.298 + ])
2.299 +
2.300 + # Find class attributes.
2.301 + # The context will be overridden for compatible class attributes
2.302 + # only.
2.303 +
2.304 + attr = unit.parent.get(node.attrname)
2.305 +
2.306 + if attr:
2.307 +
2.308 + # Constant attributes.
2.309 +
2.310 + if attr.is_strict_constant():
2.311 + v = self._generateValue(attr.get_value())
2.312 + if v: return v
2.313 +
2.314 + # Compatible class attributes.
2.315
2.316 - # NOTE: Attributes of self.
2.317 + if attr.defined_within_hierarchy():
2.318 + return compiler.ast.CallFunc(
2.319 + special_name("__loadattrcontext__"), [
2.320 + self._generateValue(attr.parent), special_name(node.attrname)
2.321 + ])
2.322 +
2.323 + # Incompatible class attributes.
2.324 +
2.325 + elif attr.defined_outside_hierarchy():
2.326 + return compiler.ast.CallFunc(
2.327 + special_name("__loadattr__"), [
2.328 + self._generateValue(attr.parent), special_name(node.attrname)
2.329 + ])
2.330 +
2.331 + # Unknown or mixed compatibility.
2.332 +
2.333 + return compiler.ast.CallFunc(
2.334 + special_name("__loadattrcontextcond__"), [
2.335 + self._generateValue(attr.parent), special_name(node.attrname)
2.336 + ])
2.337
2.338 # Usage observations.
2.339
2.340 - possible_types = self.possible_accessor_types(node, defining_users=0)
2.341 + targets = self.possible_accessors_from_usage(node, defining_users=0)
2.342
2.343 # Record whether types were already deduced. If not, get types using
2.344 # only this attribute.
2.345
2.346 - if not possible_types:
2.347 - possible_types = self.get_possible_types(node.attrname)
2.348 + if not targets:
2.349 + targets = self.possible_accessors_for_attribute(node.attrname)
2.350
2.351 - attributes = self.get_attributes(possible_types, node.attrname)
2.352 + attrs = self.get_attributes(targets, node.attrname)
2.353
2.354 # Generate optimisations where only a single attribute applies.
2.355
2.356 - if len(attributes) == 1:
2.357 - value, target, target_name = attributes[0]
2.358 -
2.359 - # Static attributes.
2.360 -
2.361 - if value is not None:
2.362 + if len(attrs) == 1:
2.363 + attr = attrs[0]
2.364
2.365 - # class.__class__ => __builtins__.type
2.366 + # Static attributes, but potentially non-static targets.
2.367
2.368 - if node.attrname == "__class__":
2.369 - return compiler.ast.CallFunc(
2.370 - special_name("__loadaddress__"),
2.371 - [special_name("__builtins__"), special_name("type")]
2.372 - )
2.373 + if attr.is_static_attribute():
2.374
2.375 # Static attributes may be accompanied by a different context
2.376 # depending on the accessor.
2.377 # NOTE: Should determine whether the context is always replaced.
2.378
2.379 return compiler.ast.CallFunc(
2.380 - special_name("__loadaddresscontextcond__"),
2.381 + special_name(instance_target and "__loadattrcontext__" or "__loadattrcontextcond__"),
2.382 [accessor, special_name(node.attrname)]
2.383 )
2.384
2.385 @@ -705,11 +787,43 @@
2.386
2.387 # With no usable deductions, generate a table-based access.
2.388
2.389 - return compiler.ast.CallFunc(
2.390 - special_name("__loadattrindex__"),
2.391 + access = compiler.ast.CallFunc(
2.392 + special_name("__loadattrindexcontextcond__"),
2.393 [accessor, special_name(node.attrname)]
2.394 )
2.395
2.396 + # class.__class__ => __builtins__.type
2.397 +
2.398 + if node.attrname == "__class__":
2.399 +
2.400 + # __storetemp__(n, <accessor>)
2.401 + # __isclass__(n) and __loadattr__(__builtins__, type) or <access>
2.402 +
2.403 + temp = quoted_name(unit.temp_usage)
2.404 + unit.temp_usage += 1
2.405 +
2.406 + return compiler.ast.Stmt([
2.407 + compiler.ast.CallFunc(special_name("__storetemp__"), [temp, access]),
2.408 + compiler.ast.Or([
2.409 + compiler.ast.And([
2.410 + compiler.ast.CallFunc(
2.411 + special_name("__isclass__"),
2.412 + [compiler.ast.CallFunc(special_name("__loadtemp__"), [temp])]
2.413 + ),
2.414 + compiler.ast.CallFunc(
2.415 + special_name("__loadattr__"),
2.416 + [special_name("__builtins__"), special_name("type")]
2.417 + )
2.418 + ]),
2.419 + access
2.420 + ])
2.421 + ])
2.422 +
2.423 + # General accesses.
2.424 +
2.425 + else:
2.426 + return access
2.427 +
2.428 def visitGenExpr(self, node):
2.429 return compiler.ast.GenExpr(self.dispatch(node.code))
2.430
2.431 @@ -795,53 +909,31 @@
2.432 return self.visitAssName(node, expr)
2.433
2.434 unit = self.get_unit()
2.435 + attr = node._attr
2.436 + scope = node._scope
2.437
2.438 # Generate appropriate name access operation.
2.439
2.440 - scope = getattr(node, "_scope", None)
2.441 - if not scope:
2.442 - attr, scope, from_name = self.get_unit()._get_with_scope(node.name)
2.443 -
2.444 if scope == "constant":
2.445 return node
2.446 - elif scope == "local":
2.447
2.448 - # Function locals are referenced normally.
2.449 + # Function locals are referenced normally.
2.450
2.451 - if isinstance(unit, Function):
2.452 - return node
2.453 -
2.454 - # Class locals are class attribute references.
2.455 - # Module locals are module attribute references.
2.456 + elif scope == "local" and isinstance(unit, Function):
2.457 + return node
2.458
2.459 - elif isinstance(unit, (Class, Module)):
2.460 - return compiler.ast.CallFunc(
2.461 - special_name("__loadaddress__"),
2.462 - [quoted_name(unit.full_name()), special_name(node.name)]
2.463 - )
2.464 - else:
2.465 - raise TranslateError("Program unit has no local %r." % name)
2.466 + # Other attributes should already be resolved.
2.467
2.468 - elif scope == "global":
2.469 -
2.470 - # Globals are references to module attributes.
2.471 -
2.472 + elif attr is not None:
2.473 return compiler.ast.CallFunc(
2.474 - special_name("__loadaddress__"),
2.475 - [quoted_name(self.get_module().full_name()), special_name(node.name)]
2.476 + special_name("__loadattr__"),
2.477 + [quoted_ref(attr.parent), special_name(node.name)]
2.478 )
2.479
2.480 - elif scope == "builtin":
2.481 -
2.482 - # Builtins are accessed via the __builtins__ module.
2.483 -
2.484 - return compiler.ast.CallFunc(
2.485 - special_name("__loadaddress__"),
2.486 - [special_name("__builtins__"), special_name(node.name)]
2.487 - )
2.488 + # NOTE: Unknown attributes may arise because a class attribute has been
2.489 + # NOTE: optimised away.
2.490
2.491 else:
2.492 - # NOTE: This may happen because a class attribute is optimised away.
2.493 return compiler.ast.CallFunc(
2.494 special_name("__loadunknown__"),
2.495 [special_name(node.name)]
2.496 @@ -895,24 +987,25 @@
2.497 def possible_accessor_types(self, node, defining_users=1):
2.498 return set([tn for (tn, st) in ASTVisitor.possible_accessor_types(self, node, defining_users)])
2.499
2.500 - def get_possible_types(self, attrname):
2.501 - objtable = self.program.get_object_table()
2.502 - return objtable.any_possible_objects([attrname])
2.503 + def get_possible_accessors(self, attrname):
2.504 +
2.505 + "Return a list of accessors supporting 'attrname'."
2.506 +
2.507 + targets = []
2.508
2.509 - def get_attributes(self, possible_types, attrname):
2.510 - objtable = self.program.get_object_table()
2.511 + for target_name in self.objtable.any_possible_objects([attrname]):
2.512 + targets.append(self.objtable.get_object(target_name))
2.513 +
2.514 + return targets
2.515 +
2.516 + def get_attributes(self, targets, attrname):
2.517 +
2.518 + "Return a list of attributes for 'targets' supporting 'attrname'."
2.519 +
2.520 attributes = []
2.521 - for target_name in possible_types:
2.522 - target = objtable.get_object(target_name)
2.523 - try:
2.524 - attr = objtable.access(target_name, attrname)
2.525 - except TableError:
2.526 - continue
2.527 - if attr.is_static_attribute():
2.528 - for v in attr.get_values():
2.529 - attributes.append((v, target, target_name))
2.530 - else:
2.531 - attributes.append((None, target, target_name))
2.532 +
2.533 + for target in targets:
2.534 + attributes.append(self.objtable.access(target.full_name(), attrname))
2.535
2.536 return attributes
2.537