static RawObject scanEscapeSequence()

in runtime/under-json-module.cpp [195:282]


static RawObject scanEscapeSequence(Thread* thread, JSONParser* env,
                                    const DataArray& data, word begin) {
  word next = env->next;
  word length = env->length;
  if (next >= length) {
    return raiseJSONDecodeError(thread, env, data, begin - 1,
                                "Unterminated string starting at");
  }
  byte ascii_result;
  byte b = data.byteAt(next++);
  switch (b) {
    case '"':
    case '\\':
    case '/':
      ascii_result = b;
      break;
    case 'b':
      ascii_result = '\b';
      break;
    case 'f':
      ascii_result = '\f';
      break;
    case 'n':
      ascii_result = '\n';
      break;
    case 'r':
      ascii_result = '\r';
      break;
    case 't':
      ascii_result = '\t';
      break;
    case 'u': {
      int32_t code_point;
      if (next >= length - kNumUEscapeChars) {
        return raiseJSONDecodeError(thread, env, data, next - 1,
                                    "Invalid \\uXXXX escape");
      }
      code_point = 0;
      word end = next + kNumUEscapeChars;
      do {
        b = data.byteAt(next++);
        code_point <<= kBitsPerHexDigit;
        if ('0' <= b && b <= '9') {
          code_point |= b - '0';
        } else if ('a' <= b && b <= 'f') {
          code_point |= b - 'a' + 10;
        } else if ('A' <= b && b <= 'F') {
          code_point |= b - 'A' + 10;
        } else {
          return raiseJSONDecodeError(thread, env, data, end - kNumUEscapeChars,
                                      "Invalid \\uXXXX escape");
        }
      } while (next < end);
      if (Unicode::isHighSurrogate(code_point) &&
          next < length - (kNumUEscapeChars + 2) && data.byteAt(next) == '\\' &&
          data.byteAt(next + 1) == 'u') {
        word next2 = next + 2;
        int32_t code_point2 = 0;
        word end2 = next2 + kNumUEscapeChars;
        do {
          byte b2 = data.byteAt(next2++);
          code_point2 <<= kBitsPerHexDigit;
          if ('0' <= b2 && b2 <= '9') {
            code_point2 |= b2 - '0';
          } else if ('a' <= b2 && b2 <= 'f') {
            code_point2 |= b2 - 'a' + 10;
          } else if ('A' <= b2 && b2 <= 'F') {
            code_point2 |= b2 - 'A' + 10;
          } else {
            code_point2 = 0;
            break;
          }
        } while (next2 < end2);
        if (Unicode::isLowSurrogate(code_point2)) {
          code_point = Unicode::combineSurrogates(code_point, code_point2);
          next = end2;
        }
      }
      env->next = next;
      return SmallStr::fromCodePoint(code_point);
    }
    default:
      return raiseJSONDecodeError(thread, env, data, next - 2,
                                  "Invalid \\escape");
  }
  env->next = next;
  return SmallStr::fromCodePoint(ascii_result);
}