| // 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: int32): bool { |
| // 0x0020 - SPACE (Intentionally out of order to fast path a commmon case) |
| if (charCode == Int32Constant(0x0020)) { |
| return true; |
| } |
| |
| // 0x0009 - HORIZONTAL TAB |
| if (charCode < Int32Constant(0x0009)) { |
| return false; |
| } |
| // 0x000A - LINE FEED OR NEW LINE |
| // 0x000B - VERTICAL TAB |
| // 0x000C - FORMFEED |
| // 0x000D - HORIZONTAL TAB |
| if (charCode <= Int32Constant(0x000D)) { |
| return true; |
| } |
| |
| // Common Non-whitespace characters |
| if (charCode < Int32Constant(0x00A0)) { |
| return false; |
| } |
| |
| // 0x00A0 - NO-BREAK SPACE |
| if (charCode == Int32Constant(0x00A0)) { |
| return true; |
| } |
| |
| // 0x1680 - Ogham Space Mark |
| if (charCode == Int32Constant(0x1680)) { |
| return true; |
| } |
| |
| // 0x2000 - EN QUAD |
| if (charCode < Int32Constant(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 <= Int32Constant(0x200A)) { |
| return true; |
| } |
| |
| // 0x2028 - LINE SEPARATOR |
| if (charCode == Int32Constant(0x2028)) { |
| return true; |
| } |
| // 0x2029 - PARAGRAPH SEPARATOR |
| if (charCode == Int32Constant(0x2029)) { |
| return true; |
| } |
| // 0x202F - NARROW NO-BREAK SPACE |
| if (charCode == Int32Constant(0x202F)) { |
| return true; |
| } |
| // 0x205F - MEDIUM MATHEMATICAL SPACE |
| if (charCode == Int32Constant(0x205F)) { |
| return true; |
| } |
| // 0xFEFF - BYTE ORDER MARK |
| if (charCode == Int32Constant(0xFEFF)) { |
| return true; |
| } |
| // 0x3000 - IDEOGRAPHIC SPACE |
| if (charCode == Int32Constant(0x3000)) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| transitioning macro StringTrim(implicit context: Context)( |
| receiver: JSAny, _arguments: Arguments, methodName: constexpr string, |
| variant: constexpr TrimMode): String { |
| const receiverString: String = ToThisString(receiver, methodName); |
| const stringLength: intptr = receiverString.length_intptr; |
| |
| const directString = Cast<DirectString>(receiverString) |
| otherwise return runtime::StringTrim( |
| receiverString, SmiTag<TrimMode>(variant)); |
| |
| let startIndex: intptr = 0; |
| let endIndex: intptr = stringLength - 1; |
| |
| // TODO(duongn): It would probably be more efficient to turn StringTrim into a |
| // tempalate for the different string types and specialize the loop for them. |
| if (variant == TrimMode::kTrim || variant == TrimMode::kTrimStart) { |
| while (true) { |
| if (startIndex == stringLength) { |
| return EmptyStringConstant(); |
| } |
| if (!IsWhiteSpaceOrLineTerminator( |
| StringCharCodeAt(directString, Unsigned(startIndex)))) { |
| break; |
| } |
| startIndex++; |
| } |
| } |
| |
| if (variant == TrimMode::kTrim || variant == TrimMode::kTrimEnd) { |
| while (true) { |
| if (endIndex == -1) { |
| return EmptyStringConstant(); |
| } |
| if (!IsWhiteSpaceOrLineTerminator( |
| StringCharCodeAt(directString, Unsigned(endIndex)))) { |
| break; |
| } |
| endIndex--; |
| } |
| } |
| |
| return SubString( |
| receiverString, Unsigned(startIndex), Unsigned(endIndex + 1)); |
| } |
| |
| // 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); |
| } |
| } |
| |
| namespace runtime { |
| extern runtime StringTrim(implicit context: Context)( |
| String, SmiTagged<string::TrimMode>): String; |
| } |