OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // ECMAScript 402 API implementation. | 5 // ECMAScript 402 API implementation. |
6 | 6 |
7 /** | 7 /** |
8 * Intl object is a single object that has some named properties, | 8 * Intl object is a single object that has some named properties, |
9 * all of which are constructors. | 9 * all of which are constructors. |
10 */ | 10 */ |
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
577 configurable: false, | 577 configurable: false, |
578 writable: false, | 578 writable: false, |
579 enumerable: true}); | 579 enumerable: true}); |
580 } | 580 } |
581 } | 581 } |
582 | 582 |
583 %object_define_property(array, 'length', {value: l, writable: false}); | 583 %object_define_property(array, 'length', {value: l, writable: false}); |
584 return array; | 584 return array; |
585 } | 585 } |
586 | 586 |
587 /* Make JS array[] out of InternalArray */ | |
588 function makeArray(input) { | |
589 var array = []; | |
590 %MoveArrayContents(input, array); | |
591 return array; | |
592 } | |
593 | |
587 | 594 |
588 /** | 595 /** |
589 * It's sometimes desireable to leave user requested locale instead of ICU | 596 * It's sometimes desireable to leave user requested locale instead of ICU |
590 * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter | 597 * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter |
591 * one, if that was what user requested). | 598 * one, if that was what user requested). |
592 * This function returns user specified tag if its maximized form matches ICU | 599 * This function returns user specified tag if its maximized form matches ICU |
593 * resolved locale. If not we return ICU result. | 600 * resolved locale. If not we return ICU result. |
594 */ | 601 */ |
595 function getOptimalLanguageTag(original, resolved) { | 602 function getOptimalLanguageTag(original, resolved) { |
596 // Returns Array<Object>, where each object has maximized and base properties. | 603 // Returns Array<Object>, where each object has maximized and base properties. |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
711 ((lowercasedPart !== 'es' && | 718 ((lowercasedPart !== 'es' && |
712 lowercasedPart !== 'of' && lowercasedPart !== 'au') ? | 719 lowercasedPart !== 'of' && lowercasedPart !== 'au') ? |
713 toTitleCaseWord(part) : lowercasedPart); | 720 toTitleCaseWord(part) : lowercasedPart); |
714 } | 721 } |
715 } | 722 } |
716 return result; | 723 return result; |
717 } | 724 } |
718 | 725 |
719 /** | 726 /** |
720 * Canonicalizes the language tag, or throws in case the tag is invalid. | 727 * Canonicalizes the language tag, or throws in case the tag is invalid. |
728 * ECMA 402 9.2.1 steps 7.c ii ~ v. | |
721 */ | 729 */ |
722 function canonicalizeLanguageTag(localeID) { | 730 function canonicalizeLanguageTag(localeID) { |
723 // null is typeof 'object' so we have to do extra check. | 731 // null is typeof 'object' so we have to do extra check. |
724 if ((!IS_STRING(localeID) && !IS_RECEIVER(localeID)) || | 732 if ((!IS_STRING(localeID) && !IS_RECEIVER(localeID)) || |
725 IS_NULL(localeID)) { | 733 IS_NULL(localeID)) { |
726 throw %make_type_error(kLanguageID); | 734 throw %make_type_error(kLanguageID); |
727 } | 735 } |
728 | 736 |
729 // Optimize for the most common case; a language code alone in | 737 // Optimize for the most common case; a language code alone in |
730 // the canonical form/lowercase (e.g. "en", "fil"). | 738 // the canonical form/lowercase (e.g. "en", "fil"). |
731 if (IS_STRING(localeID) && | 739 if (IS_STRING(localeID) && |
732 !IS_NULL(InternalRegExpMatch(/^[a-z]{2,3}$/, localeID))) { | 740 !IS_NULL(InternalRegExpMatch(/^[a-z]{2,3}$/, localeID))) { |
733 return localeID; | 741 return localeID; |
734 } | 742 } |
735 | 743 |
736 var localeString = TO_STRING(localeID); | 744 var localeString = TO_STRING(localeID); |
737 | 745 |
738 if (isValidLanguageTag(localeString) === false) { | 746 if (isStructuallyValidLanguageTag(localeString) === false) { |
739 throw %make_range_error(kInvalidLanguageTag, localeString); | 747 throw %make_range_error(kInvalidLanguageTag, localeString); |
740 } | 748 } |
741 | 749 |
750 // ECMA 402 6.2.3 | |
742 var tag = %CanonicalizeLanguageTag(localeString); | 751 var tag = %CanonicalizeLanguageTag(localeString); |
752 // TODO(jshin): This should not happen because the structual validity | |
753 // is already checked. If that's the case, remove this. | |
743 if (tag === 'invalid-tag') { | 754 if (tag === 'invalid-tag') { |
744 throw %make_range_error(kInvalidLanguageTag, localeString); | 755 throw %make_range_error(kInvalidLanguageTag, localeString); |
745 } | 756 } |
746 | 757 |
747 return tag; | 758 return tag; |
748 } | 759 } |
749 | 760 |
750 | 761 |
751 /** | 762 /** |
752 * Returns an array where all locales are canonicalized and duplicates removed. | 763 * Returns an array where all locales are canonicalized and duplicates removed. |
753 * Throws on locales that are not well formed BCP47 tags. | 764 * Throws on locales that are not well formed BCP47 tags. |
765 * ECMA 402 8.2.1 steps 1 (ECMA 402 9.2.1) and 2. | |
754 */ | 766 */ |
755 function initializeLocaleList(locales) { | 767 function canonicalizeLocaleList(locales) { |
756 var seen = new InternalArray(); | 768 var seen = new InternalArray(); |
757 if (!IS_UNDEFINED(locales)) { | 769 if (!IS_UNDEFINED(locales)) { |
758 // We allow single string localeID. | 770 // We allow single string localeID. |
759 if (typeof locales === 'string') { | 771 if (typeof locales === 'string') { |
760 %_Call(ArrayPush, seen, canonicalizeLanguageTag(locales)); | 772 %_Call(ArrayPush, seen, canonicalizeLanguageTag(locales)); |
761 return freezeArray(seen); | 773 return makeArray(seen); |
762 } | 774 } |
763 | 775 |
764 var o = TO_OBJECT(locales); | 776 var o = TO_OBJECT(locales); |
765 var len = TO_UINT32(o.length); | 777 var len = TO_LENGTH(o.length); |
766 | 778 |
767 for (var k = 0; k < len; k++) { | 779 for (var k = 0; k < len; k++) { |
768 if (k in o) { | 780 if (k in o) { |
769 var value = o[k]; | 781 var value = o[k]; |
770 | 782 |
771 var tag = canonicalizeLanguageTag(value); | 783 var tag = canonicalizeLanguageTag(value); |
772 | 784 |
773 if (%_Call(ArrayIndexOf, seen, tag) === -1) { | 785 if (%_Call(ArrayIndexOf, seen, tag) === -1) { |
774 %_Call(ArrayPush, seen, tag); | 786 %_Call(ArrayPush, seen, tag); |
775 } | 787 } |
776 } | 788 } |
777 } | 789 } |
778 } | 790 } |
779 | 791 |
780 return freezeArray(seen); | 792 return makeArray(seen); |
781 } | 793 } |
782 | 794 |
795 function initializeLocaleList(locales) { | |
796 return freezeArray(canonicalizeLocaleList(locales)); | |
Dan Ehrenberg
2016/08/12 18:59:19
This seems to make an extra copy of the array, whi
| |
797 } | |
783 | 798 |
784 /** | 799 /** |
785 * Validates the language tag. Section 2.2.9 of the bcp47 spec | 800 * Check the structual Validity of the language tag per ECMA 402 6.2.2: |
786 * defines a valid tag. | 801 * - Well-formed per RFC 5646 2.1 |
802 * - There are no duplicate variant subtags | |
803 * - There are no duplicate singletion (extension) subtags | |
804 * | |
805 * One extra-check is done (from RFC 5646 2.2.9): the tag is compared | |
806 * against the list of grandfathered tags. However, subtags for | |
807 * primary/extended language, script, region, variant are not checked | |
808 * against the IANA language subtag registry. | |
787 * | 809 * |
788 * ICU is too permissible and lets invalid tags, like | 810 * ICU is too permissible and lets invalid tags, like |
789 * hant-cmn-cn, through. | 811 * hant-cmn-cn, through. |
790 * | 812 * |
791 * Returns false if the language tag is invalid. | 813 * Returns false if the language tag is invalid. |
792 */ | 814 */ |
793 function isValidLanguageTag(locale) { | 815 function isStructuallyValidLanguageTag(locale) { |
794 // Check if it's well-formed, including grandfadered tags. | 816 // Check if it's well-formed, including grandfadered tags. |
795 if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) { | 817 if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) { |
796 return false; | 818 return false; |
797 } | 819 } |
798 | 820 |
799 // Just return if it's a x- form. It's all private. | 821 // Just return if it's a x- form. It's all private. |
800 if (%_Call(StringIndexOf, locale, 'x-') === 0) { | 822 if (%_Call(StringIndexOf, locale, 'x-') === 0) { |
801 return true; | 823 return true; |
802 } | 824 } |
803 | 825 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
878 var resolvedAccessor = { | 900 var resolvedAccessor = { |
879 get() { | 901 get() { |
880 %IncrementUseCounter(kIntlResolved); | 902 %IncrementUseCounter(kIntlResolved); |
881 return this[resolvedSymbol]; | 903 return this[resolvedSymbol]; |
882 }, | 904 }, |
883 set(value) { | 905 set(value) { |
884 this[resolvedSymbol] = value; | 906 this[resolvedSymbol] = value; |
885 } | 907 } |
886 }; | 908 }; |
887 | 909 |
910 // ECMA 402 section 8.2.1 | |
911 InstallFunction(Intl, 'getCanonicalLocales', function(locales) { | |
912 if (!IS_UNDEFINED(new.target)) { | |
913 throw %make_type_error(kOrdinaryFunctionCalledAsConstructor); | |
914 } | |
915 | |
916 return canonicalizeLocaleList(locales); | |
917 } | |
918 ); | |
919 | |
888 /** | 920 /** |
889 * Initializes the given object so it's a valid Collator instance. | 921 * Initializes the given object so it's a valid Collator instance. |
890 * Useful for subclassing. | 922 * Useful for subclassing. |
891 */ | 923 */ |
892 function initializeCollator(collator, locales, options) { | 924 function initializeCollator(collator, locales, options) { |
893 if (%IsInitializedIntlObject(collator)) { | 925 if (%IsInitializedIntlObject(collator)) { |
894 throw %make_type_error(kReinitializeIntl, "Collator"); | 926 throw %make_type_error(kReinitializeIntl, "Collator"); |
895 } | 927 } |
896 | 928 |
897 if (IS_UNDEFINED(options)) { | 929 if (IS_UNDEFINED(options)) { |
(...skipping 1348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2246 } | 2278 } |
2247 ); | 2279 ); |
2248 | 2280 |
2249 utils.Export(function(to) { | 2281 utils.Export(function(to) { |
2250 to.AddBoundMethod = AddBoundMethod; | 2282 to.AddBoundMethod = AddBoundMethod; |
2251 to.IntlParseDate = IntlParseDate; | 2283 to.IntlParseDate = IntlParseDate; |
2252 to.IntlParseNumber = IntlParseNumber; | 2284 to.IntlParseNumber = IntlParseNumber; |
2253 }); | 2285 }); |
2254 | 2286 |
2255 }) | 2287 }) |
OLD | NEW |