AK: Add a DateTimeLexer

This is an AK::GenericLexer that exposes helper methods for parsing
date and time related literals (years, months, days, hours, minutes,
seconds, fractional seconds & more)
This commit is contained in:
Idan Horowitz 2021-07-11 21:00:04 +03:00 committed by Linus Groh
parent 39a9cf4bb4
commit 141c46feda
3 changed files with 146 additions and 38 deletions

146
AK/DateTimeLexer.h Normal file
View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/CharacterTypes.h>
#include <AK/GenericLexer.h>
#include <AK/Optional.h>
namespace AK {
class DateTimeLexer : public GenericLexer {
public:
constexpr explicit DateTimeLexer(const StringView& input)
: GenericLexer(input)
{
}
Optional<StringView> consume_year()
{
if (tell_remaining() < 4)
return {};
for (auto i = 0; i < 4; ++i) {
if (!is_ascii_digit(peek(i)))
return {};
}
return consume(4);
}
Optional<StringView> consume_month()
{
if (tell_remaining() < 2)
return {};
auto tens = peek();
if (tens != '0' && tens != '1')
return {};
auto ones = peek(1);
if (!is_ascii_digit(ones))
return {};
if (tens == '0') { // 01, 02, 03, 04, 05, 06, 07, 08, 09
if (ones == '0')
return {};
} else if (ones > '2') { // 10, 11, 12
return {};
}
return consume(2);
}
Optional<StringView> consume_day()
{
if (tell_remaining() < 2)
return {};
auto tens = peek();
if (tens < '0' || tens > '3')
return {};
auto ones = peek(1);
if (!is_ascii_digit(ones))
return {};
if (tens == '0') { // 01, 02, 03, 04, 05, 06, 07, 08, 09
if (ones == '0')
return {};
} else if (tens == '3') { // 30, 31
if (ones != '0' && ones != '1')
return {};
} else if (!is_ascii_digit(ones)) { // 10 - 29
return {};
}
return consume(2);
}
Optional<StringView> consume_sign()
{
if (!tell_remaining())
return {};
if (next_is("\xE2\x88\x92"sv))
return consume(3);
else if (next_is('-') || next_is('+'))
return consume(1);
else
return {};
};
Optional<StringView> consume_hours()
{
if (tell_remaining() < 2)
return {};
char tens = peek();
if (tens != '0' && tens != '1' && tens != '2')
return {};
char ones = peek(1);
if (!is_ascii_digit(ones) || (tens == '2' && ones > '3'))
return {};
return consume(2);
}
Optional<StringView> consume_minutes_or_seconds()
{
if (tell_remaining() < 2)
return {};
char tens = peek();
if (tens < '0' || tens > '5')
return {};
if (!is_ascii_digit(peek(1)))
return {};
return consume(2);
}
Optional<StringView> consume_fractional_seconds()
{
if (!tell_remaining())
return {};
auto length = min(tell_remaining(), 9);
for (size_t i = 0; i < length; ++i) {
if (is_ascii_digit(peek(i)))
continue;
length = i;
break;
}
return consume(length);
}
};
}
using AK::DateTimeLexer;

View file

@ -1,21 +0,0 @@
/*
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/String.h>
#include <LibJS/Runtime/Temporal/ISO8601.h>
namespace JS::Temporal {
// 13.33 ISO 8601 grammar, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar
// TimeZoneNumericUTCOffset, https://tc39.es/proposal-temporal/#prod-TimeZoneNumericUTCOffset
bool is_valid_time_zone_numeric_utc_offset(String const&)
{
// TODO: Implement me :^)
return false;
}
}

View file

@ -1,17 +0,0 @@
/*
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Forward.h>
namespace JS::Temporal {
// 13.33 ISO 8601 grammar, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar
bool is_valid_time_zone_numeric_utc_offset(String const&);
}