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