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