1 package polyglot.ext.coffer.visit; 2 3 import java.util.*; 4 import java.util.Map.Entry; 5 6 import polyglot.ast.NodeFactory; 7 import polyglot.ast.ProcedureDecl; 8 import polyglot.ast.Term; 9 import polyglot.ext.coffer.Topics; 10 import polyglot.ext.coffer.extension.CofferExt; 11 import polyglot.ext.coffer.extension.ProcedureDeclExt_c; 12 import polyglot.ext.coffer.types.*; 13 import polyglot.ext.coffer.types.CofferClassType; 14 import polyglot.ext.coffer.types.CofferProcedureInstance; 15 import polyglot.ext.coffer.types.CofferTypeSystem; 16 import polyglot.ext.coffer.types.KeySet; 17 import polyglot.frontend.Job; 18 import polyglot.main.Report; 19 import polyglot.types.SemanticException; 20 import polyglot.types.Type; 21 import polyglot.types.TypeSystem; 22 import polyglot.util.InternalCompilerError; 23 import polyglot.util.Position; 24 import polyglot.visit.DataFlow; 25 import polyglot.visit.FlowGraph; 26 import polyglot.visit.FlowGraph.EdgeKey; 27 import polyglot.visit.FlowGraph.ExceptionEdgeKey; 28 29 32 public class KeyChecker extends DataFlow 33 { 34 public KeyChecker(Job job, TypeSystem ts, NodeFactory nf) { 35 super(job, ts, nf, true ); 36 CofferTypeSystem vts = (CofferTypeSystem) ts; 37 EMPTY = vts.emptyKeySet(Position.COMPILER_GENERATED); 38 } 39 40 public Item createInitialItem(FlowGraph graph, Term node) { 41 ProcedureDecl decl = (ProcedureDecl) graph.root(); 42 CofferProcedureInstance pi = (CofferProcedureInstance) 43 decl.procedureInstance(); 44 45 CofferClassType t = (CofferClassType) pi.container(); 46 47 KeySet held = pi.entryKeys(); 48 KeySet stored = EMPTY; 49 50 if (t.key() != null) { 51 stored = stored.add(t.key()); 52 stored = stored.retainAll(held); 53 } 54 55 return new DataFlowItem(held, held, stored, stored); 56 } 57 58 KeySet EMPTY; 59 60 class ExitTermItem extends Item { 61 DataFlowItem nonExItem; 62 Map excEdgesToItems; public ExitTermItem(DataFlowItem nonExItem, Map excItems) { 64 this.nonExItem = nonExItem; 65 this.excEdgesToItems = excItems; 66 } 67 68 public boolean equals(Object i) { 69 if (i instanceof ExitTermItem) { 70 ExitTermItem that = (ExitTermItem)i; 71 return this.excEdgesToItems.equals(that.excEdgesToItems) && 72 this.nonExItem.equals(that.nonExItem); 73 } 74 return false; 75 } 76 77 public int hashCode() { 78 return nonExItem.hashCode() + excEdgesToItems.hashCode(); 79 } 80 } 81 82 class DataFlowItem extends Item { 83 KeySet must_held; 85 KeySet may_held; 86 87 KeySet must_stored; 89 KeySet may_stored; 90 91 private DataFlowItem() { 92 this(EMPTY, EMPTY, EMPTY, EMPTY); 93 } 94 95 private DataFlowItem(KeySet must_held, KeySet may_held, 96 KeySet must_stored, KeySet may_stored) { 97 this.must_held = must_held; 98 this.may_held = may_held; 99 this.must_stored = must_stored; 100 this.may_stored = may_stored; 101 } 102 103 public String toString() { 104 return "held_keys(must_held=" + must_held + ", " + 105 "may_held=" + may_held + ", " + 106 "must_stored=" + must_stored + ", " + 107 "may_stored=" + may_stored + ")"; 108 } 109 110 public boolean equals(Object o) { 111 if (o instanceof DataFlowItem) { 112 DataFlowItem that = (DataFlowItem) o; 113 return this.must_held.equals(that.must_held) 114 && this.may_held.equals(that.may_held) 115 && this.must_stored.equals(that.must_stored) 116 && this.may_stored.equals(that.may_stored); 117 } 118 return false; 119 } 120 121 public int hashCode() { 122 return must_held.hashCode() + may_held.hashCode() + 123 must_stored.hashCode() + may_stored.hashCode(); 124 } 125 } 126 127 public Map flow(Item in, FlowGraph graph, Term n, Set succEdgeKeys) { 128 if (in instanceof ExitTermItem) { 129 return itemToMap(in, succEdgeKeys); 130 } 131 132 DataFlowItem df = (DataFlowItem) in; 133 134 if (n.ext() instanceof CofferExt) { 135 CofferExt ext = (CofferExt) n.ext(); 136 137 Map m = new HashMap(); 138 139 for (Iterator i = succEdgeKeys.iterator(); i.hasNext(); ) { 140 FlowGraph.EdgeKey e = (FlowGraph.EdgeKey) i.next(); 141 Type t = null; 142 143 if (e instanceof FlowGraph.ExceptionEdgeKey) { 144 t = ((FlowGraph.ExceptionEdgeKey) e).type(); 145 } 146 147 KeySet must_held = ext.keyFlow(df.must_held, t); 148 KeySet may_held = ext.keyFlow(df.may_held, t); 149 KeySet must_stored = ext.keyAlias(df.must_stored, t); 150 KeySet may_stored = ext.keyAlias(df.may_stored, t); 151 152 must_stored = must_stored.retainAll(must_held); 153 may_stored = may_stored.retainAll(may_held); 154 155 DataFlowItem newdf = new DataFlowItem(must_held, may_held, 156 must_stored, may_stored); 157 158 if (Report.should_report(Topics.keycheck, 2)) { 159 Report.report(2, "flow(" + n + "):"); 160 Report.report(2, " " + df); 161 Report.report(2, " ->" + newdf); 162 } 163 164 m.put(e, newdf); 165 } 166 167 return m; 168 } 169 170 return itemToMap(in, succEdgeKeys); 171 } 172 173 protected Item safeConfluence(List items, List itemKeys, Term node, FlowGraph graph) { 174 if (node == graph.exitNode()) { 175 return confluenceExitTerm(items, itemKeys, graph); 176 } 177 return super.safeConfluence(items, itemKeys, node, graph); 178 } 179 180 protected Item confluence(List items, List itemKeys, Term node, FlowGraph graph) { 181 if (node == graph.exitNode()) { 182 return confluenceExitTerm(items, itemKeys, graph); 183 } 184 return confluence(items, node, graph); 185 } 186 187 protected Item confluenceExitTerm(List items, List itemKeys, FlowGraph graph) { 188 List nonExcItems = filterItemsNonException(items, itemKeys); 189 DataFlowItem nonExc; 190 191 if (nonExcItems.isEmpty()) { 192 nonExc = new DataFlowItem(); 193 } 194 else { 195 nonExc = (DataFlowItem)confluence(nonExcItems, graph.exitNode(), graph); 196 } 197 198 Map excItemLists = new HashMap(); 199 for (Iterator i = items.iterator(), j = itemKeys.iterator(); 200 i.hasNext() && j.hasNext(); ) { 201 FlowGraph.EdgeKey key = (EdgeKey)j.next(); 202 DataFlowItem item = (DataFlowItem)i.next(); 203 if (key instanceof FlowGraph.ExceptionEdgeKey) { 204 List l = (List)excItemLists.get(key); 205 if (l == null) { 206 l = new ArrayList(); 207 excItemLists.put(key, l); 208 } 209 l.add(item); 210 } 211 } 212 213 Map excItems = new HashMap(excItemLists.size()); 214 for (Iterator i = excItemLists.entrySet().iterator(); i.hasNext(); ) { 215 Map.Entry e = (Entry)i.next(); 216 excItems.put(e.getKey(), confluence((List)e.getValue(), graph.exitNode(), graph)); 217 } 218 return new ExitTermItem(nonExc, excItems); 219 } 220 221 protected Item confluence(List inItems, Term node, FlowGraph graph) { 222 DataFlowItem outItem = null; 223 224 for (Iterator i = inItems.iterator(); i.hasNext(); ) { 225 DataFlowItem df = (DataFlowItem) i.next(); 226 227 if (outItem == null) { 228 outItem = new DataFlowItem(df.must_held, df.may_held, 229 df.must_stored, df.may_stored); 230 continue; 231 } 232 233 outItem.must_held = outItem.must_held.retainAll(df.must_held); 234 outItem.may_held = outItem.may_held.addAll(df.may_held); 235 236 outItem.must_stored = outItem.must_stored.retainAll(df.must_stored); 237 outItem.may_stored = outItem.may_stored.addAll(df.may_stored); 238 239 outItem.must_stored = outItem.must_stored.retainAll(outItem.must_held); 240 outItem.may_stored = outItem.may_stored.retainAll(outItem.may_held); 241 } 242 243 if (outItem == null) 244 throw new InternalCompilerError("confluence called with insufficient input items."); 245 246 if (Report.should_report(Topics.keycheck, 2)) { 247 Report.report(2, "confluence(" + node + "):"); 248 249 for (Iterator i = inItems.iterator(); i.hasNext(); ) { 250 DataFlowItem df = (DataFlowItem) i.next(); 251 Report.report(2, " " + df); 252 } 253 254 Report.report(2, " ->" + outItem); 255 } 256 257 return outItem; 258 } 259 260 public void check(FlowGraph graph, Term n, Item inItem, Map outItems) 261 throws SemanticException 262 { 263 if (n == graph.exitNode()) { 264 checkExitTerm(graph, (ExitTermItem)inItem); 265 } 266 else { 267 DataFlowItem df = (DataFlowItem) inItem; 268 check(n, df, true); 269 } 270 } 271 272 private void check(Term n, DataFlowItem df, boolean checkHeldKeys) throws SemanticException { 273 if (df == null) { 274 return; 275 } 276 277 if (Report.should_report(Topics.keycheck, 2)) { 278 Report.report(2, "check(" + n + "):"); 279 Report.report(2, " " + df); 280 } 281 282 if (! df.must_held.containsAll(df.may_held)) { 283 KeySet s = df.may_held.removeAll(df.must_held); 284 throw new SemanticException("Keys " + s + " may not be held.", 285 n.position()); 286 } 287 288 if (! df.must_stored.containsAll(df.may_stored)) { 289 KeySet s = df.may_stored.removeAll(df.must_stored); 290 throw new SemanticException("Keys " + s + " may not be saved" + 291 " in a local variable.", n.position()); 292 } 293 294 if (checkHeldKeys && n.ext() instanceof CofferExt) { 295 CofferExt ext = (CofferExt) n.ext(); 296 ext.checkHeldKeys(df.must_held, df.must_stored); 297 } 298 } 299 300 private void checkExitTerm(FlowGraph graph, ExitTermItem item) 301 throws SemanticException 302 { 303 check(graph.exitNode(), item.nonExItem, true); 304 305 List excepts; 306 ProcedureDeclExt_c ext = null; 307 308 if (graph.exitNode() instanceof ProcedureDecl) { 309 ProcedureDecl pd = (ProcedureDecl)graph.exitNode(); 310 CofferProcedureInstance pi = (CofferProcedureInstance)pd.procedureInstance(); 311 excepts = pi.throwConstraints(); 312 ext = (ProcedureDeclExt_c)pd.ext(); 313 } 314 else { 315 excepts = new ArrayList(); 316 for (Iterator i = item.excEdgesToItems.keySet().iterator(); i.hasNext(); ) { 317 FlowGraph.ExceptionEdgeKey key = (ExceptionEdgeKey)i.next(); 318 excepts.add(key.type()); 319 } 320 } 321 322 List excKeys = new ArrayList(); 323 List excItems = new ArrayList(); 324 325 for (Iterator i = item.excEdgesToItems.entrySet().iterator(); i.hasNext(); ) { 326 Entry e = (Entry)i.next(); 327 excKeys.add(e.getKey()); 328 excItems.add(e.getValue()); 329 } 330 331 for (Iterator i = excepts.iterator(); i.hasNext(); ) { 332 Object o = i.next(); 333 ThrowConstraint tc = null; 334 Type excType = null; 335 if (o instanceof ThrowConstraint) { 336 tc = (ThrowConstraint)o; 337 excType = tc.throwType(); 338 } 339 else { 340 excType = (Type)o; 341 } 342 List matchingExc = filterItemsExceptionSubclass(excItems, excKeys, excType); 343 if (!matchingExc.isEmpty()) { 344 DataFlowItem df = (DataFlowItem)confluence(matchingExc, graph.exitNode(), graph); 345 check(graph.exitNode(), df, false); 346 347 if (ext != null && tc != null) { 348 ext.checkHeldKeysThrowConstraint(tc, df.must_held, df.must_stored); 349 } 350 351 } 352 } 353 354 } 355 } 356 | Popular Tags |