Home | History | Annotate | Download | only in src
      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/v8.h"
      6 
      7 #include "src/dateparser.h"
      8 
      9 namespace v8 {
     10 namespace internal {
     11 
     12 bool DateParser::DayComposer::Write(FixedArray* output) {
     13   if (index_ < 1) return false;
     14   // Day and month defaults to 1.
     15   while (index_ < kSize) {
     16     comp_[index_++] = 1;
     17   }
     18 
     19   int year = 0;  // Default year is 0 (=> 2000) for KJS compatibility.
     20   int month = kNone;
     21   int day = kNone;
     22 
     23   if (named_month_ == kNone) {
     24     if (is_iso_date_ || (index_ == 3 && !IsDay(comp_[0]))) {
     25       // YMD
     26       year = comp_[0];
     27       month = comp_[1];
     28       day = comp_[2];
     29     } else {
     30       // MD(Y)
     31       month = comp_[0];
     32       day = comp_[1];
     33       if (index_ == 3) year = comp_[2];
     34     }
     35   } else {
     36     month = named_month_;
     37     if (index_ == 1) {
     38       // MD or DM
     39       day = comp_[0];
     40     } else if (!IsDay(comp_[0])) {
     41       // YMD, MYD, or YDM
     42       year = comp_[0];
     43       day = comp_[1];
     44     } else {
     45       // DMY, MDY, or DYM
     46       day = comp_[0];
     47       year = comp_[1];
     48     }
     49   }
     50 
     51   if (!is_iso_date_) {
     52     if (Between(year, 0, 49)) year += 2000;
     53     else if (Between(year, 50, 99)) year += 1900;
     54   }
     55 
     56   if (!Smi::IsValid(year) || !IsMonth(month) || !IsDay(day)) return false;
     57 
     58   output->set(YEAR, Smi::FromInt(year));
     59   output->set(MONTH, Smi::FromInt(month - 1));  // 0-based
     60   output->set(DAY, Smi::FromInt(day));
     61   return true;
     62 }
     63 
     64 
     65 bool DateParser::TimeComposer::Write(FixedArray* output) {
     66   // All time slots default to 0
     67   while (index_ < kSize) {
     68     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   if (hour_offset_ != kNone) {
     77     if (!IsHour12(hour)) return false;
     78     hour %= 12;
     79     hour += hour_offset_;
     80   }
     81 
     82   if (!IsHour(hour) || !IsMinute(minute) ||
     83       !IsSecond(second) || !IsMillisecond(millisecond)) return false;
     84 
     85   output->set(HOUR, Smi::FromInt(hour));
     86   output->set(MINUTE, Smi::FromInt(minute));
     87   output->set(SECOND, Smi::FromInt(second));
     88   output->set(MILLISECOND, Smi::FromInt(millisecond));
     89   return true;
     90 }
     91 
     92 
     93 bool DateParser::TimeZoneComposer::Write(FixedArray* output) {
     94   if (sign_ != kNone) {
     95     if (hour_ == kNone) hour_ = 0;
     96     if (minute_ == kNone) minute_ = 0;
     97     int total_seconds = sign_ * (hour_ * 3600 + minute_ * 60);
     98     if (!Smi::IsValid(total_seconds)) return false;
     99     output->set(UTC_OFFSET, Smi::FromInt(total_seconds));
    100   } else {
    101     output->set_null(UTC_OFFSET);
    102   }
    103   return true;
    104 }
    105 
    106 const int8_t DateParser::KeywordTable::
    107     array[][DateParser::KeywordTable::kEntrySize] = {
    108   {'j', 'a', 'n', DateParser::MONTH_NAME, 1},
    109   {'f', 'e', 'b', DateParser::MONTH_NAME, 2},
    110   {'m', 'a', 'r', DateParser::MONTH_NAME, 3},
    111   {'a', 'p', 'r', DateParser::MONTH_NAME, 4},
    112   {'m', 'a', 'y', DateParser::MONTH_NAME, 5},
    113   {'j', 'u', 'n', DateParser::MONTH_NAME, 6},
    114   {'j', 'u', 'l', DateParser::MONTH_NAME, 7},
    115   {'a', 'u', 'g', DateParser::MONTH_NAME, 8},
    116   {'s', 'e', 'p', DateParser::MONTH_NAME, 9},
    117   {'o', 'c', 't', DateParser::MONTH_NAME, 10},
    118   {'n', 'o', 'v', DateParser::MONTH_NAME, 11},
    119   {'d', 'e', 'c', DateParser::MONTH_NAME, 12},
    120   {'a', 'm', '\0', DateParser::AM_PM, 0},
    121   {'p', 'm', '\0', DateParser::AM_PM, 12},
    122   {'u', 't', '\0', DateParser::TIME_ZONE_NAME, 0},
    123   {'u', 't', 'c', DateParser::TIME_ZONE_NAME, 0},
    124   {'z', '\0', '\0', DateParser::TIME_ZONE_NAME, 0},
    125   {'g', 'm', 't', DateParser::TIME_ZONE_NAME, 0},
    126   {'c', 'd', 't', DateParser::TIME_ZONE_NAME, -5},
    127   {'c', 's', 't', DateParser::TIME_ZONE_NAME, -6},
    128   {'e', 'd', 't', DateParser::TIME_ZONE_NAME, -4},
    129   {'e', 's', 't', DateParser::TIME_ZONE_NAME, -5},
    130   {'m', 'd', 't', DateParser::TIME_ZONE_NAME, -6},
    131   {'m', 's', 't', DateParser::TIME_ZONE_NAME, -7},
    132   {'p', 'd', 't', DateParser::TIME_ZONE_NAME, -7},
    133   {'p', 's', 't', DateParser::TIME_ZONE_NAME, -8},
    134   {'t', '\0', '\0', DateParser::TIME_SEPARATOR, 0},
    135   {'\0', '\0', '\0', DateParser::INVALID, 0},
    136 };
    137 
    138 
    139 // We could use perfect hashing here, but this is not a bottleneck.
    140 int DateParser::KeywordTable::Lookup(const uint32_t* pre, int len) {
    141   int i;
    142   for (i = 0; array[i][kTypeOffset] != INVALID; i++) {
    143     int j = 0;
    144     while (j < kPrefixLength &&
    145            pre[j] == static_cast<uint32_t>(array[i][j])) {
    146       j++;
    147     }
    148     // Check if we have a match and the length is legal.
    149     // Word longer than keyword is only allowed for month names.
    150     if (j == kPrefixLength &&
    151         (len <= kPrefixLength || array[i][kTypeOffset] == MONTH_NAME)) {
    152       return i;
    153     }
    154   }
    155   return i;
    156 }
    157 
    158 
    159 int DateParser::ReadMilliseconds(DateToken token) {
    160   // Read first three significant digits of the original numeral,
    161   // as inferred from the value and the number of digits.
    162   // I.e., use the number of digits to see if there were
    163   // leading zeros.
    164   int number = token.number();
    165   int length = token.length();
    166   if (length < 3) {
    167     // Less than three digits. Multiply to put most significant digit
    168     // in hundreds position.
    169     if (length == 1) {
    170       number *= 100;
    171     } else if (length == 2) {
    172       number *= 10;
    173     }
    174   } else if (length > 3) {
    175     if (length > kMaxSignificantDigits) length = kMaxSignificantDigits;
    176     // More than three digits. Divide by 10^(length - 3) to get three
    177     // most significant digits.
    178     int factor = 1;
    179     do {
    180       DCHECK(factor <= 100000000);  // factor won't overflow.
    181       factor *= 10;
    182       length--;
    183     } while (length > 3);
    184     number /= factor;
    185   }
    186   return number;
    187 }
    188 
    189 
    190 } }  // namespace v8::internal
    191