1 #!/usr/bin/env python 2 3 """ 4 Fix name-related operations. The code in this module operates upon nodes which 5 are produced when simplifying AST node trees originating from the compiler 6 module. 7 8 Copyright (C) 2006 Paul Boddie <paul@boddie.org.uk> 9 10 This software is free software; you can redistribute it and/or 11 modify it under the terms of the GNU General Public License as 12 published by the Free Software Foundation; either version 2 of 13 the License, or (at your option) any later version. 14 15 This software is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public 21 License along with this library; see the file LICENCE.txt 22 If not, write to the Free Software Foundation, Inc., 23 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 24 """ 25 26 from simplified import * 27 import compiler 28 29 # Fixing of name-related operations. 30 31 class Fixer(Visitor): 32 33 """ 34 The name fixer which traverses the program nodes, typically depth-first, 35 and maintains a record of name usage in the different namespaces. As a 36 consequence of various observations, some parts of the program node tree are 37 modified with different operations employed to those originally defined. 38 """ 39 40 def __init__(self): 41 Visitor.__init__(self) 42 43 # Satisfy visitor issues. 44 45 self.visitor = self 46 47 def process_all(self, visitor): 48 subprograms = [] 49 for subprogram in visitor.subprograms: 50 subprograms.append(self.process(subprogram)) 51 visitor.subprograms = subprograms 52 visitor.result = self.process(visitor.result) 53 return visitor 54 55 def process(self, node): 56 57 """ 58 Process a subprogram or module 'node', discovering from attributes on 59 'node' any initial locals. Return a modified subprogram or module. 60 """ 61 62 # Obtain a namespace either based on locals or on a structure. 63 64 self.namespace = NameOrganiser(structure=getattr(node, "structure", None)) 65 66 # NOTE: Check this. 67 68 if hasattr(node, "params"): 69 for param, default in node.params: 70 self.namespace.store(param) 71 if hasattr(node, "star"): 72 param = node.star 73 self.namespace.store(param) 74 if hasattr(node, "dstar"): 75 param = node.dstar 76 self.namespace.store(param) 77 78 # Add namespace details to any structure involved. 79 80 if hasattr(node, "structure") and node.structure is not None: 81 82 # Initialise bases where appropriate. 83 84 if hasattr(node.structure, "bases"): 85 bases = [] 86 for base in node.structure.bases: 87 bases.append(self.dispatch(base)) 88 node.structure.bases = bases 89 90 # Dispatch to the code itself. 91 92 result = self.dispatch(node) 93 return result 94 95 # Visitor methods. 96 97 def default(self, node): 98 99 """ 100 Process the given 'node', given that it does not have a specific 101 handler. 102 """ 103 104 for attr in ("args",): 105 value = getattr(node, attr, None) 106 if value is not None: 107 setattr(node, attr, self.dispatches(value)) 108 for attr in ("expr", "lvalue", "test", "star", "dstar"): 109 value = getattr(node, attr, None) 110 if value is not None: 111 setattr(node, attr, self.dispatch(value)) 112 for attr in ("body", "else_", "handler", "finally_", "code", "choices"): 113 value = getattr(node, attr, None) 114 if value is not None: 115 setattr(node, attr, self.dispatches(value)) 116 return node 117 118 def dispatch(self, node, *args): 119 return Visitor.dispatch(self, node, *args) 120 121 def visitGlobal(self, global_): 122 for name in global_.names: 123 self.namespace.make_global(name) 124 return global_ 125 126 def visitLoadName(self, loadname): 127 print "Name", loadname.name, "in", self.namespace 128 scope = self.namespace.find_for_load(loadname.name) 129 if scope == "structure": 130 result = self.dispatch(LoadAttr(expr=LoadRef(ref=self.namespace.structure), name=loadname.name)) 131 elif scope == "global": 132 result = self.dispatch(LoadGlobal(name=loadname.name)) 133 else: 134 result = loadname 135 return result 136 137 def visitStoreName(self, storename): 138 scope = self.namespace.find_for_store(storename.name) 139 if scope == "structure": 140 return self.dispatch(StoreAttr(lvalue=LoadRef(ref=self.namespace.structure), name=storename.name, expr=storename.expr)) 141 elif scope == "global": 142 return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr)) 143 else: 144 storename.expr = self.dispatch(storename.expr) 145 self.namespace.store(storename.name) 146 return storename 147 148 class NameOrganiser: 149 150 """ 151 A local namespace which may either relate to a genuine set of function 152 locals or the initialisation of a structure. 153 """ 154 155 def __init__(self, structure=None): 156 self.structure = structure 157 if structure is not None: 158 self.local = "structure" 159 else: 160 self.local = "local" 161 self.names = {} 162 self.not_local = [] 163 164 def make_global(self, name): 165 if name not in self.not_local: 166 self.not_local.append(name) 167 168 def find_for_store(self, name): 169 if name not in self.not_local: 170 return self.local 171 else: 172 return "global" 173 174 def find_for_load(self, name): 175 if name not in self.not_local and self.names.has_key(name): 176 return self.local 177 else: 178 return "global" 179 180 def store(self, name, types=None): 181 if name not in self.not_local: 182 self.names[name] = types 183 else: 184 raise KeyError, name 185 186 def load(self, name): 187 if name in self.not_local or not self.names.has_key(name): 188 raise KeyError, name 189 else: 190 return self.names[name] 191 192 def __repr__(self): 193 return repr(self.names) 194 195 # vim: tabstop=4 expandtab shiftwidth=4