| // Copyright 2019 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include 'src/builtins/builtins-string-gen.h' |
| |
| namespace string { |
| |
| extern enum TrimMode extends uint31 constexpr 'String::TrimMode' { |
| kTrim, |
| kTrimStart, |
| kTrimEnd |
| } |
| |
| @export |
| macro IsWhiteSpaceOrLineTerminator(charCode: char16|char8): bool { |
| // 0x0020 - SPACE (Intentionally out of order to fast path a commmon case) |
| if (charCode == 0x0020) { |
| return true; |
| } |
| |
| // Common Non-whitespace characters from (0x000E, 0x00A0) |
| if (Unsigned(Convert<int32>(charCode) - 0x000E) < 0x0092) { |
| return false; |
| } |
| |
| // 0x0009 - HORIZONTAL TAB |
| if (charCode < 0x0009) { |
| return false; |
| } |
| // 0x000A - LINE FEED OR NEW LINE |
| // 0x000B - VERTICAL TAB |
| // 0x000C - FORMFEED |
| // 0x000D - HORIZONTAL TAB |
| if (charCode <= 0x000D) { |
| return true; |
| } |
| |
| // 0x00A0 - NO-BREAK SPACE |
| if (charCode == 0x00A0) { |
| return true; |
| } |
| |
| // 0x1680 - Ogham Space Mark |
| if (charCode == 0x1680) { |
| return true; |
| } |
| |
| // 0x2000 - EN QUAD |
| if (charCode < 0x2000) { |
| return false; |
| } |
| // 0x2001 - EM QUAD |
| // 0x2002 - EN SPACE |
| // 0x2003 - EM SPACE |
| // 0x2004 - THREE-PER-EM SPACE |
| // 0x2005 - FOUR-PER-EM SPACE |
| // 0x2006 - SIX-PER-EM SPACE |
| // 0x2007 - FIGURE SPACE |
| // 0x2008 - PUNCTUATION SPACE |
| // 0x2009 - THIN SPACE |
| // 0x200A - HAIR SPACE |
| if (charCode <= 0x200A) { |
| return true; |
| } |
| |
| // 0x2028 - LINE SEPARATOR |
| if (charCode == 0x2028) { |
| return true; |
| } |
| // 0x2029 - PARAGRAPH SEPARATOR |
| if (charCode == 0x2029) { |
| return true; |
| } |
| // 0x202F - NARROW NO-BREAK SPACE |
| if (charCode == 0x202F) { |
| return true; |
| } |
| // 0x205F - MEDIUM MATHEMATICAL SPACE |
| if (charCode == 0x205F) { |
| return true; |
| } |
| // 0xFEFF - BYTE ORDER MARK |
| if (charCode == 0xFEFF) { |
| return true; |
| } |
| // 0x3000 - IDEOGRAPHIC SPACE |
| if (charCode == 0x3000) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| transitioning macro StringTrimLoop<T: type>(implicit context: Context)( |
| stringSlice: ConstSlice<T>, startIndex: intptr, endIndex: intptr, |
| increment: intptr): intptr { |
| let index = startIndex; |
| while (true) { |
| if (index == endIndex) { |
| return index; |
| } |
| |
| const char: T = *stringSlice.AtIndex(index); |
| if (!IsWhiteSpaceOrLineTerminator(char)) { |
| return index; |
| } |
| index = index + increment; |
| } |
| unreachable; |
| } |
| |
| transitioning macro StringTrimBody<T: type>(implicit context: Context)( |
| string: String, slice: ConstSlice<T>, variant: constexpr TrimMode): String { |
| const stringLength: intptr = string.length_intptr; |
| |
| let startIndex: intptr = 0; |
| let endIndex: intptr = stringLength - 1; |
| if (variant == TrimMode::kTrim || variant == TrimMode::kTrimStart) { |
| startIndex = StringTrimLoop(slice, startIndex, stringLength, 1); |
| if (startIndex == stringLength) { |
| return kEmptyString; |
| } |
| } |
| |
| if (variant == TrimMode::kTrim || variant == TrimMode::kTrimEnd) { |
| endIndex = StringTrimLoop(slice, endIndex, -1, -1); |
| if (endIndex == -1) { |
| return kEmptyString; |
| } |
| } |
| |
| return SubString(string, Unsigned(startIndex), Unsigned(endIndex + 1)); |
| } |
| |
| transitioning macro StringTrim(implicit context: Context)( |
| receiver: JSAny, _arguments: Arguments, methodName: constexpr string, |
| variant: constexpr TrimMode): String { |
| const receiverString: String = ToThisString(receiver, methodName); |
| |
| try { |
| StringToSlice(receiverString) otherwise OneByte, TwoByte; |
| } label OneByte(slice: ConstSlice<char8>) { |
| return StringTrimBody(receiverString, slice, variant); |
| } label TwoByte(slice: ConstSlice<char16>) { |
| return StringTrimBody(receiverString, slice, variant); |
| } |
| } |
| |
| // ES6 #sec-string.prototype.trim |
| transitioning javascript builtin |
| StringPrototypeTrim( |
| js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { |
| const methodName: constexpr string = 'String.prototype.trim'; |
| return StringTrim(receiver, arguments, methodName, TrimMode::kTrim); |
| } |
| |
| // https://github.com/tc39/proposal-string-left-right-trim |
| transitioning javascript builtin |
| StringPrototypeTrimStart( |
| js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { |
| const methodName: constexpr string = 'String.prototype.trimLeft'; |
| return StringTrim(receiver, arguments, methodName, TrimMode::kTrimStart); |
| } |
| |
| // https://github.com/tc39/proposal-string-left-right-trim |
| transitioning javascript builtin |
| StringPrototypeTrimEnd( |
| js-implicit context: NativeContext, receiver: JSAny)(...arguments): String { |
| const methodName: constexpr string = 'String.prototype.trimRight'; |
| return StringTrim(receiver, arguments, methodName, TrimMode::kTrimEnd); |
| } |
| } |