Changeset 194328 in webkit


Ignore:
Timestamp:
Dec 21, 2015 2:03:36 AM (8 years ago)
Author:
commit-queue@webkit.org
Message:

[INTL] Implement String.prototype.localeCompare in ECMA-402
https://bugs.webkit.org/show_bug.cgi?id=147607

Patch by Andy VanWagoner <thetalecrafter@gmail.com> on 2015-12-21
Reviewed by Darin Adler.

Source/JavaScriptCore:

Add localeCompare in builtin JavaScript that delegates comparing to Intl.Collator.
Keep existing native implementation for use if INTL flag is disabled.

  • CMakeLists.txt:
  • DerivedSources.make:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • builtins/StringPrototype.js: Added.

(localeCompare):

  • runtime/StringPrototype.cpp:

(JSC::StringPrototype::finishCreation):

LayoutTests:

  • js/script-tests/string-localeCompare.js:
  • js/script-tests/string-prototype-properties.js: Update error message.
  • js/string-localeCompare-expected.txt:
  • js/string-prototype-properties-expected.txt: Update error message.
  • js/string-localeCompare.html:
Location:
trunk
Files:
1 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r194326 r194328  
     12015-12-21  Andy VanWagoner  <thetalecrafter@gmail.com>
     2
     3        [INTL] Implement String.prototype.localeCompare in ECMA-402
     4        https://bugs.webkit.org/show_bug.cgi?id=147607
     5
     6        Reviewed by Darin Adler.
     7
     8        * js/script-tests/string-localeCompare.js:
     9        * js/script-tests/string-prototype-properties.js: Update error message.
     10        * js/string-localeCompare-expected.txt:
     11        * js/string-prototype-properties-expected.txt: Update error message.
     12        * js/string-localeCompare.html:
     13
    1142015-12-20  Jeremy Zerfas  <WebKit@JeremyZerfas.com>
    215
  • trunk/LayoutTests/js/dom/script-tests/string-prototype-properties.js

    r156066 r194328  
    2121shouldThrow("String.prototype.toLowerCase.call(undefined)");
    2222shouldThrow("String.prototype.toUpperCase.call(undefined)");
    23 shouldThrow("String.prototype.localeCompare.call(undefined, '1224')");
     23shouldThrow("String.prototype.localeCompare.call(undefined, '1224')", "'TypeError: String.prototype.localeCompare requires that |this| not be undefined'");
    2424shouldThrow("String.prototype.toLocaleLowerCase.call(undefined)");
    2525shouldThrow("String.prototype.toLocaleUpperCase.call(undefined)");
  • trunk/LayoutTests/js/dom/string-prototype-properties-expected.txt

    r156066 r194328  
    2121PASS String.prototype.toLowerCase.call(undefined) threw exception TypeError: Type error.
    2222PASS String.prototype.toUpperCase.call(undefined) threw exception TypeError: Type error.
    23 PASS String.prototype.localeCompare.call(undefined, '1224') threw exception TypeError: Type error.
     23PASS String.prototype.localeCompare.call(undefined, '1224') threw exception TypeError: String.prototype.localeCompare requires that |this| not be undefined.
    2424PASS String.prototype.toLocaleLowerCase.call(undefined) threw exception TypeError: Type error.
    2525PASS String.prototype.toLocaleUpperCase.call(undefined) threw exception TypeError: Type error.
  • trunk/LayoutTests/js/script-tests/string-localeCompare.js

    r129601 r194328  
    1 description("This test checks String.localeCompare().");
     1description("This test checks the behavior of String.prototype.localeCompare as described in the ECMAScript Internationalization API Specification (ECMA-402 2.0).");
    22
     3shouldBe("String.prototype.localeCompare.length", "1");
     4shouldBeFalse("Object.getOwnPropertyDescriptor(String.prototype, 'localeCompare').enumerable");
     5shouldBeTrue("Object.getOwnPropertyDescriptor(String.prototype, 'localeCompare').configurable");
     6shouldBeTrue("Object.getOwnPropertyDescriptor(String.prototype, 'localeCompare').writable");
     7
     8// Test RequireObjectCoercible.
     9shouldThrow("String.prototype.localeCompare.call()", "'TypeError: String.prototype.localeCompare requires that |this| not be undefined'");
     10shouldThrow("String.prototype.localeCompare.call(undefined)", "'TypeError: String.prototype.localeCompare requires that |this| not be undefined'");
     11shouldThrow("String.prototype.localeCompare.call(null)", "'TypeError: String.prototype.localeCompare requires that |this| not be null'");
     12shouldNotThrow("String.prototype.localeCompare.call({}, '')");
     13shouldNotThrow("String.prototype.localeCompare.call([], '')");
     14shouldNotThrow("String.prototype.localeCompare.call(NaN, '')");
     15shouldNotThrow("String.prototype.localeCompare.call(5, '')");
     16shouldNotThrow("String.prototype.localeCompare.call('', '')");
     17shouldNotThrow("String.prototype.localeCompare.call(() => {}, '')");
     18
     19// Test toString fails.
     20shouldThrow("''.localeCompare.call({ toString() { throw 'thisFail' } }, '')", "'thisFail'");
     21shouldThrow("''.localeCompare({ toString() { throw 'thatFail' } })", "'thatFail'");
     22shouldNotThrow("''.localeCompare()");
     23shouldNotThrow("''.localeCompare(null)");
     24
     25// Basic support.
    326shouldBeTrue('"a".localeCompare("aa") < 0');
    427shouldBeTrue('"a".localeCompare("b") < 0');
     
    932shouldBeTrue('"aa".localeCompare("a") > 0');
    1033shouldBeTrue('"b".localeCompare("a") > 0');
     34
     35// Uses Intl.Collator.
     36shouldThrow("'a'.localeCompare('b', '$')", "'RangeError: invalid language tag: $'");
     37shouldThrow("'a'.localeCompare('b', 'en', {usage: 'Sort'})", '\'RangeError: usage must be either "sort" or "search"\'');
     38
     39shouldBe("'ä'.localeCompare('z', 'en')", "-1");
     40shouldBe("'ä'.localeCompare('z', 'sv')", "1");
     41
     42shouldBe("'a'.localeCompare('b', 'en', { sensitivity:'base' })", "-1");
     43shouldBe("'a'.localeCompare('ä', 'en', { sensitivity:'base' })", "0");
     44shouldBe("'a'.localeCompare('A', 'en', { sensitivity:'base' })", "0");
     45shouldBe("'a'.localeCompare('ⓐ', 'en', { sensitivity:'base' })", "0");
     46
     47shouldBe("'a'.localeCompare('b', 'en', { sensitivity:'accent' })", "-1");
     48shouldBe("'a'.localeCompare('ä', 'en', { sensitivity:'accent' })", "-1");
     49shouldBe("'a'.localeCompare('A', 'en', { sensitivity:'accent' })", "0");
     50shouldBe("'a'.localeCompare('ⓐ', 'en', { sensitivity:'accent' })", "0");
     51
     52shouldBe("'a'.localeCompare('b', 'en', { sensitivity:'case' })", "-1");
     53shouldBe("'a'.localeCompare('ä', 'en', { sensitivity:'case' })", "0");
     54shouldBe("'a'.localeCompare('A', 'en', { sensitivity:'case' })", "-1");
     55shouldBe("'a'.localeCompare('ⓐ', 'en', { sensitivity:'case' })", "0");
     56
     57shouldBe("'a'.localeCompare('b', 'en', { sensitivity:'variant' })", "-1");
     58shouldBe("'a'.localeCompare('ä', 'en', { sensitivity:'variant' })", "-1");
     59shouldBe("'a'.localeCompare('A', 'en', { sensitivity:'variant' })", "-1");
     60shouldBe("'a'.localeCompare('ⓐ', 'en', { sensitivity:'variant' })", "-1");
     61
     62shouldBe("'1'.localeCompare('2', 'en', { numeric:false })", "-1");
     63shouldBe("'2'.localeCompare('10', 'en', { numeric:false })", "1");
     64shouldBe("'01'.localeCompare('1', 'en', { numeric:false })", "-1");
     65shouldBe("'๑'.localeCompare('๒', 'en', { numeric:false })", "-1");
     66shouldBe("'๒'.localeCompare('๑๐', 'en', { numeric:false })", "1");
     67shouldBe("'๐๑'.localeCompare('๑', 'en', { numeric:false })", "-1");
     68
     69shouldBe("'1'.localeCompare('2', 'en', { numeric:true })", "-1");
     70shouldBe("'2'.localeCompare('10', 'en', { numeric:true })", "-1");
     71shouldBe("'01'.localeCompare('1', 'en', { numeric:true })", "0");
     72shouldBe("'๑'.localeCompare('๒', 'en', { numeric:true })", "-1");
     73shouldBe("'๒'.localeCompare('๑๐', 'en', { numeric:true })", "-1");
     74shouldBe("'๐๑'.localeCompare('๑', 'en', { numeric:true })", "0");
     75
  • trunk/LayoutTests/js/string-localeCompare-expected.txt

    r129601 r194328  
    1 This test checks String.localeCompare().
     1This test checks the behavior of String.prototype.localeCompare as described in the ECMAScript Internationalization API Specification (ECMA-402 2.0).
    22
    33On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
    44
    55
     6PASS String.prototype.localeCompare.length is 1
     7PASS Object.getOwnPropertyDescriptor(String.prototype, 'localeCompare').enumerable is false
     8PASS Object.getOwnPropertyDescriptor(String.prototype, 'localeCompare').configurable is true
     9PASS Object.getOwnPropertyDescriptor(String.prototype, 'localeCompare').writable is true
     10PASS String.prototype.localeCompare.call() threw exception TypeError: String.prototype.localeCompare requires that |this| not be undefined.
     11PASS String.prototype.localeCompare.call(undefined) threw exception TypeError: String.prototype.localeCompare requires that |this| not be undefined.
     12PASS String.prototype.localeCompare.call(null) threw exception TypeError: String.prototype.localeCompare requires that |this| not be null.
     13PASS String.prototype.localeCompare.call({}, '') did not throw exception.
     14PASS String.prototype.localeCompare.call([], '') did not throw exception.
     15PASS String.prototype.localeCompare.call(NaN, '') did not throw exception.
     16PASS String.prototype.localeCompare.call(5, '') did not throw exception.
     17PASS String.prototype.localeCompare.call('', '') did not throw exception.
     18PASS String.prototype.localeCompare.call(() => {}, '') did not throw exception.
     19PASS ''.localeCompare.call({ toString() { throw 'thisFail' } }, '') threw exception thisFail.
     20PASS ''.localeCompare({ toString() { throw 'thatFail' } }) threw exception thatFail.
     21PASS ''.localeCompare() did not throw exception.
     22PASS ''.localeCompare(null) did not throw exception.
    623PASS "a".localeCompare("aa") < 0 is true
    724PASS "a".localeCompare("b") < 0 is true
     
    1027PASS "aa".localeCompare("a") > 0 is true
    1128PASS "b".localeCompare("a") > 0 is true
     29PASS 'a'.localeCompare('b', '$') threw exception RangeError: invalid language tag: $.
     30PASS 'a'.localeCompare('b', 'en', {usage: 'Sort'}) threw exception RangeError: usage must be either "sort" or "search".
     31PASS 'ä'.localeCompare('z', 'en') is -1
     32PASS 'ä'.localeCompare('z', 'sv') is 1
     33PASS 'a'.localeCompare('b', 'en', { sensitivity:'base' }) is -1
     34PASS 'a'.localeCompare('ä', 'en', { sensitivity:'base' }) is 0
     35PASS 'a'.localeCompare('A', 'en', { sensitivity:'base' }) is 0
     36PASS 'a'.localeCompare('ⓐ', 'en', { sensitivity:'base' }) is 0
     37PASS 'a'.localeCompare('b', 'en', { sensitivity:'accent' }) is -1
     38PASS 'a'.localeCompare('ä', 'en', { sensitivity:'accent' }) is -1
     39PASS 'a'.localeCompare('A', 'en', { sensitivity:'accent' }) is 0
     40PASS 'a'.localeCompare('ⓐ', 'en', { sensitivity:'accent' }) is 0
     41PASS 'a'.localeCompare('b', 'en', { sensitivity:'case' }) is -1
     42PASS 'a'.localeCompare('ä', 'en', { sensitivity:'case' }) is 0
     43PASS 'a'.localeCompare('A', 'en', { sensitivity:'case' }) is -1
     44PASS 'a'.localeCompare('ⓐ', 'en', { sensitivity:'case' }) is 0
     45PASS 'a'.localeCompare('b', 'en', { sensitivity:'variant' }) is -1
     46PASS 'a'.localeCompare('ä', 'en', { sensitivity:'variant' }) is -1
     47PASS 'a'.localeCompare('A', 'en', { sensitivity:'variant' }) is -1
     48PASS 'a'.localeCompare('ⓐ', 'en', { sensitivity:'variant' }) is -1
     49PASS '1'.localeCompare('2', 'en', { numeric:false }) is -1
     50PASS '2'.localeCompare('10', 'en', { numeric:false }) is 1
     51PASS '01'.localeCompare('1', 'en', { numeric:false }) is -1
     52PASS '๑'.localeCompare('๒', 'en', { numeric:false }) is -1
     53PASS '๒'.localeCompare('๑๐', 'en', { numeric:false }) is 1
     54PASS '๐๑'.localeCompare('๑', 'en', { numeric:false }) is -1
     55PASS '1'.localeCompare('2', 'en', { numeric:true }) is -1
     56PASS '2'.localeCompare('10', 'en', { numeric:true }) is -1
     57PASS '01'.localeCompare('1', 'en', { numeric:true }) is 0
     58PASS '๑'.localeCompare('๒', 'en', { numeric:true }) is -1
     59PASS '๒'.localeCompare('๑๐', 'en', { numeric:true }) is -1
     60PASS '๐๑'.localeCompare('๑', 'en', { numeric:true }) is 0
    1261PASS successfullyParsed is true
    1362
  • trunk/LayoutTests/js/string-localeCompare.html

    r155452 r194328  
    22<html>
    33<head>
     4<meta charset="utf-8">
    45<script src="../resources/js-test-pre.js"></script>
    56</head>
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r194294 r194328  
    12501250    ${JAVASCRIPTCORE_DIR}/builtins/StringConstructor.js
    12511251    ${JAVASCRIPTCORE_DIR}/builtins/StringIteratorPrototype.js
     1252    ${JAVASCRIPTCORE_DIR}/builtins/StringPrototype.js
    12521253    ${JAVASCRIPTCORE_DIR}/builtins/TypedArrayConstructor.js
    12531254    ${JAVASCRIPTCORE_DIR}/builtins/TypedArrayPrototype.js
  • trunk/Source/JavaScriptCore/ChangeLog

    r194320 r194328  
     12015-12-21  Andy VanWagoner  <thetalecrafter@gmail.com>
     2
     3        [INTL] Implement String.prototype.localeCompare in ECMA-402
     4        https://bugs.webkit.org/show_bug.cgi?id=147607
     5
     6        Reviewed by Darin Adler.
     7
     8        Add localeCompare in builtin JavaScript that delegates comparing to Intl.Collator.
     9        Keep existing native implementation for use if INTL flag is disabled.
     10
     11        * CMakeLists.txt:
     12        * DerivedSources.make:
     13        * JavaScriptCore.xcodeproj/project.pbxproj:
     14        * builtins/StringPrototype.js: Added.
     15        (localeCompare):
     16        * runtime/StringPrototype.cpp:
     17        (JSC::StringPrototype::finishCreation):
     18
    1192015-12-18  Filip Pizlo  <fpizlo@apple.com>
    220
  • trunk/Source/JavaScriptCore/DerivedSources.make

    r194242 r194328  
    9999    $(JavaScriptCore)/builtins/StringConstructor.js \
    100100    $(JavaScriptCore)/builtins/StringIteratorPrototype.js \
     101    $(JavaScriptCore)/builtins/StringPrototype.js \
    101102    $(JavaScriptCore)/builtins/TypedArrayConstructor.js \
    102103    $(JavaScriptCore)/builtins/TypedArrayPrototype.js \
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r194317 r194328  
    20552055                FEA08620182B7A0400F6D851 /* Breakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861E182B7A0400F6D851 /* Breakpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
    20562056                FEA08621182B7A0400F6D851 /* DebuggerPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */; settings = {ATTRIBUTES = (Private, ); }; };
    2057                 FEA1E4391C213A2B00277A16 /* ValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEA1E4381C213A2600277A16 /* ValueProfile.cpp */; settings = {ASSET_TAGS = (); }; };
     2057                FEA1E4391C213A2B00277A16 /* ValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEA1E4381C213A2600277A16 /* ValueProfile.cpp */; };
    20582058                FEB137571BB11EF900CD5100 /* MacroAssemblerARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEB137561BB11EEE00CD5100 /* MacroAssemblerARM64.cpp */; };
    20592059                FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEB51F6B1A97B688001F921C /* Regress141809.mm */; };
     
    36743674                A1D792FA1B43864B004516F5 /* IntlNumberFormatPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlNumberFormatPrototype.cpp; sourceTree = "<group>"; };
    36753675                A1D792FB1B43864B004516F5 /* IntlNumberFormatPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlNumberFormatPrototype.h; sourceTree = "<group>"; };
     3676                A1E0451B1C25B4B100BB663C /* StringPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = StringPrototype.js; sourceTree = "<group>"; };
    36763677                A503FA13188E0FAF00110F14 /* JavaScriptCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JavaScriptCallFrame.cpp; sourceTree = "<group>"; };
    36773678                A503FA14188E0FAF00110F14 /* JavaScriptCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptCallFrame.h; sourceTree = "<group>"; };
     
    67676768                                7CF9BC601B65D9B1009DB1EF /* StringConstructor.js */,
    67686769                                7CF9BC611B65D9B1009DB1EF /* StringIteratorPrototype.js */,
     6770                                A1E0451B1C25B4B100BB663C /* StringPrototype.js */,
    67696771                                53917E831B791CB8000EBD33 /* TypedArrayPrototype.js */,
    67706772                                534C457A1BC703DC007476A7 /* TypedArrayConstructor.js */,
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r194310 r194328  
    3030#include "Executable.h"
    3131#include "IntlObject.h"
     32#include "JSCBuiltins.h"
    3233#include "JSCInlines.h"
    3334#include "JSGlobalObjectFunctions.h"
     
    131132    JSC_NATIVE_FUNCTION("toLowerCase", stringProtoFuncToLowerCase, DontEnum, 0);
    132133    JSC_NATIVE_FUNCTION("toUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
    133     JSC_NATIVE_FUNCTION("localeCompare", stringProtoFuncLocaleCompare, DontEnum, 1);
    134134#if ENABLE(INTL)
     135    JSC_BUILTIN_FUNCTION("localeCompare", stringPrototypeLocaleCompareCodeGenerator, DontEnum);
    135136    JSC_NATIVE_FUNCTION("toLocaleLowerCase", stringProtoFuncToLocaleLowerCase, DontEnum, 0);
    136137    JSC_NATIVE_FUNCTION("toLocaleUpperCase", stringProtoFuncToLocaleUpperCase, DontEnum, 0);
    137138#else
     139    JSC_NATIVE_FUNCTION("localeCompare", stringProtoFuncLocaleCompare, DontEnum, 1);
    138140    JSC_NATIVE_FUNCTION("toLocaleLowerCase", stringProtoFuncToLowerCase, DontEnum, 0);
    139141    JSC_NATIVE_FUNCTION("toLocaleUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
Note: See TracChangeset for help on using the changeset viewer.