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', indicating any initial 'locals' 59 and 'globals' if either are defined. Return an annotated subprogram or 60 module. Note that this method may mutate nodes in the original program. 61 """ 62 63 # Obtain a namespace either based on locals or on a structure. 64 65 self.namespace = NameOrganiser(structure=getattr(node, "structure", None)) 66 67 # Add namespace details to any structure involved. 68 69 if hasattr(node, "structure") and node.structure is not None: 70 71 # Initialise bases where appropriate. 72 73 if hasattr(node.structure, "bases"): 74 bases = [] 75 for base in node.structure.bases: 76 bases.append(self.dispatch(base)) 77 node.structure.bases = bases 78 79 # Dispatch to the code itself. 80 81 result = self.dispatch(node) 82 return result 83 84 # Visitor methods. 85 86 def default(self, node): 87 88 """ 89 Process the given 'node', given that it does not have a specific 90 handler. 91 """ 92 93 for attr in ("args",): 94 value = getattr(node, attr, None) 95 if value is not None: 96 setattr(node, attr, self.dispatches(value)) 97 for attr in ("expr", "lvalue", "test", "handler", "star", "dstar"): 98 value = getattr(node, attr, None) 99 if value is not None: 100 setattr(node, attr, self.dispatch(value)) 101 for attr in ("body", "else_", "finally_", "code", "choices"): 102 value = getattr(node, attr, None) 103 if value is not None: 104 setattr(node, attr, self.dispatches(value)) 105 return node 106 107 def dispatch(self, node, *args): 108 return Visitor.dispatch(self, node, *args) 109 110 def visitGlobal(self, global_): 111 for name in global_.names: 112 self.namespace.make_global(name) 113 return global_ 114 115 def visitLoadName(self, loadname): 116 scope = self.namespace.find_for_load(loadname.name) 117 if scope == "structure": 118 result = self.dispatch(LoadAttr(expr=LoadRef(ref=self.namespace.structure), name=loadname.name)) 119 elif scope == "global": 120 result = self.dispatch(LoadGlobal(name=loadname.name)) 121 else: 122 result = loadname 123 return result 124 125 def visitStoreName(self, storename): 126 scope = self.namespace.find_for_store(storename.name) 127 if scope == "structure": 128 return self.dispatch(StoreAttr(lvalue=LoadRef(ref=self.namespace.structure), name=storename.name, expr=storename.expr)) 129 elif scope == "global": 130 return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr)) 131 else: 132 storename.expr = self.dispatch(storename.expr) 133 self.namespace.store(storename.name) 134 return storename 135 136 class NameOrganiser: 137 138 """ 139 A local namespace which may either relate to a genuine set of function 140 locals or the initialisation of a structure. 141 """ 142 143 def __init__(self, structure=None): 144 self.structure = structure 145 if structure is not None: 146 self.local = "structure" 147 else: 148 self.local = "local" 149 self.names = {} 150 self.not_local = [] 151 152 def make_global(self, name): 153 if name not in self.not_local: 154 self.not_local.append(name) 155 156 def find_for_store(self, name): 157 if name not in self.not_local: 158 return self.local 159 else: 160 return "global" 161 162 def find_for_load(self, name): 163 if name not in self.not_local and self.names.has_key(name): 164 return self.local 165 else: 166 return "global" 167 168 def store(self, name, types=None): 169 if name not in self.not_local: 170 self.names[name] = types 171 else: 172 raise KeyError, name 173 174 def load(self, name): 175 if name in self.not_local or not self.names.has_key(name): 176 raise KeyError, name 177 else: 178 return self.names[name] 179 180 # vim: tabstop=4 expandtab shiftwidth=4