• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_DATE_PARSE_H
17 #define ECMASCRIPT_DATE_PARSE_H
18 
19 #include "ecmascript/js_date.h"
20 
21 namespace panda::ecmascript {
22 class DateParse {
23 public:
24     static const std::array<CString, MOUTH_PER_YEAR> MONTH_NAME;
25     static bool ParseDateString(const char *str, int length, int *time);
26 
27 private:
IsBetween(int n,int lower,int hign)28     static bool IsBetween(int n, int lower, int hign)
29     {
30         if (n < lower || n > hign) {
31             return false;
32         }
33         return true;
34     }
35     class StringReader {
36         public:
StringReader(const char * str,int length)37             explicit StringReader(const char *str, int length) : data_(str), length_(length)
38             {
39                 NextChar();
40             }
41 
NextChar()42             void NextChar()
43             {
44                 value_ = (index_ < length_) ? data_[index_] : DEL;
45                 index_++;
46             }
47 
GetIndex()48             int GetIndex() const
49             {
50                 return index_;
51             }
52 
ReadNumber(int * len)53             int ReadNumber(int *len)
54             {
55                 int index = 0;
56                 int num = 0;
57                 while (IsDigit()) {
58                     num = (value_ - '0') + num * JSDate::TEN;
59                     index++;
60                     const int maxDecimal = (std::numeric_limits<int>::max() - JSDate::NUM_NINE) / JSDate::TEN;
61                     if (num > maxDecimal) {
62                         break;
63                     }
64                     NextChar();
65                 }
66                 // read the followed digit
67                 while (IsDigit()) {
68                     NextChar();
69                 }
70                 *len = index;
71                 return num;
72             }
73 
ReadAlphabet(char * word,int size)74             int ReadAlphabet(char *word, int size)
75             {
76                 int length = 0;
77                 for (; IsAlpha(); length++) {
78                     if (length < size) {
79                         word[length] = GetLower(value_);
80                     }
81                     NextChar();
82                 }
83                 return length;
84             }
85 
GetLower(char ch)86             char GetLower(char ch)
87             {
88                 if (ch >= 'A' && ch <= 'Z') {
89                     // 32: 'a' - 'A'
90                     return ch + 32;
91                 }
92                 return ch;
93             }
94 
IsDigit()95             bool IsDigit() const
96             {
97                 if (value_ >= '0' && value_ <= '9') {
98                     return true;
99                 }
100                 return false;
101             }
102 
IsSign()103             bool IsSign() const
104             {
105                 if (value_ == '+' || value_ == '-') {
106                     return true;
107                 }
108                 return false;
109             }
110 
IsEnd()111             bool IsEnd() const
112             {
113                 return value_ == DEL;
114             }
115 
IsThisChar(char ch)116             bool IsThisChar(char ch) const
117             {
118                 return value_ == ch;
119             }
120 
IsAlpha()121             bool IsAlpha() const
122             {
123                 if (value_ >= 'A' && value_ <= 'z') {
124                     return true;
125                 }
126                 return false;
127             }
128 
IsSpaceOrTab()129             bool IsSpaceOrTab() const
130             {
131                 if (value_ == ' ' || value_ == '\t') {
132                     return true;
133                 }
134                 return false;
135             }
136 
IsChar(char ch)137             bool IsChar(char ch)
138             {
139                 if (value_ != ch) {
140                     return false;
141                 }
142                 return true;
143             }
144         private:
145             const char *data_;
146             int index_ {0};
147             int length_;
148             char value_;
149     };
150 
151     enum DateValueType : int8_t {
152         DATE_INVALID,
153         DATE_UNKNOWN,
154         DATE_NUMBER,
155         DATE_SYMBOL,
156         DATE_SPACE,
157         DATE_STRING_END,
158         DATE_TIME_ZONE,
159         DATE_TIME_FALG,
160         DATE_MONTH,
161         DATE_INVALID_WORD,
162         DATE_WORD_START = DATE_TIME_ZONE,
163     };
164 
165     class DateUnit {
166         public:
IsInvalid()167             bool IsInvalid() const
168             {
169                 return type_ == DATE_INVALID;
170             }
171 
IsUnknown()172             bool IsUnknown() const
173             {
174                 return type_ == DATE_UNKNOWN;
175             }
176 
IsNumber()177             bool IsNumber() const
178             {
179                 return type_ == DATE_NUMBER;
180             }
181 
IsSymbol()182             bool IsSymbol() const
183             {
184                 return type_ == DATE_SYMBOL;
185             }
186 
IsSymbol(char ch)187             bool IsSymbol(char ch) const
188             {
189                 return type_ == DATE_SYMBOL && static_cast<int>(ch) == value_;
190             }
191 
IsStringEnd()192             bool IsStringEnd() const
193             {
194                 return type_ == DATE_STRING_END;
195             }
196 
IsTimeZone()197             bool IsTimeZone() const
198             {
199                 return type_ == DATE_TIME_ZONE;
200             }
201 
IsTimeFlag()202             bool IsTimeFlag() const
203             {
204                 return type_ == DATE_TIME_FALG;
205             }
206 
IsInvalidWord()207             bool IsInvalidWord() const
208             {
209                 return type_ == DATE_INVALID_WORD;
210             }
211 
IsMonth()212             bool IsMonth() const
213             {
214                 return type_ == DATE_MONTH;
215             }
216 
IsWord()217             bool IsWord() const
218             {
219                 return type_ >= DATE_TIME_ZONE;
220             }
221 
IsSign()222             bool IsSign() const
223             {
224                 return type_ == DATE_SYMBOL && (value_ == '-' || value_ == '+');
225             }
226 
IsSixDecimalDigit()227             bool IsSixDecimalDigit() const
228             {
229                 // 6: 6 decimal digit
230                 return type_ == DATE_NUMBER && len_ == 6;
231             }
232 
IsFourDecimalDigit()233             bool IsFourDecimalDigit() const
234             {
235                 // 4: 4 decimal digit
236                 return type_ == DATE_NUMBER && len_ == 4;
237             }
238 
IsTwoDecimalDigit()239             bool IsTwoDecimalDigit() const
240             {
241                 // 2: 2 decimal digit
242                 return type_ == DATE_NUMBER && len_ == 2;
243             }
244 
IsWordZ()245             bool IsWordZ() const
246             {
247                 return type_ == DATE_TIME_ZONE && value_ == 0;
248             }
249 
IsSpaceOrTab()250             bool IsSpaceOrTab() const
251             {
252                 return type_ == DATE_SPACE;
253             }
254 
IsValidFinallyTime()255             bool IsValidFinallyTime()
256             {
257                 return IsStringEnd() || IsSign() || IsWordZ() || IsSpaceOrTab();
258             }
259 
Number(int value,int len)260             static DateUnit Number(int value, int len)
261             {
262                 return DateUnit(DATE_NUMBER, value, len);
263             }
264 
Symbol(char ch)265             static DateUnit Symbol(char ch)
266             {
267                 return DateUnit(DATE_SYMBOL, static_cast<int>(ch), 1);
268             }
269 
Word(DateValueType type,int value,int len)270             static DateUnit Word(DateValueType type, int value, int len)
271             {
272                 return DateUnit(type, value, len);
273             }
274 
Space()275             static DateUnit Space()
276             {
277                 return DateUnit(DATE_SPACE, 0, 1);
278             }
279 
StringEnd()280             static DateUnit StringEnd()
281             {
282                 return DateUnit(DATE_STRING_END, 0, 0);
283             }
284 
Invalid()285             static DateUnit Invalid()
286             {
287                 return DateUnit(DATE_INVALID, 0, 0);
288             }
289 
Unknown()290             static DateUnit Unknown()
291             {
292                 return DateUnit(DATE_UNKNOWN, 0, 1);
293             }
294 
GetValue()295             int GetValue() const
296             {
297                 return value_;
298             }
299 
GetSymbol()300             char GetSymbol() const
301             {
302                 return static_cast<char>(value_);
303             }
304 
GetType()305             DateValueType GetType() const
306             {
307                 return type_;
308             }
309 
GetLength()310             uint32_t GetLength() const
311             {
312                 return len_;
313             }
314         private:
DateUnit(DateValueType type,int value,int len)315             explicit DateUnit(DateValueType type, int value, int len) : type_(type), value_(value), len_(len) {}
316             DateValueType type_;
317             int value_;
318             uint32_t len_;
319     };
320 
321     class DateProxy {
322         public:
DateProxy(StringReader * str)323             explicit DateProxy(StringReader *str) : str_(str), date_(Read()) {}
GetDate()324             DateUnit GetDate() const
325             {
326                 return date_;
327             }
328 
NextDate()329             DateUnit NextDate()
330             {
331                 DateUnit cur = GetDate();
332                 date_ = Read();
333                 return cur;
334             }
335 
IgnoreSymbol(char ch)336             bool IgnoreSymbol(char ch)
337             {
338                 if (!date_.IsSymbol(ch)) {
339                     return false;
340                 }
341                 date_ = Read();
342                 return true;
343             }
344         private:
345             DateUnit Read();
346             DateValueType MatchKeyWord(const CString &str, int *value);
347 
348             StringReader *str_;
349             DateUnit date_;
350     };
351 
352     class TimeZone {
353         public:
SetSign(int sign)354             void SetSign(int sign)
355             {
356                 sign_ = sign;
357             }
358 
SetHour(int hour)359             void SetHour(int hour)
360             {
361                 hour_ = hour;
362             }
363 
SetMin(int min)364             void SetMin(int min)
365             {
366                 min_ = min;
367             }
368 
SetUTC()369             void SetUTC()
370             {
371                 sign_ = 1;
372                 hour_ = 0;
373                 min_ = 0;
374             }
375 
IsUTC()376             bool IsUTC()
377             {
378                 return (hour_ == 0 && min_ == 0);
379             }
380 
IsLocal()381             bool IsLocal() const
382             {
383                 return hour_ == INT_MAX;
384             }
385 
386             bool SetTimeZone(int *time);
387         private:
388             int sign_ {INT_MAX};
389             int hour_ {INT_MAX};
390             int min_ {INT_MAX};
391     };
392 
393     class TimeValue {
394         public:
SetData(int data)395             bool SetData(int data)
396             {
397                 if (index_ < TIME_LEN) {
398                     data_[index_] = data;
399                     index_++;
400                     return true;
401                 }
402                 return false;
403             }
404 
MinuteIsValid(int n)405             static bool MinuteIsValid(int n)
406             {
407                 // 59 : max min
408                 return IsBetween(n, 0, 59);
409             }
410 
SecondIsValid(int n)411             static bool SecondIsValid(int n)
412             {
413                 // 59 : max sec
414                 return IsBetween(n, 0, 59);
415             }
416 
HourIsValid(int n)417             static bool HourIsValid(int n)
418             {
419                 // 24: max hour
420                 return IsBetween(n, 0, 24);
421             }
422 
MilliSecondIsValid(int n)423             static bool MilliSecondIsValid(int n)
424             {
425                 // 999 : max millisecond
426                 return IsBetween(n, 0, 999);
427             }
428 
NormMilliSecond(DateUnit sec)429             static int NormMilliSecond(DateUnit sec)
430             {
431                 uint32_t len = sec.GetLength();
432                 int value = sec.GetValue();
433                 // 3: "sss" norm length
434                 if (len == 3) {
435                     return value;
436                 }
437                 // 2: ms length
438                 if (len == 2) {
439                     return value * JSDate::TEN;
440                 }
441                 if (len == 1) {
442                     return value * JSDate::HUNDRED;
443                 }
444                 int divisor = 1;
445                 // 3: "sss" norm length
446                 while (len > 3) {
447                     divisor *= JSDate::TEN;
448                     len--;
449                 }
450                 return value / divisor;
451             }
452 
GetIndex()453             int GetIndex() const
454             {
455                 return index_;
456             }
457 
IsValid(int n)458             bool IsValid(int n) const
459             {
460                 // 2: index of second
461                 return (index_ == 1 && MinuteIsValid(n)) || (index_ == 2 && SecondIsValid(n));
462             }
463 
IsValidSecond(int n)464             bool IsValidSecond(int n) const
465             {
466                 // 2: index of second
467                 return (index_ == 2 && SecondIsValid(n));
468             }
469 
470             bool SetTimeValue(int *time);
471         private:
472             static constexpr int TIME_LEN = 4;
473             int data_[TIME_LEN];
474             int index_ {0};
475     };
476 
477     class DayValue {
478         public:
SetData(int data)479             bool SetData(int data)
480             {
481                 if (index_ < DAY_LEN) {
482                     data_[index_++] = data;
483                     return true;
484                 }
485                 return false;
486             }
487 
SetIsoFlag(bool flag)488             void SetIsoFlag(bool flag)
489             {
490                 isIsoFlag_ = flag;
491             }
492 
SetMonth(int month)493             void SetMonth(int month)
494             {
495                 month_ = month;
496             }
497 
MonthIsValid(int n)498             static bool MonthIsValid(int n)
499             {
500                 return IsBetween(n, 1, MOUTH_PER_YEAR);
501             }
502 
DayIsValid(int n)503             static bool DayIsValid(int n)
504             {
505                 return IsBetween(n, 1, JSDate::MAX_DAYS_MONTH);
506             }
507 
IsIso()508             bool IsIso() const
509             {
510                 return isIsoFlag_;
511             }
512 
IsFull()513             bool IsFull() const
514             {
515                 return index_ == DAY_LEN;
516             }
517 
GetIndex()518             int GetIndex() const
519             {
520                 return index_;
521             }
522 
523             bool SetDayValue(int *time);
524         private:
525             static constexpr int DAY_LEN = 3;
526             int data_[DAY_LEN];
527             int index_ {0};
528             int month_ {INT_MAX};
529             bool isIsoFlag_ {false};
530     };
531     static bool IsIsoDateTime(DateProxy *proxy, DayValue *dayValue);
532     static bool ParseIsoDateTime(DateProxy *proxy, DayValue *dayValue, TimeValue *timeValue,
533         TimeZone *timeZone);
534     static bool ParseLegacyDates(DateProxy *proxy, DayValue *dayValue, TimeValue *timeValue,
535         TimeZone *timeZone);
536 };
537 }  // namespace panda::ecmascript
538 
539 #endif  // ECMASCRIPT_DATE_PARSE_H
540