Changeset 194394 in webkit


Ignore:
Timestamp:
Dec 23, 2015 12:02:37 PM (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-23
Reviewed by Benjamin Poulain.

Source/JavaScriptCore:

Add localeCompare in builtin JavaScript that delegates comparing to Intl.Collator.
Keep existing native implementation for use if INTL flag is disabled.
For the common case where no locale or options are specified, avoid creating
a new collator and just use the prototype which is initialized with the defaults.

  • 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

    r194393 r194394  
     12015-12-23  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 Benjamin Poulain.
     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-23  Ryan Haddad  <ryanhaddad@apple.com>
    215
  • trunk/LayoutTests/js/dom/script-tests/string-prototype-properties.js

    r194332 r194394  
    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

    r194332 r194394  
    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

    r194332 r194394  
    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

    r194332 r194394  
    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

    r194332 r194394  
    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

    r194363 r194394  
    12521252    ${JAVASCRIPTCORE_DIR}/builtins/StringConstructor.js
    12531253    ${JAVASCRIPTCORE_DIR}/builtins/StringIteratorPrototype.js
     1254    ${JAVASCRIPTCORE_DIR}/builtins/StringPrototype.js
    12541255    ${JAVASCRIPTCORE_DIR}/builtins/TypedArrayConstructor.js
    12551256    ${JAVASCRIPTCORE_DIR}/builtins/TypedArrayPrototype.js
  • trunk/Source/JavaScriptCore/ChangeLog

    r194389 r194394  
     12015-12-23  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 Benjamin Poulain.
     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        For the common case where no locale or options are specified, avoid creating
     11        a new collator and just use the prototype which is initialized with the defaults.
     12
     13        * CMakeLists.txt:
     14        * DerivedSources.make:
     15        * JavaScriptCore.xcodeproj/project.pbxproj:
     16        * builtins/StringPrototype.js: Added.
     17        (localeCompare):
     18        * runtime/StringPrototype.cpp:
     19        (JSC::StringPrototype::finishCreation):
     20
    1212015-12-23  Benjamin Poulain  <benjamin@webkit.org>
    222
  • trunk/Source/JavaScriptCore/DerivedSources.make

    r194332 r194394  
    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

    r194372 r194394  
    20602060                FEA08620182B7A0400F6D851 /* Breakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861E182B7A0400F6D851 /* Breakpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
    20612061                FEA08621182B7A0400F6D851 /* DebuggerPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */; settings = {ATTRIBUTES = (Private, ); }; };
    2062                 FEA1E4391C213A2B00277A16 /* ValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEA1E4381C213A2600277A16 /* ValueProfile.cpp */; settings = {ASSET_TAGS = (); }; };
     2062                FEA1E4391C213A2B00277A16 /* ValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEA1E4381C213A2600277A16 /* ValueProfile.cpp */; };
    20632063                FEB137571BB11EF900CD5100 /* MacroAssemblerARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEB137561BB11EEE00CD5100 /* MacroAssemblerARM64.cpp */; };
    20642064                FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEB51F6B1A97B688001F921C /* Regress141809.mm */; };
     
    36823682                A1D792FA1B43864B004516F5 /* IntlNumberFormatPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlNumberFormatPrototype.cpp; sourceTree = "<group>"; };
    36833683                A1D792FB1B43864B004516F5 /* IntlNumberFormatPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlNumberFormatPrototype.h; sourceTree = "<group>"; };
     3684                A1E0451B1C25B4B100BB663C /* StringPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = StringPrototype.js; sourceTree = "<group>"; };
    36843685                A503FA13188E0FAF00110F14 /* JavaScriptCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JavaScriptCallFrame.cpp; sourceTree = "<group>"; };
    36853686                A503FA14188E0FAF00110F14 /* JavaScriptCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptCallFrame.h; sourceTree = "<group>"; };
     
    67826783                                7CF9BC601B65D9B1009DB1EF /* StringConstructor.js */,
    67836784                                7CF9BC611B65D9B1009DB1EF /* StringIteratorPrototype.js */,
     6785                                A1E0451B1C25B4B100BB663C /* StringPrototype.js */,
    67846786                                53917E831B791CB8000EBD33 /* TypedArrayPrototype.js */,
    67856787                                534C457A1BC703DC007476A7 /* TypedArrayConstructor.js */,
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r194332 r194394  
    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.