11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include 'src/builtins/builtins-string-gen.h'
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_cinamespace string {
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciextern enum TrimMode extends uint31 constexpr 'String::TrimMode' {
101cb0ef41Sopenharmony_ci  kTrim,
111cb0ef41Sopenharmony_ci  kTrimStart,
121cb0ef41Sopenharmony_ci  kTrimEnd
131cb0ef41Sopenharmony_ci}
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci@export
161cb0ef41Sopenharmony_cimacro IsWhiteSpaceOrLineTerminator(charCode: char16|char8): bool {
171cb0ef41Sopenharmony_ci  // 0x0020 - SPACE (Intentionally out of order to fast path a commmon case)
181cb0ef41Sopenharmony_ci  if (charCode == 0x0020) {
191cb0ef41Sopenharmony_ci    return true;
201cb0ef41Sopenharmony_ci  }
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci  // Common Non-whitespace characters from (0x000E, 0x00A0)
231cb0ef41Sopenharmony_ci  if (Unsigned(Convert<int32>(charCode) - 0x000E) < 0x0092) {
241cb0ef41Sopenharmony_ci    return false;
251cb0ef41Sopenharmony_ci  }
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci  // 0x0009 - HORIZONTAL TAB
281cb0ef41Sopenharmony_ci  if (charCode < 0x0009) {
291cb0ef41Sopenharmony_ci    return false;
301cb0ef41Sopenharmony_ci  }
311cb0ef41Sopenharmony_ci  // 0x000A - LINE FEED OR NEW LINE
321cb0ef41Sopenharmony_ci  // 0x000B - VERTICAL TAB
331cb0ef41Sopenharmony_ci  // 0x000C - FORMFEED
341cb0ef41Sopenharmony_ci  // 0x000D - HORIZONTAL TAB
351cb0ef41Sopenharmony_ci  if (charCode <= 0x000D) {
361cb0ef41Sopenharmony_ci    return true;
371cb0ef41Sopenharmony_ci  }
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci  // 0x00A0 - NO-BREAK SPACE
401cb0ef41Sopenharmony_ci  if (charCode == 0x00A0) {
411cb0ef41Sopenharmony_ci    return true;
421cb0ef41Sopenharmony_ci  }
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  // 0x1680 - Ogham Space Mark
451cb0ef41Sopenharmony_ci  if (charCode == 0x1680) {
461cb0ef41Sopenharmony_ci    return true;
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  // 0x2000 - EN QUAD
501cb0ef41Sopenharmony_ci  if (charCode < 0x2000) {
511cb0ef41Sopenharmony_ci    return false;
521cb0ef41Sopenharmony_ci  }
531cb0ef41Sopenharmony_ci  // 0x2001 - EM QUAD
541cb0ef41Sopenharmony_ci  // 0x2002 - EN SPACE
551cb0ef41Sopenharmony_ci  // 0x2003 - EM SPACE
561cb0ef41Sopenharmony_ci  // 0x2004 - THREE-PER-EM SPACE
571cb0ef41Sopenharmony_ci  // 0x2005 - FOUR-PER-EM SPACE
581cb0ef41Sopenharmony_ci  // 0x2006 - SIX-PER-EM SPACE
591cb0ef41Sopenharmony_ci  // 0x2007 - FIGURE SPACE
601cb0ef41Sopenharmony_ci  // 0x2008 - PUNCTUATION SPACE
611cb0ef41Sopenharmony_ci  // 0x2009 - THIN SPACE
621cb0ef41Sopenharmony_ci  // 0x200A - HAIR SPACE
631cb0ef41Sopenharmony_ci  if (charCode <= 0x200A) {
641cb0ef41Sopenharmony_ci    return true;
651cb0ef41Sopenharmony_ci  }
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  // 0x2028 - LINE SEPARATOR
681cb0ef41Sopenharmony_ci  if (charCode == 0x2028) {
691cb0ef41Sopenharmony_ci    return true;
701cb0ef41Sopenharmony_ci  }
711cb0ef41Sopenharmony_ci  // 0x2029 - PARAGRAPH SEPARATOR
721cb0ef41Sopenharmony_ci  if (charCode == 0x2029) {
731cb0ef41Sopenharmony_ci    return true;
741cb0ef41Sopenharmony_ci  }
751cb0ef41Sopenharmony_ci  // 0x202F - NARROW NO-BREAK SPACE
761cb0ef41Sopenharmony_ci  if (charCode == 0x202F) {
771cb0ef41Sopenharmony_ci    return true;
781cb0ef41Sopenharmony_ci  }
791cb0ef41Sopenharmony_ci  // 0x205F - MEDIUM MATHEMATICAL SPACE
801cb0ef41Sopenharmony_ci  if (charCode == 0x205F) {
811cb0ef41Sopenharmony_ci    return true;
821cb0ef41Sopenharmony_ci  }
831cb0ef41Sopenharmony_ci  // 0xFEFF - BYTE ORDER MARK
841cb0ef41Sopenharmony_ci  if (charCode == 0xFEFF) {
851cb0ef41Sopenharmony_ci    return true;
861cb0ef41Sopenharmony_ci  }
871cb0ef41Sopenharmony_ci  // 0x3000 - IDEOGRAPHIC SPACE
881cb0ef41Sopenharmony_ci  if (charCode == 0x3000) {
891cb0ef41Sopenharmony_ci    return true;
901cb0ef41Sopenharmony_ci  }
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  return false;
931cb0ef41Sopenharmony_ci}
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_citransitioning macro StringTrimLoop<T: type>(implicit context: Context)(
961cb0ef41Sopenharmony_ci    stringSlice: ConstSlice<T>, startIndex: intptr, endIndex: intptr,
971cb0ef41Sopenharmony_ci    increment: intptr): intptr {
981cb0ef41Sopenharmony_ci  let index = startIndex;
991cb0ef41Sopenharmony_ci  while (true) {
1001cb0ef41Sopenharmony_ci    if (index == endIndex) {
1011cb0ef41Sopenharmony_ci      return index;
1021cb0ef41Sopenharmony_ci    }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci    const char: T = *stringSlice.AtIndex(index);
1051cb0ef41Sopenharmony_ci    if (!IsWhiteSpaceOrLineTerminator(char)) {
1061cb0ef41Sopenharmony_ci      return index;
1071cb0ef41Sopenharmony_ci    }
1081cb0ef41Sopenharmony_ci    index = index + increment;
1091cb0ef41Sopenharmony_ci  }
1101cb0ef41Sopenharmony_ci  unreachable;
1111cb0ef41Sopenharmony_ci}
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_citransitioning macro StringTrimBody<T: type>(implicit context: Context)(
1141cb0ef41Sopenharmony_ci    string: String, slice: ConstSlice<T>, variant: constexpr TrimMode): String {
1151cb0ef41Sopenharmony_ci  const stringLength: intptr = string.length_intptr;
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  let startIndex: intptr = 0;
1181cb0ef41Sopenharmony_ci  let endIndex: intptr = stringLength - 1;
1191cb0ef41Sopenharmony_ci  if (variant == TrimMode::kTrim || variant == TrimMode::kTrimStart) {
1201cb0ef41Sopenharmony_ci    startIndex = StringTrimLoop(slice, startIndex, stringLength, 1);
1211cb0ef41Sopenharmony_ci    if (startIndex == stringLength) {
1221cb0ef41Sopenharmony_ci      return kEmptyString;
1231cb0ef41Sopenharmony_ci    }
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  if (variant == TrimMode::kTrim || variant == TrimMode::kTrimEnd) {
1271cb0ef41Sopenharmony_ci    endIndex = StringTrimLoop(slice, endIndex, -1, -1);
1281cb0ef41Sopenharmony_ci    if (endIndex == -1) {
1291cb0ef41Sopenharmony_ci      return kEmptyString;
1301cb0ef41Sopenharmony_ci    }
1311cb0ef41Sopenharmony_ci  }
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  return SubString(string, Unsigned(startIndex), Unsigned(endIndex + 1));
1341cb0ef41Sopenharmony_ci}
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_citransitioning macro StringTrim(implicit context: Context)(
1371cb0ef41Sopenharmony_ci    receiver: JSAny, _arguments: Arguments, methodName: constexpr string,
1381cb0ef41Sopenharmony_ci    variant: constexpr TrimMode): String {
1391cb0ef41Sopenharmony_ci  const receiverString: String = ToThisString(receiver, methodName);
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci  try {
1421cb0ef41Sopenharmony_ci    StringToSlice(receiverString) otherwise OneByte, TwoByte;
1431cb0ef41Sopenharmony_ci  } label OneByte(slice: ConstSlice<char8>) {
1441cb0ef41Sopenharmony_ci    return StringTrimBody(receiverString, slice, variant);
1451cb0ef41Sopenharmony_ci  } label TwoByte(slice: ConstSlice<char16>) {
1461cb0ef41Sopenharmony_ci    return StringTrimBody(receiverString, slice, variant);
1471cb0ef41Sopenharmony_ci  }
1481cb0ef41Sopenharmony_ci}
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci// ES6 #sec-string.prototype.trim
1511cb0ef41Sopenharmony_citransitioning javascript builtin
1521cb0ef41Sopenharmony_ciStringPrototypeTrim(
1531cb0ef41Sopenharmony_ci    js-implicit context: NativeContext, receiver: JSAny)(...arguments): String {
1541cb0ef41Sopenharmony_ci  const methodName: constexpr string = 'String.prototype.trim';
1551cb0ef41Sopenharmony_ci  return StringTrim(receiver, arguments, methodName, TrimMode::kTrim);
1561cb0ef41Sopenharmony_ci}
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci// https://github.com/tc39/proposal-string-left-right-trim
1591cb0ef41Sopenharmony_citransitioning javascript builtin
1601cb0ef41Sopenharmony_ciStringPrototypeTrimStart(
1611cb0ef41Sopenharmony_ci    js-implicit context: NativeContext, receiver: JSAny)(...arguments): String {
1621cb0ef41Sopenharmony_ci  const methodName: constexpr string = 'String.prototype.trimLeft';
1631cb0ef41Sopenharmony_ci  return StringTrim(receiver, arguments, methodName, TrimMode::kTrimStart);
1641cb0ef41Sopenharmony_ci}
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci// https://github.com/tc39/proposal-string-left-right-trim
1671cb0ef41Sopenharmony_citransitioning javascript builtin
1681cb0ef41Sopenharmony_ciStringPrototypeTrimEnd(
1691cb0ef41Sopenharmony_ci    js-implicit context: NativeContext, receiver: JSAny)(...arguments): String {
1701cb0ef41Sopenharmony_ci  const methodName: constexpr string = 'String.prototype.trimRight';
1711cb0ef41Sopenharmony_ci  return StringTrim(receiver, arguments, methodName, TrimMode::kTrimEnd);
1721cb0ef41Sopenharmony_ci}
1731cb0ef41Sopenharmony_ci}
174