// 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(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(implicit context: Context)( stringSlice: ConstSlice, 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(implicit context: Context)( string: String, slice: ConstSlice, 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) { return StringTrimBody(receiverString, slice, variant); } label TwoByte(slice: ConstSlice) { 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); } }