summaryrefslogtreecommitdiff
path: root/AK/DateTimeLexer.h
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2021-07-11 21:00:04 +0300
committerLinus Groh <mail@linusgroh.de>2021-07-12 19:05:17 +0100
commit141c46feda1c91f3b50948749463ecf7c380aa1a (patch)
treee2d379aa146d9fef5c6b2432e99923f7cc040b15 /AK/DateTimeLexer.h
parent39a9cf4bb49751b49c63fa8b1c65555afc73d0e7 (diff)
downloadserenity-141c46feda1c91f3b50948749463ecf7c380aa1a.zip
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)
Diffstat (limited to 'AK/DateTimeLexer.h')
-rw-r--r--AK/DateTimeLexer.h146
1 files changed, 146 insertions, 0 deletions
diff --git a/AK/DateTimeLexer.h b/AK/DateTimeLexer.h
new file mode 100644
index 0000000000..51de0c4266
--- /dev/null
+++ b/AK/DateTimeLexer.h
@@ -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;