@@ -71,18 +71,71 @@ pub(crate) fn parse_annotated_date_time<'a, T: EncodingType>(
71
71
} )
72
72
}
73
73
74
- /// Parses an AnnotatedMonthDay.
75
- pub ( crate ) fn parse_annotated_month_day < ' a , T : EncodingType > (
74
+ /// Parses a `DateTime` record.
75
+ fn parse_date_time < T : EncodingType > ( cursor : & mut Cursor < T > ) -> ParserResult < DateTimeRecord > {
76
+ let date = parse_date ( cursor) ?;
77
+
78
+ // If there is no `DateTimeSeparator`, return date early.
79
+ if !cursor. check_or ( false , is_date_time_separator) ? {
80
+ return Ok ( DateTimeRecord {
81
+ date : Some ( date) ,
82
+ time : None ,
83
+ time_zone : None ,
84
+ } ) ;
85
+ }
86
+
87
+ cursor. advance ( ) ;
88
+
89
+ let time = parse_time_record ( cursor) ?;
90
+
91
+ let time_zone = if cursor. check_or ( false , |ch| is_ascii_sign ( ch) || is_utc_designator ( ch) ) ? {
92
+ Some ( timezone:: parse_date_time_utc_offset ( cursor) ?)
93
+ } else {
94
+ None
95
+ } ;
96
+
97
+ Ok ( DateTimeRecord {
98
+ date : Some ( date) ,
99
+ time : Some ( time) ,
100
+ time_zone,
101
+ } )
102
+ }
103
+
104
+ /// Parses `Date` record.
105
+ fn parse_date < T : EncodingType > ( cursor : & mut Cursor < T > ) -> ParserResult < DateRecord > {
106
+ let year = parse_date_year ( cursor) ?;
107
+ let hyphenated = cursor
108
+ . check ( is_hyphen) ?
109
+ . ok_or ( ParseError :: abrupt_end ( "Date" ) ) ?;
110
+
111
+ cursor. advance_if ( hyphenated) ;
112
+
113
+ let month = parse_date_month ( cursor) ?;
114
+
115
+ let second_hyphen = cursor. check_or ( false , is_hyphen) ?;
116
+ assert_syntax ! ( hyphenated == second_hyphen, DateSeparator ) ;
117
+ cursor. advance_if ( second_hyphen) ;
118
+
119
+ let day = parse_date_day ( cursor) ?;
120
+
121
+ check_date_validity ( year, month, day) ?;
122
+
123
+ Ok ( DateRecord { year, month, day } )
124
+ }
125
+
126
+ // ==== `YearMonth` parsing functions ====
127
+
128
+ /// Parse an annotated YearMonth
129
+ pub ( crate ) fn parse_annotated_year_month < ' a , T : EncodingType > (
76
130
cursor : & mut Cursor < ' a , T > ,
77
131
handler : impl FnMut ( Annotation < ' a , T > ) -> Option < Annotation < ' a , T > > ,
78
132
) -> ParserResult < IxdtfParseRecord < ' a , T > > {
79
- let date = parse_month_day ( cursor) ?;
80
-
133
+ let year_month = parse_year_month ( cursor) ?;
81
134
if !cursor. check_or ( false , is_annotation_open) ? {
82
135
cursor. close ( ) ?;
83
136
84
137
return Ok ( IxdtfParseRecord {
85
- date : Some ( date ) ,
138
+ date : Some ( year_month ) ,
86
139
time : None ,
87
140
offset : None ,
88
141
tz : None ,
@@ -93,28 +146,36 @@ pub(crate) fn parse_annotated_month_day<'a, T: EncodingType>(
93
146
let annotation_set = annotations:: parse_annotation_set ( cursor, handler) ?;
94
147
95
148
Ok ( IxdtfParseRecord {
96
- date : Some ( date ) ,
149
+ date : Some ( year_month ) ,
97
150
time : None ,
98
151
offset : None ,
99
152
tz : annotation_set. tz ,
100
153
calendar : annotation_set. calendar ,
101
154
} )
102
155
}
103
156
104
- /// Parse an annotated YearMonth
105
- pub ( crate ) fn parse_annotated_year_month < ' a , T : EncodingType > (
106
- cursor : & mut Cursor < ' a , T > ,
107
- handler : impl FnMut ( Annotation < ' a , T > ) -> Option < Annotation < ' a , T > > ,
108
- ) -> ParserResult < IxdtfParseRecord < ' a , T > > {
157
+ pub ( crate ) fn parse_year_month < T : EncodingType > (
158
+ cursor : & mut Cursor < T > ,
159
+ ) -> ParserResult < DateRecord > {
109
160
let year = parse_date_year ( cursor) ?;
110
161
cursor. advance_if ( cursor. check_or ( false , is_hyphen) ?) ;
111
162
let month = parse_date_month ( cursor) ?;
112
163
113
- let date = DateRecord {
164
+ Ok ( DateRecord {
114
165
year,
115
166
month,
116
167
day : 1 ,
117
- } ;
168
+ } )
169
+ }
170
+
171
+ // ==== `MonthDay` parsing functions ====
172
+
173
+ /// Parses an AnnotatedMonthDay.
174
+ pub ( crate ) fn parse_annotated_month_day < ' a , T : EncodingType > (
175
+ cursor : & mut Cursor < ' a , T > ,
176
+ handler : impl FnMut ( Annotation < ' a , T > ) -> Option < Annotation < ' a , T > > ,
177
+ ) -> ParserResult < IxdtfParseRecord < ' a , T > > {
178
+ let date = parse_month_day ( cursor) ?;
118
179
119
180
if !cursor. check_or ( false , is_annotation_open) ? {
120
181
cursor. close ( ) ?;
@@ -139,60 +200,6 @@ pub(crate) fn parse_annotated_year_month<'a, T: EncodingType>(
139
200
} )
140
201
}
141
202
142
- /// Parses a `DateTime` record.
143
- fn parse_date_time < T : EncodingType > ( cursor : & mut Cursor < T > ) -> ParserResult < DateTimeRecord > {
144
- let date = parse_date ( cursor) ?;
145
-
146
- // If there is no `DateTimeSeparator`, return date early.
147
- if !cursor. check_or ( false , is_date_time_separator) ? {
148
- return Ok ( DateTimeRecord {
149
- date : Some ( date) ,
150
- time : None ,
151
- time_zone : None ,
152
- } ) ;
153
- }
154
-
155
- cursor. advance ( ) ;
156
-
157
- let time = parse_time_record ( cursor) ?;
158
-
159
- let time_zone = if cursor. check_or ( false , |ch| is_ascii_sign ( ch) || is_utc_designator ( ch) ) ? {
160
- Some ( timezone:: parse_date_time_utc_offset ( cursor) ?)
161
- } else {
162
- None
163
- } ;
164
-
165
- Ok ( DateTimeRecord {
166
- date : Some ( date) ,
167
- time : Some ( time) ,
168
- time_zone,
169
- } )
170
- }
171
-
172
- /// Parses `Date` record.
173
- fn parse_date < T : EncodingType > ( cursor : & mut Cursor < T > ) -> ParserResult < DateRecord > {
174
- let year = parse_date_year ( cursor) ?;
175
- let hyphenated = cursor
176
- . check ( is_hyphen) ?
177
- . ok_or ( ParseError :: abrupt_end ( "Date" ) ) ?;
178
-
179
- cursor. advance_if ( hyphenated) ;
180
-
181
- let month = parse_date_month ( cursor) ?;
182
-
183
- let second_hyphen = cursor. check_or ( false , is_hyphen) ?;
184
- assert_syntax ! ( hyphenated == second_hyphen, DateSeparator ) ;
185
- cursor. advance_if ( second_hyphen) ;
186
-
187
- let day = parse_date_day ( cursor) ?;
188
-
189
- check_date_validity ( year, month, day) ?;
190
-
191
- Ok ( DateRecord { year, month, day } )
192
- }
193
-
194
- // ==== `MonthDay` parsing functions ====
195
-
196
203
/// Parses a `DateSpecMonthDay`
197
204
pub ( crate ) fn parse_month_day < T : EncodingType > ( cursor : & mut Cursor < T > ) -> ParserResult < DateRecord > {
198
205
let hyphenated = cursor
@@ -215,7 +222,9 @@ pub(crate) fn parse_month_day<T: EncodingType>(cursor: &mut Cursor<T>) -> Parser
215
222
216
223
let day = parse_date_day ( cursor) ?;
217
224
218
- assert_syntax ! ( cursor. check_or( true , is_annotation_open) ?, InvalidEnd ) ;
225
+ if !is_valid_month_day ( day, month) {
226
+ return Err ( ParseError :: InvalidMonthDay ) ;
227
+ }
219
228
220
229
Ok ( DateRecord {
221
230
year : 0 ,
@@ -224,6 +233,14 @@ pub(crate) fn parse_month_day<T: EncodingType>(cursor: &mut Cursor<T>) -> Parser
224
233
} )
225
234
}
226
235
236
+ fn is_valid_month_day ( month : u8 , day : u8 ) -> bool {
237
+ match month {
238
+ 2 | 4 | 6 | 9 | 11 if day >= 31 => false ,
239
+ 2 if day == 30 => false ,
240
+ _ => day <= 31 ,
241
+ }
242
+ }
243
+
227
244
// ==== Unit Parsers ====
228
245
229
246
#[ inline]
0 commit comments