001package daikon; 002 003import daikon.chicory.DaikonVariableInfo; 004import daikon.derive.Derivation; 005import daikon.derive.binary.BinaryDerivation; 006import daikon.derive.binary.SequenceFloatSubscript; 007import daikon.derive.binary.SequenceScalarSubscript; 008import daikon.derive.binary.SequenceStringSubscript; 009import daikon.derive.binary.SequenceSubsequence; 010import daikon.derive.ternary.SequenceFloatArbitrarySubsequence; 011import daikon.derive.ternary.SequenceScalarArbitrarySubsequence; 012import daikon.derive.ternary.SequenceStringArbitrarySubsequence; 013import daikon.derive.unary.SequenceLength; 014import daikon.derive.unary.UnaryDerivation; 015import daikon.inv.OutputFormat; 016import java.io.IOException; 017import java.io.ObjectInputStream; 018import java.io.Serializable; 019import java.lang.ref.WeakReference; 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.Comparator; 025import java.util.HashSet; 026import java.util.List; 027import java.util.ListIterator; 028import java.util.Set; 029import java.util.StringJoiner; 030import java.util.WeakHashMap; 031import java.util.logging.Level; 032import java.util.logging.Logger; 033import org.checkerframework.checker.interning.qual.InternMethod; 034import org.checkerframework.checker.interning.qual.Interned; 035import org.checkerframework.checker.lock.qual.GuardSatisfied; 036import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; 037import org.checkerframework.checker.nullness.qual.Nullable; 038import org.checkerframework.dataflow.qual.Pure; 039import org.checkerframework.dataflow.qual.SideEffectFree; 040import org.plumelib.util.StringsPlume; 041 042// This class is deprecated. It should be removed as soon as Daikon no 043// longer supports the old decl format. 044 045// If you change this file, also change class daikon.test.VarInfoNameTest. 046 047/** 048 * VarInfoName represents the "name" of a variable. Calling it a "name", however, is somewhat 049 * misleading. It can be some expression that includes more than one variable, term, etc. We 050 * separate this from the VarInfo itself because clients wish to manipulate names into new 051 * expressions independent of the VarInfo that they might be associated with. VarInfoName's child 052 * classes are specific types of names, like applying a function to something. For example, "a" is a 053 * name, and "sin(a)" is a name that is the name "a" with the function "sin" applied to it. 054 */ 055@SuppressWarnings({"nullness", "interning"}) // deprecated file 056public abstract @Interned class VarInfoName implements Serializable, Comparable<VarInfoName> { 057 058 /** Debugging Logger. */ 059 public static Logger debug = Logger.getLogger("daikon.VarInfoName"); 060 061 static final long serialVersionUID = 20020614L; 062 063 /** 064 * When true, apply orig directly to variables, do not apply orig to derived variables. For 065 * example, create 'size(orig(a[]))' rather than 'orig(size(a[]))'. 066 */ 067 public static boolean dkconfig_direct_orig = false; 068 069 /** 070 * Given the standard String representation of a variable name (like what appears in the normal 071 * output format), return the corresponding VarInfoName. This method can't parse all the strings 072 * that the VarInfoName name() method might produce, but it should be able to handle anything that 073 * appears in a decls file. Specifically, it can only handle a subset of the grammar of derived 074 * variables. For some values of "name", "name.equals(parse(e.name()))" might throw an exception, 075 * but if it completes normally, the result should be true. 076 */ 077 public static VarInfoName parse(String name) { 078 079 // Remove the array indication from the new decl format 080 name = name.replace("[..]", "[]"); 081 082 // orig(x) 083 if (name.startsWith("orig(")) { 084 // throw new Error("orig() variables shouldn't appear in .decls files"); 085 assert name.endsWith(")") : name; 086 return parse(name.substring(5, name.length() - 1)).applyPrestate(); 087 } 088 089 // x.class 090 if (name.endsWith(DaikonVariableInfo.class_suffix)) { 091 return parse(name.substring(0, name.length() - DaikonVariableInfo.class_suffix.length())) 092 .applyTypeOf(); 093 } 094 095 // a quoted string 096 if (name.startsWith("\"") && name.endsWith("\"")) { 097 String content = name.substring(1, name.length() - 1); 098 if (content.equals(StringsPlume.escapeJava(StringsPlume.unescapeJava(content)))) { 099 return new Simple(name).intern(); 100 } 101 } 102 103 // x or this.x 104 if ((name.indexOf('[') == -1) && (name.indexOf('(') == -1)) { 105 // checking for only legal characters would be more robust 106 int dot = name.lastIndexOf('.'); 107 int arrow = name.lastIndexOf("->"); 108 if (dot >= 0 && dot > arrow) { 109 String first = name.substring(0, dot); 110 String field = name.substring(dot + 1); 111 return parse(first).applyField(field); 112 } else if (arrow >= 0 && arrow > dot) { 113 String first = name.substring(0, arrow); 114 String field = name.substring(arrow + 2); 115 return parse(first).applyField(field); 116 } else { 117 return new Simple(name).intern(); 118 } 119 } 120 121 // a[] 122 if (name.endsWith("[]")) { 123 return parse(name.substring(0, name.length() - 2)).applyElements(); 124 } 125 126 // foo[bar] -- IOA input only (pre-derived) 127 if (name.endsWith("]")) { 128 // This isn't quite right: we really want the matching open bracket, 129 // not the last open bracket. 130 int lbracket = name.lastIndexOf("["); 131 if (lbracket >= 0) { 132 String seqname = name.substring(0, lbracket) + "[]"; 133 String idxname = name.substring(lbracket + 1, name.length() - 1); 134 VarInfoName seq = parse(seqname); 135 VarInfoName idx = parse(idxname); 136 return seq.applySubscript(idx); 137 } 138 } 139 140 // a[].foo or a[].foo.bar 141 if (name.indexOf("[]") >= 0) { 142 int brackets = name.lastIndexOf("[]"); 143 int dot = name.lastIndexOf('.'); 144 int arrow = name.lastIndexOf("->"); 145 if (dot >= brackets && dot > arrow) { 146 String first = name.substring(0, dot); 147 String field = name.substring(dot + 1); 148 return parse(first).applyField(field); 149 } else if (arrow >= brackets && arrow > dot) { 150 String first = name.substring(0, arrow); 151 String field = name.substring(arrow + 2); 152 return parse(first).applyField(field); 153 } 154 } 155 156 // A.B, where A is complex: foo(x).y, x[7].y, etc. 157 int dot = name.lastIndexOf('.'); 158 int arrow = name.lastIndexOf("->"); 159 if (dot >= 0 && dot > arrow) { 160 String first = name.substring(0, dot); 161 String field = name.substring(dot + 1); 162 return parse(first).applyField(field); 163 } 164 165 // A->B, where A is complex: foo(x)->y, x[7]->y, etc. 166 if (arrow >= 0 && arrow > dot) { 167 String first = name.substring(0, arrow); 168 String field = name.substring(arrow + 2); 169 return parse(first).applyField(field); 170 } 171 172 // New decl format permits arbitrary uninterpreted strings as names 173 if (FileIO.new_decl_format) { 174 return new Simple(name).intern(); 175 } else { 176 throw new UnsupportedOperationException("parse error: '" + name + "'"); 177 } 178 } 179 180 /** 181 * Return the String representation of this name in the default output format. 182 * 183 * @return the string representation (interned) of this name, in the default output format 184 */ 185 @Pure 186 public @Interned String name(@GuardSatisfied VarInfoName this) { 187 if (name_cached == null) { 188 try { 189 name_cached = name_impl().intern(); 190 } catch (RuntimeException e) { 191 System.err.println("repr = " + repr()); 192 throw e; 193 } 194 } 195 return name_cached; 196 } 197 198 private @Interned String name_cached = null; // interned 199 200 /** 201 * Returns the String representation of this name in the default output format. Result is not 202 * interned; the client (name()) does so, then caches the interned value. 203 */ 204 protected abstract String name_impl(@GuardSatisfied VarInfoName this); 205 206 /** 207 * Return the String representation of this name in the esc style output format. 208 * 209 * @return the string representation (interned) of this name, in the esc style output format 210 */ 211 public @Interned String esc_name() { 212 if (esc_name_cached == null) { 213 try { 214 esc_name_cached = esc_name_impl().intern(); 215 } catch (RuntimeException e) { 216 System.err.println("repr = " + repr()); 217 throw e; 218 } 219 } 220 // System.out.println("esc_name = " + esc_name_cached + " for " + name() + " of class " + 221 // this.getClass().getName()); 222 return esc_name_cached; 223 } 224 225 private @Interned String esc_name_cached = null; // interned 226 227 /** 228 * Returns the String representation of this name in the ESC style output format. Cached by {@link 229 * #esc_name()}. 230 */ 231 protected abstract String esc_name_impl(); 232 233 /** 234 * Returns the string representation (interned) of this name, in the Simplify tool output format 235 * in the pre-state context. 236 * 237 * @return the string representation (interned) of this name, in the Simplify tool output format 238 * in the pre-state context 239 */ 240 public @Interned String simplify_name() { 241 return simplify_name(false); 242 } 243 244 /** 245 * Returns the string representation (interned) of this name, in the Simplify tool output format, 246 * in the given pre/post-state context. 247 * 248 * @param prestate if true, return the variable in a prestate context; if false, return the 249 * variable in a poststate context 250 * @return the string representation (interned) of this name, in the Simplify tool output format, 251 * in the given pre/post-state context 252 */ 253 protected @Interned String simplify_name(boolean prestate) { 254 int which = prestate ? 0 : 1; 255 if (simplify_name_cached[which] == null) { 256 try { 257 simplify_name_cached[which] = simplify_name_impl(prestate).intern(); 258 } catch (RuntimeException e) { 259 System.err.println("repr = " + repr()); 260 throw e; 261 } 262 } 263 return simplify_name_cached[which]; 264 } 265 266 // each element is interned 267 private @Interned String[] simplify_name_cached = new @Interned String[2]; 268 269 /** 270 * Returns the String representation of this name in the simplify output format in either prestate 271 * or poststate context. 272 */ 273 protected abstract String simplify_name_impl(boolean prestate); 274 275 /** 276 * Return the String representation of this name in the java style output format. 277 * 278 * @return the string representation (interned) of this name, in the java style output format 279 */ 280 public @Interned String java_name(VarInfo v) { 281 if (java_name_cached == null) { 282 try { 283 java_name_cached = java_name_impl(v).intern(); 284 } catch (RuntimeException e) { 285 System.err.println("repr = " + repr()); 286 throw e; 287 } 288 } 289 return java_name_cached; 290 } 291 292 private @Interned String java_name_cached = null; // interned 293 294 /** 295 * Return the String representation of this name in java format. Cached and interned by {@link 296 * #java_name}. 297 */ 298 protected abstract String java_name_impl(VarInfo v); 299 300 /** Return the String representation of this name in the JML style output format. */ 301 public @Interned String jml_name(VarInfo v) { 302 if (jml_name_cached == null) { 303 try { 304 jml_name_cached = jml_name_impl(v).intern(); 305 } catch (RuntimeException e) { 306 System.err.println("repr = " + repr()); 307 throw e; 308 } 309 } 310 // System.out.println("jml_name = " + jml_name_cached + " for " + name() + " of class " + 311 // this.getClass().getName()); 312 return jml_name_cached; 313 } 314 315 private @Interned String jml_name_cached = null; // interned 316 317 /** Returns the name in JML style output format. Cached and interned by {@link #jml_name}. */ 318 protected abstract String jml_name_impl(VarInfo v); 319 320 // For DBC, Java and JML formats, the formatting methods take as 321 // argument the VarInfo related to the VarInfoName in question. This 322 // causes trouble with VarInfoNameDriver (a class for testing 323 // VarInfoName), because there are no VarInfo's to pass to the 324 // formatting methods. So in places where the VarInfo argument is 325 // required by the formatting code, we use this variable to check 326 // whether we're doing testing. If we are, then we know that the 327 // VarInfo being passed is probably null, and we do something other 328 // than the normal thing (which would probably be to signal an 329 // error). Unfortunately, this prevents testing of some of those 330 // formats that make use of VarInfo information. 331 public static boolean testCall = false; 332 333 /** 334 * Return the String representation of this name in the dbc style output format. 335 * 336 * @param var the VarInfo which goes along with this VarInfoName. Used to determine the type of 337 * the variable. 338 * <p>If var is null, the only repercussion is that if `this' is an "orig(x)" expression, it 339 * will be formatted in jml-style, something like "\old(x)". 340 * <p>If var is not null and `this' is an "orig(x)" expressions, it will be formatted in 341 * Jtest's DBC style, as "$pre(<em>type</em>, x)". 342 * @return the string representation (interned) of this name, in the dbc style output format 343 */ 344 public @Interned String dbc_name(VarInfo var) { 345 if (dbc_name_cached == null) { 346 try { 347 dbc_name_cached = dbc_name_impl(var).intern(); 348 } catch (RuntimeException e) { 349 System.err.println("repr = " + repr()); 350 throw e; 351 } 352 } 353 return dbc_name_cached; 354 } 355 356 private @Interned String dbc_name_cached = null; // interned 357 358 /** 359 * Return the name in the DBC style output format. If v is null, uses JML style instead. Cached 360 * and interned by {@link #dbc_name}. 361 */ 362 protected abstract String dbc_name_impl(VarInfo v); 363 364 /** Return the String representation of this name using only letters, numbers, and underscores. */ 365 public @Interned String identifier_name() { 366 if (identifier_name_cached == null) { 367 try { 368 identifier_name_cached = identifier_name_impl().intern(); 369 } catch (RuntimeException e) { 370 System.err.println("repr = " + repr()); 371 throw e; 372 } 373 } 374 // System.out.println("identifier_name = " + identifier_name_cached + " for " + name() + " of 375 // class " + this.getClass().getName()); 376 return identifier_name_cached; 377 } 378 379 private @Interned String identifier_name_cached = null; // interned 380 381 /** 382 * Returns the name using only letters, numbers, and underscores. Cached and interned by {@link 383 * #identifier_name()}. 384 * 385 * @return the name using only letters, numbers, and underscores 386 */ 387 protected abstract String identifier_name_impl(); 388 389 /** 390 * Returns name of this in the specified format. 391 * 392 * @param format the format in which to return this variable name 393 * @param vi the VarInfo for this variable name 394 * @return name of this in the specified format 395 */ 396 public String name_using(OutputFormat format, VarInfo vi) { 397 398 if (format == OutputFormat.DAIKON) { 399 return name(); 400 } 401 if (format == OutputFormat.SIMPLIFY) { 402 return simplify_name(); 403 } 404 if (format == OutputFormat.ESCJAVA) { 405 return esc_name(); 406 } 407 if (format == OutputFormat.JAVA) { 408 return java_name(vi); 409 } 410 if (format == OutputFormat.JML) { 411 return jml_name(vi); 412 } 413 if (format == OutputFormat.DBCJAVA) { 414 return dbc_name(vi); 415 } 416 throw new UnsupportedOperationException("Unknown format requested: " + format); 417 } 418 419 /** 420 * Returns the name, in a debugging format. 421 * 422 * @return the name, in a debugging format 423 */ 424 public String repr(@GuardSatisfied VarInfoName this) { 425 // AAD: Used to be interned for space reasons, but removed during 426 // profiling when it was determined that the interns are unique 427 // anyway. 428 if (repr_cached == null) { 429 repr_cached = repr_impl(); // .intern(); 430 } 431 return repr_cached; 432 } 433 434 /** The cached output of {@link #repr_impl}, or null. */ 435 private String repr_cached = null; 436 437 /** 438 * Returns the name in a verbose debugging format. Cached by {@link #repr}. 439 * 440 * @return the name in a verbose debugging format 441 */ 442 protected abstract String repr_impl(@GuardSatisfied VarInfoName this); 443 444 // It would be nice if a generalized form of the mechanics of 445 // interning were abstracted out somewhere. 446 private static final WeakHashMap<VarInfoName, WeakReference<VarInfoName>> internTable = 447 new WeakHashMap<>(); 448 449 // This does not make any guarantee that the components of the 450 // VarInfoName are themselves interned. Should it? (I suspect so...) 451 @InternMethod 452 public VarInfoName intern() { 453 WeakReference<VarInfoName> ref = internTable.get(this); 454 if (ref != null) { 455 VarInfoName result = ref.get(); 456 return result; 457 } else { 458 @SuppressWarnings("interning") // intern method 459 @Interned VarInfoName this_interned = this; 460 internTable.put(this_interned, new WeakReference<>(this_interned)); 461 return this_interned; 462 } 463 } 464 465 // ============================================================ 466 // Constants 467 468 public static final VarInfoName ZERO = parse("0"); 469 public static final VarInfoName THIS = parse("this"); 470 public static final VarInfoName ORIG_THIS = parse("this").applyPrestate(); 471 472 // ============================================================ 473 // Observers 474 475 /** 476 * Returns true when this is "0", "-1", "1", etc. 477 * 478 * @return true when this is "0", "-1", "1", etc 479 */ 480 @Pure 481 public boolean isLiteralConstant() { 482 return false; 483 } 484 485 /** 486 * Returns the nodes of this, as given by an inorder traversal. 487 * 488 * @return the nodes of this, as given by an inorder traversal 489 */ 490 public Collection<VarInfoName> inOrderTraversal(@Interned VarInfoName this) { 491 return Collections.unmodifiableCollection(new InorderFlattener(this).nodes()); 492 } 493 494 /** 495 * Returns true iff the given node can be found in this. If the node has children, the whole 496 * subtree must match. 497 * 498 * @param node a variable name 499 * @return true iff the given node can be found in this. If the node has children, the whole 500 * subtree must match 501 */ 502 public boolean hasNode(VarInfoName node) { 503 return inOrderTraversal().contains(node); 504 } 505 506 /** 507 * Returns true iff a node of the given type exists in this. 508 * 509 * @param type the type to search for 510 * @return true iff a node of the given type exists in this 511 */ 512 public boolean hasNodeOfType(Class<?> type) { 513 for (VarInfoName vin : inOrderTraversal()) { 514 if (type.equals(vin.getClass())) { 515 return true; 516 } 517 } 518 return false; 519 } 520 521 /** 522 * Returns true iff a TypeOf node exists in this. 523 * 524 * @return true iff a TypeOf node exists in this 525 */ 526 public boolean hasTypeOf() { 527 return hasNodeOfType(VarInfoName.TypeOf.class); 528 } 529 530 /** 531 * Returns whether or not this name refers to the 'this' variable of a class. True for both normal 532 * and prestate versions of the variable. 533 */ 534 @Pure 535 public boolean isThis() { 536 if (name() == "this") { // interned 537 return true; 538 } 539 if (this instanceof VarInfoName.Prestate 540 && ((VarInfoName.Prestate) this).term.name() == "this") { // interned 541 return true; 542 } 543 544 return false; 545 } 546 547 /** 548 * Returns true if the given node is in a prestate context within this tree. 549 * 550 * @param node a member of this tree 551 * @return true if the given node is in a prestate context within this tree 552 */ 553 public boolean inPrestateContext(@Interned VarInfoName this, VarInfoName node) { 554 return new NodeFinder(this, node).inPre(); 555 } 556 557 /** 558 * Returns true if every variable in the name is an orig(...) variable. 559 * 560 * @return true if every variable in the name is an orig(...) variable 561 */ 562 @Pure 563 public boolean isAllPrestate(@Interned VarInfoName this) { 564 return new IsAllPrestateVisitor(this).result(); 565 } 566 567 /** 568 * Returns true if this VarInfoName contains a simple variable whose name is NAME. 569 * 570 * @param name the name to search for in this VarInfoName 571 * @return true if this VarInfoName contains a simple variable whose name is NAME 572 */ 573 public boolean includesSimpleName(@Interned VarInfoName this, String name) { 574 return new SimpleNamesVisitor(this).simples().contains(name); 575 } 576 577 // ============================================================ 578 // Special producers, or other helpers 579 580 /** Replace the first instance of node by replacement, in the data structure rooted at this. */ 581 public VarInfoName replace( 582 @Interned VarInfoName this, VarInfoName node, VarInfoName replacement) { 583 if (node == replacement) { // "interned": equality optimization pattern 584 return this; 585 } 586 Replacer r = new Replacer(node, replacement); 587 return r.replace(this).intern(); 588 } 589 590 /** Replace all instances of node by replacement, in the data structure rooted at this. */ 591 public VarInfoName replaceAll( 592 @Interned VarInfoName this, VarInfoName node, VarInfoName replacement) { 593 if (node == replacement) { // "interned": equality optimization pattern 594 return this; 595 } 596 597 // assert ! replacement.hasNode(node); // no infinite loop 598 599 // It doesn't make sense to assert this as we have plenty of times when 600 // we want to replace x by y where y may contain x. 601 602 Replacer r = new Replacer(node, replacement); 603 604 // This code used to loop as long as node was in result, but this isn't 605 // necessary -- all occurances are replaced by replacer. 606 607 VarInfoName result = r.replace(this).intern(); 608 return result; 609 } 610 611 // ============================================================ 612 // The usual Object methods 613 614 @EnsuresNonNullIf(result = true, expression = "#1") 615 @Pure 616 @Override 617 public boolean equals(@GuardSatisfied VarInfoName this, @GuardSatisfied @Nullable Object o) { 618 return (o instanceof VarInfoName) && equalsVarInfoName((VarInfoName) o); 619 } 620 621 @EnsuresNonNullIf(result = true, expression = "#1") 622 @Pure 623 public boolean equalsVarInfoName( 624 @GuardSatisfied @Interned VarInfoName this, @GuardSatisfied VarInfoName other) { 625 return ((other == this) // "interned": equality optimization pattern 626 || ((other != null) && this.repr().equals(other.repr()))); 627 } 628 629 // This should be safe even in the absence of caching, because "repr()" 630 // returns a new string each time, but it is equal() to any other 631 // returned string, so their hashCode()s should be the same. 632 @Pure 633 @Override 634 public int hashCode(@GuardSatisfied VarInfoName this) { 635 return repr().hashCode(); 636 } 637 638 @Pure 639 @Override 640 public int compareTo(@GuardSatisfied VarInfoName this, VarInfoName other) { 641 int nameCmp = name().compareTo(other.name()); 642 if (nameCmp != 0) { 643 return nameCmp; 644 } 645 int reprCmp = repr().compareTo(other.repr()); 646 return reprCmp; 647 } 648 649 // This is a debugging method, not intended for ordinary output. 650 // Code producing output should usually call name() rather than 651 // calling toString (perhaps implicitly). 652 @SideEffectFree 653 @Override 654 public String toString(@GuardSatisfied VarInfoName this) { 655 return repr(); 656 } 657 658 // Interning is lost when an object is serialized and deserialized. 659 // Manually re-intern any interned fields upon deserialization. 660 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 661 in.defaultReadObject(); 662 if (name_cached != null) { 663 name_cached = name_cached.intern(); 664 } 665 if (esc_name_cached != null) { 666 esc_name_cached = esc_name_cached.intern(); 667 } 668 if (simplify_name_cached[0] != null) { 669 simplify_name_cached[0] = simplify_name_cached[0].intern(); 670 } 671 if (simplify_name_cached[1] != null) { 672 simplify_name_cached[1] = simplify_name_cached[1].intern(); 673 } 674 if (java_name_cached != null) { 675 java_name_cached = java_name_cached.intern(); 676 } 677 if (jml_name_cached != null) { 678 jml_name_cached = jml_name_cached.intern(); 679 } 680 if (dbc_name_cached != null) { 681 dbc_name_cached = dbc_name_cached.intern(); 682 } 683 } 684 685 // ============================================================ 686 // Static inner classes that form the expression langugage 687 688 /** A simple identifier like "a", etc. */ 689 public static @Interned class Simple extends VarInfoName { 690 // We are Serializable, so we specify a version to allow changes to 691 // method signatures without breaking serialization. If you add or 692 // remove fields, you should change this number to the current date. 693 static final long serialVersionUID = 20020130L; 694 695 public final String name; 696 697 public Simple(String name) { 698 assert name != null; 699 this.name = name; 700 } 701 702 @Pure 703 @Override 704 public boolean isLiteralConstant() { 705 try { 706 Integer.parseInt(name); 707 return true; 708 } catch (NumberFormatException e) { 709 return false; 710 } 711 } 712 713 @Override 714 protected String repr_impl(@GuardSatisfied Simple this) { 715 return name; 716 } 717 718 @Override 719 protected String name_impl(@GuardSatisfied Simple this) { 720 return name; 721 } 722 723 @Override 724 protected String esc_name_impl() { 725 return "return".equals(name) ? "\\result" : name; 726 } 727 728 @Override 729 protected String simplify_name_impl(boolean prestate) { 730 if (isLiteralConstant()) { 731 return name; 732 } else { 733 return simplify_name_impl(name, prestate); 734 } 735 } 736 737 // Names must be either a legal C/Java style identifier, or 738 // surrounded by vertical bars (Simplify's quoting mechanism); 739 // other than that, they only have to be consistent within one 740 // execution of Daikon. 741 protected static String simplify_name_impl(String s, boolean prestate) { 742 if (s.startsWith("~") && s.endsWith("~")) { 743 s = s.substring(1, s.length() - 2) + ":closure"; 744 } 745 if (prestate) { 746 s = "__orig__" + s; 747 } 748 return "|" + s + "|"; 749 } 750 751 @Override 752 protected String java_name_impl(VarInfo v) { 753 return "return".equals(name) ? "\\result" : name; 754 } 755 756 @Override 757 protected String jml_name_impl(VarInfo v) { 758 return "return".equals(name) ? "\\result" : name; 759 } 760 761 @Override 762 protected String dbc_name_impl(VarInfo v) { 763 if (name.equals("return")) { 764 return "$result"; 765 } else { 766 return name; 767 } 768 } 769 770 @Override 771 protected String identifier_name_impl() { 772 if (name.equals("return")) { 773 return "Daikon_return"; 774 } else if (name.equals("this")) { 775 return "Daikon_this"; 776 } else { 777 StringBuilder buf = new StringBuilder(); 778 for (int i = 0; i < name.length(); i++) { 779 char c = name.charAt(i); 780 if (Character.isLetterOrDigit(c)) buf.append(c); 781 else if (c == '_') buf.append("__"); 782 else if (c == '$') buf.append("_dollar_"); 783 else if (c == ':') buf.append("_colon_"); 784 else if (c == '*') buf.append("star_"); 785 else { 786 throw new Error("Unexpected character in VarInfoName$Simple"); 787 } 788 } 789 return buf.toString(); 790 } 791 } 792 793 @Override 794 public <T> T accept(Visitor<T> v) { 795 return v.visitSimple(this); 796 } 797 } 798 799 /** 800 * Returns true iff applySize will not throw an exception. 801 * 802 * @return true iff applySize will not throw an exception 803 * @see #applySize 804 */ 805 @Pure 806 public boolean isApplySizeSafe() { 807 return new ElementsFinder(this).elems() != null; 808 } 809 810 /** 811 * Returns a name for the size of this (this object should be a sequence). Form is like 812 * "size(a[])" or "a.length". 813 * 814 * @return a name for the size of this 815 */ 816 public VarInfoName applySize(@Interned VarInfoName this) { 817 // The simple approach: 818 // return new SizeOf((Elements) this).intern(); 819 // is wrong because this might be "orig(a[])". 820 if (dkconfig_direct_orig) { 821 return new SizeOf(this).intern(); 822 } else { 823 Elements elems = new ElementsFinder(this).elems(); 824 if (elems == null) { 825 throw new Error( 826 "applySize should have elements to use in " 827 + name() 828 + ";" 829 + Global.lineSep 830 + "that is, " 831 + name() 832 + " does not appear to be a sequence/collection." 833 + Global.lineSep 834 + "Perhaps its name should be suffixed by \"[]\"?" 835 + Global.lineSep 836 + " this.class = " 837 + getClass().getName()); 838 } 839 840 // If this is orig, replace the elems with sizeof, leaving orig 841 // where it is. If it is not orig, simply return the sizeof the 842 // elems (ignoring anthing outside of the elems (like additional 843 // fields or typeof)). This allows this code to work correctly 844 // for variables such as a[].b.c (returns size(a[])) or 845 // a[].getClass().getName() (returns size(a[])) 846 if (this instanceof Prestate) { 847 VarInfoName size = new SizeOf(elems).intern(); 848 return new Prestate(size).intern(); 849 // Replacer r = new Replacer(elems, new SizeOf(elems).intern()); 850 // return r.replace(this).intern(); 851 } else { 852 return new SizeOf(elems).intern(); 853 } 854 } 855 } 856 857 /** 858 * If this is a slice, (potentially in pre-state), return its lower and upper bounds, which can be 859 * subtracted to get one less than its size. 860 */ 861 public @Interned VarInfoName[] getSliceBounds(@Interned VarInfoName this) { 862 VarInfoName vin = this; 863 boolean inPrestate = false; 864 if (vin instanceof Prestate) { 865 inPrestate = true; 866 vin = ((Prestate) vin).term; 867 } 868 while (vin instanceof Field) { 869 vin = ((Field) vin).term; 870 } 871 if (!(vin instanceof Slice)) { 872 return null; 873 } 874 Slice slice = (Slice) vin; 875 @Interned VarInfoName[] ret = new @Interned VarInfoName[2]; 876 if (slice.i != null) { 877 ret[0] = slice.i; 878 } else { 879 ret[0] = ZERO; 880 } 881 if (slice.j != null) { 882 ret[1] = slice.j; 883 } else { 884 ret[1] = slice.sequence.applySize().applyAdd(-1); 885 } 886 if (inPrestate) { 887 ret[0] = ret[0].applyPrestate(); 888 ret[1] = ret[1].applyPrestate(); 889 } 890 return ret; 891 } 892 893 /** The size of a contained sequence; form is like "size(sequence)" or "sequence.length". */ 894 public static @Interned class SizeOf extends VarInfoName { 895 // We are Serializable, so we specify a version to allow changes to 896 // method signatures without breaking serialization. If you add or 897 // remove fields, you should change this number to the current date. 898 static final long serialVersionUID = 20020130L; 899 900 public final VarInfoName sequence; 901 902 public SizeOf(VarInfoName sequence) { 903 assert sequence != null; 904 this.sequence = sequence; 905 } 906 907 @Override 908 protected String repr_impl(@GuardSatisfied SizeOf this) { 909 return "SizeOf[" + sequence.repr() + "]"; 910 } 911 912 @Override 913 protected String name_impl(@GuardSatisfied SizeOf this) { 914 return "size(" + sequence.name() + ")"; 915 916 // I'm not sure how to get this right; seems to require info about 917 // the variable type. 918 // // The result could be either "sequence.length" or "sequence.size()", 919 // // depending on the type of "sequence". 920 // String seqname = sequence.name(); 921 // if (seqname.endsWith("[]") 922 // // This clause is too confusing for C output, where some 923 // // variables get "size(seq)" and some get seq.length. 924 // // && ! seqname.startsWith("::") 925 // ) { 926 // return sequence.term.name() + ".length"; 927 // } else { 928 // return seqname + ".size()"; 929 // } 930 } 931 932 /** Returns the hashcode that is the base of the array. */ 933 @Pure 934 public VarInfoName get_term() { 935 if (sequence instanceof Elements) { 936 return ((Elements) sequence).term; 937 } else if (sequence instanceof Prestate) { 938 VarInfoName term = ((Prestate) sequence).term; 939 return ((Elements) term).term; 940 } 941 throw new RuntimeException("unexpected term in sizeof " + this); 942 } 943 944 @Override 945 protected String esc_name_impl() { 946 return get_term().esc_name() + ".length"; 947 } 948 949 @Override 950 protected String simplify_name_impl(boolean prestate) { 951 return "(arrayLength " + get_term().simplify_name(prestate) + ")"; 952 } 953 954 @Override 955 protected String java_name_impl(VarInfo v) { 956 return java_family_impl(OutputFormat.JAVA, v); 957 } 958 959 @Override 960 protected String jml_name_impl(VarInfo v) { 961 return java_family_impl(OutputFormat.JML, v); 962 } 963 964 @Override 965 protected String dbc_name_impl(VarInfo v) { 966 return java_family_impl(OutputFormat.DBCJAVA, v); 967 } 968 969 protected String java_family_impl(OutputFormat format, VarInfo v) { 970 971 // See declaration of testCall for explanation of this flag. 972 if (testCall) { 973 return "no format when testCall."; 974 } 975 976 assert v != null; 977 assert v.isDerived(); 978 Derivation derived = v.derived; 979 assert derived instanceof SequenceLength; 980 VarInfo seqVarInfo = ((SequenceLength) derived).base; 981 String prefix = get_term().name_using(format, seqVarInfo); 982 return "daikon.Quant.size(" + prefix + ")"; 983 // if (seqVarInfo.type.pseudoDimensions() > seqVarInfo.type.dimensions()) { 984 // if (prefix.startsWith("daikon.Quant.collect")) { 985 // // Quant collect methods returns an array 986 // return prefix + ".length"; 987 // } else { 988 // // It's a Collection 989 // return prefix + ".size()"; 990 // } 991 // } else { 992 // // It's an array 993 // return prefix + ".length"; 994 // } 995 } 996 997 @Override 998 protected String identifier_name_impl() { 999 return "size_of" + sequence.identifier_name() + "___"; 1000 } 1001 1002 @Override 1003 public <T> T accept(Visitor<T> v) { 1004 return v.visitSizeOf(this); 1005 } 1006 } 1007 1008 /** 1009 * Returns a name for a unary function applied to this object. The result is like "sum(this)". 1010 * 1011 * @param function the function to apply 1012 * @return a name for the function applied to this 1013 */ 1014 public VarInfoName applyFunction(@Interned VarInfoName this, String function) { 1015 return new FunctionOf(function, this).intern(); 1016 } 1017 1018 /** 1019 * Returns a name for a function applied to more than one argument. The result is like "sum(var1, 1020 * var2)". 1021 * 1022 * @param function the name of the function 1023 * @param vars the arguments to the function, of type VarInfoName 1024 * @return a name for a function applied to multiple arguments 1025 */ 1026 public static VarInfoName applyFunctionOfN(String function, List<VarInfoName> vars) { 1027 return new FunctionOfN(function, vars).intern(); 1028 } 1029 1030 /** 1031 * Returns a name for a function of more than one argument. The result is like "sum(var1, var2)". 1032 * 1033 * @param function the name of the function 1034 * @param vars the arguments to the function 1035 */ 1036 public static VarInfoName applyFunctionOfN(String function, @Interned VarInfoName[] vars) { 1037 // This causes an odd error with the Interned checker: 1038 // return applyFunctionOfN(function, Arrays.<@Interned VarInfoName>asList(vars)); 1039 return applyFunctionOfN(function, Arrays.asList(vars)); 1040 } 1041 1042 /** A function over a term, like "sum(argument)". */ 1043 public static @Interned class FunctionOf extends VarInfoName { 1044 // We are Serializable, so we specify a version to allow changes to 1045 // method signatures without breaking serialization. If you add or 1046 // remove fields, you should change this number to the current date. 1047 static final long serialVersionUID = 20020130L; 1048 1049 public final String function; 1050 public final VarInfoName argument; 1051 1052 public FunctionOf(String function, VarInfoName argument) { 1053 assert function != null; 1054 assert argument != null; 1055 this.function = function; 1056 this.argument = argument; 1057 } 1058 1059 @Override 1060 protected String repr_impl(@GuardSatisfied FunctionOf this) { 1061 return "FunctionOf{" + function + "}[" + argument.repr() + "]"; 1062 } 1063 1064 @Override 1065 protected String name_impl(@GuardSatisfied FunctionOf this) { 1066 return function + "(" + argument.name() + ")"; 1067 } 1068 1069 @Override 1070 protected String esc_name_impl() { 1071 return "(warning: format_esc() needs to be implemented: " 1072 + function 1073 + " on " 1074 + argument.repr() 1075 + ")"; 1076 } 1077 1078 @Override 1079 protected String simplify_name_impl(boolean prestate) { 1080 return "(warning: format_simplify() needs to be implemented: " 1081 + function 1082 + " on " 1083 + argument.repr() 1084 + ")"; 1085 } 1086 1087 @Override 1088 protected String java_name_impl(VarInfo v) { 1089 return java_family_name_impl(OutputFormat.JAVA, v); 1090 } 1091 1092 @Override 1093 protected String jml_name_impl(VarInfo v) { 1094 return java_family_name_impl(OutputFormat.JML, v); 1095 } 1096 1097 @Override 1098 protected String dbc_name_impl(VarInfo v) { 1099 return java_family_name_impl(OutputFormat.DBCJAVA, v); 1100 } 1101 1102 protected String java_family_name_impl(OutputFormat format, VarInfo v) { 1103 1104 // See declaration of testCall for explanation of this flag. 1105 if (testCall) { 1106 return "no format when testCall."; 1107 } 1108 1109 assert v != null; 1110 assert v.isDerived(); 1111 Derivation derived = v.derived; 1112 assert derived instanceof UnaryDerivation; 1113 VarInfo argVarInfo = ((UnaryDerivation) derived).base; 1114 return "daikon.Quant." + function + "(" + argument.name_using(format, argVarInfo) + ")"; 1115 } 1116 1117 @Override 1118 protected String identifier_name_impl() { 1119 return function + "_of_" + argument.identifier_name() + "___"; 1120 } 1121 1122 @Override 1123 public <T> T accept(Visitor<T> v) { 1124 return v.visitFunctionOf(this); 1125 } 1126 } 1127 1128 /** A function of multiple parameters. */ 1129 public static @Interned class FunctionOfN extends VarInfoName { 1130 /** If you add or remove fields, change this number to the current date. */ 1131 static final long serialVersionUID = 20020130L; 1132 1133 /** The function being invoked. */ 1134 public final String function; 1135 1136 /** The parameters. */ 1137 @SuppressWarnings("serial") 1138 public final List<VarInfoName> args; 1139 1140 /** 1141 * Construct a new function of multiple arguments. 1142 * 1143 * @param function the name of the function 1144 * @param args the arguments to the function, of type VarInfoName 1145 */ 1146 public FunctionOfN(String function, List<VarInfoName> args) { 1147 assert function != null; 1148 assert args != null; 1149 this.args = args; 1150 this.function = function; 1151 } 1152 1153 /** 1154 * Returns a string representation of the elements of this. 1155 * 1156 * @return a string representation of the elements of this 1157 */ 1158 private List<String> elts_repr(@GuardSatisfied FunctionOfN this) { 1159 List<String> elts = new ArrayList<>(args.size()); 1160 for (VarInfoName vin : args) { 1161 elts.add(vin.repr()); 1162 } 1163 return elts; 1164 } 1165 1166 /** 1167 * Return a comma-separated list of element names. 1168 * 1169 * @return comma-separated list of element names 1170 */ 1171 private String elts_repr_commas(@GuardSatisfied FunctionOfN this) { 1172 return String.join(", ", elts_repr()); 1173 } 1174 1175 @Override 1176 protected String repr_impl(@GuardSatisfied FunctionOfN this) { 1177 return "FunctionOfN{" + function + "}[" + elts_repr_commas() + "]"; 1178 } 1179 1180 @Override 1181 protected String name_impl(@GuardSatisfied FunctionOfN this) { 1182 return function + "(" + elts_repr_commas() + ")"; 1183 } 1184 1185 @Override 1186 protected String esc_name_impl() { 1187 return "(warning: format_esc() needs to be implemented: " 1188 + function 1189 + " on " 1190 + elts_repr_commas() 1191 + ")"; 1192 } 1193 1194 @Override 1195 protected String simplify_name_impl(boolean prestate) { 1196 return "(warning: format_simplify() needs to be implemented: " 1197 + function 1198 + " on " 1199 + elts_repr_commas() 1200 + ")"; 1201 } 1202 1203 @Override 1204 protected String java_name_impl(VarInfo v) { 1205 return java_family_name_impl(OutputFormat.JAVA, v); 1206 } 1207 1208 @Override 1209 protected String jml_name_impl(VarInfo v) { 1210 return java_family_name_impl(OutputFormat.JML, v); 1211 } 1212 1213 @Override 1214 protected String dbc_name_impl(VarInfo v) { 1215 return java_family_name_impl(OutputFormat.DBCJAVA, v); 1216 } 1217 1218 // Only works for two-argument functions. There are currently no 1219 // ternary (or greater) function applications in Daikon. 1220 protected String java_family_name_impl(OutputFormat format, VarInfo v) { 1221 1222 // See declaration of testCall for explanation of this flag. 1223 if (testCall) { 1224 return "no format when testCall."; 1225 } 1226 1227 assert v != null; 1228 assert v.isDerived(); 1229 Derivation derived = v.derived; 1230 assert derived instanceof BinaryDerivation; 1231 // || derived instanceof TernaryDerivation); 1232 assert args.size() == 2; 1233 VarInfo arg1VarInfo = ((BinaryDerivation) derived).base1; 1234 VarInfo arg2VarInfo = ((BinaryDerivation) derived).base2; 1235 return "daikon.Quant." 1236 + function 1237 + "(" 1238 + args.get(0).name_using(format, arg1VarInfo) 1239 + ", " 1240 + args.get(1).name_using(format, arg2VarInfo) 1241 + ")"; 1242 } 1243 1244 @Override 1245 protected String identifier_name_impl() { 1246 List<String> elts = new ArrayList<>(args.size()); 1247 for (VarInfoName vin : args) { 1248 elts.add(vin.identifier_name()); 1249 } 1250 return function + "_of_" + String.join("_comma_", elts) + "___"; 1251 } 1252 1253 /** Shortcut getter to avoid repeated type casting. */ 1254 public VarInfoName getArg(int n) { 1255 return args.get(n); 1256 } 1257 1258 @Override 1259 public <T> T accept(Visitor<T> v) { 1260 return v.visitFunctionOfN(this); 1261 } 1262 } 1263 1264 /** 1265 * Returns a name for the intersection of with another sequence, like "intersect(a[], b[])". 1266 * 1267 * @param seq2 the variable to intersect with 1268 * @return the name for the intersection of this and seq2 1269 */ 1270 public VarInfoName applyIntersection(@Interned VarInfoName this, VarInfoName seq2) { 1271 assert seq2 != null; 1272 return new Intersection(this, seq2).intern(); 1273 } 1274 1275 /** 1276 * Intersection of two sequences. Extends FunctionOfN, and the only change is that it does special 1277 * formatting for IOA. 1278 */ 1279 public static @Interned class Intersection extends FunctionOfN { 1280 // We are Serializable, so we specify a version to allow changes to 1281 // method signatures without breaking serialization. If you add or 1282 // remove fields, you should change this number to the current date. 1283 static final long serialVersionUID = 20020130L; 1284 1285 public Intersection(VarInfoName seq1, VarInfoName seq2) { 1286 super("intersection", Arrays.asList(seq1, seq2)); 1287 } 1288 } 1289 1290 /** 1291 * Returns a name for the union of this with another sequence, like "union(a[], b[])". 1292 * 1293 * @param seq2 the variable to union with 1294 * @return the name for the intersection of this and seq2 1295 */ 1296 public VarInfoName applyUnion(@Interned VarInfoName this, VarInfoName seq2) { 1297 assert seq2 != null; 1298 return new Union(this, seq2).intern(); 1299 } 1300 1301 /** 1302 * Union of two sequences. Extends FunctionOfN, and the only change is that it does special 1303 * formatting for IOA. 1304 */ 1305 public static @Interned class Union extends FunctionOfN { 1306 // We are Serializable, so we specify a version to allow changes to 1307 // method signatures without breaking serialization. If you add or 1308 // remove fields, you should change this number to the current date. 1309 static final long serialVersionUID = 20020130L; 1310 1311 public Union(VarInfoName seq1, VarInfoName seq2) { 1312 super("intersection", Arrays.asList(seq1, seq2)); 1313 } 1314 } 1315 1316 /** 1317 * Returns a 'getter' operation for some field of this name, like a.foo if this is a. 1318 * 1319 * @param field the field 1320 * @return the name for the given field of this 1321 */ 1322 public VarInfoName applyField(@Interned VarInfoName this, String field) { 1323 return new Field(this, field).intern(); 1324 } 1325 1326 /** A 'getter' operation for some field, like a.foo. */ 1327 public static @Interned class Field extends VarInfoName { 1328 // We are Serializable, so we specify a version to allow changes to 1329 // method signatures without breaking serialization. If you add or 1330 // remove fields, you should change this number to the current date. 1331 static final long serialVersionUID = 20020130L; 1332 1333 public final VarInfoName term; 1334 public final String field; 1335 1336 public Field(VarInfoName term, String field) { 1337 assert term != null; 1338 assert field != null; 1339 this.term = term; 1340 this.field = field; 1341 } 1342 1343 @Override 1344 protected String repr_impl(@GuardSatisfied Field this) { 1345 return "Field{" + field + "}[" + term.repr() + "]"; 1346 } 1347 1348 @Override 1349 protected String name_impl(@GuardSatisfied Field this) { 1350 return term.name() + "." + field; 1351 } 1352 1353 @Override 1354 protected String esc_name_impl() { 1355 return term.esc_name() + "." + field; 1356 } 1357 1358 @Override 1359 protected String simplify_name_impl(boolean prestate) { 1360 return "(select " 1361 + Simple.simplify_name_impl(field, false) 1362 + " " 1363 + term.simplify_name(prestate) 1364 + ")"; 1365 } 1366 1367 @Override 1368 protected String java_name_impl(VarInfo v) { 1369 return java_family_name(OutputFormat.JAVA, v); 1370 } 1371 1372 @Override 1373 protected String jml_name_impl(VarInfo v) { 1374 return java_family_name(OutputFormat.JML, v); 1375 } 1376 1377 @Override 1378 protected String dbc_name_impl(VarInfo v) { 1379 return java_family_name(OutputFormat.DBCJAVA, v); 1380 } 1381 1382 // Special case: the fake "toString" field in Daikon is output 1383 // with parens, so that it's legal Java. 1384 protected String java_field(String f) { 1385 if (f.equals("toString")) { 1386 return "toString()"; 1387 } else { 1388 return f; 1389 } 1390 } 1391 1392 // For JAVA, JML and DBC formats. 1393 protected String java_family_name(OutputFormat format, VarInfo v) { 1394 1395 // See declaration of testCall for explanation of this flag. 1396 if (testCall) { 1397 return "no format when testCall."; 1398 } 1399 1400 if (term.name().indexOf("..") != -1) { 1401 // We cannot translate arr[i..].x because this translates into 1402 // 1403 // "daikon.Quant.collect(daikon.Quant.slice(arr,i,arr.length),"x")" 1404 // 1405 // but slice() returns an array of Objects, so an error will 1406 // occur when method collect() tries to query for field "x". 1407 return "(warning: " 1408 + format 1409 + " format cannot express a field applied to a slice:" 1410 + " [repr=" 1411 + repr() 1412 + "])"; 1413 } 1414 1415 boolean hasBrackets = (term.name().indexOf("[]") != -1); 1416 1417 if (format == OutputFormat.JAVA) { 1418 assert !hasBrackets || v.type.dimensions() > 0 1419 : "hasBrackets:" + hasBrackets + ", dimensions:" + v.type.dimensions() + ", v:" + v; 1420 } 1421 1422 if (!hasBrackets && format != OutputFormat.JAVA) { 1423 // Case 1: Not an array collection 1424 String term_name = null; 1425 if (format == OutputFormat.JML) { 1426 term_name = term.jml_name(v); 1427 } else { 1428 term_name = term.dbc_name(v); 1429 } 1430 return term_name + "." + java_field(field); 1431 } 1432 1433 // Case 2: An array collection 1434 1435 // How to translate foo[].f, which is the array obtained from 1436 // collecting o.f for every element o in the array foo? Just as 1437 // we did for slices, we'll translate this into a call of an 1438 // external function to do the job: 1439 1440 // x.y.foo[].bar.f 1441 // ---translates-into---> 1442 // daikon.Quant.collect_TYPE_(x, "y.foo[].bar.f") 1443 1444 // The method Quant.collect takes care of the "y.foo[].bar.f" 1445 // mess for object x. 1446 1447 if (field.equals("toString")) { 1448 return "(warning: " 1449 + format 1450 + " format cannot express a slice with String objects:" 1451 + " obtained by toString(): [repr=" 1452 + repr() 1453 + "])"; 1454 } 1455 1456 String term_name_no_brackets = term.name().replaceAll("\\[\\]", "") + "." + field; 1457 1458 @SuppressWarnings("keyfor") // PACKAGE_NAME is always a key 1459 String packageName = v.aux.getValue(VarInfoAux.PACKAGE_NAME); 1460 if (packageName.equals(VarInfoAux.NO_PACKAGE_NAME)) { 1461 packageName = ""; 1462 } 1463 1464 String[] splits; 1465 boolean isStatic = false; 1466 String packageNamePrefix = null; 1467 // if (isStatic) { 1468 if (term_name_no_brackets.startsWith(packageName + ".")) { 1469 // throw new Error("packageName=" + packageName + ", term_name_no_brackets=" + 1470 // term_name_no_brackets); 1471 // } 1472 // Before splitting, remove the package name. 1473 packageNamePrefix = (packageName.equals("") ? "" : packageName + "."); 1474 isStatic = true; 1475 splits = term_name_no_brackets.substring(packageNamePrefix.length()).split("\\."); 1476 } else { 1477 packageNamePrefix = ""; 1478 isStatic = false; 1479 splits = term_name_no_brackets.split("\\."); 1480 } 1481 1482 String object = splits[0]; 1483 if (isStatic) { 1484 object += DaikonVariableInfo.class_suffix; 1485 } 1486 if (object.equals("return")) { 1487 if (format == OutputFormat.DBCJAVA) { 1488 object = "$return"; 1489 } else { 1490 object = "\\result"; 1491 } 1492 } 1493 1494 String fields = ""; 1495 for (int j = 1; j < splits.length; j++) { 1496 if (j != 1) { 1497 fields += "."; 1498 } 1499 fields += splits[j]; 1500 } 1501 1502 String collectType = (v.type.baseIsPrimitive() ? v.type.base() : "Object"); 1503 1504 if (format == OutputFormat.JAVA) { 1505 return 1506 // On one line to enable searches for "collect.*_field". 1507 "daikon.Quant.collect" 1508 + collectType 1509 + (!v.is_array() ? "_field" : "") 1510 + "(" 1511 + packageNamePrefix 1512 + object 1513 + ", " 1514 + "\"" 1515 + fields 1516 + "\"" 1517 + ")"; 1518 } else { 1519 return "daikon.Quant.collect" 1520 + collectType 1521 + "(" 1522 + packageNamePrefix 1523 + object 1524 + ", " 1525 + "\"" 1526 + fields 1527 + "\"" 1528 + ")"; 1529 } 1530 } 1531 1532 @Override 1533 protected String identifier_name_impl() { 1534 return term.identifier_name() + "_dot_" + field; 1535 } 1536 1537 @Override 1538 public <T> T accept(Visitor<T> v) { 1539 return v.visitField(this); 1540 } 1541 } 1542 1543 /** 1544 * Returns a name for the type of this object; form is like "this.getClass().getName()" or 1545 * "\typeof(this)". 1546 * 1547 * @return the name for the type of this object 1548 */ 1549 public VarInfoName applyTypeOf(@Interned VarInfoName this) { 1550 return new TypeOf(this).intern(); 1551 } 1552 1553 /** The type of the term, like "term.getClass().getName()" or "\typeof(term)". */ 1554 public static @Interned class TypeOf extends VarInfoName { 1555 // We are Serializable, so we specify a version to allow changes to 1556 // method signatures without breaking serialization. If you add or 1557 // remove fields, you should change this number to the current date. 1558 static final long serialVersionUID = 20020130L; 1559 1560 public final VarInfoName term; 1561 1562 public TypeOf(VarInfoName term) { 1563 assert term != null; 1564 this.term = term; 1565 } 1566 1567 @Override 1568 protected String repr_impl(@GuardSatisfied TypeOf this) { 1569 return "TypeOf[" + term.repr() + "]"; 1570 } 1571 1572 @Override 1573 protected String name_impl(@GuardSatisfied TypeOf this) { 1574 return term.name() + DaikonVariableInfo.class_suffix; 1575 } 1576 1577 @Override 1578 protected String esc_name_impl() { 1579 return "\\typeof(" + term.esc_name() + ")"; 1580 } 1581 1582 @Override 1583 protected String simplify_name_impl(boolean prestate) { 1584 return "(typeof " + term.simplify_name(prestate) + ")"; 1585 } 1586 1587 @SideEffectFree 1588 protected String javaFamilyFormat(String varname, boolean isArray) { 1589 if (isArray) { 1590 return "daikon.Quant.typeArray(" + varname + ")"; 1591 } else { 1592 return varname + DaikonVariableInfo.class_suffix; 1593 } 1594 } 1595 1596 @Override 1597 protected String java_name_impl(VarInfo v) { 1598 if (testCall) { 1599 return "no format when testCall."; 1600 } 1601 return javaFamilyFormat(term.java_name(v), v.type.isArray()); 1602 } 1603 1604 @Override 1605 protected String jml_name_impl(VarInfo v) { 1606 if (testCall) { 1607 return "no format when testCall."; 1608 } 1609 return javaFamilyFormat(term.jml_name(v), v.type.isArray()); 1610 } 1611 1612 @Override 1613 protected String dbc_name_impl(VarInfo v) { 1614 if (testCall) { 1615 return "no format when testCall."; 1616 } 1617 return javaFamilyFormat(term.dbc_name(v), v.type.isArray()); 1618 } 1619 1620 @Override 1621 protected String identifier_name_impl() { 1622 return "type_of_" + term.identifier_name() + "___"; 1623 } 1624 1625 @Override 1626 public <T> T accept(Visitor<T> v) { 1627 return v.visitTypeOf(this); 1628 } 1629 } 1630 1631 /** 1632 * Returns a name for a the prestate value of this object; form is like "orig(this)" or 1633 * "\old(this)". 1634 * 1635 * @return a name for the prestate value of this object 1636 */ 1637 public VarInfoName applyPrestate(@Interned VarInfoName this) { 1638 if (this instanceof Poststate) { 1639 return ((Poststate) this).term; 1640 } else if ((this instanceof Add) && ((Add) this).term instanceof Poststate) { 1641 Add a = (Add) this; 1642 Poststate p = (Poststate) a.term; 1643 return p.term.applyAdd(a.amount); 1644 } else { 1645 return new Prestate(this).intern(); 1646 } 1647 } 1648 1649 /** The prestate value of a term, like "orig(term)" or "\old(term)". */ 1650 public static @Interned class Prestate extends VarInfoName { 1651 // We are Serializable, so we specify a version to allow changes to 1652 // method signatures without breaking serialization. If you add or 1653 // remove fields, you should change this number to the current date. 1654 static final long serialVersionUID = 20020130L; 1655 1656 public final VarInfoName term; 1657 1658 public Prestate(VarInfoName term) { 1659 assert term != null; 1660 this.term = term; 1661 } 1662 1663 @Override 1664 protected String repr_impl(@GuardSatisfied Prestate this) { 1665 return "Prestate[" + term.repr() + "]"; 1666 } 1667 1668 @Override 1669 protected String name_impl(@GuardSatisfied Prestate this) { 1670 return "orig(" + term.name() + ")"; 1671 } 1672 1673 @Override 1674 protected String esc_name_impl() { 1675 return "\\old(" + term.esc_name() + ")"; 1676 } 1677 1678 @Override 1679 protected String simplify_name_impl(boolean prestate) { 1680 return term.simplify_name(true); 1681 } 1682 1683 @Override 1684 protected String java_name_impl(VarInfo v) { 1685 if (PrintInvariants.dkconfig_replace_prestate) { 1686 return PrintInvariants.addPrestateExpression(term.java_name(v)); 1687 } 1688 return "\\old(" + term.java_name(v) + ")"; 1689 } 1690 1691 @Override 1692 protected String jml_name_impl(VarInfo v) { 1693 return "\\old(" + term.jml_name(v) + ")"; 1694 } 1695 1696 @Override 1697 protected String dbc_name_impl(VarInfo v) { 1698 1699 // See declaration of testCall for explanation of this flag. 1700 if (testCall) { 1701 return "no format when testCall."; 1702 } 1703 1704 String brackets = ""; 1705 assert v != null; 1706 String preType = v.type.base(); 1707 if ((term instanceof Slice) 1708 // Slices are obtained by calling daikon.Quant.slice(...) 1709 // which returns things of type java.lang.Object 1710 && v.type.dimensions() > 0 1711 && v.type.base().equals("java.lang.Object")) { 1712 preType = "java.lang.Object"; 1713 } 1714 for (int i = 0; i < v.type.dimensions(); i++) { 1715 brackets += "[]"; 1716 } 1717 return "$pre(" + preType + brackets + ", " + term.dbc_name(v) + ")"; 1718 } 1719 1720 @Override 1721 protected String identifier_name_impl() { 1722 return "orig_of_" + term.identifier_name() + "___"; 1723 } 1724 1725 @Override 1726 public <T> T accept(Visitor<T> v) { 1727 return v.visitPrestate(this); 1728 } 1729 } 1730 1731 // sansOrig() 1732 // int origpos = s.indexOf("orig("); 1733 // assert origpos != -1; 1734 // int rparenpos = s.lastIndexOf(")"); 1735 // return s.substring(0, origpos) 1736 // + s.substring(origpos+5, rparenpos) 1737 // + s.substring(rparenpos+1); 1738 1739 // int origpos = s.indexOf("\\old("); 1740 // assert origpos != -1; 1741 // int rparenpos = s.lastIndexOf(")"); 1742 // return s.substring(0, origpos) 1743 // + s.substring(origpos+5, rparenpos) 1744 // + s.substring(rparenpos+1); 1745 1746 /** 1747 * Returns a name for a the poststate value of this object; form is like "new(this)" or 1748 * "\new(this)". 1749 * 1750 * @return the name for the poststate value of this object 1751 */ 1752 public VarInfoName applyPoststate(@Interned VarInfoName this) { 1753 return new Poststate(this).intern(); 1754 } 1755 1756 /** 1757 * The poststate value of a term, like "new(term)". Only used within prestate, so like 1758 * "orig(this.myArray[new(index)]". 1759 */ 1760 public static @Interned class Poststate extends VarInfoName { 1761 // We are Serializable, so we specify a version to allow changes to 1762 // method signatures without breaking serialization. If you add or 1763 // remove fields, you should change this number to the current date. 1764 static final long serialVersionUID = 20020130L; 1765 1766 public final VarInfoName term; 1767 1768 public Poststate(VarInfoName term) { 1769 assert term != null; 1770 this.term = term; 1771 } 1772 1773 @Override 1774 protected String repr_impl(@GuardSatisfied Poststate this) { 1775 return "Poststate[" + term.repr() + "]"; 1776 } 1777 1778 @Override 1779 protected String name_impl(@GuardSatisfied Poststate this) { 1780 return "post(" + term.name() + ")"; 1781 } 1782 1783 @Override 1784 protected String esc_name_impl() { 1785 return "\\new(" + term.esc_name() + ")"; 1786 } 1787 1788 @Override 1789 protected String simplify_name_impl(boolean prestate) { 1790 return term.simplify_name(false); 1791 } 1792 1793 @Override 1794 protected String java_name_impl(VarInfo v) { 1795 return "\\post(" + term.java_name(v) + ")"; 1796 } 1797 1798 @Override 1799 protected String jml_name_impl(VarInfo v) { 1800 return "\\new(" + term.jml_name(v) + ")"; 1801 // return "(warning: JML format cannot express a Poststate" 1802 // + " [repr=" + repr() + "])"; 1803 } 1804 1805 @Override 1806 protected String dbc_name_impl(VarInfo v) { 1807 return "(warning: DBC format cannot express a Poststate [repr=" + repr() + "])"; 1808 } 1809 1810 @Override 1811 protected String identifier_name_impl() { 1812 return "post_of_" + term.identifier_name() + "___"; 1813 } 1814 1815 @Override 1816 public <T> T accept(Visitor<T> v) { 1817 return v.visitPoststate(this); 1818 } 1819 } 1820 1821 /** Returns a name for the this term plus a constant, like "this-1" or "this+1". */ 1822 public VarInfoName applyAdd(@Interned VarInfoName this, int amount) { 1823 if (amount == 0) { 1824 return this; 1825 } else { 1826 return new Add(this, amount).intern(); 1827 } 1828 } 1829 1830 /** An integer amount more or less than some other value, like "x+2". */ 1831 public static @Interned class Add extends VarInfoName { 1832 // We are Serializable, so we specify a version to allow changes to 1833 // method signatures without breaking serialization. If you add or 1834 // remove fields, you should change this number to the current date. 1835 static final long serialVersionUID = 20020130L; 1836 1837 public final VarInfoName term; 1838 public final int amount; 1839 1840 public Add(VarInfoName term, int amount) { 1841 assert term != null; 1842 this.term = term; 1843 this.amount = amount; 1844 } 1845 1846 private String amount(@GuardSatisfied Add this) { 1847 return (amount < 0) ? String.valueOf(amount) : "+" + amount; 1848 } 1849 1850 @Override 1851 protected String repr_impl(@GuardSatisfied Add this) { 1852 return "Add{" + amount() + "}[" + term.repr() + "]"; 1853 } 1854 1855 @Override 1856 protected String name_impl(@GuardSatisfied Add this) { 1857 return term.name() + amount(); 1858 } 1859 1860 @Override 1861 protected String esc_name_impl() { 1862 return term.esc_name() + amount(); 1863 } 1864 1865 @Override 1866 protected String simplify_name_impl(boolean prestate) { 1867 return (amount < 0) 1868 ? "(- " + term.simplify_name(prestate) + " " + -amount + ")" 1869 : "(+ " + term.simplify_name(prestate) + " " + amount + ")"; 1870 } 1871 1872 @Override 1873 protected String java_name_impl(VarInfo v) { 1874 return term.java_name(v) + amount(); 1875 } 1876 1877 @Override 1878 protected String jml_name_impl(VarInfo v) { 1879 return term.jml_name(v) + amount(); 1880 } 1881 1882 @Override 1883 protected String dbc_name_impl(VarInfo v) { 1884 return term.dbc_name(v) + amount(); 1885 } 1886 1887 @Override 1888 protected String identifier_name_impl() { 1889 if (amount >= 0) { 1890 return term.identifier_name() + "_plus" + amount; 1891 } else { 1892 return term.identifier_name() + "_minus" + -amount; 1893 } 1894 } 1895 1896 @Override 1897 public <T> T accept(Visitor<T> v) { 1898 return v.visitAdd(this); 1899 } 1900 1901 // override for cleanliness 1902 @Override 1903 public VarInfoName applyAdd(int _amount) { 1904 int amt = _amount + this.amount; 1905 return (amt == 0) ? term : term.applyAdd(amt); 1906 } 1907 } 1908 1909 /** Returns a name for the decrement of this term, like "this-1". */ 1910 public VarInfoName applyDecrement(@Interned VarInfoName this) { 1911 return applyAdd(-1); 1912 } 1913 1914 /** Returns a name for the increment of this term, like "this+1". */ 1915 public VarInfoName applyIncrement(@Interned VarInfoName this) { 1916 return applyAdd(+1); 1917 } 1918 1919 /** 1920 * Returns a name for the elements of a container (as opposed to the identity of the container) 1921 * like "this[]" or "(elements this)". 1922 * 1923 * @return the name for the elements of this container 1924 */ 1925 public VarInfoName applyElements(@Interned VarInfoName this) { 1926 return new Elements(this).intern(); 1927 } 1928 1929 /** The elements of a container, like "term[]". */ 1930 public static @Interned class Elements extends VarInfoName { 1931 // We are Serializable, so we specify a version to allow changes to 1932 // method signatures without breaking serialization. If you add or 1933 // remove fields, you should change this number to the current date. 1934 static final long serialVersionUID = 20020130L; 1935 1936 public final VarInfoName term; 1937 1938 public Elements(VarInfoName term) { 1939 assert term != null; 1940 this.term = term; 1941 } 1942 1943 @Override 1944 protected String repr_impl(@GuardSatisfied Elements this) { 1945 return "Elements[" + term.repr() + "]"; 1946 } 1947 1948 @Override 1949 protected String name_impl(@GuardSatisfied Elements this) { 1950 return name_impl(""); 1951 } 1952 1953 protected String name_impl(@GuardSatisfied Elements this, String index) { 1954 return term.name() + "[" + index + "]"; 1955 } 1956 1957 @Override 1958 protected String esc_name_impl() { 1959 throw new UnsupportedOperationException( 1960 "ESC cannot format an unquantified sequence of elements [repr=" + repr() + "]"); 1961 } 1962 1963 protected String esc_name_impl(String index) { 1964 return term.esc_name() + "[" + index + "]"; 1965 } 1966 1967 @Override 1968 protected String simplify_name_impl(boolean prestate) { 1969 return "(select elems " + term.simplify_name(prestate) + ")"; 1970 } 1971 1972 @Override 1973 protected String java_name_impl(VarInfo v) { 1974 return term.java_name(v); 1975 } 1976 1977 protected String java_name_impl(String index, VarInfo v) { 1978 return java_family_impl(OutputFormat.JAVA, v, index); 1979 } 1980 1981 @Override 1982 protected String jml_name_impl(VarInfo v) { 1983 return term.jml_name(v); 1984 } 1985 1986 protected String jml_name_impl(String index, VarInfo v) { 1987 return java_family_impl(OutputFormat.JML, v, index); 1988 } 1989 1990 @Override 1991 protected String dbc_name_impl(VarInfo v) { 1992 return term.dbc_name(v); 1993 } 1994 1995 protected String dbc_name_impl(String index, VarInfo v) { 1996 return java_family_impl(OutputFormat.DBCJAVA, v, index); 1997 } 1998 1999 protected String java_family_impl(OutputFormat format, VarInfo v, String index) { 2000 2001 // If the collection goes through daikon.Quant.collect___, then 2002 // it will be returned as an array no matter what. 2003 String formatted = term.name_using(format, v); 2004 String collectType = (v.type.baseIsPrimitive() ? v.type.base() : "Object"); 2005 return "daikon.Quant.getElement_" + collectType + "(" + formatted + ", " + index + ")"; 2006 // // XXX temporary fix: sometimes long is passed as index. 2007 // // I can't find where the VarInfo for "index" is found. Wherever that is, 2008 // // we should check if its type is long, and do the casting only for that 2009 // // case. 2010 // if (formatted.startsWith("daikon.Quant.collect")) { 2011 // return formatted + "[(int)" + index + "]"; 2012 // } else { 2013 // if (v.type.pseudoDimensions() > v.type.dimensions()) { 2014 // // it's a collection 2015 // return formatted + ".get((int)" + index + ")"; 2016 // } else { 2017 // // it's an array 2018 // return formatted + "[(int)" + index + "]"; 2019 // } 2020 // } 2021 } 2022 2023 protected String identifier_name_impl(String index) { 2024 if (index.equals("")) { 2025 return term.identifier_name() + "_elems"; 2026 } else { 2027 return term.identifier_name() + "_in_" + index + "_dex_"; 2028 } 2029 } 2030 2031 @Override 2032 protected String identifier_name_impl() { 2033 return identifier_name_impl(""); 2034 } 2035 2036 @Override 2037 public <T> T accept(Visitor<T> v) { 2038 return v.visitElements(this); 2039 } 2040 2041 public VarInfoName getLowerBound() { 2042 return ZERO; 2043 } 2044 2045 public VarInfoName getUpperBound() { 2046 return applySize().applyDecrement(); 2047 } 2048 2049 public VarInfoName getSubscript(VarInfoName index) { 2050 return applySubscript(index); 2051 } 2052 } 2053 2054 /** 2055 * Caller is subscripting an orig(a[]) array. Take the requested index and make it useful in that 2056 * context. 2057 * 2058 * @param index an index into an orig array 2059 * @return a name for the indexed orig item 2060 */ 2061 static VarInfoName indexToPrestate(VarInfoName index) { 2062 // 1 orig(a[]) . orig(index) -> orig(a[index]) 2063 // 2 orig(a[]) . index -> orig(a[post(index)]) 2064 if (index instanceof Prestate) { 2065 index = ((Prestate) index).term; // #1 2066 } else if (index instanceof Add) { 2067 Add add = (Add) index; 2068 if (add.term instanceof Prestate) { 2069 index = ((Prestate) add.term).term.applyAdd(add.amount); // #1 2070 } else { 2071 index = index.applyPoststate(); // #2 2072 } 2073 } else if (index.isLiteralConstant()) { 2074 // we don't want orig(a[post(0)]), so leave index alone 2075 } else { 2076 index = index.applyPoststate(); // #2 2077 } 2078 return index; 2079 } 2080 2081 /** Returns a name for an element selected from a sequence, like "this[i]". */ 2082 public VarInfoName applySubscript(@Interned VarInfoName this, VarInfoName index) { 2083 assert index != null; 2084 ElementsFinder finder = new ElementsFinder(this); 2085 Elements elems = finder.elems(); 2086 assert elems != null : "applySubscript should have elements to use in " + this; 2087 if (finder.inPre()) { 2088 index = indexToPrestate(index); 2089 } 2090 Replacer r = new Replacer(elems, new Subscript(elems, index).intern()); 2091 return r.replace(this).intern(); 2092 } 2093 2094 // Given a sequence and subscript index, convert the index to an 2095 // explicit form if necessary (e.g. a[-1] becomes a[a.length-1]). 2096 // Result is not interned, because it is only ever used for printing. 2097 static VarInfoName indexExplicit(Elements sequence, VarInfoName index) { 2098 if (!index.isLiteralConstant()) { 2099 return index; 2100 } 2101 2102 int i = Integer.parseInt(index.name()); 2103 if (i >= 0) { 2104 return index; 2105 } 2106 2107 return sequence.applySize().applyAdd(i); 2108 } 2109 2110 /** An element from a sequence, like "sequence[index]". */ 2111 public static @Interned class Subscript extends VarInfoName { 2112 // We are Serializable, so we specify a version to allow changes to 2113 // method signatures without breaking serialization. If you add or 2114 // remove fields, you should change this number to the current date. 2115 static final long serialVersionUID = 20020130L; 2116 2117 public final Elements sequence; 2118 public final VarInfoName index; 2119 2120 public Subscript(Elements sequence, VarInfoName index) { 2121 assert sequence != null; 2122 assert index != null; 2123 this.sequence = sequence; 2124 this.index = index; 2125 } 2126 2127 @Override 2128 protected String repr_impl(@GuardSatisfied Subscript this) { 2129 return "Subscript{" + index.repr() + "}[" + sequence.repr() + "]"; 2130 } 2131 2132 @Override 2133 protected String name_impl(@GuardSatisfied Subscript this) { 2134 return sequence.name_impl(index.name()); 2135 } 2136 2137 @Override 2138 protected String esc_name_impl() { 2139 return sequence.esc_name_impl(indexExplicit(sequence, index).esc_name()); 2140 } 2141 2142 @Override 2143 protected String simplify_name_impl(boolean prestate) { 2144 return "(select " 2145 + sequence.simplify_name(prestate) 2146 + " " 2147 + indexExplicit(sequence, index).simplify_name(prestate) 2148 + ")"; 2149 } 2150 2151 @Override 2152 protected String java_name_impl(VarInfo v) { 2153 return java_family_impl(OutputFormat.JAVA, v); 2154 } 2155 2156 @Override 2157 protected String jml_name_impl(VarInfo v) { 2158 return java_family_impl(OutputFormat.JML, v); 2159 } 2160 2161 @Override 2162 protected String dbc_name_impl(VarInfo v) { 2163 return java_family_impl(OutputFormat.DBCJAVA, v); 2164 } 2165 2166 protected String java_family_impl(OutputFormat format, VarInfo v) { 2167 2168 // See declaration of testCall for explanation of this flag. 2169 if (testCall) { 2170 return "no format when testCall."; 2171 } 2172 2173 assert v != null; 2174 assert v.isDerived(); 2175 Derivation derived = v.derived; 2176 assert derived instanceof SequenceScalarSubscript 2177 || derived instanceof SequenceStringSubscript 2178 || derived instanceof SequenceFloatSubscript; 2179 VarInfo indexVarInfo = ((BinaryDerivation) derived).base2; 2180 VarInfo seqVarInfo = ((BinaryDerivation) derived).base1; 2181 if (format == OutputFormat.JAVA) { 2182 return sequence.java_name_impl(index.java_name_impl(indexVarInfo), seqVarInfo); 2183 } else if (format == OutputFormat.JML) { 2184 return sequence.jml_name_impl(index.jml_name_impl(indexVarInfo), seqVarInfo); 2185 } else { // format == OutputFormat.DBCJAVA 2186 return sequence.dbc_name_impl(index.dbc_name_impl(indexVarInfo), seqVarInfo); 2187 } 2188 } 2189 2190 @Override 2191 protected String identifier_name_impl() { 2192 return sequence.identifier_name_impl(index.identifier_name()); 2193 } 2194 2195 @Override 2196 public <T> T accept(Visitor<T> v) { 2197 return v.visitSubscript(this); 2198 } 2199 } 2200 2201 /** 2202 * Returns a name for a slice of element selected from a sequence, like "this[i..j]". If an 2203 * endpoint is null, it means "from the start" or "to the end". 2204 */ 2205 public VarInfoName applySlice( 2206 @Interned VarInfoName this, @Nullable VarInfoName i, @Nullable VarInfoName j) { 2207 // a[] -> a[index..] 2208 // orig(a[]) -> orig(a[post(index)..]) 2209 ElementsFinder finder = new ElementsFinder(this); 2210 Elements elems = finder.elems(); 2211 assert elems != null; 2212 if (finder.inPre()) { 2213 if (i != null) { 2214 i = indexToPrestate(i); 2215 } 2216 if (j != null) { 2217 j = indexToPrestate(j); 2218 } 2219 } 2220 Replacer r = new Replacer(finder.elems(), new Slice(elems, i, j).intern()); 2221 return r.replace(this).intern(); 2222 } 2223 2224 /** A slice of elements from a sequence, like "sequence[i..j]". */ 2225 public static @Interned class Slice extends VarInfoName { 2226 // We are Serializable, so we specify a version to allow changes to 2227 // method signatures without breaking serialization. If you add or 2228 // remove fields, you should change this number to the current date. 2229 static final long serialVersionUID = 20020130L; 2230 2231 public final Elements sequence; 2232 public final VarInfoName i, j; 2233 2234 public Slice(Elements sequence, VarInfoName i, VarInfoName j) { 2235 assert sequence != null; 2236 assert (i != null) || (j != null); 2237 this.sequence = sequence; 2238 this.i = i; 2239 this.j = j; 2240 } 2241 2242 @Override 2243 protected String repr_impl(@GuardSatisfied Slice this) { 2244 return "Slice{" 2245 + ((i == null) ? "" : i.repr()) 2246 + "," 2247 + ((j == null) ? "" : j.repr()) 2248 + "}[" 2249 + sequence.repr() 2250 + "]"; 2251 } 2252 2253 @Override 2254 protected String name_impl(@GuardSatisfied Slice this) { 2255 return sequence.name_impl( 2256 "" + ((i == null) ? "0" : i.name()) + ".." + ((j == null) ? "" : j.name())); 2257 } 2258 2259 @Override 2260 protected String esc_name_impl() { 2261 // return the default implementation for now. 2262 // return name_impl(); 2263 throw new UnsupportedOperationException( 2264 "ESC cannot format an unquantified slice of elements"); 2265 } 2266 2267 @Override 2268 protected String simplify_name_impl(boolean prestate) { 2269 System.out.println(" seq: " + sequence + " " + i + " " + j); 2270 throw new UnsupportedOperationException( 2271 "Simplify cannot format an unquantified slice of elements"); 2272 } 2273 2274 @Override 2275 protected String java_name_impl(VarInfo v) { 2276 return slice_helper(OutputFormat.JAVA, v); 2277 } 2278 2279 @Override 2280 protected String jml_name_impl(VarInfo v) { 2281 return slice_helper(OutputFormat.JML, v); 2282 } 2283 2284 @Override 2285 protected String dbc_name_impl(VarInfo v) { 2286 return slice_helper(OutputFormat.DBCJAVA, v); 2287 } 2288 2289 // Helper for JML, Java and DBC formats 2290 protected String slice_helper(OutputFormat format, VarInfo v) { 2291 2292 // See declaration of testCall for explanation of this flag. 2293 if (testCall) { 2294 return "no format when testCall."; 2295 } 2296 2297 assert v != null; 2298 assert v.isDerived(); 2299 Derivation derived = v.derived; 2300 assert derived instanceof SequenceSubsequence 2301 || derived instanceof SequenceScalarArbitrarySubsequence 2302 || derived instanceof SequenceFloatArbitrarySubsequence 2303 || derived instanceof SequenceStringArbitrarySubsequence; 2304 if (derived instanceof SequenceSubsequence) { 2305 assert i == null || j == null; 2306 if (i == null) { // sequence[0..j] 2307 assert j != null; 2308 return "daikon.Quant.slice(" 2309 + sequence.name_using(format, ((SequenceSubsequence) derived).seqvar()) 2310 + ", 0, " 2311 + j.name_using(format, ((SequenceSubsequence) derived).sclvar()) 2312 + ")"; 2313 } else { 2314 VarInfo seqVarInfo = ((SequenceSubsequence) derived).seqvar(); 2315 String prefix = sequence.name_using(format, seqVarInfo); 2316 String lastIdxString = "daikon.Quant.size(" + prefix + ")"; 2317 // if (seqVarInfo.type.pseudoDimensions() > seqVarInfo.type.dimensions()) { 2318 // if (prefix.startsWith("daikon.Quant.collect")) { 2319 // // Quant collect methods returns an array 2320 // lastIdxString = prefix + ".length-1"; 2321 // } else { 2322 // // it's a collection 2323 // lastIdxString = prefix + ".size()-1"; 2324 // } 2325 // } else { 2326 // // it's an array 2327 // lastIdxString = prefix + ".length-1"; 2328 // } 2329 return "daikon.Quant.slice(" 2330 + sequence.name_using(format, ((SequenceSubsequence) derived).seqvar()) 2331 + ", " 2332 + i.name_using(format, ((SequenceSubsequence) derived).sclvar()) 2333 + ", " 2334 + lastIdxString 2335 + ")"; 2336 } 2337 } else { 2338 assert i != null && j != null; 2339 if (derived instanceof SequenceScalarArbitrarySubsequence) { 2340 SequenceScalarArbitrarySubsequence derived2 = 2341 (SequenceScalarArbitrarySubsequence) derived; 2342 return "daikon.Quant.slice(" 2343 + sequence.name_using(format, derived2.seqvar()) 2344 + ", " 2345 + i.name_using(format, derived2.startvar()) 2346 + ", " 2347 + j.name_using(format, derived2.endvar()) 2348 + ")"; 2349 } else if (derived instanceof SequenceFloatArbitrarySubsequence) { 2350 SequenceFloatArbitrarySubsequence derived2 = (SequenceFloatArbitrarySubsequence) derived; 2351 return "daikon.Quant.slice(" 2352 + sequence.name_using(format, derived2.seqvar()) 2353 + ", " 2354 + i.name_using(format, derived2.startvar()) 2355 + ", " 2356 + j.name_using(format, derived2.endvar()) 2357 + ")"; 2358 } else { 2359 SequenceStringArbitrarySubsequence derived2 = 2360 (SequenceStringArbitrarySubsequence) derived; 2361 return "daikon.Quant.slice(" 2362 + sequence.name_using(format, derived2.seqvar()) 2363 + ", " 2364 + i.name_using(format, derived2.startvar()) 2365 + ", " 2366 + j.name_using(format, derived2.endvar()) 2367 + ")"; 2368 } 2369 } 2370 } 2371 2372 @Override 2373 protected String identifier_name_impl() { 2374 String start = (i == null) ? "0" : i.identifier_name(); 2375 String end = (j == null) ? "" : j.identifier_name(); 2376 return sequence.identifier_name_impl(start + "_to_" + end); 2377 } 2378 2379 @Override 2380 public <T> T accept(Visitor<T> v) { 2381 return v.visitSlice(this); 2382 } 2383 2384 public VarInfoName getLowerBound() { 2385 return (i != null) ? i : ZERO; 2386 } 2387 2388 public VarInfoName getUpperBound() { 2389 return (j != null) ? j : sequence.getUpperBound(); 2390 } 2391 2392 public VarInfoName getSubscript(VarInfoName index) { 2393 return sequence.getSubscript(index); 2394 } 2395 } 2396 2397 /** Accept the actions of a visitor. */ 2398 public abstract <T> T accept(Visitor<T> v); 2399 2400 /** Visitor framework for processing of VarInfoNames. */ 2401 public static interface Visitor<T> { 2402 public T visitSimple(Simple o); 2403 2404 public T visitSizeOf(SizeOf o); 2405 2406 public T visitFunctionOf(FunctionOf o); 2407 2408 public T visitFunctionOfN(FunctionOfN o); 2409 2410 public T visitField(Field o); 2411 2412 public T visitTypeOf(TypeOf o); 2413 2414 public T visitPrestate(Prestate o); 2415 2416 public T visitPoststate(Poststate o); 2417 2418 public T visitAdd(Add o); 2419 2420 public T visitElements(Elements o); 2421 2422 public T visitSubscript(Subscript o); 2423 2424 public T visitSlice(Slice o); 2425 } 2426 2427 /** 2428 * Traverse the tree elements that have exactly one branch (so the traversal order doesn't 2429 * matter). Visitors need to implement methods for traversing elements (e.g. FunctionOfN) with 2430 * more than one branch. 2431 */ 2432 public abstract static class AbstractVisitor<T> implements Visitor<T> { 2433 @Override 2434 public T visitSimple(Simple o) { 2435 // nothing to do; leaf node 2436 return null; 2437 } 2438 2439 @Override 2440 public T visitSizeOf(SizeOf o) { 2441 return o.sequence.accept(this); 2442 } 2443 2444 @Override 2445 public T visitFunctionOf(FunctionOf o) { 2446 return o.argument.accept(this); 2447 } 2448 2449 /** By default, return effect on first argument, but traverse all, backwards. */ 2450 @Override 2451 public T visitFunctionOfN(FunctionOfN o) { 2452 T retval = null; 2453 for (ListIterator<VarInfoName> i = o.args.listIterator(o.args.size()); i.hasPrevious(); ) { 2454 VarInfoName vin = i.previous(); 2455 retval = vin.accept(this); 2456 } 2457 return retval; 2458 } 2459 2460 @Override 2461 public T visitField(Field o) { 2462 return o.term.accept(this); 2463 } 2464 2465 @Override 2466 public T visitTypeOf(TypeOf o) { 2467 return o.term.accept(this); 2468 } 2469 2470 @Override 2471 public T visitPrestate(Prestate o) { 2472 return o.term.accept(this); 2473 } 2474 2475 @Override 2476 public T visitPoststate(Poststate o) { 2477 return o.term.accept(this); 2478 } 2479 2480 @Override 2481 public T visitAdd(Add o) { 2482 return o.term.accept(this); 2483 } 2484 2485 @Override 2486 public T visitElements(Elements o) { 2487 return o.term.accept(this); 2488 } 2489 2490 // leave abstract; traversal order and return values matter 2491 @Override 2492 public abstract T visitSubscript(Subscript o); 2493 2494 // leave abstract; traversal order and return values matter 2495 @Override 2496 public abstract T visitSlice(Slice o); 2497 } 2498 2499 /** 2500 * Use to report whether a node is in a pre- or post-state context. Throws an assertion error if a 2501 * given goal isn't present. 2502 */ 2503 public static class NodeFinder extends AbstractVisitor<VarInfoName> { 2504 /** 2505 * Creates a new NodeFinder. 2506 * 2507 * @param root the root of the tree to search 2508 * @param goal the goal to find 2509 */ 2510 public NodeFinder(VarInfoName root, VarInfoName goal) { 2511 this.goal = goal; 2512 assert root.accept(this) != null; 2513 } 2514 2515 // state and accessors 2516 private final VarInfoName goal; 2517 private boolean pre; 2518 2519 public boolean inPre() { 2520 return pre; 2521 } 2522 2523 // visitor methods that get the job done 2524 @Override 2525 public VarInfoName visitSimple(Simple o) { 2526 return (o == goal) ? goal : null; 2527 } 2528 2529 @Override 2530 public VarInfoName visitSizeOf(SizeOf o) { 2531 return (o == goal) ? goal : super.visitSizeOf(o); 2532 } 2533 2534 @Override 2535 public VarInfoName visitFunctionOf(FunctionOf o) { 2536 return (o == goal) ? goal : super.visitFunctionOf(o); 2537 } 2538 2539 @Override 2540 public VarInfoName visitFunctionOfN(FunctionOfN o) { 2541 VarInfoName retval = null; 2542 for (VarInfoName vin : o.args) { 2543 retval = vin.accept(this); 2544 if (retval != null) { 2545 return retval; 2546 } 2547 } 2548 return retval; 2549 } 2550 2551 @Override 2552 public VarInfoName visitField(Field o) { 2553 return (o == goal) ? goal : super.visitField(o); 2554 } 2555 2556 @Override 2557 public VarInfoName visitTypeOf(TypeOf o) { 2558 return (o == goal) ? goal : super.visitTypeOf(o); 2559 } 2560 2561 @Override 2562 public VarInfoName visitPrestate(Prestate o) { 2563 pre = true; 2564 return super.visitPrestate(o); 2565 } 2566 2567 @Override 2568 public VarInfoName visitPoststate(Poststate o) { 2569 pre = false; 2570 return super.visitPoststate(o); 2571 } 2572 2573 @Override 2574 public VarInfoName visitAdd(Add o) { 2575 return (o == goal) ? goal : super.visitAdd(o); 2576 } 2577 2578 @Override 2579 public VarInfoName visitElements(Elements o) { 2580 return (o == goal) ? goal : super.visitElements(o); 2581 } 2582 2583 @Override 2584 public VarInfoName visitSubscript(Subscript o) { 2585 if (o == goal) { 2586 return goal; 2587 } 2588 if (o.sequence.accept(this) != null) { 2589 return goal; 2590 } 2591 if (o.index.accept(this) != null) { 2592 return goal; 2593 } 2594 return null; 2595 } 2596 2597 @Override 2598 public VarInfoName visitSlice(Slice o) { 2599 if (o == goal) { 2600 return goal; 2601 } 2602 if (o.sequence.accept(this) != null) { 2603 return goal; 2604 } 2605 if ((o.i != null) && (o.i.accept(this) != null)) { 2606 return goal; 2607 } 2608 if ((o.j != null) && (o.j.accept(this) != null)) { 2609 return goal; 2610 } 2611 return null; 2612 } 2613 } 2614 2615 /** 2616 * Finds if a given VarInfoName is contained in a set of nodes in the VarInfoName tree using == 2617 * comparison. Recurse through everything except fields, so in x.a, we don't look at a. 2618 */ 2619 public static class Finder extends AbstractVisitor<VarInfoName> { 2620 // state and accessors 2621 private final Set<VarInfoName> goals; 2622 2623 /** 2624 * Creates a new Finder. Uses equals() to find. 2625 * 2626 * @param argGoals the goals to find 2627 */ 2628 public Finder(Set<VarInfoName> argGoals) { 2629 goals = new HashSet<VarInfoName>(); 2630 for (VarInfoName name : argGoals) { 2631 this.goals.add(name.intern()); 2632 } 2633 } 2634 2635 /** Returns true iff some part of root is contained in this.goals. */ 2636 @EnsuresNonNullIf(result = true, expression = "getPart(#1") 2637 public boolean contains(VarInfoName root) { 2638 VarInfoName o = getPart(root); 2639 return (o != null); 2640 } 2641 2642 /** Returns the part of root that is contained in this.goals, or null if not found. */ 2643 public @Nullable VarInfoName getPart(VarInfoName root) { 2644 VarInfoName o = root.intern().accept(this); 2645 return o; 2646 } 2647 2648 // visitor methods that get the job done 2649 @Override 2650 public VarInfoName visitSimple(Simple o) { 2651 return goals.contains(o) ? o : null; 2652 } 2653 2654 @Override 2655 public VarInfoName visitSizeOf(SizeOf o) { 2656 return goals.contains(o) ? o : o.sequence.intern().accept(this); 2657 } 2658 2659 @Override 2660 public VarInfoName visitFunctionOf(FunctionOf o) { 2661 return goals.contains(o) ? o : super.visitFunctionOf(o); 2662 } 2663 2664 @Override 2665 public VarInfoName visitFunctionOfN(FunctionOfN o) { 2666 VarInfoName result = null; 2667 if (goals.contains(o)) { 2668 return o; 2669 } 2670 for (VarInfoName vin : o.args) { 2671 result = vin.accept(this); 2672 if (result != null) { 2673 return result; 2674 } 2675 } 2676 return result; 2677 } 2678 2679 @Override 2680 public VarInfoName visitField(Field o) { 2681 return goals.contains(o) ? o : super.visitField(o); 2682 } 2683 2684 @Override 2685 public VarInfoName visitTypeOf(TypeOf o) { 2686 return goals.contains(o) ? o : super.visitTypeOf(o); 2687 } 2688 2689 @Override 2690 public VarInfoName visitPrestate(Prestate o) { 2691 if (goals.contains(o)) { 2692 return o; 2693 } 2694 return super.visitPrestate(o); 2695 } 2696 2697 @Override 2698 public VarInfoName visitPoststate(Poststate o) { 2699 if (goals.contains(o)) { 2700 return o; 2701 } 2702 return super.visitPoststate(o); 2703 } 2704 2705 @Override 2706 public VarInfoName visitAdd(Add o) { 2707 return goals.contains(o) ? o : super.visitAdd(o); 2708 } 2709 2710 @Override 2711 public VarInfoName visitElements(Elements o) { 2712 return goals.contains(o) ? o : super.visitElements(o); 2713 } 2714 2715 @Override 2716 public VarInfoName visitSubscript(Subscript o) { 2717 if (goals.contains(o)) { 2718 return o; 2719 } 2720 VarInfoName temp = o.sequence.accept(this); 2721 if (temp != null) { 2722 return temp; 2723 } 2724 temp = o.index.accept(this); 2725 if (temp != null) { 2726 return temp; 2727 } 2728 return null; 2729 } 2730 2731 @Override 2732 public VarInfoName visitSlice(Slice o) { 2733 if (goals.contains(o)) { 2734 return o; 2735 } 2736 VarInfoName temp = o.sequence.accept(this); 2737 if (temp != null) { 2738 return temp; 2739 } 2740 if (o.i != null) { 2741 temp = o.i.accept(this); 2742 if (temp != null) { 2743 return temp; 2744 } 2745 } 2746 if (o.j != null) { 2747 temp = o.j.accept(this); 2748 if (temp != null) { 2749 return temp; 2750 } 2751 } 2752 return null; 2753 } 2754 } 2755 2756 // An abstract base class for visitors that compute some predicate 2757 // of a conjunctive nature (true only if true on all subparts), 2758 // returning Boolean.FALSE or Boolean.TRUE. 2759 public abstract static class BooleanAndVisitor extends AbstractVisitor<Boolean> { 2760 private boolean result; 2761 2762 protected BooleanAndVisitor(VarInfoName name) { 2763 result = (name.accept(this) != null); 2764 } 2765 2766 public boolean result() { 2767 return result; 2768 } 2769 2770 @Override 2771 public Boolean visitFunctionOfN(FunctionOfN o) { 2772 Boolean retval = null; 2773 for (ListIterator<VarInfoName> i = o.args.listIterator(o.args.size()); i.hasPrevious(); ) { 2774 VarInfoName vin = i.previous(); 2775 retval = vin.accept(this); 2776 if (retval != null) { 2777 return null; 2778 } 2779 } 2780 return retval; 2781 } 2782 2783 @Override 2784 public Boolean visitSubscript(Subscript o) { 2785 Boolean temp = o.sequence.accept(this); 2786 if (temp == null) { 2787 return temp; 2788 } 2789 temp = o.index.accept(this); 2790 return temp; 2791 } 2792 2793 @Override 2794 public Boolean visitSlice(Slice o) { 2795 Boolean temp = o.sequence.accept(this); 2796 if (temp == null) { 2797 return temp; 2798 } 2799 if (o.i != null) { 2800 temp = o.i.accept(this); 2801 if (temp == null) { 2802 return temp; 2803 } 2804 } 2805 if (o.j != null) { 2806 temp = o.j.accept(this); 2807 if (temp == null) { 2808 return temp; 2809 } 2810 } 2811 return temp; 2812 } 2813 } 2814 2815 public static class IsAllPrestateVisitor extends BooleanAndVisitor { 2816 2817 public IsAllPrestateVisitor(VarInfoName vin) { 2818 super(vin); 2819 } 2820 2821 @Override 2822 public Boolean visitSimple(Simple o) { 2823 // Any var not inside an orig() isn't prestate 2824 return null; 2825 } 2826 2827 @Override 2828 public Boolean visitPrestate(Prestate o) { 2829 // orig(...) is all prestate unless it contains post(...) 2830 return new IsAllNonPoststateVisitor(o).result() ? Boolean.TRUE : null; 2831 } 2832 } 2833 2834 public static class IsAllNonPoststateVisitor extends BooleanAndVisitor { 2835 public IsAllNonPoststateVisitor(VarInfoName vin) { 2836 super(vin); 2837 } 2838 2839 @Override 2840 public Boolean visitSimple(Simple o) { 2841 // Any var not inside a post() isn't poststate 2842 return Boolean.TRUE; 2843 } 2844 2845 @Override 2846 public Boolean visitPoststate(Poststate o) { 2847 // If we see a post(...), we aren't all poststate. 2848 return null; 2849 } 2850 } 2851 2852 /** 2853 * Use to traverse a tree, find the first (elements ...) node, and report whether it's in pre or 2854 * post-state. 2855 */ 2856 public static class ElementsFinder extends AbstractVisitor<Elements> { 2857 public ElementsFinder(VarInfoName name) { 2858 elems = name.accept(this); 2859 } 2860 2861 // state and accessors 2862 private boolean pre = false; 2863 private Elements elems = null; 2864 2865 public boolean inPre() { 2866 return pre; 2867 } 2868 2869 public Elements elems() { 2870 return elems; 2871 } 2872 2873 // visitor methods that get the job done 2874 @Override 2875 public Elements visitFunctionOfN(FunctionOfN o) { 2876 Elements retval = null; 2877 for (VarInfoName vin : o.args) { 2878 retval = vin.accept(this); 2879 if (retval != null) { 2880 return retval; 2881 } 2882 } 2883 return retval; 2884 } 2885 2886 @Override 2887 public Elements visitPrestate(Prestate o) { 2888 pre = true; 2889 return super.visitPrestate(o); 2890 } 2891 2892 @Override 2893 public Elements visitPoststate(Poststate o) { 2894 pre = false; 2895 return super.visitPoststate(o); 2896 } 2897 2898 @Override 2899 public Elements visitElements(Elements o) { 2900 return o; 2901 } 2902 2903 @Override 2904 public Elements visitSubscript(Subscript o) { 2905 // skip the subscripted sequence 2906 Elements tmp = o.sequence.term.accept(this); 2907 if (tmp == null) { 2908 tmp = o.index.accept(this); 2909 } 2910 return tmp; 2911 } 2912 2913 @Override 2914 public Elements visitSlice(Slice o) { 2915 // skip the sliced sequence 2916 Elements tmp = o.sequence.term.accept(this); 2917 if (tmp == null && o.i != null) { 2918 tmp = o.i.accept(this); 2919 } 2920 if (tmp == null && o.j != null) { 2921 tmp = o.j.accept(this); 2922 } 2923 return tmp; 2924 } 2925 } 2926 2927 /** 2928 * A Replacer is a Visitor that makes a copy of a tree, but replaces some node (and its children) 2929 * with another. The result is *not* interned; the client must do that if desired. 2930 */ 2931 public static class Replacer extends AbstractVisitor<VarInfoName> { 2932 private final VarInfoName old; 2933 private final VarInfoName _new; 2934 2935 public Replacer(VarInfoName old, VarInfoName _new) { 2936 this.old = old; 2937 this._new = _new; 2938 } 2939 2940 public VarInfoName replace(VarInfoName root) { 2941 return root.accept(this); 2942 } 2943 2944 @Override 2945 public VarInfoName visitSimple(Simple o) { 2946 return (o == old) ? _new : o; 2947 } 2948 2949 @Override 2950 public VarInfoName visitSizeOf(SizeOf o) { 2951 return (o == old) ? _new : super.visitSizeOf(o).applySize(); 2952 } 2953 2954 @Override 2955 public VarInfoName visitFunctionOf(FunctionOf o) { 2956 return (o == old) ? _new : super.visitFunctionOf(o).applyFunction(o.function); 2957 } 2958 2959 @Override 2960 public VarInfoName visitFunctionOfN(FunctionOfN o) { 2961 // If o is getting replaced, then just replace it 2962 // otherwise, create a new function and check if arguments get replaced 2963 if (o == old) { 2964 return _new; 2965 } 2966 ArrayList<VarInfoName> newArgs = new ArrayList<>(); 2967 for (VarInfoName vin : o.args) { 2968 VarInfoName retval = vin.accept(this); 2969 newArgs.add(retval); 2970 } 2971 return VarInfoName.applyFunctionOfN(o.function, newArgs); 2972 } 2973 2974 @Override 2975 public VarInfoName visitField(Field o) { 2976 return (o == old) ? _new : super.visitField(o).applyField(o.field); 2977 } 2978 2979 @Override 2980 public VarInfoName visitTypeOf(TypeOf o) { 2981 return (o == old) ? _new : super.visitTypeOf(o).applyTypeOf(); 2982 } 2983 2984 @Override 2985 public VarInfoName visitPrestate(Prestate o) { 2986 return (o == old) ? _new : super.visitPrestate(o).applyPrestate(); 2987 } 2988 2989 @Override 2990 public VarInfoName visitPoststate(Poststate o) { 2991 return (o == old) ? _new : super.visitPoststate(o).applyPoststate(); 2992 } 2993 2994 @Override 2995 public VarInfoName visitAdd(Add o) { 2996 return (o == old) ? _new : super.visitAdd(o).applyAdd(o.amount); 2997 } 2998 2999 @Override 3000 public VarInfoName visitElements(Elements o) { 3001 return (o == old) ? _new : super.visitElements(o).applyElements(); 3002 } 3003 3004 @Override 3005 public VarInfoName visitSubscript(Subscript o) { 3006 return (o == old) ? _new : o.sequence.accept(this).applySubscript(o.index.accept(this)); 3007 } 3008 3009 @Override 3010 public VarInfoName visitSlice(Slice o) { 3011 return (o == old) 3012 ? _new 3013 : o.sequence 3014 .accept(this) 3015 .applySlice( 3016 (o.i == null) ? null : o.i.accept(this), (o.j == null) ? null : o.j.accept(this)); 3017 } 3018 } 3019 3020 /** 3021 * Replace pre states by normal variables, and normal variables by post states. We should do this 3022 * for all variables except for variables derived from return. This piggybacks on replacer but the 3023 * actual replacement is done elsewhere. 3024 */ 3025 public static class PostPreConverter extends Replacer { 3026 3027 public PostPreConverter() { 3028 super(null, null); 3029 } 3030 3031 @Override 3032 public VarInfoName visitSimple(Simple o) { 3033 if (o.name.equals("return")) { 3034 return o; 3035 } 3036 return o.applyPoststate(); 3037 } 3038 3039 @Override 3040 public VarInfoName visitPrestate(Prestate o) { 3041 return o.term; 3042 } 3043 } 3044 3045 public static class NoReturnValue {} 3046 3047 /** 3048 * Use to collect all elements in a tree into an inorder-traversal list. Result includes the root 3049 * element. All methods return null; to obtain the result, call nodes(). 3050 */ 3051 public static class InorderFlattener extends AbstractVisitor<NoReturnValue> { 3052 public InorderFlattener(VarInfoName root) { 3053 root.accept(this); 3054 } 3055 3056 // state and accessors 3057 private final List<VarInfoName> result = new ArrayList<>(); 3058 3059 /** Method returning the actual results (the nodes in order). */ 3060 public List<VarInfoName> nodes() { 3061 return Collections.unmodifiableList(result); 3062 } 3063 3064 // visitor methods that get the job done 3065 @Override 3066 public NoReturnValue visitSimple(Simple o) { 3067 result.add(o); 3068 return super.visitSimple(o); 3069 } 3070 3071 @Override 3072 public NoReturnValue visitSizeOf(SizeOf o) { 3073 result.add(o); 3074 return super.visitSizeOf(o); 3075 } 3076 3077 @Override 3078 public NoReturnValue visitFunctionOf(FunctionOf o) { 3079 result.add(o); 3080 return super.visitFunctionOf(o); 3081 } 3082 3083 @Override 3084 public NoReturnValue visitFunctionOfN(FunctionOfN o) { 3085 result.add(o); 3086 for (VarInfoName vin : o.args) { 3087 vin.accept(this); 3088 } 3089 return null; 3090 } 3091 3092 @Override 3093 public NoReturnValue visitField(Field o) { 3094 result.add(o); 3095 return super.visitField(o); 3096 } 3097 3098 @Override 3099 public NoReturnValue visitTypeOf(TypeOf o) { 3100 result.add(o); 3101 return super.visitTypeOf(o); 3102 } 3103 3104 @Override 3105 public NoReturnValue visitPrestate(Prestate o) { 3106 result.add(o); 3107 return super.visitPrestate(o); 3108 } 3109 3110 @Override 3111 public NoReturnValue visitPoststate(Poststate o) { 3112 result.add(o); 3113 return super.visitPoststate(o); 3114 } 3115 3116 @Override 3117 public NoReturnValue visitAdd(Add o) { 3118 result.add(o); 3119 return super.visitAdd(o); 3120 } 3121 3122 @Override 3123 public NoReturnValue visitElements(Elements o) { 3124 result.add(o); 3125 return super.visitElements(o); 3126 } 3127 3128 @Override 3129 public NoReturnValue visitSubscript(Subscript o) { 3130 result.add(o); 3131 o.sequence.accept(this); 3132 o.index.accept(this); 3133 return null; 3134 } 3135 3136 @Override 3137 public NoReturnValue visitSlice(Slice o) { 3138 result.add(o); 3139 o.sequence.accept(this); 3140 if (o.i != null) { 3141 o.i.accept(this); 3142 } 3143 if (o.j != null) { 3144 o.j.accept(this); 3145 } 3146 return null; 3147 } 3148 } 3149 3150 // ============================================================ 3151 // Quantification for formatting in ESC or Simplify 3152 3153 public static class SimpleNamesVisitor extends AbstractVisitor<NoReturnValue> { 3154 public SimpleNamesVisitor(VarInfoName root) { 3155 assert root != null; 3156 simples = new HashSet<String>(); 3157 root.accept(this); 3158 } 3159 3160 /** 3161 * See {@link #simples()}. 3162 * 3163 * @see #simples() 3164 */ 3165 private Set<String> simples; 3166 3167 /** 3168 * Returns collection of simple identifiers used in this expression, as Strings. (Used, for 3169 * instance, to check for conflict with a quantifier variable name.) 3170 * 3171 * @return collection of simple identifiers used in this expression, as Strings 3172 */ 3173 public Set<String> simples() { 3174 return Collections.unmodifiableSet(simples); 3175 } 3176 3177 // visitor methods that get the job done 3178 @Override 3179 public NoReturnValue visitSimple(Simple o) { 3180 simples.add(o.name); 3181 return super.visitSimple(o); 3182 } 3183 3184 @Override 3185 public NoReturnValue visitElements(Elements o) { 3186 return super.visitElements(o); 3187 } 3188 3189 @Override 3190 public NoReturnValue visitFunctionOf(FunctionOf o) { 3191 simples.add(o.function); 3192 return super.visitFunctionOf(o); 3193 } 3194 3195 @Override 3196 public NoReturnValue visitFunctionOfN(FunctionOfN o) { 3197 simples.add(o.function); 3198 return super.visitFunctionOfN(o); 3199 } 3200 3201 @Override 3202 public NoReturnValue visitSubscript(Subscript o) { 3203 o.sequence.accept(this); 3204 return o.index.accept(this); 3205 } 3206 3207 @Override 3208 public NoReturnValue visitSlice(Slice o) { 3209 if (o.i != null) { 3210 o.i.accept(this); 3211 } 3212 if (o.j != null) { 3213 o.j.accept(this); 3214 } 3215 return o.sequence.accept(this); 3216 } 3217 } 3218 3219 /** 3220 * A quantifier visitor can be used to search a tree and return all unquantified sequences (e.g. 3221 * a[] or a[i..j]). 3222 */ 3223 public static class QuantifierVisitor extends AbstractVisitor<NoReturnValue> { 3224 public QuantifierVisitor(VarInfoName root) { 3225 assert root != null; 3226 unquant = new HashSet<VarInfoName>(); 3227 root.accept(this); 3228 } 3229 3230 // state and accessors 3231 /** 3232 * See {@link #unquants()}. 3233 * 3234 * @see #unquants() 3235 */ 3236 private Set<VarInfoName> /*actually <Elements || Slice>*/ unquant; 3237 3238 /** 3239 * Returns a collection of the nodes under the root that need quantification. Each node 3240 * represents an array; in particular, the values are either of type Elements or Slice. 3241 * 3242 * @return the nodes under the root that need quantification 3243 */ 3244 // Here are some inputs and the corresponding output sets: 3245 // terms[index].elts[num] ==> { } 3246 // terms[index].elts[] ==> { terms[index].elts[] } 3247 // terms[].elts[] ==> { terms[], terms[].elts[] } 3248 // ary[row][col] ==> { } 3249 // ary[row][] ==> { ary[row][] } 3250 // ary[][] ==> { ary[], ary[][] } 3251 public Set<VarInfoName> unquants() { 3252 if (QuantHelper.debug.isLoggable(Level.FINE)) { 3253 QuantHelper.debug.fine("unquants: " + unquant); 3254 } 3255 return Collections.unmodifiableSet(unquant); 3256 } 3257 3258 // visitor methods that get the job done 3259 @Override 3260 public NoReturnValue visitSimple(Simple o) { 3261 return super.visitSimple(o); 3262 } 3263 3264 @Override 3265 public NoReturnValue visitElements(Elements o) { 3266 unquant.add(o); 3267 return super.visitElements(o); 3268 } 3269 3270 @Override 3271 public NoReturnValue visitFunctionOf(FunctionOf o) { 3272 return null; 3273 // return o.args.get(0).accept(this); // Return value doesn't matter 3274 // We only use one of them because we don't want double quantifiers 3275 } 3276 3277 /** 3278 * We do *not* want to pull out array members of FunctionOfN because a FunctionOfN creates a 3279 * black-box array with respect to quantification. (Also, otherwise, there may be two or more 3280 * arrays that are returned, making the quantification engine think it's working with 2-d 3281 * arrays.) 3282 */ 3283 @Override 3284 public NoReturnValue visitFunctionOfN(FunctionOfN o) { 3285 return null; 3286 // return o.args.get(0).accept(this); // Return value doesn't matter 3287 // We only use one of them because we don't want double quantifiers 3288 } 3289 3290 @Override 3291 public NoReturnValue visitSizeOf(SizeOf o) { 3292 // don't visit the sequence; we aren't using the elements of it, 3293 // just the length, so we don't want to include it in the results 3294 return o.get_term().accept(this); 3295 } 3296 3297 @Override 3298 public NoReturnValue visitSubscript(Subscript o) { 3299 o.index.accept(this); 3300 // don't visit the sequence; it is fixed with an exact 3301 // subscript, so we don't want to include it in the results 3302 return o.sequence.term.accept(this); 3303 } 3304 3305 @Override 3306 public NoReturnValue visitSlice(Slice o) { 3307 unquant.add(o); 3308 if (o.i != null) { 3309 o.i.accept(this); 3310 } 3311 if (o.j != null) { 3312 o.j.accept(this); 3313 } 3314 // don't visit the sequence; we will replace the slice with the 3315 // subscript, so we want to leave the elements alone 3316 return o.sequence.term.accept(this); 3317 } 3318 } 3319 3320 // ============================================================ 3321 // Quantification for formatting in ESC or Simplify: QuantHelper 3322 3323 /** 3324 * Helper for writing parts of quantification expressions. Formatting methods in invariants call 3325 * the formatting methods in this class to get commonly-used parts, like how universal 3326 * quanitifiers look in the different formatting schemes. 3327 */ 3328 public static class QuantHelper { 3329 3330 /** Debug tracer. */ 3331 public static final Logger debug = Logger.getLogger("daikon.inv.Invariant.print.QuantHelper"); 3332 3333 /** 3334 * A FreeVar is very much like a Simple, except that it doesn't care if it's in prestate or 3335 * poststate for simplify formatting. 3336 */ 3337 public static class FreeVar extends Simple { 3338 // We are Serializable, so we specify a version to allow changes to 3339 // method signatures without breaking serialization. If you add or 3340 // remove fields, you should change this number to the current date. 3341 static final long serialVersionUID = 20020130L; 3342 3343 public FreeVar(String name) { 3344 super(name); 3345 } 3346 3347 @Override 3348 protected String repr_impl(@GuardSatisfied FreeVar this) { 3349 return "Free[" + super.repr_impl() + "]"; 3350 } 3351 3352 @Override 3353 protected String jml_name_impl(VarInfo v) { 3354 return super.jml_name_impl(v); 3355 } 3356 3357 // protected String esc_name_impl() { 3358 // return super.esc_name_impl(); 3359 // } 3360 @Override 3361 protected String simplify_name_impl(boolean prestate) { 3362 return super.simplify_name_impl(false); 3363 } 3364 } 3365 3366 // <root, needy, index> -> <root', lower, upper> 3367 /** 3368 * Replaces a needy (unquantified term) with its subscripted equivalent, using the given index 3369 * variable. 3370 * 3371 * @param root the root of the expression to be modified. Substitution occurs only in the 3372 * subtree reachable from root. 3373 * @param needy the term to be subscripted (must be of type Elements or Slice) 3374 * @param index the variable to place in the subscript 3375 * @return a 3-element array consisting of the new root, the lower bound for the index 3376 * (inclusive), and the upper bound for the index (inclusive), in that order 3377 */ 3378 public static VarInfoName[] replace(VarInfoName root, VarInfoName needy, VarInfoName index) { 3379 assert root != null; 3380 assert needy != null; 3381 assert index != null; 3382 assert (needy instanceof Elements) || (needy instanceof Slice); 3383 3384 // Figure out what to replace needy with, and the appropriate 3385 // bounds to use 3386 VarInfoName replace_with; 3387 VarInfoName lower, upper; 3388 if (needy instanceof Elements) { 3389 Elements sequence = (Elements) needy; 3390 replace_with = sequence.getSubscript(index); 3391 lower = sequence.getLowerBound(); 3392 upper = sequence.getUpperBound(); 3393 } else if (needy instanceof Slice) { 3394 Slice slice = (Slice) needy; 3395 replace_with = slice.getSubscript(index); 3396 lower = slice.getLowerBound(); 3397 upper = slice.getUpperBound(); 3398 } else { 3399 // unreachable; placate javac 3400 throw new IllegalStateException(); 3401 } 3402 assert replace_with != null; 3403 3404 // If needy was in prestate, adjust bounds appropriately 3405 if (root.inPrestateContext(needy)) { 3406 if (!lower.isLiteralConstant()) { 3407 if (lower instanceof Poststate) { 3408 lower = ((Poststate) lower).term; 3409 } else { 3410 lower = lower.applyPrestate(); 3411 } 3412 } 3413 if (!upper.isLiteralConstant()) { 3414 if (upper instanceof Poststate) { 3415 upper = ((Poststate) upper).term; 3416 } else { 3417 upper = upper.applyPrestate(); 3418 } 3419 } 3420 } 3421 3422 // replace needy 3423 VarInfoName root_prime = new Replacer(needy, replace_with).replace(root).intern(); 3424 3425 assert root_prime != null; 3426 assert lower != null; 3427 assert upper != null; 3428 3429 return new VarInfoName[] {root_prime, lower, upper}; 3430 } 3431 3432 /** 3433 * Assuming that root is a sequence, return a VarInfoName representing the 3434 * (index_base+index_off)-th element of that sequence. index_base may be null, to represent 0. 3435 */ 3436 public static VarInfoName selectNth( 3437 VarInfoName root, @Nullable VarInfoName index_base, int index_off) { 3438 QuantifierVisitor qv = new QuantifierVisitor(root); 3439 List<VarInfoName> unquants = new ArrayList<>(qv.unquants()); 3440 if (unquants.size() == 0) { 3441 // Nothing to do? 3442 return null; 3443 } else if (unquants.size() == 1) { 3444 VarInfoName index_vin; 3445 if (index_base != null) { 3446 index_vin = index_base; 3447 if (index_off != 0) { 3448 index_vin = index_vin.applyAdd(index_off); 3449 } 3450 } else { 3451 index_vin = new Simple(Integer.toString(index_off)).intern(); 3452 } 3453 VarInfoName to_replace = unquants.get(0); 3454 @Interned VarInfoName[] replace_result = replace(root, to_replace, index_vin); 3455 return replace_result[0]; 3456 } else { 3457 throw new Error("Can't handle multi-dim array in VarInfoName.QuantHelper.select_nth()"); 3458 } 3459 } 3460 3461 /** 3462 * Assuming that root is a sequence, return a VarInfoName representing the 3463 * (index_base+index_off)-th element of that sequence. index_base may be null, to represent 0. 3464 */ 3465 public static VarInfoName selectNth( 3466 VarInfoName root, String index_base, boolean free, int index_off) { 3467 QuantifierVisitor qv = new QuantifierVisitor(root); 3468 List<VarInfoName> unquants = new ArrayList<>(qv.unquants()); 3469 if (unquants.size() == 0) { 3470 // Nothing to do? 3471 return null; 3472 } else if (unquants.size() == 1) { 3473 VarInfoName index_vin; 3474 if (index_base != null) { 3475 if (index_off != 0) { 3476 index_base += "+" + index_off; 3477 } 3478 if (free) { 3479 index_vin = new FreeVar(index_base); 3480 } else { 3481 index_vin = VarInfoName.parse(index_base); 3482 } 3483 // if (index_base.contains ("a")) 3484 // System.out.printf("selectNth: '%s' '%s'%n", index_base, 3485 // index_vin); 3486 } else { 3487 index_vin = new Simple(Integer.toString(index_off)); 3488 } 3489 VarInfoName to_replace = unquants.get(0); 3490 VarInfoName[] replace_result = replace(root, to_replace, index_vin); 3491 // if ((index_base != null) && index_base.contains ("a")) 3492 // System.out.printf("root = %s, to_replace = %s, index_vin = %s%n", 3493 // root, to_replace, index_vin); 3494 return replace_result[0]; 3495 } else { 3496 throw new Error("Can't handle multi-dim array in VarInfoName.QuantHelper.select_nth()"); 3497 } 3498 } 3499 3500 // Return a string distinct from any of the strings in "taken". 3501 private static String freshDistinctFrom(Set<String> taken) { 3502 char c = 'i'; 3503 String name; 3504 do { 3505 name = String.valueOf(c++); 3506 } while (taken.contains(name)); 3507 return name; 3508 } 3509 3510 /** Return a fresh variable name that doesn't appear in the given variable names. */ 3511 public static VarInfoName getFreeIndex(VarInfoName... vins) { 3512 Set<String> simples = new HashSet<>(); 3513 for (VarInfoName vin : vins) { 3514 simples.addAll(new SimpleNamesVisitor(vin).simples()); 3515 } 3516 return new FreeVar(freshDistinctFrom(simples)); 3517 } 3518 3519 /** Record type for return value of the quantify method below. */ 3520 public static class QuantifyReturn { 3521 public @Interned VarInfoName[] root_primes; 3522 public List<@Interned VarInfoName[]> 3523 bound_vars; // each element is VarInfoName[3] = <variable, lower, upper> 3524 } 3525 3526 // <root*> -> <root'*, <index, lower, upper>*> 3527 // (The lengths of root* and root'* are the same; not sure about <i,l,u>*.) 3528 /** 3529 * Given a list of roots, changes all Elements and Slice terms to Subscripts by inserting a new 3530 * free variable; also return bounds for the new variables. 3531 */ 3532 public static QuantifyReturn quantify(VarInfoName[] roots) { 3533 assert roots != null; 3534 3535 if (QuantHelper.debug.isLoggable(Level.FINE)) { 3536 QuantHelper.debug.fine("roots: " + Arrays.asList(roots)); 3537 } 3538 3539 // create empty result 3540 QuantifyReturn result = new QuantifyReturn(); 3541 result.root_primes = new VarInfoName[roots.length]; 3542 result.bound_vars = new ArrayList<VarInfoName[]>(); 3543 3544 // all of the simple identifiers used by these roots 3545 Set<String> simples = new HashSet<>(); 3546 3547 // build helper for each roots; collect identifiers 3548 QuantifierVisitor[] helper = new QuantifierVisitor[roots.length]; 3549 for (int i = 0; i < roots.length; i++) { 3550 if (QuantHelper.debug.isLoggable(Level.FINE)) { 3551 QuantHelper.debug.fine("Calling quanthelper on: " + i + " " + roots[i]); 3552 } 3553 3554 helper[i] = new QuantifierVisitor(roots[i]); 3555 simples.addAll(new SimpleNamesVisitor(roots[i]).simples()); 3556 } 3557 3558 // choose names for the indices that don't conflict, and then 3559 // replace the right stuff in the term 3560 char tmp = 'i'; 3561 for (int i = 0; i < roots.length; i++) { 3562 List<VarInfoName> uq = new ArrayList<>(helper[i].unquants()); 3563 if (uq.size() == 0) { 3564 // nothing needs quantification 3565 result.root_primes[i] = roots[i]; 3566 } else { 3567 if (QuantHelper.debug.isLoggable(Level.FINE)) { 3568 QuantHelper.debug.fine("root: " + roots[i]); 3569 QuantHelper.debug.fine("uq_elts: " + uq.toString()); 3570 } 3571 3572 // We assume that the input was one unquantified sequence 3573 // variable. If uq has more than one element, then the 3574 // sequence had more than one dimension. 3575 assert uq.size() == 1 : "We can only handle 1D arrays for now"; 3576 3577 VarInfoName uq_elt = uq.get(0); 3578 3579 String idx_name; 3580 do { 3581 idx_name = String.valueOf(tmp++); 3582 } while (simples.contains(idx_name)); 3583 assert tmp <= 'z' : "Ran out of letters in quantification"; 3584 VarInfoName idx = new FreeVar(idx_name).intern(); 3585 3586 if (QuantHelper.debug.isLoggable(Level.FINE)) { 3587 QuantHelper.debug.fine("idx: " + idx); 3588 } 3589 3590 // call replace and unpack results 3591 VarInfoName[] replace_result = replace(roots[i], uq_elt, idx); 3592 VarInfoName root_prime = replace_result[0]; 3593 VarInfoName lower = replace_result[1]; 3594 VarInfoName upper = replace_result[2]; 3595 3596 result.root_primes[i] = root_prime; 3597 result.bound_vars.add(new VarInfoName[] {idx, lower, upper}); 3598 } 3599 } 3600 3601 return result; 3602 } 3603 3604 // <root*> -> <string string* string> 3605 /** 3606 * Given a list of roots, return a String array where the first element is a ESC-style 3607 * quantification over newly-introduced bound variables, the last element is a closer, and the 3608 * other elements are esc-named strings for the provided roots (with sequences subscripted by 3609 * one of the new bound variables). 3610 */ 3611 public static String[] format_esc(VarInfoName[] roots) { 3612 return format_esc(roots, false); 3613 } 3614 3615 public static String[] format_esc(VarInfoName[] roots, boolean elementwise) { 3616 // The call to format_esc is now handled by the combined formatter format_java_style 3617 return format_java_style(roots, elementwise, true, OutputFormat.ESCJAVA); 3618 } 3619 3620 // <root*> -> <string string*> 3621 // /** 3622 // * Given a list of roots, return a String array where the first element is a JML-style 3623 // * quantification over newly-introduced bound variables, the last element is a closer, and 3624 // the 3625 // * other elements are jml-named strings for the provided roots (with sequenced subscripted by 3626 // * one of the new bound variables). 3627 // */ 3628 // public static String[] format_jml(VarInfoName[] roots) { 3629 // return format_jml(roots, false); 3630 // } 3631 // public static String[] format_jml(VarInfoName[] roots, boolean elementwise) { 3632 // return format_jml(roots, elementwise, true); 3633 // } 3634 // public static String[] format_jml(VarInfoName[] roots, boolean elementwise, boolean forall) { 3635 // return format_java_style(roots, elementwise, forall, OutputFormat.JML); 3636 // } 3637 3638 /* CP: Quantification for DBC: We would like quantified expression 3639 * to always return a boolean value, and in the previous 3640 * implementation (commented out below), quantification was 3641 * expressed as a for-loop, which does not return boolean 3642 * values. An alternative solution would be to use Jtest's $forall 3643 * and $exists constrcuts, but testing showed that Jtest does not 3644 * allow these constructs in @post annotations (!). The current 3645 * implementation uses helper methods defined in a separate class 3646 * daikon.Quant (not currently included with Daikon's 3647 * distribution). These methods always return a boolean value and 3648 * look something like this: 3649 * 3650 * Quant.eltsEqual(this.theArray, null) 3651 * Quant.subsetOf(this.arr, new int[] { 1, 2, 3 }) 3652 * 3653 */ 3654 // /** 3655 // * vi is the Varinfo corresponding to the VarInfoName var. Uses 3656 // * the variable i to iterate. This could mean a conflict with the 3657 // * name of the argument var. 3658 // */ 3659 // public static String dbcForalli(VarInfoName.Elements var, VarInfo vi, 3660 // String condition) { 3661 // if (vi.type.isArray()) { 3662 // return 3663 // "(java.util.Arrays.asList(" + var.term.dbc_name(vi) 3664 // + ")).$forall(" + vi.type.base() + " i, " 3665 // + condition + ")"; 3666 // } 3667 // return var.term.dbc_name(vi) 3668 // + ".$forall(" + vi.type.base() + " i, " 3669 // + condition + ")"; 3670 // } 3671 3672 // /** 3673 // * vi is the Varinfo corresponding to the VarInfoName var. Uses 3674 // * the variable i to iterate. This could mean a conflict with the 3675 // * name of the argument var. 3676 // */ 3677 // public static String dbcExistsi(VarInfoName.Elements var, VarInfo vi, 3678 // String condition) { 3679 // if (vi.type.isArray()) { 3680 // return 3681 // "(java.util.Arrays.asList(" + var.term.dbc_name(vi) 3682 // + ")).$exists(" + vi.type.base() + " i, " 3683 // + condition + ")"; 3684 // } 3685 // return var.term.dbc_name(vi) 3686 // + ".$exists(" + vi.type.base() + " i, " 3687 // + condition + ")"; 3688 // } 3689 3690 // //@tx 3691 // public static String[] format_dbc(VarInfoName[] roots, VarInfo[] varinfos) { 3692 // return format_dbc(roots, true, varinfos); 3693 // } 3694 // public static String[] format_dbc(VarInfoName[] roots, boolean elementwise, 3695 // VarInfo[] varinfos) { 3696 // return format_dbc(roots, elementwise, true, varinfos); 3697 // } 3698 // public static String[] format_dbc(VarInfoName[] roots, boolean elementwise, 3699 // boolean forall, VarInfo[] varinfos) { 3700 // assert roots != null; 3701 3702 // QuantifyReturn qret = quantify(roots); 3703 3704 // // build the "\forall ..." predicate 3705 // String[] result = new String[roots.length + 2]; 3706 // StringBuilder int_list, conditions, closing; 3707 // StringBuilder tempResult; 3708 // { 3709 // tempResult = new StringBuilder(); 3710 // // "i, j, ..." 3711 // int_list = new StringBuilder(); 3712 // // "ai <= i && i <= bi && aj <= j && j <= bj && ..." 3713 // // if elementwise, also do "(i-ai) == (b-bi) && ..." 3714 // conditions = new StringBuilder(); 3715 // closing = new StringBuilder(); 3716 // for (int i = 0; i < qret.bound_vars.size(); i++) { 3717 // int_list.setLength(0); 3718 // conditions.setLength(0); 3719 // closing.setLength(0); 3720 3721 // VarInfoName[] boundv = qret.bound_vars.get(i); 3722 // VarInfoName idx = boundv[0], low = boundv[1], high = boundv[2]; 3723 // if (i != 0) { 3724 // //int_list.append(", "); 3725 // //conditions.append(" && "); 3726 // //closing.append(", "); 3727 // closing.append(idx.dbc_name(null)); 3728 // closing.append("++"); 3729 // } else { 3730 // closing.append(idx.dbc_name(null)); 3731 // closing.append("++"); 3732 // } 3733 // int_list.append(idx.dbc_name(null)); 3734 // int_list.append(" = "); //@TX 3735 // int_list.append(low.dbc_name(null)); 3736 3737 // conditions.append(idx.dbc_name(null)); 3738 // conditions.append(" <= "); 3739 // conditions.append(high.dbc_name(null)); 3740 3741 // if (elementwise && (i >= 1)) { 3742 // VarInfoName[] _boundv = qret.bound_vars.get(i - 1); 3743 // VarInfoName _idx = _boundv[0], _low = _boundv[1]; 3744 // conditions.append(" && "); 3745 // if (ZERO.equals(_low)) { 3746 // conditions.append(_idx); 3747 // } else { 3748 // conditions.append("("); 3749 // conditions.append(_idx.dbc_name(null)); 3750 // conditions.append("-("); 3751 // conditions.append(_low.dbc_name(null)); 3752 // conditions.append("))"); 3753 // } 3754 // conditions.append(" == "); 3755 // if (ZERO.equals(low)) { 3756 // conditions.append(idx.dbc_name(null)); 3757 // } else { 3758 // conditions.append("("); 3759 // conditions.append(idx.dbc_name(null)); 3760 // conditions.append("-("); 3761 // conditions.append(low.dbc_name(null)); 3762 // conditions.append("))"); 3763 // } 3764 // } 3765 // tempResult.append(" for (int " + int_list + " ; " + conditions + "; " + closing + 3766 // ") "); 3767 // } 3768 // } 3769 // //result[0] = "{ for (int " + int_list + " ; " + conditions + "; " 3770 // + closing + ") $assert ("; //@TX 3771 // result[0] = "{ " + tempResult + " $assert ("; //@TX 3772 // result[result.length - 1] = "); }"; 3773 3774 // // stringify the terms 3775 // for (int i = 0; i < roots.length; i++) { 3776 // result[i + 1] = qret.root_primes[i].dbc_name(null); 3777 // } 3778 3779 // return result; 3780 // } 3781 3782 // ////////////////////////// 3783 3784 public static String[] simplifyNameAndBounds(VarInfoName name) { 3785 String[] results = new String[3]; 3786 boolean preState = false; 3787 if (name instanceof Prestate) { 3788 Prestate wrapped = (Prestate) name; 3789 name = wrapped.term; 3790 preState = true; 3791 } 3792 if (name instanceof Elements) { 3793 Elements sequence = (Elements) name; 3794 VarInfoName array = sequence.term; 3795 results[0] = array.simplify_name(preState); 3796 results[1] = sequence.getLowerBound().simplify_name(preState); 3797 results[2] = sequence.getUpperBound().simplify_name(preState); 3798 return results; 3799 } else if (name instanceof Slice) { 3800 Slice slice = (Slice) name; 3801 VarInfoName array = slice.sequence.term; 3802 results[0] = array.simplify_name(preState); 3803 results[1] = slice.getLowerBound().simplify_name(preState); 3804 results[2] = slice.getUpperBound().simplify_name(preState); 3805 return results; 3806 } else { 3807 // There are some other cases this scheme can't handle. 3808 // For instance, if every Book has an ISBN, a front-end 3809 // might distribute the access to that field over an array 3810 // of books, so that "books[].isbn" is an array of ISBNs, 3811 // though its name has type Field. 3812 return null; 3813 } 3814 } 3815 3816 // <root*> -> <string string*> 3817 /** 3818 * Given a list of roots, return a String array where the first element is a simplify-style 3819 * quantification over newly-introduced bound variables, the last element is a closer, and the 3820 * other elements are simplify-named strings for the provided roots (with sequences subscripted 3821 * by one of the new bound variables). 3822 * 3823 * <p>If elementwise is true, include the additional contraint that the indices (there must be 3824 * exactly two in this case) refer to corresponding positions. If adjacent is true, include the 3825 * additional constraint that the second index be one more than the first. If distinct is true, 3826 * include the constraint that the two indices are different. If includeIndex is true, return 3827 * additional strings, after the roots but before the closer, with the names of the index 3828 * variables. 3829 */ 3830 // XXX This argument list is starting to get out of hand. -smcc 3831 public static String[] format_simplify(VarInfoName[] roots) { 3832 return format_simplify(roots, false, false, false, false); 3833 } 3834 3835 public static String[] format_simplify(VarInfoName[] roots, boolean eltwise) { 3836 return format_simplify(roots, eltwise, false, false, false); 3837 } 3838 3839 public static String[] format_simplify(VarInfoName[] roots, boolean eltwise, boolean adjacent) { 3840 return format_simplify(roots, eltwise, adjacent, false, false); 3841 } 3842 3843 public static String[] format_simplify( 3844 VarInfoName[] roots, boolean eltwise, boolean adjacent, boolean distinct) { 3845 return format_simplify(roots, eltwise, adjacent, distinct, false); 3846 } 3847 3848 public static String[] format_simplify( 3849 VarInfoName[] roots, 3850 boolean elementwise, 3851 boolean adjacent, 3852 boolean distinct, 3853 boolean includeIndex) { 3854 assert roots != null; 3855 3856 if (adjacent || distinct) { 3857 assert roots.length == 2; 3858 } 3859 3860 QuantifyReturn qret = quantify(roots); 3861 3862 // build the forall predicate 3863 String[] result = new String[(includeIndex ? 2 : 1) * roots.length + 2]; 3864 3865 StringJoiner int_list, conditions; 3866 { 3867 // "i j ..." 3868 int_list = new StringJoiner(" "); 3869 // "(AND (<= ai i) (<= i bi) (<= aj j) (<= j bj) ...)" 3870 // if elementwise, also insert "(EQ (- i ai) (- j aj)) ..." 3871 conditions = new StringJoiner(" "); 3872 for (int i = 0; i < qret.bound_vars.size(); i++) { 3873 VarInfoName[] boundv = qret.bound_vars.get(i); 3874 VarInfoName idx = boundv[0], low = boundv[1], high = boundv[2]; 3875 int_list.add(idx.simplify_name()); 3876 conditions.add("(<= " + low.simplify_name() + " " + idx.simplify_name() + ")"); 3877 conditions.add("(<= " + idx.simplify_name() + " " + high.simplify_name() + ")"); 3878 if (elementwise && (i >= 1)) { 3879 VarInfoName[] _boundv = qret.bound_vars.get(i - 1); 3880 VarInfoName _idx = _boundv[0], _low = _boundv[1]; 3881 if (_low.simplify_name().equals(low.simplify_name())) { 3882 conditions.add("(EQ " + _idx.simplify_name() + " " + idx.simplify_name() + ")"); 3883 } else { 3884 conditions.add(" (EQ (- " + _idx.simplify_name() + " " + _low.simplify_name() + ")"); 3885 conditions.add("(- " + idx.simplify_name() + " " + low.simplify_name() + "))"); 3886 } 3887 } 3888 if (i == 1 && (adjacent || distinct)) { 3889 VarInfoName[] _boundv = qret.bound_vars.get(i - 1); 3890 VarInfoName prev_idx = _boundv[0]; 3891 if (adjacent) { 3892 conditions.add( 3893 "(EQ (+ " + prev_idx.simplify_name() + " 1) " + idx.simplify_name() + ")"); 3894 } 3895 if (distinct) { 3896 conditions.add("(NEQ " + prev_idx.simplify_name() + " " + idx.simplify_name() + ")"); 3897 } 3898 } 3899 } 3900 } 3901 result[0] = "(FORALL (" + int_list + ") (IMPLIES (AND " + conditions + ") "; 3902 3903 // stringify the terms 3904 for (int i = 0; i < qret.root_primes.length; i++) { 3905 result[i + 1] = qret.root_primes[i].simplify_name(); 3906 } 3907 3908 // stringify the indices, if requested 3909 // note that the index should be relative to the slice, not relative 3910 // to the original array (we used to get this wrong) 3911 if (includeIndex) { 3912 for (int i = 0; i < qret.root_primes.length; i++) { 3913 VarInfoName[] boundv = qret.bound_vars.get(i); 3914 VarInfoName idx_var = boundv[0]; 3915 String idx_var_name = idx_var.simplify_name(); 3916 String lower_bound = qret.bound_vars.get(i)[1].simplify_name(); 3917 String idx_expr = "(- " + idx_var_name + " " + lower_bound + ")"; 3918 result[i + qret.root_primes.length + 1] = idx_expr; 3919 } 3920 } 3921 3922 result[result.length - 1] = "))"; // close IMPLIES, FORALL 3923 3924 return result; 3925 } 3926 3927 // Important Note: The Java quantification style actually makes no 3928 // sense as is. The resultant quantifications are statements as 3929 // opposed to expressions, and thus no value can be derived from 3930 // them. This must be fixed before the java statements are of any 3931 // value. However, the ESC and JML quantifications are fine because 3932 // they actually produce expressions with values. 3933 3934 // <root*> -> <string string* string> 3935 /** 3936 * Given a list of roots, return a String array where the first element is a Java-style 3937 * quantification over newly-introduced bound variables, the last element is a closer, and the 3938 * other elements are java-named strings for the provided roots (with sequences subscripted by 3939 * one of the new bound variables). 3940 */ 3941 // public static String[] format_java(VarInfoName[] roots) { 3942 // return format_java(roots, false); 3943 // } 3944 // public static String[] format_java(VarInfoName[] roots, boolean elementwise) { 3945 // return format_java_style(roots, false, true, OutputFormat.JAVA); 3946 // } 3947 3948 // This set of functions quantifies in the same manner to the ESC quantification, except that 3949 // JML names are used instead of ESC names, and minor formatting changes are incorporated 3950 // public static String[] format_jml(QuantifyReturn qret) { 3951 // return format_java_style(qret, false, true, OutputFormat.JML); 3952 // } 3953 // public static String[] format_jml(QuantifyReturn qret, boolean elementwise) { 3954 // return format_java_style(qret, elementwise, true, OutputFormat.JML); 3955 // } 3956 // public static String[] format_jml(QuantifyReturn qret, boolean elementwise, boolean 3957 // forall) { 3958 // return format_java_style(qret, elementwise, forall, OutputFormat.JML); 3959 // } 3960 3961 // This set of functions assists in quantification for all of the java style 3962 // output formats, that is, Java, ESC, and JML. It does the actual work behind 3963 // those formatting functions. This function was meant to be called only through 3964 // the other public formatting functions. 3965 // 3966 // The OutputFormat must be one of those three previously mentioned. 3967 // Also, if the Java format is selected, forall must be true. 3968 3969 protected static String[] format_java_style(VarInfoName[] roots, OutputFormat format) { 3970 return format_java_style(roots, false, true, format); 3971 } 3972 3973 protected static String[] format_java_style( 3974 VarInfoName[] roots, boolean elementwise, OutputFormat format) { 3975 return format_java_style(roots, elementwise, true, format); 3976 } 3977 3978 protected static String[] format_java_style( 3979 VarInfoName[] roots, boolean elementwise, boolean forall, OutputFormat format) { 3980 assert roots != null; 3981 3982 QuantifyReturn qret = quantify(roots); 3983 3984 return format_java_style(qret, elementwise, forall, format); 3985 } 3986 3987 // This form allows the indicies and bounds to be modified before quantification 3988 protected static String[] format_java_style(QuantifyReturn qret, OutputFormat format) { 3989 return format_java_style(qret, false, true, format); 3990 } 3991 3992 protected static String[] format_java_style( 3993 QuantifyReturn qret, boolean elementwise, OutputFormat format) { 3994 return format_java_style(qret, elementwise, true, format); 3995 } 3996 3997 protected static String[] format_java_style( 3998 QuantifyReturn qret, boolean elementwise, boolean forall, OutputFormat format) { 3999 // build the "\forall ..." predicate 4000 String[] result = new String[qret.root_primes.length + 2]; 4001 StringBuilder int_list, conditions, closing; 4002 { 4003 // "i, j, ..." 4004 int_list = new StringBuilder(); 4005 // "ai <= i && i <= bi && aj <= j && j <= bj && ..." 4006 // if elementwise, also do "(i-ai) == (b-bi) && ..." 4007 conditions = new StringBuilder(); 4008 closing = new StringBuilder(); 4009 for (int i = 0; i < qret.bound_vars.size(); i++) { 4010 VarInfoName[] boundv = qret.bound_vars.get(i); 4011 VarInfoName idx = boundv[0], low = boundv[1], high = boundv[2]; 4012 if (i != 0) { 4013 int_list.append(", "); 4014 conditions.append(" && "); 4015 } 4016 closing.append(quant_increment(idx, i, format)); 4017 4018 int_list.append(quant_var_initial_state(idx, low, format)); 4019 conditions.append(quant_execution_condition(low, idx, high, format)); 4020 4021 if (elementwise && (i >= 1)) { 4022 VarInfoName[] _boundv = qret.bound_vars.get(i - 1); 4023 VarInfoName _idx = _boundv[0], _low = _boundv[1]; 4024 if (format == OutputFormat.JAVA) { 4025 conditions.append(" || "); 4026 } else { 4027 conditions.append(" && "); 4028 } 4029 4030 conditions.append(quant_element_conditions(_idx, _low, idx, low, format)); 4031 } 4032 } 4033 } 4034 4035 if (forall) { 4036 result[0] = quant_format_forall(format); 4037 } else { 4038 result[0] = quant_format_exists(format); 4039 } 4040 4041 result[0] += 4042 (int_list 4043 + quant_separator1(format) 4044 + conditions 4045 + quant_separator2(format) 4046 + closing 4047 + quant_step_terminator(format)); 4048 result[result.length - 1] = ")"; 4049 4050 // stringify the terms 4051 for (int i = 0; i < qret.root_primes.length; i++) { 4052 result[i + 1] = qret.root_primes[i].name_using(format, null); 4053 } 4054 4055 return result; 4056 } 4057 4058 // This set of functions are helper functions to the quantification function. 4059 4060 /** 4061 * This function creates a string that represents how to increment the variables involved in 4062 * quantification. Since the increment is not stated explicitly in the JML and ESC formats this 4063 * function merely returns an empty string for those formats. 4064 */ 4065 protected static String quant_increment(VarInfoName idx, int i, OutputFormat format) { 4066 if (format != OutputFormat.JAVA) { 4067 return ""; 4068 } else { 4069 if (i != 0) { 4070 return (", " + idx.esc_name() + "++"); 4071 } else { 4072 return (idx.esc_name() + "++"); 4073 } 4074 } 4075 } 4076 4077 /** 4078 * This function returns a string that represents the initial condition for the index variable. 4079 */ 4080 protected static String quant_var_initial_state( 4081 VarInfoName idx, VarInfoName low, OutputFormat format) { 4082 if (format == OutputFormat.JAVA) { 4083 return idx.esc_name() + " == " + low.esc_name(); 4084 } else { 4085 return idx.name_using(format, null); 4086 } 4087 } 4088 4089 /** 4090 * This function returns a string that represents the execution condition for the 4091 * quantification. 4092 */ 4093 protected static String quant_execution_condition( 4094 VarInfoName low, VarInfoName idx, VarInfoName high, OutputFormat format) { 4095 if (format == OutputFormat.JAVA) { 4096 return idx.esc_name() + " <= " + high.esc_name(); 4097 } else { 4098 return low.name_using(format, null) 4099 + " <= " 4100 + idx.name_using(format, null) 4101 + " && " 4102 + idx.name_using(format, null) 4103 + " <= " 4104 + high.name_using(format, null); 4105 } 4106 } 4107 4108 /** 4109 * This function returns a string representing the extra conditions necessary if the 4110 * quantification is element-wise. 4111 */ 4112 protected static String quant_element_conditions( 4113 VarInfoName _idx, VarInfoName _low, VarInfoName idx, VarInfoName low, OutputFormat format) { 4114 StringBuilder conditions = new StringBuilder(); 4115 4116 if (ZERO.equals(_low)) { 4117 conditions.append(_idx.name_using(format, null)); 4118 } else { 4119 conditions.append("("); 4120 conditions.append(_idx.name_using(format, null)); 4121 conditions.append("-("); 4122 conditions.append(_low.name_using(format, null)); 4123 conditions.append("))"); 4124 } 4125 conditions.append(" == "); 4126 if (ZERO.equals(low)) { 4127 conditions.append(idx.name_using(format, null)); 4128 } else { 4129 conditions.append("("); 4130 conditions.append(idx.name_using(format, null)); 4131 conditions.append("-("); 4132 conditions.append(low.name_using(format, null)); 4133 conditions.append("))"); 4134 } 4135 4136 return conditions.toString(); 4137 } 4138 4139 /** 4140 * This function returns a string representing how to format a forall statement in a given 4141 * output mode. 4142 */ 4143 protected static String quant_format_forall(OutputFormat format) { 4144 if (format == OutputFormat.JAVA) { 4145 return "(for (int "; 4146 } else { 4147 return "(\\forall int "; 4148 } 4149 } 4150 4151 /** 4152 * This function returns a string representing how to format an exists statement in a given 4153 * output mode. 4154 */ 4155 protected static String quant_format_exists(OutputFormat format) { 4156 return "(\\exists int "; 4157 } 4158 4159 /** 4160 * This function returns a string representing how to format the first seperation in the 4161 * quantification, that is, the one between the intial condition and the execution condition. 4162 */ 4163 protected static String quant_separator1(OutputFormat format) { 4164 if (format == OutputFormat.JML) { 4165 return "; "; 4166 } else { 4167 return "; ("; 4168 } 4169 } 4170 4171 /** 4172 * This function returns a string representing how to format the second seperation in the 4173 * quantification, that is, the one between the execution condition and the assertion. 4174 */ 4175 protected static String quant_separator2(OutputFormat format) { 4176 if (format == OutputFormat.ESCJAVA) { 4177 return ") ==> "; 4178 } else { 4179 return "; "; 4180 } 4181 } 4182 4183 /** 4184 * This function returns a string representing how to format the final seperation in the 4185 * quantification, that is, the one between the assertion and any closing symbols. 4186 */ 4187 protected static String quant_step_terminator(OutputFormat format) { 4188 if (format == OutputFormat.JAVA) { 4189 return ")"; 4190 } 4191 return ""; 4192 } 4193 } // QuantHelper 4194 4195 // Special JML capability, since JML cannot format a sequence of elements, 4196 // often what is wanted is the name of the reference (we have a[], we want 4197 // a. This function provides the appropriate name for these circumstances. 4198 public VarInfoName JMLElementCorrector() { 4199 if (this instanceof Elements) { 4200 return ((Elements) this).term; 4201 } else if (this instanceof Slice) { 4202 return ((Slice) this).sequence.term; 4203 } else if (this instanceof Prestate) { 4204 return ((Prestate) this).term.JMLElementCorrector().applyPrestate(); 4205 } else if (this instanceof Poststate) { 4206 return ((Poststate) this).term.JMLElementCorrector().applyPoststate(); 4207 } 4208 return this; 4209 } 4210 4211 // ============================================================ 4212 // Transformation framework 4213 4214 /** Specifies a function that performs a transformation on VarInfoNames. */ 4215 public interface Transformer { 4216 /** Perform a transformation on the argument. */ 4217 public VarInfoName transform(VarInfoName v); 4218 } 4219 4220 /** A pass-through transformer. */ 4221 public static final Transformer IDENTITY_TRANSFORMER = 4222 new Transformer() { 4223 @Override 4224 public VarInfoName transform(VarInfoName v) { 4225 return v; 4226 } 4227 }; 4228 4229 /** Compare VarInfoNames alphabetically. */ 4230 public static class LexicalComparator implements Comparator<VarInfoName> { 4231 @Pure 4232 @Override 4233 public int compare(VarInfoName name1, VarInfoName name2) { 4234 return name1.compareTo(name2); 4235 } 4236 } 4237}