buildString = function buildString(str, type, a11yStrings) {
  if (!str) {
    return;
  }

  var ret;

  if (type === "open") {
    ret = str in openMap ? openMap[str] : stringMap[str] || str;
  } else if (type === "close") {
    ret = str in closeMap ? closeMap[str] : stringMap[str] || str;
  } else if (type === "bin") {
    ret = binMap[str] || str;
  } else if (type === "rel") {
    ret = relMap[str] || str;
  } else {
    ret = stringMap[str] || str;
  } // If the text to add is a number and there is already a string
  // in the list and the last string is a number then we should
  // combine them into a single number


  if (/^\d+$/.test(ret) && a11yStrings.length > 0 && // TODO(kevinb): check that the last item in a11yStrings is a string
  // I think we might be able to drop the nested arrays, which would make
  // this easier to type - $FlowFixMe
  /^\d+$/.test(a11yStrings[a11yStrings.length - 1])) {
    a11yStrings[a11yStrings.length - 1] += ret;
  } else if (ret) {
    a11yStrings.push(ret);
  }
}
renderA11yString returns a readable string.

In some cases the string will have the proper semantic math
meaning,:
  renderA11yString("\\frac{1}{2}"")
  -> "start fraction, 1, divided by, 2, end fraction"

However, other cases do not:
  renderA11yString("f(x) = x^2")
  -> "f, left parenthesis, x, right parenthesis, equals, x, squared"

The commas in the string aim to increase ease of understanding
when read by a screenreader.