# HG changeset patch # User Paul Boddie # Date 1386463303 -3600 # Node ID fe0c7e0224b51c679ff1a686cb4ed588c71c70ad # Parent 1d18a182148bb042b4e087ad30bbc063f793d529 Support operator method access using the generic attribute access mechanism. diff -r 1d18a182148b -r fe0c7e0224b5 micropython/common.py --- a/micropython/common.py Sun Dec 08 00:05:51 2013 +0100 +++ b/micropython/common.py Sun Dec 08 01:41:43 2013 +0100 @@ -117,14 +117,14 @@ return isinstance(value, (Const, Constant)) - def provides_self_access(self, node, unit): + def provides_self_access(self, expr, unit): """ - Return whether the 'node' in the given 'unit' provides a self-based + Return whether the 'expr' in the given 'unit' provides a self-based attribute access. """ - attr_value = self.get_attribute_and_value(node._expr) + attr_value = self.get_attribute_and_value(expr) if attr_value: target, value = attr_value @@ -134,20 +134,19 @@ return False - def possible_attributes_from_annotation(self, node): + def possible_attributes_from_annotation(self, expr, attr, attrname): """ - Return (attribute, value) details provided by any _expr or _attr - annotations on 'node'. + Return (attribute, value) details provided by the 'expr' or 'attr' + annotations on a node for an access involving 'attrname'. """ - attr_value = self.get_attribute_and_value(node._attr) + attr_value = self.get_attribute_and_value(attr) if attr_value: return [attr_value] attrs = set() - expr = node._expr if expr: @@ -163,13 +162,13 @@ # attribute. for expr in exprs: - attr = expr.all_attributes().get(node.attrname) + found_attr = expr.all_attributes().get(attrname) # Where an attribute can be obtained, record its # details. - if attr: - attrs.add((attr, attr.get_value())) + if found_attr: + attrs.add((found_attr, found_attr.get_value())) return attrs diff -r 1d18a182148b -r fe0c7e0224b5 micropython/deduce.py --- a/micropython/deduce.py Sun Dec 08 00:05:51 2013 +0100 +++ b/micropython/deduce.py Sun Dec 08 01:41:43 2013 +0100 @@ -90,8 +90,6 @@ that can be used by subsequent activities. """ - unit = self.get_unit() - # Remember to permit deductions on the expression node. Here, we may # also obtain a concrete type associated with an instantiation. @@ -104,14 +102,24 @@ # an instance: all other "instances" may actually be classes in certain # cases. - target = node._expr + self._annotateAttr(node, node._expr, node.attrname) + + def _annotateAttr(self, node, target, attrname): + + """ + Annotate the access on the given 'node' using the 'target' and + 'attrname' information. + """ + + unit = self.get_unit() + instance_target = isinstance(target, TypedInstance) typed_instance_attr = isinstance(target, BaseAttr) and isinstance(target.get_value(), TypedInstance) - self_access = self.provides_self_access(node, unit) + self_access = self.provides_self_access(target, unit) # Attempt to deduce attributes from explicit annotations. - node._attrs_deduced = attrs = self.possible_attributes_from_annotation(node) + node._attrs_deduced = attrs = self.possible_attributes_from_annotation(target, node._attr, attrname) if len(attrs) == 1: for attr, value in attrs: @@ -168,11 +176,11 @@ # Find instance attributes. - attr = cls.instance_attributes().get(node.attrname) + attr = cls.instance_attributes().get(attrname) # Where self is involved, descendants can also provide attributes. - attrs = self_access and filter(None, [desc.instance_attributes().get(node.attrname) for desc in cls.descendants]) or [] + attrs = self_access and filter(None, [desc.instance_attributes().get(attrname) for desc in cls.descendants]) or [] # A "leaf" class whose instances provide an attribute. @@ -207,7 +215,7 @@ # The context will be overridden for compatible class attributes # only. - attr = cls.all_class_attributes().get(node.attrname) + attr = cls.all_class_attributes().get(attrname) if attr: @@ -252,7 +260,7 @@ # only this attribute. if not specific_targets or not targets: - attribute_targets = self.possible_accessors_for_attribute(node.attrname) + attribute_targets = self.possible_accessors_for_attribute(attrname) if not specific_targets: specific_targets = attribute_targets if not targets: @@ -260,8 +268,8 @@ # Get the attributes from the deduced targets. - node._attrs_deduced_from_specific_usage = self.get_attributes(specific_targets, node.attrname) - node._attrs_deduced_from_usage = attrs = self.get_attributes(targets, node.attrname) + node._attrs_deduced_from_specific_usage = self.get_attributes(specific_targets, attrname) + node._attrs_deduced_from_usage = attrs = self.get_attributes(targets, attrname) # Generate optimisations where only a single attribute applies. @@ -364,6 +372,28 @@ if value and isinstance(value, Class): return TypedInstance(value) + def _visitOperator(self, node): + + "Annotate operators with function information." + + self._annotateAttr(node, node._module, node._attr.name) + + visitAdd = \ + visitBitand = \ + visitBitor = \ + visitBitxor = \ + visitDiv = \ + visitFloorDiv = \ + visitInvert = \ + visitLeftShift = \ + visitMod = \ + visitMul = \ + visitPower = \ + visitRightShift = \ + visitSub = \ + visitUnaryAdd = \ + visitUnarySub = _visitOperator + # Convenience functions. def deduce(program): diff -r 1d18a182148b -r fe0c7e0224b5 micropython/inspect.py --- a/micropython/inspect.py Sun Dec 08 00:05:51 2013 +0100 +++ b/micropython/inspect.py Sun Dec 08 01:41:43 2013 +0100 @@ -665,6 +665,7 @@ operator_module = self._ensureOperators(node) operator_fn = operator_functions[operator_name or node.__class__.__name__] self.use_specific_attribute(operator_module.full_name(), operator_fn) + node._attr = node._module.get(operator_fn) or make_instance() return self.OP(node) def _visitAttr(self, expr, attrname, node): diff -r 1d18a182148b -r fe0c7e0224b5 micropython/syspython.py --- a/micropython/syspython.py Sun Dec 08 00:05:51 2013 +0100 +++ b/micropython/syspython.py Sun Dec 08 01:41:43 2013 +0100 @@ -556,32 +556,31 @@ # Expression-related helper methods. def _visitBitBinary(self, node): - op_name = operator_functions[node.__class__.__name__] + attr = self._visitAttr(node, special_name(node._module.full_name()), node._attr.name) last = self.dispatch(node.nodes[0]) for n in node.nodes[1:]: - last = compiler.ast.CallFunc( - special_name("apply"), - [module_attribute("operator", op_name), last, self.dispatch(n)] + last = self._visitCallFunc( + node._attr, + [attr, last, self.dispatch(n)] ) return last def _visitBinary(self, node): - op_name = operator_functions[node.__class__.__name__] + attr = self._visitAttr(node, special_name(node._module.full_name()), node._attr.name) - return compiler.ast.CallFunc( - special_name("apply"), - [module_attribute("operator", op_name), - self.dispatch(node.left), self.dispatch(node.right)] + return self._visitCallFunc( + node._attr, + [attr, self.dispatch(node.left), self.dispatch(node.right)] ) def _visitUnary(self, node): - op_name = operator_functions[node.__class__.__name__] + attr = self._visitAttr(node, special_name(node._module.full_name()), node._attr.name) - return compiler.ast.CallFunc( - special_name("apply"), - [module_attribute("operator", op_name), self.dispatch(node.expr)] + return self._visitCallFunc( + node._attr, + [attr, self.dispatch(node.expr)] ) def _generateValue(self, value): @@ -598,7 +597,7 @@ return None - def _visitAttr(self, node, expr=None): + def _visitAttr(self, node, accessor, attrname, expr=None): unit = self.get_unit() # Choose the appropriate special functions. @@ -606,8 +605,6 @@ (opattrcontext, opattrcontextcond, opattr, opattrindexcontextcond, opconstant) = \ expr and assattr_functions or getattr_functions - accessor = self.dispatch(node.expr) - # Generate already-deduced accesses. if node._access_type == "constant": @@ -646,13 +643,13 @@ # Handle unsupported operations. if not op: - raise TranslateError("Storing of class attribute %r via self not permitted." % node.attrname) + raise TranslateError("Storing of class attribute %r via self not permitted." % attrname) # Define the arguments: accessor, attribute name and optional value. args = [ parent or accessor, - special_name(node.attrname) + special_name(attrname) ] if expr: @@ -668,21 +665,21 @@ # Positioned accesses are normal accesses via instances. if node._access_type == "positioned": - args = [accessor, special_name(node.attrname)] + args = [accessor, special_name(attrname)] if expr: args.append(expr) return compiler.ast.CallFunc(special_name(opattr), args) # With no usable deductions, generate a table-based access. - args = [accessor, special_name(node.attrname)] + args = [accessor, special_name(attrname)] if expr: args.append(expr) access = compiler.ast.CallFunc(special_name(opattrindexcontextcond), args) # class.__class__ => __builtins__.type - if node.attrname == "__class__": + if attrname == "__class__": # storetemp(n, ) # isclass(n) and __builtins__.type or @@ -724,7 +721,7 @@ if compiler.ast.is_deletion(node): return compiler.ast.Stmt([]) - return self._visitAttr(node, expr) + return self._visitAttr(node, self.dispatch(node.expr), node.attrname, expr) def visitAssList(self, node, expr=None): @@ -764,22 +761,20 @@ visitAssTuple = visitAssList - def visitBitand(self, node): - self._visitBitBinary(node) + visitBitand = _visitBitBinary - def visitBitor(self, node): - self._visitBitBinary(node) + visitBitor = _visitBitBinary - def visitBitxor(self, node): - self._visitBitBinary(node) + visitBitxor = _visitBitBinary def visitCallFunc(self, node): # Determine whether the invocation target is known. args = [self.dispatch(node.node)] + [self.dispatch(arg) for arg in node.args] + return self._visitCallFunc(node.node, args, node.star_args, node.dstar_args) - target = node.node + def _visitCallFunc(self, target, args, star_args=None, dstar_args=None): # Attribute information is only known for specific accessors. @@ -830,8 +825,8 @@ return compiler.ast.CallFunc( special_name(op), args, - node.star_args and self.dispatch(node.star_args), - node.dstar_args and self.dispatch(node.dstar_args) + star_args and self.dispatch(star_args), + dstar_args and self.dispatch(dstar_args) ) def visitCompare(self, node): @@ -881,7 +876,7 @@ return self._visitBinary(node) def visitGetattr(self, node, expr=None): - return self._visitAttr(node, expr) + return self._visitAttr(node, self.dispatch(node.expr), node.attrname, expr) def visitGenExpr(self, node): return compiler.ast.GenExpr(self.dispatch(node.code))