whole_func_string: function GetSubstitution(matched, string, position, captures, replacement) {
    var matchLength = matched.length;
    var stringLength = string.length;
    var capturesLength = captures.length;
    var tailPos = position + matchLength;
    var result = "";
    var pos, expansion, peek, next, scaledIndex, advance, newScaledIndex;
  
    var next = %StringIndexOf(replacement, '$', 0);
    if (next < 0) {
      result += replacement;
      return result;
    }
  
    if (next > 0) result += %_SubString(replacement, 0, next);
  
    while (true) {
      expansion = '$';
      pos = next + 1;
      if (pos < replacement.length) {
        peek = %_StringCharCodeAt(replacement, pos);
        if (peek == 36) {         // $$
          ++pos;
          result += '$';
        } else if (peek == 38) {  // $& - match
          ++pos;
          result += matched;
        } else if (peek == 96) {  // $` - prefix
          ++pos;
          result += %_SubString(string, 0, position);
        } else if (peek == 39) {  // $' - suffix
          ++pos;
          result += %_SubString(string, tailPos, stringLength);
        } else if (peek >= 48 && peek <= 57) {
          // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
          scaledIndex = (peek - 48);
          advance = 1;
          if (pos + 1 < replacement.length) {
            next = %_StringCharCodeAt(replacement, pos + 1);
            if (next >= 48 && next <= 57) {
              newScaledIndex = scaledIndex * 10 + ((next - 48));
              if (newScaledIndex < capturesLength) {
                scaledIndex = newScaledIndex;
                advance = 2;
              }
            }
          }
          if (scaledIndex != 0 && scaledIndex < capturesLength) {
            var capture = captures[scaledIndex];
            if (!IS_UNDEFINED(capture)) result += capture;
            pos += advance;
          } else {
            result += '$';
          }
        } else {
          result += '$';
        }
      } else {
        result += '$';
      }
  
      // Go the the next $ in the replacement.
      next = %StringIndexOf(replacement, '$', pos);
  
      // Return if there are no more $ characters in the replacement. If we
      // haven't reached the end, we need to append the suffix.
      if (next < 0) {
        if (pos < replacement.length) {
          result += %_SubString(replacement, pos, replacement.length);
        }
        return result;
      }
  
      // Append substring between the previous and the next $ character.
      if (next > pos) {
        result += %_SubString(replacement, pos, next);
      }
    }
    return result;
  }
func_code_string: function GetSubstitution(matched, string, position, captures, replacement) {
    var matchLength = matched.length;
    var stringLength = string.length;
    var capturesLength = captures.length;
    var tailPos = position + matchLength;
    var result = "";
    var pos, expansion, peek, next, scaledIndex, advance, newScaledIndex;
  
    var next = %StringIndexOf(replacement, '$', 0);
    if (next < 0) {
      result += replacement;
      return result;
    }
  
    if (next > 0) result += %_SubString(replacement, 0, next);
  
    while (true) {
      expansion = '$';
      pos = next + 1;
      if (pos < replacement.length) {
        peek = %_StringCharCodeAt(replacement, pos);
        if (peek == 36) {         // $$
          ++pos;
          result += '$';
        } else if (peek == 38) {  // $& - match
          ++pos;
          result += matched;
        } else if (peek == 96) {  // $` - prefix
          ++pos;
          result += %_SubString(string, 0, position);
        } else if (peek == 39) {  // $' - suffix
          ++pos;
          result += %_SubString(string, tailPos, stringLength);
        } else if (peek >= 48 && peek <= 57) {
          // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
          scaledIndex = (peek - 48);
          advance = 1;
          if (pos + 1 < replacement.length) {
            next = %_StringCharCodeAt(replacement, pos + 1);
            if (next >= 48 && next <= 57) {
              newScaledIndex = scaledIndex * 10 + ((next - 48));
              if (newScaledIndex < capturesLength) {
                scaledIndex = newScaledIndex;
                advance = 2;
              }
            }
          }
          if (scaledIndex != 0 && scaledIndex < capturesLength) {
            var capture = captures[scaledIndex];
            if (!IS_UNDEFINED(capture)) result += capture;
            pos += advance;
          } else {
            result += '$';
          }
        } else {
          result += '$';
        }
      } else {
        result += '$';
      }
  
      // Go the the next $ in the replacement.
      next = %StringIndexOf(replacement, '$', pos);
  
      // Return if there are no more $ characters in the replacement. If we
      // haven't reached the end, we need to append the suffix.
      if (next < 0) {
        if (pos < replacement.length) {
          result += %_SubString(replacement, pos, replacement.length);
        }
        return result;
      }
  
      // Append substring between the previous and the next $ character.
      if (next > pos) {
        result += %_SubString(replacement, pos, next);
      }
    }
    return result;
  }
func_documentation_string: ES#sec-getsubstitution GetSubstitution(matched, str, position, captures, replacement) Expand the $-expressions in the string and return a new string with the result. TODO(littledan): Call this function from String.prototype.replace instead of the very similar ExpandReplacement in src/js/string.js