Line data Source code
1 : // Copyright 2011 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/dateparser.h"
6 :
7 : #include "src/char-predicates-inl.h"
8 : #include "src/objects-inl.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 :
13 57972 : bool DateParser::DayComposer::Write(FixedArray output) {
14 57972 : if (index_ < 1) return false;
15 : // Day and month defaults to 1.
16 169053 : while (index_ < kSize) {
17 55563 : comp_[index_++] = 1;
18 : }
19 :
20 : int year = 0; // Default year is 0 (=> 2000) for KJS compatibility.
21 : int month = kNone;
22 : int day = kNone;
23 :
24 57927 : if (named_month_ == kNone) {
25 3584 : if (is_iso_date_ || (index_ == 3 && !IsDay(comp_[0]))) {
26 : // YMD
27 3138 : year = comp_[0];
28 3138 : month = comp_[1];
29 3138 : day = comp_[2];
30 : } else {
31 : // MD(Y)
32 54 : month = comp_[0];
33 54 : day = comp_[1];
34 54 : if (index_ == 3) year = comp_[2];
35 : }
36 : } else {
37 : month = named_month_;
38 54735 : if (index_ == 1) {
39 : // MD or DM
40 0 : day = comp_[0];
41 109470 : } else if (!IsDay(comp_[0])) {
42 : // YMD, MYD, or YDM
43 : year = comp_[0];
44 0 : day = comp_[1];
45 : } else {
46 : // DMY, MDY, or DYM
47 : day = comp_[0];
48 54735 : year = comp_[1];
49 : }
50 : }
51 :
52 57927 : if (!is_iso_date_) {
53 55127 : if (Between(year, 0, 49)) year += 2000;
54 54749 : else if (Between(year, 50, 99)) year += 1900;
55 : }
56 :
57 115827 : if (!Smi::IsValid(year) || !IsMonth(month) || !IsDay(day)) return false;
58 :
59 : output->set(YEAR, Smi::FromInt(year));
60 : output->set(MONTH, Smi::FromInt(month - 1)); // 0-based
61 : output->set(DAY, Smi::FromInt(day));
62 57900 : return true;
63 : }
64 :
65 57900 : bool DateParser::TimeComposer::Write(FixedArray output) {
66 : // All time slots default to 0
67 63848 : while (index_ < kSize) {
68 2974 : comp_[index_++] = 0;
69 : }
70 :
71 : int& hour = comp_[0];
72 : int& minute = comp_[1];
73 : int& second = comp_[2];
74 : int& millisecond = comp_[3];
75 :
76 57900 : if (hour_offset_ != kNone) {
77 972 : if (!IsHour12(hour)) return false;
78 486 : hour %= 12;
79 486 : hour += hour_offset_;
80 : }
81 :
82 289365 : if (!IsHour(hour) || !IsMinute(minute) ||
83 231465 : !IsSecond(second) || !IsMillisecond(millisecond)) {
84 : // A 24th hour is allowed if minutes, seconds, and milliseconds are 0
85 45 : if (hour != 24 || minute != 0 || second != 0 || millisecond != 0) {
86 : return false;
87 : }
88 : }
89 :
90 : output->set(HOUR, Smi::FromInt(hour));
91 57891 : output->set(MINUTE, Smi::FromInt(minute));
92 57891 : output->set(SECOND, Smi::FromInt(second));
93 57891 : output->set(MILLISECOND, Smi::FromInt(millisecond));
94 57891 : return true;
95 : }
96 :
97 57891 : bool DateParser::TimeZoneComposer::Write(FixedArray output) {
98 57891 : if (sign_ != kNone) {
99 57308 : if (hour_ == kNone) hour_ = 0;
100 57308 : if (minute_ == kNone) minute_ = 0;
101 : // Avoid signed integer overflow (undefined behavior) by doing unsigned
102 : // arithmetic.
103 57308 : unsigned total_seconds_unsigned = hour_ * 3600U + minute_ * 60U;
104 57308 : if (total_seconds_unsigned > Smi::kMaxValue) return false;
105 : int total_seconds = static_cast<int>(total_seconds_unsigned);
106 57308 : if (sign_ < 0) {
107 54072 : total_seconds = -total_seconds;
108 : }
109 : DCHECK(Smi::IsValid(total_seconds));
110 : output->set(UTC_OFFSET, Smi::FromInt(total_seconds));
111 : } else {
112 583 : output->set_null(UTC_OFFSET);
113 : }
114 : return true;
115 : }
116 :
117 : const int8_t DateParser::KeywordTable::
118 : array[][DateParser::KeywordTable::kEntrySize] = {
119 : {'j', 'a', 'n', DateParser::MONTH_NAME, 1},
120 : {'f', 'e', 'b', DateParser::MONTH_NAME, 2},
121 : {'m', 'a', 'r', DateParser::MONTH_NAME, 3},
122 : {'a', 'p', 'r', DateParser::MONTH_NAME, 4},
123 : {'m', 'a', 'y', DateParser::MONTH_NAME, 5},
124 : {'j', 'u', 'n', DateParser::MONTH_NAME, 6},
125 : {'j', 'u', 'l', DateParser::MONTH_NAME, 7},
126 : {'a', 'u', 'g', DateParser::MONTH_NAME, 8},
127 : {'s', 'e', 'p', DateParser::MONTH_NAME, 9},
128 : {'o', 'c', 't', DateParser::MONTH_NAME, 10},
129 : {'n', 'o', 'v', DateParser::MONTH_NAME, 11},
130 : {'d', 'e', 'c', DateParser::MONTH_NAME, 12},
131 : {'a', 'm', '\0', DateParser::AM_PM, 0},
132 : {'p', 'm', '\0', DateParser::AM_PM, 12},
133 : {'u', 't', '\0', DateParser::TIME_ZONE_NAME, 0},
134 : {'u', 't', 'c', DateParser::TIME_ZONE_NAME, 0},
135 : {'z', '\0', '\0', DateParser::TIME_ZONE_NAME, 0},
136 : {'g', 'm', 't', DateParser::TIME_ZONE_NAME, 0},
137 : {'c', 'd', 't', DateParser::TIME_ZONE_NAME, -5},
138 : {'c', 's', 't', DateParser::TIME_ZONE_NAME, -6},
139 : {'e', 'd', 't', DateParser::TIME_ZONE_NAME, -4},
140 : {'e', 's', 't', DateParser::TIME_ZONE_NAME, -5},
141 : {'m', 'd', 't', DateParser::TIME_ZONE_NAME, -6},
142 : {'m', 's', 't', DateParser::TIME_ZONE_NAME, -7},
143 : {'p', 'd', 't', DateParser::TIME_ZONE_NAME, -7},
144 : {'p', 's', 't', DateParser::TIME_ZONE_NAME, -8},
145 : {'t', '\0', '\0', DateParser::TIME_SEPARATOR, 0},
146 : {'\0', '\0', '\0', DateParser::INVALID, 0},
147 : };
148 :
149 :
150 : // We could use perfect hashing here, but this is not a bottleneck.
151 167615 : int DateParser::KeywordTable::Lookup(const uint32_t* pre, int len) {
152 : int i;
153 5732565 : for (i = 0; array[i][kTypeOffset] != INVALID; i++) {
154 : int j = 0;
155 7004265 : while (j < kPrefixLength &&
156 3224420 : pre[j] == static_cast<uint32_t>(array[i][j])) {
157 441945 : j++;
158 : }
159 : // Check if we have a match and the length is legal.
160 : // Word longer than keyword is only allowed for month names.
161 2895955 : if (j == kPrefixLength &&
162 117 : (len <= kPrefixLength || array[i][kTypeOffset] == MONTH_NAME)) {
163 : return i;
164 : }
165 : }
166 : return i;
167 : }
168 :
169 :
170 2364 : int DateParser::ReadMilliseconds(DateToken token) {
171 : // Read first three significant digits of the original numeral,
172 : // as inferred from the value and the number of digits.
173 : // I.e., use the number of digits to see if there were
174 : // leading zeros.
175 : int number = token.number();
176 : int length = token.length();
177 2364 : if (length < 3) {
178 : // Less than three digits. Multiply to put most significant digit
179 : // in hundreds position.
180 45 : if (length == 1) {
181 36 : number *= 100;
182 9 : } else if (length == 2) {
183 9 : number *= 10;
184 : }
185 2319 : } else if (length > 3) {
186 18 : if (length > kMaxSignificantDigits) length = kMaxSignificantDigits;
187 : // More than three digits. Divide by 10^(length - 3) to get three
188 : // most significant digits.
189 : int factor = 1;
190 : do {
191 : DCHECK_LE(factor, 100000000); // factor won't overflow.
192 63 : factor *= 10;
193 63 : length--;
194 63 : } while (length > 3);
195 18 : number /= factor;
196 : }
197 2364 : return number;
198 : }
199 :
200 :
201 : } // namespace internal
202 122036 : } // namespace v8
|