1 #!/usr/bin/env python 2 3 """ 4 Simplified program utilities. 5 6 Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk> 7 8 This software is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 2 of 11 the License, or (at your option) any later version. 12 13 This software is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public 19 License along with this library; see the file LICENCE.txt 20 If not, write to the Free Software Foundation, Inc., 21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 22 """ 23 24 from compiler.visitor import ASTVisitor 25 26 # Exceptions. 27 28 class SimplifiedError(Exception): 29 30 "An error in the annotation process." 31 32 def __init__(self, exc, node, *args): 33 34 """ 35 Initialise the error with an existing exception 'exc', the 'node' at 36 which this error occurs, along with additional optional arguments. 37 """ 38 39 Exception.__init__(self, *args) 40 self.nodes = [node] 41 self.exc = exc 42 43 def add(self, node): 44 45 "Add the given 'node' to the path of nodes leading from the exception." 46 47 self.nodes.append(node) 48 49 def __str__(self): 50 51 "Return a string showing the principal exception details." 52 53 return "%s, %s" % (self.exc, self.nodes) 54 55 # Elementary visitor support. 56 57 class Visitor(ASTVisitor): 58 59 "A visitor base class." 60 61 def __init__(self): 62 ASTVisitor.__init__(self) 63 64 def default(self, node, *args): 65 raise SimplifiedError, (None, node) 66 67 def dispatch(self, node, *args): 68 return ASTVisitor.dispatch(self, node, *args) 69 70 def dispatches(self, nodes, *args): 71 results = [] 72 for node in nodes: 73 results.append(self.dispatch(node, *args)) 74 return results 75 76 def dispatch_dict(self, d, *args): 77 results = {} 78 for name, node in d.items(): 79 results[name] = self.dispatch(node, *args) 80 return results 81 82 # Unique name registration. 83 84 class Naming: 85 86 "Maintain records of unique names for each simple name." 87 88 index_separator = "-" 89 90 def __init__(self): 91 self.names = {} 92 93 def get(self, obj): 94 return obj._unique_name 95 96 def set(self, obj, name): 97 if hasattr(obj, "_unique_name"): 98 return 99 if not self.names.has_key(name): 100 self.names[name] = 0 101 n = self.names[name] + 1 102 self.names[name] = n 103 obj._unique_name = "%s%s%d" % (name, self.index_separator, n) 104 105 def name(obj, name): 106 107 "Return a unique name for the given 'obj', indicating the base 'name'." 108 109 naming.set(obj, name) 110 return naming.get(obj) 111 112 # Naming singleton. 113 114 naming = Naming() 115 116 # Named nodes are those which can be referenced in some way. 117 118 class WithName: 119 120 "Node naming." 121 122 def __init__(self): 123 124 "Initialise the object's full name." 125 126 self._full_name = name(self, self.name or "$untitled") 127 128 def full_name(self): 129 130 "Return the object's full name." 131 132 return self._full_name 133 134 # Comparable nodes based on naming. 135 136 class Comparable: 137 138 "Comparable nodes implementing the 'full_name' method." 139 140 def __eq__(self, other): 141 142 "This object is equal to 'other' if the full names are the same." 143 144 # NOTE: Single instance: all instances are the same 145 # NOTE: Multiple instances: all instances are different 146 if hasattr(other, "full_name"): 147 return self.full_name() == other.full_name() 148 else: 149 return NotImplemented 150 151 def __hash__(self): 152 153 "The hash of this object is based on its full name." 154 155 return hash(self.full_name()) 156 157 # Structure nodes indicating namespace-bearing objects. 158 159 class Structure(Comparable): 160 161 "A non-program node containing some kind of namespace." 162 163 def __init__(self, **kw): 164 for name, value in kw.items(): 165 setattr(self, name, value) 166 167 # vim: tabstop=4 expandtab shiftwidth=4