Example #1
0
  private void setupTokenizer() {
    st.resetSyntax();
    st.wordChars('a', 'z');
    st.wordChars('A', 'Z');
    st.wordChars('0', '9');
    st.wordChars(':', ':');
    st.wordChars('.', '.');
    st.wordChars('_', '_');
    st.wordChars('-', '-');
    st.wordChars('/', '/');
    st.wordChars('\\', '\\');
    st.wordChars('$', '$');
    st.wordChars('{', '{'); // need {} for property subst
    st.wordChars('}', '}');
    st.wordChars('*', '*');
    st.wordChars('+', '+');
    st.wordChars('~', '~');
    // XXX check ASCII table and add all other characters except special

    // special: #="(),
    st.whitespaceChars(0, ' ');
    st.commentChar('#');
    st.eolIsSignificant(true);
    st.quoteChar('\"');
  }
Example #2
0
  /**
   * Returns the string array associated with a key, assuming it is defined. It is recommended to
   * check that it is defined first with {@link #hasValue(String)}.
   *
   * @throws RuntimeException if the key is not defined.
   * @see #hasValue(String)
   */
  public String[] getList(/*@KeyFor("this.map")*/ String key) {
    try {
      if (!hasValue(key)) {
        throw new RuntimeException(String.format("Key '%s' is not defined", key));
      }
      final String sValue = getValue(key);
      StreamTokenizer tok = new StreamTokenizer(new StringReader(sValue));
      tok.quoteChar('"');
      tok.whitespaceChars(' ', ' ');
      ArrayList<String> lValues = new ArrayList<String>();

      int tokInfo = tok.nextToken();
      while (tokInfo != StreamTokenizer.TT_EOF) {
        if (tok.ttype != '"') continue;
        assert tok.sval != null
            : "@AssumeAssertion(nullness)"; // tok.type == '"' guarantees not null
        lValues.add(tok.sval.trim());
        tokInfo = tok.nextToken();
      }
      return lValues.toArray(new String[] {});
    } catch (IOException ex) {
      throw new RuntimeException(String.format("Parsing for key '%s' failed", key), ex);
    }
  }
Example #3
0
  /**
   * Return an interned VarInfoAux that represents a given string. Elements are separated by commas,
   * in the form:
   *
   * <p>x = a, "a key" = "a value"
   *
   * <p>Parse allow for quoted elements. White space to the left and right of keys and values do not
   * matter, but inbetween does.
   */
  public static /*@Interned*/ VarInfoAux parse(String inString) throws IOException {
    Reader inStringReader = new StringReader(inString);
    StreamTokenizer tok = new StreamTokenizer(inStringReader);
    tok.resetSyntax();
    tok.wordChars(0, Integer.MAX_VALUE);
    tok.quoteChar('\"');
    tok.whitespaceChars(' ', ' ');
    tok.ordinaryChar('[');
    tok.ordinaryChar(']');
    tok.ordinaryChars(',', ',');
    tok.ordinaryChars('=', '=');
    Map</*@Interned*/ String, /*@Interned*/ String> map = theDefault.map;

    String key = "";
    String value = "";
    boolean seenEqual = false;
    boolean insideVector = false;
    for (int tokInfo = tok.nextToken();
        tokInfo != StreamTokenizer.TT_EOF;
        tokInfo = tok.nextToken()) {
      @SuppressWarnings("interning") // initialization-checking pattern
      boolean mapUnchanged = (map == theDefault.map);
      if (mapUnchanged) {
        // We use default values if none are specified.  We initialize
        // here rather than above to save time when there are no tokens.

        map = new HashMap</*@Interned*/ String, /*@Interned*/ String>(theDefault.map);
      }

      /*@Interned*/ String token;
      if (tok.ttype == StreamTokenizer.TT_WORD || tok.ttype == '\"') {
        assert tok.sval != null
            : "@AssumeAssertion(nullness): representation invariant of StreamTokenizer";
        token = tok.sval.trim().intern();
      } else {
        token = ((char) tok.ttype + "").intern();
      }

      debug.fine("Token info: " + tokInfo + " " + token);

      if (token == "[") { // interned
        if (!seenEqual) throw new IOException("Aux option did not contain an '='");
        if (insideVector) throw new IOException("Vectors cannot be nested in an aux option");
        if (value.length() > 0) throw new IOException("Cannot mix scalar and vector values");

        insideVector = true;
        value = "";
      } else if (token == "]") { // interned
        if (!insideVector) throw new IOException("']' without preceding '['");
        insideVector = false;
      } else if (token == ",") { // interned
        if (!seenEqual) throw new IOException("Aux option did not contain an '='");
        if (insideVector) throw new IOException("',' cannot be used inside a vector");
        map.put(key.intern(), value.intern());
        key = "";
        value = "";
        seenEqual = false;
      } else if (token == "=") { // interned
        if (seenEqual) throw new IOException("Aux option contained more than one '='");
        if (insideVector) throw new IOException("'=' cannot be used inside a vector");
        seenEqual = true;
      } else {
        if (!seenEqual) {
          key = (key + " " + token).trim();
        } else if (insideVector) {
          value = value + " \"" + token.trim() + "\"";
        } else {
          value = (value + " " + token).trim();
        }
      }
    }

    if (seenEqual) {
      map.put(key.intern(), value.intern());
    }

    // Interning
    VarInfoAux result = new VarInfoAux(map).intern();
    assert interningMap != null
        : "@AssumeAssertion(nullness):  application invariant:  postcondition of intern(), which was just called";
    if (debug.isLoggable(Level.FINE)) {
      debug.fine("New parse " + result);
      debug.fine("Intern table size: " + new Integer(interningMap.size()));
    }
    return result;
  }