Lichen

referencing.py

25:fa9a7f9773dc
2016-09-04 Paul Boddie Minor comment reformatting.
     1 #!/usr/bin/env python     2      3 """     4 Reference abstractions.     5      6 Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20 """    21     22 class Reference:    23     24     "A reference abstraction."    25     26     def __init__(self, kind, origin=None, name=None):    27     28         """    29         Initialise a reference using 'kind' to indicate the kind of object,    30         'origin' to indicate the actual origin of a referenced object, and a    31         'name' indicating an alias for the object in the program structure.    32         """    33     34         if isinstance(kind, Reference):    35             raise ValueError, (kind, origin)    36         self.kind = kind    37         self.origin = origin    38         self.name = name    39     40     def __repr__(self):    41         return "Reference(%r, %r, %r)" % (self.kind, self.origin, self.name)    42     43     def __str__(self):    44     45         """    46         Serialise the reference as '<var>' or a description incorporating the    47         kind and origin.    48         """    49     50         if self.kind == "<var>":    51             return self.kind    52         else:    53             return "%s:%s" % (self.kind, self.origin)    54     55     def __hash__(self):    56     57         "Hash instances using the kind and origin only."    58     59         return hash((self.kind, self.get_origin()))    60     61     def __cmp__(self, other):    62     63         "Compare with 'other' using the kind and origin only."    64     65         if isinstance(other, Reference):    66             return cmp((self.kind, self.get_origin()), (other.kind, other.get_origin()))    67         else:    68             return cmp(str(self), other)    69     70     def get_name(self):    71     72         "Return the name used for this reference."    73     74         return self.name    75     76     def get_origin(self):    77     78         "Return the origin of the reference."    79     80         return self.kind != "<var>" and self.origin or None    81     82     def get_kind(self):    83     84         "Return the kind of object referenced."    85     86         return self.kind    87     88     def has_kind(self, kinds):    89     90         """    91         Return whether the reference describes an object from the given 'kinds',    92         where such kinds may be "<class>", "<function>", "<instance>",    93         "<module>" or "<var>".    94         """    95     96         if not isinstance(kinds, (list, tuple)):    97             kinds = [kinds]    98         return self.get_kind() in kinds    99    100     def get_path(self):   101    102         "Return the attribute names comprising the path to the origin."   103    104         return self.get_origin().split(".")   105    106     def static(self):   107    108         "Return this reference if it refers to a static object, None otherwise."   109    110         return not self.has_kind(["<var>", "<instance>"]) and self or None   111    112     def final(self):   113    114         "Return a reference to either a static object or None."   115    116         static = self.static()   117         return static and static.origin or None   118    119     def instance_of(self):   120    121         "Return a reference to an instance of the referenced class."   122    123         return self.has_kind("<class>") and Reference("<instance>", self.origin) or None   124    125     def as_var(self):   126    127         """   128         Return a variable version of this reference. Any origin information is   129         discarded since variable references are deliberately ambiguous.   130         """   131    132         return Reference("<var>", None, self.name)   133    134     def alias(self, name):   135    136         "Alias this reference employing 'name'."   137    138         return Reference(self.get_kind(), self.get_origin(), name)   139    140     def ancestors(self):   141    142         """   143         Return ancestors of this reference's origin in order of decreasing   144         depth.   145         """   146    147         if not self.origin:   148             return None   149    150         parts = self.get_origin().split(".")   151         ancestors = []   152    153         for i in range(len(parts) - 1, 0, -1):   154             ancestors.append(".".join(parts[:i]))   155    156         return ancestors   157    158 def decode_reference(s, name=None):   159    160     "Decode 's', making a reference."   161    162     if isinstance(s, Reference):   163         return s.alias(name)   164    165     # Null value.   166    167     elif not s:   168         return Reference("<var>", None, name)   169    170     # Kind and origin.   171    172     elif ":" in s:   173         kind, origin = s.split(":")   174         return Reference(kind, origin, name)   175    176     # Kind-only, origin is indicated name.   177    178     elif s[0] == "<":   179         return Reference(s, name, name)   180    181     # Module-only.   182    183     else:   184         return Reference("<module>", s, name)   185    186 # vim: tabstop=4 expandtab shiftwidth=4