001package daikon.chicory;
002
003import java.util.EnumSet;
004import java.util.Iterator;
005import java.util.List;
006import java.util.StringJoiner;
007
008/**
009 * The StringInfo class is a subtype of DaikonVariableInfo used for variable types that can be
010 * converted into strings (.toString()).
011 */
012public class StringInfo extends DaikonVariableInfo {
013  public StringInfo(
014      String theName, String typeName, String repTypeName, String receiverName, boolean arr) {
015    super(theName, typeName, repTypeName, arr);
016
017    function_args = receiverName;
018  }
019
020  @Override
021  public Object getMyValFromParentVal(Object value) {
022    if ((value == null) || (value instanceof NonsensicalObject)) {
023      return NonsensicalObject.getInstance();
024    }
025    return value;
026  }
027
028  /** Returns a String that contains a string representation of val, used for dtrace information. */
029  @Override
030  public String getDTraceValueString(Object val) {
031    if (isArray) {
032      List<?> valAsList = (List<?>) val;
033      return getStringList(valAsList);
034    } else {
035      return getValueStringNonArr(val);
036    }
037  }
038
039  /**
040   * Returns a space-separated String of the elements in theValues. If theValues is null, returns
041   * "null." If theValues is nonsensical, returns "nonsensical". Also contains the modbit, on a
042   * separate line.
043   *
044   * @param theValues a list of values, each is a String or NonsensicalObject or NonsensicalList
045   * @return a space-separated String of the elements in theValues
046   */
047  public static String getStringList(List<?> theValues) {
048    if (theValues == null) {
049      // buf.append("null");
050      return "null" + DaikonWriter.lineSep + "1";
051    }
052
053    // assert !NonsensicalList.isNonsensicalList (theValues);
054    if (NonsensicalList.isNonsensicalList(theValues)
055    // How can this happen, given the declared type of theValues?
056    // || theValues instanceof NonsensicalObject
057    ) {
058      // buf.append("nonsensical");
059      return "nonsensical" + DaikonWriter.lineSep + "2";
060    }
061
062    StringJoiner buf = new StringJoiner(" ", "[", "]");
063
064    for (Iterator<?> iter = theValues.iterator(); iter.hasNext(); ) {
065      Object str = iter.next();
066
067      if (str == null) {
068        buf.add("null");
069      } else if (str instanceof String) {
070        buf.add("\"" + encodeString((String) str) + "\"");
071      } else if (str instanceof NonsensicalObject || str instanceof NonsensicalList) {
072        buf.add("nonsensical");
073      } else {
074        throw new Error("Impossible");
075      }
076    }
077
078    if (NonsensicalList.isNonsensicalList(theValues)) {
079      return buf.toString() + DaikonWriter.lineSep + "2";
080    } else {
081      return buf.toString() + DaikonWriter.lineSep + "1";
082    }
083  }
084
085  /** Similar to showStringList, but used for non-array objects. */
086  public String getValueStringNonArr(Object val) {
087    String retString;
088
089    if (val == null) {
090      retString = "null";
091    } else if (val instanceof NonsensicalObject) {
092      retString = "nonsensical";
093    } else {
094      retString = getString((String) val);
095    }
096    retString += DaikonWriter.lineSep;
097
098    if (val instanceof NonsensicalObject) {
099      retString += "2";
100    } else {
101      retString += "1";
102    }
103
104    return retString;
105  }
106
107  // encodes a string: surrounds in quotes and removes line breaks
108  private String getString(String stringRef) {
109    return ("\"" + encodeString(stringRef) + "\"");
110  }
111
112  // removes endlines in string
113  private static String encodeString(String input) {
114    return Runtime.quote(input);
115  }
116
117  /** toString is a function. */
118  @Override
119  public VarKind get_var_kind() {
120    return VarKind.FUNCTION;
121  }
122
123  /** Returns the name of this function. */
124  @Override
125  public String get_relative_name() {
126    return "toString()";
127  }
128
129  @Override
130  public EnumSet<VarFlags> get_var_flags() {
131    EnumSet<VarFlags> flags = super.get_var_flags();
132    flags.add(VarFlags.SYNTHETIC);
133    flags.add(VarFlags.TO_STRING);
134    return flags;
135  }
136}