1 #!/usr/bin/env python 2 3 """ 4 Traverse and annotate simplified AST structures. 5 6 Copyright (C) 2006 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 simplified import * 25 import compiler 26 27 class Namespace: 28 def __init__(self, local_is_structure=0): 29 if local_is_structure: 30 self.local = "structure" 31 else: 32 self.local = "local" 33 self.names = {} 34 self.not_local = [] 35 36 def make_global(self, name): 37 if name not in self.not_local: 38 self.not_local.append(name) 39 40 def find_for_store(self, name): 41 if name not in self.not_local: 42 return self.local 43 else: 44 return "global" 45 46 def find_for_load(self, name): 47 if name not in self.not_local and self.names.has_key(name): 48 return self.local 49 else: 50 return "global" 51 52 def store(self, name, types): 53 if name not in self.not_local: 54 self.names[name] = types 55 else: 56 raise KeyError, name 57 58 def load(self, name): 59 if name in self.not_local or not self.names.has_key(name): 60 raise KeyError, name 61 else: 62 return self.names[name] 63 64 def merge(self, namespace): 65 for name, types in namespace.names.items(): 66 if not self.names.has_key(name): 67 self.names[name] = types 68 else: 69 existing = self.names[name] 70 for type in types: 71 if type not in existing: 72 existing.append(type) 73 74 class System: 75 def __init__(self): 76 self.count = 0 77 def init(self, node): 78 if not hasattr(node, "types"): 79 node.types = [] 80 def annotate(self, node, types): 81 for type in types: 82 if type not in node.types: 83 node.types.append(type) 84 self.count += 1 85 86 class Annotator(Visitor): 87 def __init__(self): 88 Visitor.__init__(self) 89 self.system = System() 90 self.types = None 91 self.temp = {} 92 93 def process(self, node, global_namespace=None): 94 if hasattr(node, "structure"): 95 self.structure = node.structure 96 has_structure = 1 97 else: 98 self.structure = None 99 has_structure = 0 100 101 self.namespace = Namespace(self.structure is not None) 102 self.global_namespace = global_namespace or self.namespace # NOTE: Improve this. 103 104 if has_structure: 105 node.structure.namespace = self.namespace 106 node.namespace = self.namespace 107 108 self.visitor = self 109 result = self.dispatch(node) 110 111 return result 112 113 def default(self, node): 114 for attr in ("args",): 115 value = getattr(node, attr, None) 116 if value is not None: 117 setattr(node, attr, self.dispatches(value)) 118 119 # NOTE: This will eventually use both defaults and supplied arguments. 120 121 for attr in ("params",): 122 value = getattr(node, attr, None) 123 if value is not None: 124 params = [] 125 for name, default in value: 126 if default is not None: 127 n = self.dispatch(default) 128 self.namespace.store(name, self.types) 129 else: 130 n = None 131 self.namespace.store(name, []) 132 params.append((name, n)) 133 setattr(node, attr, params) 134 for attr in ("expr", "lvalue", "test", "handler", "star", "dstar"): 135 value = getattr(node, attr, None) 136 if value is not None: 137 setattr(node, attr, self.dispatch(value)) 138 for attr in ("body", "else_", "finally_", "code"): 139 value = getattr(node, attr, None) 140 if value is not None: 141 setattr(node, attr, self.dispatches(value)) 142 return node 143 144 def dispatch(self, node, *args): 145 return Visitor.dispatch(self, node, *args) 146 147 def visitGlobal(self, global_): 148 for name in global_.names: 149 self.namespace.make_global(name) 150 return global_ 151 152 def visitLoadRef(self, loadref): 153 self.types = [loadref.ref] 154 return loadref 155 156 def visitLoadName(self, loadname): 157 scope = self.namespace.find_for_load(loadname.name) 158 print "LoadName", scope 159 if scope == "structure": 160 return self.dispatch(LoadAttr(expr=LoadRef(ref=self.structure), name=loadname.name)) 161 elif scope == "global": 162 return self.dispatch(LoadGlobal(name=loadname.name)) 163 else: 164 self.types = self.namespace.load(loadname.name) 165 return loadname 166 167 def visitStoreName(self, storename): 168 scope = self.namespace.find_for_store(storename.name) 169 print "StoreName", scope 170 if scope == "structure": 171 return self.dispatch(StoreAttr(lvalue=LoadRef(ref=self.structure), name=storename.name, expr=storename.expr)) 172 elif scope == "global": 173 return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr)) 174 else: 175 storename.expr = self.dispatch(storename.expr) 176 self.namespace.store(storename.name, self.types) 177 return storename 178 179 def visitLoadGlobal(self, loadglobal): 180 self.types = self.global_namespace.load(loadglobal.name) 181 return loadglobal 182 183 def visitStoreGlobal(self, storeglobal): 184 storeglobal.expr = self.dispatch(storeglobal.expr) 185 186 # NOTE: This may always be a merge operation. 187 188 self.global_namespace.store(storeglobal.name, self.types) 189 return storeglobal 190 191 def visitLoadTemp(self, loadtemp): 192 index = getattr(loadtemp, "index", None) 193 self.types = self.temp[index] 194 return loadtemp 195 196 def visitStoreTemp(self, storetemp): 197 storetemp.expr = self.dispatch(storetemp.expr) 198 index = getattr(storetemp, "index", None) 199 self.temp[index] = self.types 200 return storetemp 201 202 def visitReleaseTemp(self, releasetemp): 203 index = getattr(releasetemp, "index", None) 204 del self.temp[index] 205 return releasetemp 206 207 def visitLoadAttr(self, loadattr): 208 loadattr.expr = self.dispatch(loadattr.expr) 209 types = [] 210 for ref in self.types: 211 types += ref.namespace.load(loadattr.name) 212 self.types = types 213 return loadattr 214 215 def visitStoreAttr(self, storeattr): 216 storeattr.expr = self.dispatch(storeattr.expr) 217 expr = self.types 218 storeattr.lvalue = self.dispatch(storeattr.lvalue) 219 for ref in self.types: 220 ref.namespace.store(storeattr.name, expr) 221 return storeattr 222 223 # vim: tabstop=4 expandtab shiftwidth=4