| 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 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 return LANGUAGE_SINGLETON_RE; | 169 return LANGUAGE_SINGLETON_RE; |
| 170 } | 170 } |
| 171 | 171 |
| 172 /** | 172 /** |
| 173 * Matches valid IANA time zone names. | 173 * Matches valid IANA time zone names. |
| 174 */ | 174 */ |
| 175 var TIMEZONE_NAME_CHECK_RE = UNDEFINED; | 175 var TIMEZONE_NAME_CHECK_RE = UNDEFINED; |
| 176 | 176 |
| 177 function GetTimezoneNameCheckRE() { | 177 function GetTimezoneNameCheckRE() { |
| 178 if (IS_UNDEFINED(TIMEZONE_NAME_CHECK_RE)) { | 178 if (IS_UNDEFINED(TIMEZONE_NAME_CHECK_RE)) { |
| 179 TIMEZONE_NAME_CHECK_RE = | 179 TIMEZONE_NAME_CHECK_RE = new GlobalRegExp( |
| 180 new GlobalRegExp('^([A-Za-z]+)/([A-Za-z]+)(?:_([A-Za-z]+))*$'); | 180 '^([A-Za-z]+)/([A-Za-z_-]+)((?:\/[A-Za-z_-]+)+)*$'); |
| 181 } | 181 } |
| 182 return TIMEZONE_NAME_CHECK_RE; | 182 return TIMEZONE_NAME_CHECK_RE; |
| 183 } | 183 } |
| 184 | 184 |
| 185 /** | 185 /** |
| 186 * Matches valid location parts of IANA time zone names. |
| 187 */ |
| 188 var TIMEZONE_NAME_LOCATION_PART_RE = UNDEFINED; |
| 189 |
| 190 function GetTimezoneNameLocationPartRE() { |
| 191 if (IS_UNDEFINED(TIMEZONE_NAME_LOCATION_PART_RE)) { |
| 192 TIMEZONE_NAME_LOCATION_PART_RE = |
| 193 new GlobalRegExp('^([A-Za-z]+)((?:[_-][A-Za-z]+)+)*$'); |
| 194 } |
| 195 return TIMEZONE_NAME_LOCATION_PART_RE; |
| 196 } |
| 197 |
| 198 /** |
| 186 * Adds bound method to the prototype of the given object. | 199 * Adds bound method to the prototype of the given object. |
| 187 */ | 200 */ |
| 188 function addBoundMethod(obj, methodName, implementation, length) { | 201 function addBoundMethod(obj, methodName, implementation, length) { |
| 189 %CheckIsBootstrapping(); | 202 %CheckIsBootstrapping(); |
| 190 function getter() { | 203 function getter() { |
| 191 if (!%IsInitializedIntlObject(this)) { | 204 if (!%IsInitializedIntlObject(this)) { |
| 192 throw MakeTypeError(kMethodCalledOnWrongObject, methodName); | 205 throw MakeTypeError(kMethodCalledOnWrongObject, methodName); |
| 193 } | 206 } |
| 194 var internalName = '__bound' + methodName + '__'; | 207 var internalName = '__bound' + methodName + '__'; |
| 195 if (IS_UNDEFINED(this[internalName])) { | 208 if (IS_UNDEFINED(this[internalName])) { |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 | 685 |
| 673 /** | 686 /** |
| 674 * Returns titlecased word, aMeRricA -> America. | 687 * Returns titlecased word, aMeRricA -> America. |
| 675 */ | 688 */ |
| 676 function toTitleCaseWord(word) { | 689 function toTitleCaseWord(word) { |
| 677 return %StringToUpperCase(%_Call(StringSubstr, word, 0, 1)) + | 690 return %StringToUpperCase(%_Call(StringSubstr, word, 0, 1)) + |
| 678 %StringToLowerCase(%_Call(StringSubstr, word, 1)); | 691 %StringToLowerCase(%_Call(StringSubstr, word, 1)); |
| 679 } | 692 } |
| 680 | 693 |
| 681 /** | 694 /** |
| 695 * Returns titlecased location, bueNos_airES -> Buenos_Aires |
| 696 * or ho_cHi_minH -> Ho_Chi_Minh. It is locale-agnostic and only |
| 697 * deals with ASCII only characters. |
| 698 * 'of', 'au' and 'es' are special-cased and lowercased. |
| 699 */ |
| 700 function toTitleCaseTimezoneLocation(location) { |
| 701 var match = %_Call(StringMatch, location, GetTimezoneNameLocationPartRE()); |
| 702 if (IS_NULL(match)) throw MakeRangeError(kExpectedLocation, location); |
| 703 |
| 704 var result = toTitleCaseWord(match[1]); |
| 705 if (!IS_UNDEFINED(match[2]) && 2 < match.length) { |
| 706 // The first character is a separator, '_' or '-'. |
| 707 // None of IANA zone names has both '_' and '-'. |
| 708 var separator = %_Call(StringSubstring, match[2], 0, 1); |
| 709 var parts = %_Call(StringSplit, match[2], separator); |
| 710 for (var i = 1; i < parts.length; i++) { |
| 711 var part = parts[i] |
| 712 var lowercasedPart = %StringToLowerCase(part); |
| 713 result = result + separator + |
| 714 ((lowercasedPart !== 'es' && |
| 715 lowercasedPart !== 'of' && lowercasedPart !== 'au') ? |
| 716 toTitleCaseWord(part) : lowercasedPart); |
| 717 } |
| 718 } |
| 719 return result; |
| 720 } |
| 721 |
| 722 /** |
| 682 * Canonicalizes the language tag, or throws in case the tag is invalid. | 723 * Canonicalizes the language tag, or throws in case the tag is invalid. |
| 683 */ | 724 */ |
| 684 function canonicalizeLanguageTag(localeID) { | 725 function canonicalizeLanguageTag(localeID) { |
| 685 // null is typeof 'object' so we have to do extra check. | 726 // null is typeof 'object' so we have to do extra check. |
| 686 if (typeof localeID !== 'string' && typeof localeID !== 'object' || | 727 if (typeof localeID !== 'string' && typeof localeID !== 'object' || |
| 687 IS_NULL(localeID)) { | 728 IS_NULL(localeID)) { |
| 688 throw MakeTypeError(kLanguageID); | 729 throw MakeTypeError(kLanguageID); |
| 689 } | 730 } |
| 690 | 731 |
| 691 var localeString = GlobalString(localeID); | 732 var localeString = GlobalString(localeID); |
| (...skipping 1036 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1728 GlobalString(value)); | 1769 GlobalString(value)); |
| 1729 } | 1770 } |
| 1730 | 1771 |
| 1731 | 1772 |
| 1732 // 0 because date is optional argument. | 1773 // 0 because date is optional argument. |
| 1733 addBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0); | 1774 addBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0); |
| 1734 addBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1); | 1775 addBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1); |
| 1735 | 1776 |
| 1736 | 1777 |
| 1737 /** | 1778 /** |
| 1738 * Returns canonical Area/Location name, or throws an exception if the zone | 1779 * Returns canonical Area/Location(/Location) name, or throws an exception |
| 1739 * name is invalid IANA name. | 1780 * if the zone name is invalid IANA name. |
| 1740 */ | 1781 */ |
| 1741 function canonicalizeTimeZoneID(tzID) { | 1782 function canonicalizeTimeZoneID(tzID) { |
| 1742 // Skip undefined zones. | 1783 // Skip undefined zones. |
| 1743 if (IS_UNDEFINED(tzID)) { | 1784 if (IS_UNDEFINED(tzID)) { |
| 1744 return tzID; | 1785 return tzID; |
| 1745 } | 1786 } |
| 1746 | 1787 |
| 1747 // Special case handling (UTC, GMT). | 1788 // Special case handling (UTC, GMT). |
| 1748 var upperID = %StringToUpperCase(tzID); | 1789 var upperID = %StringToUpperCase(tzID); |
| 1749 if (upperID === 'UTC' || upperID === 'GMT' || | 1790 if (upperID === 'UTC' || upperID === 'GMT' || |
| 1750 upperID === 'ETC/UTC' || upperID === 'ETC/GMT') { | 1791 upperID === 'ETC/UTC' || upperID === 'ETC/GMT') { |
| 1751 return 'UTC'; | 1792 return 'UTC'; |
| 1752 } | 1793 } |
| 1753 | 1794 |
| 1754 // We expect only _ and / beside ASCII letters. | 1795 // TODO(jshin): Add support for Etc/GMT[+-]([1-9]|1[0-2]) |
| 1755 // All inputs should conform to Area/Location from now on. | 1796 |
| 1797 // We expect only _, '-' and / beside ASCII letters. |
| 1798 // All inputs should conform to Area/Location(/Location)* from now on. |
| 1756 var match = %_Call(StringMatch, tzID, GetTimezoneNameCheckRE()); | 1799 var match = %_Call(StringMatch, tzID, GetTimezoneNameCheckRE()); |
| 1757 if (IS_NULL(match)) throw MakeRangeError(kExpectedLocation, tzID); | 1800 if (IS_NULL(match)) throw MakeRangeError(kExpectedTimezoneID, tzID); |
| 1758 | 1801 |
| 1759 var result = toTitleCaseWord(match[1]) + '/' + toTitleCaseWord(match[2]); | 1802 var result = toTitleCaseTimezoneLocation(match[1]) + '/' + |
| 1760 var i = 3; | 1803 toTitleCaseTimezoneLocation(match[2]); |
| 1761 while (!IS_UNDEFINED(match[i]) && i < match.length) { | 1804 |
| 1762 result = result + '_' + toTitleCaseWord(match[i]); | 1805 if (!IS_UNDEFINED(match[3]) && 3 < match.length) { |
| 1763 i++; | 1806 var locations = %_Call(StringSplit, match[3], '/'); |
| 1807 // The 1st element is empty. Starts with i=1. |
| 1808 for (var i = 1; i < locations.length; i++) { |
| 1809 result = result + '/' + toTitleCaseTimezoneLocation(locations[i]); |
| 1810 } |
| 1764 } | 1811 } |
| 1765 | 1812 |
| 1766 return result; | 1813 return result; |
| 1767 } | 1814 } |
| 1768 | 1815 |
| 1769 /** | 1816 /** |
| 1770 * Initializes the given object so it's a valid BreakIterator instance. | 1817 * Initializes the given object so it's a valid BreakIterator instance. |
| 1771 * Useful for subclassing. | 1818 * Useful for subclassing. |
| 1772 */ | 1819 */ |
| 1773 function initializeBreakIterator(iterator, locales, options) { | 1820 function initializeBreakIterator(iterator, locales, options) { |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2113 } | 2160 } |
| 2114 | 2161 |
| 2115 var locales = %_Arguments(0); | 2162 var locales = %_Arguments(0); |
| 2116 var options = %_Arguments(1); | 2163 var options = %_Arguments(1); |
| 2117 return toLocaleDateTime( | 2164 return toLocaleDateTime( |
| 2118 this, locales, options, 'time', 'time', 'dateformattime'); | 2165 this, locales, options, 'time', 'time', 'dateformattime'); |
| 2119 } | 2166 } |
| 2120 ); | 2167 ); |
| 2121 | 2168 |
| 2122 }) | 2169 }) |
| OLD | NEW |