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}