micropython

Change of micropython/common.py

645:bdc835dee81d
micropython/common.py syspython-as-target
     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      """