1.1 --- a/micropython/syspython.py Sat Apr 20 00:59:58 2013 +0200
1.2 +++ b/micropython/syspython.py Thu Apr 25 18:08:32 2013 +0200
1.3 @@ -43,6 +43,15 @@
1.4 def quoted_name(s):
1.5 return compiler.ast.Const(s)
1.6
1.7 +# Special function names.
1.8 +# NOTE: Some of the assignment operations should not be supported unless
1.9 +# NOTE: attribute usage observations are being made.
1.10 +
1.11 +assattr_functions = ("__storeattrcontext__", "__storeattrcontext__", "__storeattr__",
1.12 + "__storeattrindex__", None)
1.13 +getattr_functions = ("__loadattrcontext__", "__loadattrcontextcond__", "__loadattr__",
1.14 + "__loadattrindex__", "__loadattrindexcontextcond__")
1.15 +
1.16 # Source code classes.
1.17
1.18 class ConvertedSource(ASTVisitor):
1.19 @@ -475,6 +484,96 @@
1.20
1.21 return None
1.22
1.23 + def _visitAttr(self, node, expr=None):
1.24 + unit = self.get_unit()
1.25 +
1.26 + # Choose the appropriate special functions.
1.27 +
1.28 + (opattrcontext, opattrcontextcond, opattr,
1.29 + opattrindex, opattrindexcontextcond) = expr and assattr_functions or getattr_functions
1.30 +
1.31 + accessor = self.dispatch(node.expr)
1.32 +
1.33 + # Generate already-deduced accesses.
1.34 +
1.35 + if node._access_type == "constant":
1.36 + return self._generateValue(node._value_deduced)
1.37 +
1.38 + # Generate accesses via static objects and instances.
1.39 +
1.40 + if node._attr_deduced:
1.41 + if node._set_context == "set":
1.42 + op = opattrcontext
1.43 + elif node._set_context == "cond":
1.44 + op = opattrcontextcond
1.45 + else:
1.46 + op = opattr
1.47 +
1.48 + # Handle unsupported operations.
1.49 +
1.50 + if not op:
1.51 + raise TranslateError("Storing of class attribute %r via self not permitted." % node.attrname)
1.52 +
1.53 + # Define the arguments: accessor, attribute name and optional value.
1.54 +
1.55 + args = [
1.56 + node._access_type == "static" and \
1.57 + self._generateValue(node._attr_deduced.parent) or accessor,
1.58 + special_name(node.attrname)
1.59 + ]
1.60 +
1.61 + if expr:
1.62 + args.append(expr)
1.63 +
1.64 + return compiler.ast.CallFunc(special_name(op), args)
1.65 +
1.66 + # Positioned accesses are normal accesses via instances.
1.67 +
1.68 + if node._access_type == "positioned":
1.69 + args = [accessor, special_name(node.attrname)]
1.70 + if expr:
1.71 + args.append(expr)
1.72 + return compiler.ast.CallFunc(special_name(opattr), args)
1.73 +
1.74 + # With no usable deductions, generate a table-based access.
1.75 +
1.76 + args = [accessor, special_name(node.attrname)]
1.77 + if expr:
1.78 + args.append(expr)
1.79 + access = compiler.ast.CallFunc(special_name(opattrindexcontextcond), args)
1.80 +
1.81 + # class.__class__ => __builtins__.type
1.82 +
1.83 + if node.attrname == "__class__":
1.84 +
1.85 + # __storetemp__(n, <accessor>)
1.86 + # __isclass__(n) and __loadattr__(__builtins__, type) or <access>
1.87 +
1.88 + temp = quoted_name(unit.temp_usage)
1.89 + unit.temp_usage += 1
1.90 +
1.91 + return compiler.ast.Stmt([
1.92 + compiler.ast.CallFunc(special_name("__storetemp__"), [temp, access]),
1.93 + compiler.ast.Or([
1.94 + compiler.ast.And([
1.95 + compiler.ast.CallFunc(
1.96 + special_name("__isclass__"),
1.97 + [compiler.ast.CallFunc(special_name("__loadtemp__"), [temp])]
1.98 + ),
1.99 + compiler.ast.CallFunc(
1.100 + special_name("__loadattr__"),
1.101 + [special_name("__builtins__"), special_name("type")]
1.102 + )
1.103 + ]),
1.104 + access
1.105 + ])
1.106 + ])
1.107 +
1.108 + # General accesses.
1.109 +
1.110 + else:
1.111 + return access
1.112 +
1.113 # Expressions.
1.114
1.115 def visitAdd(self, node):
1.116 @@ -484,63 +583,7 @@
1.117 return compiler.ast.And([self.dispatch(n) for n in node.nodes])
1.118
1.119 def visitAssAttr(self, node, expr):
1.120 -
1.121 - # NOTE: Derived from Getattr support.
1.122 -
1.123 - accessor = self.dispatch(node.expr)
1.124 -
1.125 - # NOTE: Replicate the _generateAttr logic.
1.126 - # NOTE: Should be able to store concrete value details on generated
1.127 - # NOTE: nodes, such as whether an expression yields a constant.
1.128 -
1.129 - # NOTE: Known targets:
1.130 - # NOTE: __storeattr__ and __storeattrcontext__
1.131 -
1.132 - # NOTE: Attributes of self.
1.133 -
1.134 - # Usage observations.
1.135 -
1.136 - targets = self.possible_accessors_from_usage(node, defining_users=0)
1.137 -
1.138 - # Record whether types were already deduced. If not, get types using
1.139 - # only this attribute.
1.140 -
1.141 - if not targets:
1.142 - targets = self.possible_accessors_for_attribute(node.attrname)
1.143 -
1.144 - attrs = self.get_attributes(targets, node.attrname)
1.145 -
1.146 - # Generate optimisations where only a single attribute applies.
1.147 -
1.148 - if len(attrs) == 1:
1.149 - attr = attrs[0]
1.150 -
1.151 - # Static attributes.
1.152 -
1.153 - if attr.is_static_attribute():
1.154 -
1.155 - # Static attributes may be accompanied by a different context
1.156 - # depending on the accessor.
1.157 - # NOTE: Should determine whether the context is always replaced.
1.158 -
1.159 - return compiler.ast.CallFunc(
1.160 - special_name("__storeattrcontextcond__"),
1.161 - [accessor, special_name(node.attrname), expr]
1.162 - )
1.163 -
1.164 - # Non-static attributes.
1.165 -
1.166 - return compiler.ast.CallFunc(
1.167 - special_name("__storeattr__"),
1.168 - [accessor, special_name(node.attrname), expr]
1.169 - )
1.170 -
1.171 - # With no usable deductions, generate a table-based access.
1.172 -
1.173 - return compiler.ast.CallFunc(
1.174 - special_name("__storeattrindex__"),
1.175 - [accessor, special_name(node.attrname), expr]
1.176 - )
1.177 + return self._visitAttr(node, expr)
1.178
1.179 def visitAssList(self, node, expr):
1.180 return compiler.ast.Stmt([
1.181 @@ -660,169 +703,7 @@
1.182 return self._visitBinary(node)
1.183
1.184 def visitGetattr(self, node, expr=None):
1.185 - if expr:
1.186 - return self.visitAssAttr(node, expr)
1.187 -
1.188 - unit = self.get_unit()
1.189 -
1.190 - accessor = self.dispatch(node.expr)
1.191 -
1.192 - # The target, on which the access is performed, may influence the effect
1.193 - # on the context. We can only reliably assume that a literal constant is
1.194 - # an instance: all other "instances" may actually be classes in certain
1.195 - # cases.
1.196 -
1.197 - target = node._expr
1.198 - instance_target = isinstance(target, Const)
1.199 -
1.200 - # Attempt to deduce attributes from explicit annotations.
1.201 -
1.202 - attrs = self.possible_attributes_from_annotation(node)
1.203 -
1.204 - if len(attrs) == 1:
1.205 - attr, value = attrs[0]
1.206 -
1.207 - # Constant values can be obtained directly.
1.208 -
1.209 - v = self._generateValue(value)
1.210 - if v: return v
1.211 -
1.212 - # Static attributes can be obtained via their parent.
1.213 -
1.214 - if attr.is_static_attribute():
1.215 - return compiler.ast.CallFunc(
1.216 - special_name(instance_target and "__loadattrcontext__" or "__loadattr__"),
1.217 - [self._generateValue(attr.parent), special_name(node.attrname)])
1.218 -
1.219 - # Attributes of self, which is by definition an instance.
1.220 -
1.221 - if self.provides_self_access(node, unit):
1.222 -
1.223 - # Find instance attributes.
1.224 -
1.225 - attr = unit.parent.instance_attributes().get(node.attrname)
1.226 -
1.227 - if attr:
1.228 -
1.229 - # Emit self.attrname without context overriding.
1.230 -
1.231 - return compiler.ast.CallFunc(
1.232 - special_name("__loadattr__"), [
1.233 - accessor, special_name(node.attrname)
1.234 - ])
1.235 -
1.236 - # Find class attributes.
1.237 - # The context will be overridden for compatible class attributes
1.238 - # only.
1.239 -
1.240 - attr = unit.parent.get(node.attrname)
1.241 -
1.242 - if attr:
1.243 -
1.244 - # Constant attributes.
1.245 -
1.246 - if attr.is_strict_constant():
1.247 - v = self._generateValue(attr.get_value())
1.248 - if v: return v
1.249 -
1.250 - # Compatible class attributes.
1.251 -
1.252 - if attr.defined_within_hierarchy():
1.253 - return compiler.ast.CallFunc(
1.254 - special_name("__loadattrcontext__"), [
1.255 - self._generateValue(attr.parent), special_name(node.attrname)
1.256 - ])
1.257 -
1.258 - # Incompatible class attributes.
1.259 -
1.260 - elif attr.defined_outside_hierarchy():
1.261 - return compiler.ast.CallFunc(
1.262 - special_name("__loadattr__"), [
1.263 - self._generateValue(attr.parent), special_name(node.attrname)
1.264 - ])
1.265 -
1.266 - # Unknown or mixed compatibility.
1.267 -
1.268 - return compiler.ast.CallFunc(
1.269 - special_name("__loadattrcontextcond__"), [
1.270 - self._generateValue(attr.parent), special_name(node.attrname)
1.271 - ])
1.272 -
1.273 - # Usage observations.
1.274 -
1.275 - targets = self.possible_accessors_from_usage(node, defining_users=0)
1.276 -
1.277 - # Record whether types were already deduced. If not, get types using
1.278 - # only this attribute.
1.279 -
1.280 - if not targets:
1.281 - targets = self.possible_accessors_for_attribute(node.attrname)
1.282 -
1.283 - attrs = self.get_attributes(targets, node.attrname)
1.284 -
1.285 - # Generate optimisations where only a single attribute applies.
1.286 -
1.287 - if len(attrs) == 1:
1.288 - attr = attrs[0]
1.289 -
1.290 - # Static attributes, but potentially non-static targets.
1.291 -
1.292 - if attr.is_static_attribute():
1.293 -
1.294 - # Static attributes may be accompanied by a different context
1.295 - # depending on the accessor.
1.296 - # NOTE: Should determine whether the context is always replaced.
1.297 -
1.298 - return compiler.ast.CallFunc(
1.299 - special_name(instance_target and "__loadattrcontext__" or "__loadattrcontextcond__"),
1.300 - [accessor, special_name(node.attrname)]
1.301 - )
1.302 -
1.303 - # Non-static attributes.
1.304 -
1.305 - return compiler.ast.CallFunc(
1.306 - special_name("__loadattr__"),
1.307 - [accessor, special_name(node.attrname)]
1.308 - )
1.309 -
1.310 - # With no usable deductions, generate a table-based access.
1.311 -
1.312 - access = compiler.ast.CallFunc(
1.313 - special_name("__loadattrindexcontextcond__"),
1.314 - [accessor, special_name(node.attrname)]
1.315 - )
1.316 -
1.317 - # class.__class__ => __builtins__.type
1.318 -
1.319 - if node.attrname == "__class__":
1.320 -
1.321 - # __storetemp__(n, <accessor>)
1.322 - # __isclass__(n) and __loadattr__(__builtins__, type) or <access>
1.323 -
1.324 - temp = quoted_name(unit.temp_usage)
1.325 - unit.temp_usage += 1
1.326 -
1.327 - return compiler.ast.Stmt([
1.328 - compiler.ast.CallFunc(special_name("__storetemp__"), [temp, access]),
1.329 - compiler.ast.Or([
1.330 - compiler.ast.And([
1.331 - compiler.ast.CallFunc(
1.332 - special_name("__isclass__"),
1.333 - [compiler.ast.CallFunc(special_name("__loadtemp__"), [temp])]
1.334 - ),
1.335 - compiler.ast.CallFunc(
1.336 - special_name("__loadattr__"),
1.337 - [special_name("__builtins__"), special_name("type")]
1.338 - )
1.339 - ]),
1.340 - access
1.341 - ])
1.342 - ])
1.343 -
1.344 - # General accesses.
1.345 -
1.346 - else:
1.347 - return access
1.348 + return self._visitAttr(node, expr)
1.349
1.350 def visitGenExpr(self, node):
1.351 return compiler.ast.GenExpr(self.dispatch(node.code))
1.352 @@ -982,33 +863,6 @@
1.353 def visitUnarySub(self, node):
1.354 return self._visitUnary(node)
1.355
1.356 - # Type-related methods.
1.357 -
1.358 - def possible_accessor_types(self, node, defining_users=1):
1.359 - return set([tn for (tn, st) in ASTVisitor.possible_accessor_types(self, node, defining_users)])
1.360 -
1.361 - def get_possible_accessors(self, attrname):
1.362 -
1.363 - "Return a list of accessors supporting 'attrname'."
1.364 -
1.365 - targets = []
1.366 -
1.367 - for target_name in self.objtable.any_possible_objects([attrname]):
1.368 - targets.append(self.objtable.get_object(target_name))
1.369 -
1.370 - return targets
1.371 -
1.372 - def get_attributes(self, targets, attrname):
1.373 -
1.374 - "Return a list of attributes for 'targets' supporting 'attrname'."
1.375 -
1.376 - attributes = []
1.377 -
1.378 - for target in targets:
1.379 - attributes.append(self.objtable.access(target.full_name(), attrname))
1.380 -
1.381 - return attributes
1.382 -
1.383 # Convenience functions.
1.384
1.385 def convert(module, program, filename):