summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Runtime/Temporal/ISO8601.h
blob: 5b631bac3dcfc1af33ec65e13735e231c20e865f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/*
 * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/GenericLexer.h>
#include <AK/Optional.h>
#include <AK/StringView.h>
#include <AK/Vector.h>

namespace JS::Temporal {

struct ParseResult {
    Optional<StringView> sign;
    Optional<StringView> date_year;
    Optional<StringView> date_month;
    Optional<StringView> date_day;
    Optional<StringView> time_hour;
    Optional<StringView> time_minute;
    Optional<StringView> time_second;
    Optional<StringView> time_fraction;
    Optional<StringView> time_hour_not_valid_month;
    Optional<StringView> time_hour_not_thirty_one_day_month;
    Optional<StringView> time_hour_two_only;
    Optional<StringView> time_minute_not_valid_day;
    Optional<StringView> time_minute_thirty_only;
    Optional<StringView> time_minute_thirty_one_only;
    Optional<StringView> time_second_not_valid_month;
    Optional<StringView> calendar_name;
    Optional<StringView> utc_designator;
    Optional<StringView> time_zone_numeric_utc_offset;
    Optional<StringView> time_zone_utc_offset_sign;
    Optional<StringView> time_zone_utc_offset_hour;
    Optional<StringView> time_zone_utc_offset_minute;
    Optional<StringView> time_zone_utc_offset_second;
    Optional<StringView> time_zone_utc_offset_fractional_part;
    Optional<StringView> time_zone_iana_name;
    Optional<StringView> duration_years;
    Optional<StringView> duration_months;
    Optional<StringView> duration_weeks;
    Optional<StringView> duration_days;
    Optional<StringView> duration_whole_hours;
    Optional<StringView> duration_hours_fraction;
    Optional<StringView> duration_whole_minutes;
    Optional<StringView> duration_minutes_fraction;
    Optional<StringView> duration_whole_seconds;
    Optional<StringView> duration_seconds_fraction;
};

enum class Production {
    TemporalInstantString,
    TemporalDateString,
    TemporalDateTimeString,
    TemporalDurationString,
    TemporalMonthDayString,
    TemporalTimeString,
    TemporalTimeZoneString,
    TemporalYearMonthString,
    TemporalZonedDateTimeString,
    TemporalCalendarString,
    TemporalRelativeToString,
};

Optional<ParseResult> parse_iso8601(Production, StringView);

namespace Detail {

// 13.33 ISO 8601 grammar, https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar
class ISO8601Parser {
public:
    explicit ISO8601Parser(StringView input)
        : m_input(input)
        , m_state({
              .lexer = GenericLexer { input },
              .parse_result = {},
          })
    {
    }

    [[nodiscard]] GenericLexer const& lexer() const { return m_state.lexer; }
    [[nodiscard]] ParseResult const& parse_result() const { return m_state.parse_result; }

    [[nodiscard]] bool parse_decimal_digits();
    [[nodiscard]] bool parse_decimal_digit();
    [[nodiscard]] bool parse_non_zero_digit();
    [[nodiscard]] bool parse_ascii_sign();
    [[nodiscard]] bool parse_sign();
    [[nodiscard]] bool parse_hour();
    [[nodiscard]] bool parse_minute_second();
    [[nodiscard]] bool parse_decimal_separator();
    [[nodiscard]] bool parse_days_designator();
    [[nodiscard]] bool parse_hours_designator();
    [[nodiscard]] bool parse_minutes_designator();
    [[nodiscard]] bool parse_months_designator();
    [[nodiscard]] bool parse_duration_designator();
    [[nodiscard]] bool parse_seconds_designator();
    [[nodiscard]] bool parse_date_time_separator();
    [[nodiscard]] bool parse_time_designator();
    [[nodiscard]] bool parse_weeks_designator();
    [[nodiscard]] bool parse_years_designator();
    [[nodiscard]] bool parse_utc_designator();
    [[nodiscard]] bool parse_date_year();
    [[nodiscard]] bool parse_date_month();
    [[nodiscard]] bool parse_date_day();
    [[nodiscard]] bool parse_date_spec_year_month();
    [[nodiscard]] bool parse_date_spec_month_day();
    [[nodiscard]] bool parse_date();
    [[nodiscard]] bool parse_time_hour();
    [[nodiscard]] bool parse_time_minute();
    [[nodiscard]] bool parse_time_second();
    [[nodiscard]] bool parse_time_hour_not_valid_month();
    [[nodiscard]] bool parse_time_hour_not_thirty_one_day_month();
    [[nodiscard]] bool parse_time_hour_two_only();
    [[nodiscard]] bool parse_time_minute_not_valid_day();
    [[nodiscard]] bool parse_time_minute_thirty_only();
    [[nodiscard]] bool parse_time_minute_thirty_one_only();
    [[nodiscard]] bool parse_time_second_not_valid_month();
    [[nodiscard]] bool parse_fractional_part();
    [[nodiscard]] bool parse_fraction();
    [[nodiscard]] bool parse_time_fraction();
    [[nodiscard]] bool parse_time_zone_utc_offset_sign();
    [[nodiscard]] bool parse_time_zone_utc_offset_hour();
    [[nodiscard]] bool parse_time_zone_utc_offset_minute();
    [[nodiscard]] bool parse_time_zone_utc_offset_second();
    [[nodiscard]] bool parse_time_zone_utc_offset_fractional_part();
    [[nodiscard]] bool parse_time_zone_utc_offset_fraction();
    [[nodiscard]] bool parse_time_zone_numeric_utc_offset();
    [[nodiscard]] bool parse_time_zone_utc_offset();
    [[nodiscard]] bool parse_time_zone_numeric_utc_offset_not_ambiguous();
    [[nodiscard]] bool parse_time_zone_numeric_utc_offset_not_ambiguous_allowed_negative_hour();
    [[nodiscard]] bool parse_time_zone_utc_offset_name();
    [[nodiscard]] bool parse_tz_leading_char();
    [[nodiscard]] bool parse_tz_char();
    [[nodiscard]] bool parse_time_zone_iana_component();
    [[nodiscard]] bool parse_time_zone_iana_name_tail();
    [[nodiscard]] bool parse_time_zone_iana_name();
    [[nodiscard]] bool parse_time_zone_bracketed_name();
    [[nodiscard]] bool parse_time_zone_bracketed_annotation();
    [[nodiscard]] bool parse_time_zone_offset_required();
    [[nodiscard]] bool parse_time_zone_name_required();
    [[nodiscard]] bool parse_time_zone();
    [[nodiscard]] bool parse_calendar_name();
    [[nodiscard]] bool parse_calendar();
    [[nodiscard]] bool parse_time_spec();
    [[nodiscard]] bool parse_time_hour_minute_basic_format_not_ambiguous();
    [[nodiscard]] bool parse_time_spec_with_optional_time_zone_not_ambiguous();
    [[nodiscard]] bool parse_time_spec_separator();
    [[nodiscard]] bool parse_date_time();
    [[nodiscard]] bool parse_calendar_time();
    [[nodiscard]] bool parse_calendar_date_time();
    [[nodiscard]] bool parse_calendar_date_time_time_required();
    [[nodiscard]] bool parse_duration_whole_seconds();
    [[nodiscard]] bool parse_duration_seconds_fraction();
    [[nodiscard]] bool parse_duration_seconds_part();
    [[nodiscard]] bool parse_duration_whole_minutes();
    [[nodiscard]] bool parse_duration_minutes_fraction();
    [[nodiscard]] bool parse_duration_minutes_part();
    [[nodiscard]] bool parse_duration_whole_hours();
    [[nodiscard]] bool parse_duration_hours_fraction();
    [[nodiscard]] bool parse_duration_hours_part();
    [[nodiscard]] bool parse_duration_time();
    [[nodiscard]] bool parse_duration_days();
    [[nodiscard]] bool parse_duration_days_part();
    [[nodiscard]] bool parse_duration_weeks();
    [[nodiscard]] bool parse_duration_weeks_part();
    [[nodiscard]] bool parse_duration_months();
    [[nodiscard]] bool parse_duration_months_part();
    [[nodiscard]] bool parse_duration_years();
    [[nodiscard]] bool parse_duration_years_part();
    [[nodiscard]] bool parse_duration_date();
    [[nodiscard]] bool parse_duration();
    [[nodiscard]] bool parse_temporal_instant_string();
    [[nodiscard]] bool parse_temporal_date_string();
    [[nodiscard]] bool parse_temporal_date_time_string();
    [[nodiscard]] bool parse_temporal_duration_string();
    [[nodiscard]] bool parse_temporal_month_day_string();
    [[nodiscard]] bool parse_temporal_time_string();
    [[nodiscard]] bool parse_temporal_time_zone_identifier();
    [[nodiscard]] bool parse_temporal_time_zone_string();
    [[nodiscard]] bool parse_temporal_year_month_string();
    [[nodiscard]] bool parse_temporal_zoned_date_time_string();
    [[nodiscard]] bool parse_temporal_calendar_string();
    [[nodiscard]] bool parse_temporal_relative_to_string();

private:
    struct State {
        GenericLexer lexer;
        ParseResult parse_result;
    };

    struct StateTransaction {
        explicit StateTransaction(ISO8601Parser& parser)
            : m_parser(parser)
            , m_saved_state(parser.m_state)
            , m_start_index(parser.m_state.lexer.tell())
        {
        }

        ~StateTransaction()
        {
            if (!m_commit)
                m_parser.m_state = move(m_saved_state);
        }

        void commit() { m_commit = true; }
        StringView parsed_string_view() const
        {
            return m_parser.m_input.substring_view(m_start_index, m_parser.m_state.lexer.tell() - m_start_index);
        }

    private:
        ISO8601Parser& m_parser;
        State m_saved_state;
        size_t m_start_index { 0 };
        bool m_commit { false };
    };

    StringView m_input;
    State m_state;
};

}

}