1use crate::{
8 ast::*,
9 error::{Error, ErrorKind},
10 pos::Span,
11 scanner::{ScalarStyle, Scanner, Token, TokenKind},
12};
13use oxc_allocator::{Allocator, Box, Vec};
14
15type ParseResult<T> = Result<T, Error>;
16
17pub struct Parser<'a> {
18 allocator: &'a Allocator,
19 source: &'a str,
20 scanner: Scanner<'a>,
21 peeked: Option<Token>,
22}
23
24impl<'a> Parser<'a> {
25 pub fn new(allocator: &'a Allocator, source: &'a str) -> Self {
26 Self { allocator, source, scanner: Scanner::new(allocator, source), peeked: None }
27 }
28
29 #[expect(clippy::cast_possible_truncation)] pub fn parse(mut self) -> ParseResult<Root<'a>> {
35 if u32::try_from(self.source.len()).is_err() {
36 return Err(Error::new(ErrorKind::SourceTooLong, Span::empty(0)));
37 }
38 let source_len = self.source.len() as u32;
39
40 let first = self.next()?;
41 debug_assert!(first.kind == TokenKind::StreamStart);
42
43 let mut children = Vec::new_in(&self.allocator);
44 loop {
45 if self.peek()?.kind == TokenKind::StreamEnd {
46 break;
47 }
48 children.push(self.parse_document()?);
49 }
50
51 let comments = std::mem::replace(&mut self.scanner.comments, Vec::new_in(&self.allocator));
53
54 Ok(Root { span: Span::new(0, source_len), children, comments })
55 }
56
57 fn next(&mut self) -> ParseResult<Token> {
60 if let Some(t) = self.peeked.take() {
61 return Ok(t);
62 }
63 self.scanner.next_token()?.ok_or_else(|| {
64 Error::point(ErrorKind::UnexpectedEof, self.source.len().saturating_sub(1))
65 })
66 }
67
68 fn peek(&mut self) -> ParseResult<&Token> {
69 if self.peeked.is_none() {
70 self.peeked = Some(self.next()?);
71 }
72 Ok(self.peeked.as_ref().unwrap())
73 }
74
75 fn peek_kind(&mut self) -> ParseResult<TokenKind> {
76 Ok(self.peek()?.kind)
77 }
78
79 fn eat(&mut self, kind: TokenKind) -> ParseResult<Option<Token>> {
80 if self.peek()?.kind == kind {
81 return Ok(Some(self.next()?));
82 }
83 Ok(None)
84 }
85
86 fn alloc<T>(&self, value: T) -> Box<'a, T> {
87 Box::new_in(value, &self.allocator)
88 }
89
90 fn parse_optional_node(&mut self, allow_indentless: bool) -> ParseResult<Option<Content<'a>>> {
94 let kind = self.peek_kind()?;
95 let starts =
96 if allow_indentless { kind.starts_mapping_entry_node() } else { kind.starts_node() };
97 if starts { Ok(Some(self.parse_node(allow_indentless)?)) } else { Ok(None) }
98 }
99
100 fn parse_document(&mut self) -> ParseResult<Document<'a>> {
103 let head_start = self.peek()?.span.start;
104 let mut directives = Vec::new_in(&self.allocator);
105 while self.peek_kind()? == TokenKind::Directive {
106 let token = self.next()?;
107 directives.push(self.build_directive(token));
108 }
109 let head_end = directives.last().map_or(head_start, |d: &Directive<'a>| d.span.end);
110
111 let directives_end_marker = self.eat(TokenKind::DocumentStart)?.map(|t| t.span);
112 if !directives.is_empty() && directives_end_marker.is_none() {
113 return Err(Error::new(
114 ErrorKind::ExpectedDocumentStart,
115 Span::new(head_start, head_end),
116 ));
117 }
118
119 let head = DocumentHead {
120 span: Span::new(head_start, directives_end_marker.map_or(head_end, |s| s.end)),
121 directives,
122 };
123
124 let content = self.parse_optional_node(false)?;
125
126 let body_span = content.as_ref().map_or_else(
127 || Span::empty(directives_end_marker.map_or(head_start, |s| s.end)),
128 Content::span,
129 );
130 let body = DocumentBody { span: body_span, content };
131
132 let document_end_marker = self.eat(TokenKind::DocumentEnd)?.map(|t| t.span);
133 if document_end_marker.is_none() {
137 match self.peek_kind()? {
138 TokenKind::StreamEnd | TokenKind::DocumentStart | TokenKind::Directive => {}
139 _ => {
140 let span = self.peek()?.span;
141 return Err(Error::new(ErrorKind::ExpectedDocumentEnd, span));
142 }
143 }
144 }
145
146 let span_end = document_end_marker.map_or(body.span.end.max(head.span.end), |s| s.end);
149
150 Ok(Document {
151 span: Span::new(head_start, span_end),
152 head,
153 body,
154 directives_end_marker,
155 document_end_marker,
156 })
157 }
158
159 fn build_directive(&self, token: Token) -> Directive<'a> {
160 let text = token.span.slice(self.source);
161 let mut words = text.trim_start_matches('%').split_ascii_whitespace();
162 let name = words.next().unwrap_or("");
163 let parameters = Vec::from_iter_in(words, &self.allocator);
164 Directive { span: token.span, name, parameters }
165 }
166
167 fn parse_props(&mut self) -> ParseResult<Props> {
170 let mut props = Props { anchor: None, tag: None };
171 loop {
172 match self.peek_kind()? {
173 TokenKind::Anchor => {
174 let token = self.next()?;
175 if props.anchor.is_some() {
176 return Err(Error::new(ErrorKind::DuplicatedNodeProperty, token.span));
177 }
178 props.anchor = Some(Anchor { span: token.span });
179 }
180 TokenKind::Tag => {
181 let token = self.next()?;
182 if props.tag.is_some() {
183 return Err(Error::new(ErrorKind::DuplicatedNodeProperty, token.span));
184 }
185 props.tag = Some(Tag { span: token.span });
186 }
187 _ => break,
188 }
189 }
190 Ok(props)
191 }
192
193 fn parse_node(&mut self, allow_indentless: bool) -> ParseResult<Content<'a>> {
198 let props = self.parse_props()?;
199
200 let token = *self.peek()?;
201 match token.kind {
202 TokenKind::Alias => {
203 self.next()?;
204 if props.anchor.is_some() || props.tag.is_some() {
205 return Err(Error::new(ErrorKind::DuplicatedNodeProperty, token.span));
206 }
207 Ok(Content::Alias(self.alloc(Alias { span: token.span, props })))
208 }
209 TokenKind::Scalar(style, header_index) => {
210 self.next()?;
211 Ok(self.build_scalar(props, style, header_index, token.span))
212 }
213 TokenKind::FlowSequenceStart => self.parse_flow_sequence(props),
214 TokenKind::FlowMappingStart => self.parse_flow_mapping(props),
215 TokenKind::BlockSequenceStart => self.parse_block_sequence(props),
216 TokenKind::BlockMappingStart => self.parse_block_mapping(props),
217 TokenKind::BlockEntry if allow_indentless => self.parse_indentless_sequence(props),
222 _ => {
223 if props.anchor.is_some() || props.tag.is_some() {
226 let at = props
227 .anchor
228 .map(|a| a.span.end)
229 .max(props.tag.map(|t| t.span.end))
230 .unwrap();
231 return Ok(Content::Plain(self.alloc(Plain { span: Span::empty(at), props })));
232 }
233 Err(Error::new(ErrorKind::ExpectedNode, token.span))
234 }
235 }
236 }
237
238 fn build_scalar(
239 &self,
240 props: Props,
241 style: ScalarStyle,
242 header_index: Option<crate::scanner::BlockHeaderIndex>,
243 span: Span,
244 ) -> Content<'a> {
245 match style {
246 ScalarStyle::Plain => Content::Plain(self.alloc(Plain { span, props })),
247 ScalarStyle::SingleQuoted => {
248 Content::QuoteSingle(self.alloc(QuoteSingle { span, props }))
249 }
250 ScalarStyle::DoubleQuoted => {
251 Content::QuoteDouble(self.alloc(QuoteDouble { span, props }))
252 }
253 ScalarStyle::Literal | ScalarStyle::Folded => {
254 let index = header_index.expect("block scalar token must carry a header index");
255 let header = self.scanner.block_headers[index.get()];
256 let node = BlockScalar {
257 span,
258 props,
259 chomping: header.chomping,
260 indent: header.indent,
261 content_start: header.content_start,
262 };
263 if style == ScalarStyle::Literal {
264 Content::BlockLiteral(self.alloc(node))
265 } else {
266 Content::BlockFolded(self.alloc(node))
267 }
268 }
269 }
270 }
271
272 fn parse_sequence_item(&mut self) -> ParseResult<SequenceItem<'a>> {
274 let entry_token = self.next()?;
275 debug_assert!(entry_token.kind == TokenKind::BlockEntry);
276 let content = self.parse_optional_node(false)?;
277 let end = content.as_ref().map_or(entry_token.span.end, |c| c.span().end);
278 Ok(SequenceItem { span: Span::new(entry_token.span.start, end), content })
279 }
280
281 fn parse_block_sequence(&mut self, props: Props) -> ParseResult<Content<'a>> {
282 let start_token = self.next()?; let mut children = Vec::new_in(&self.allocator);
284
285 loop {
286 match self.peek_kind()? {
287 TokenKind::BlockEnd => {
288 self.next()?;
289 break;
290 }
291 TokenKind::BlockEntry => children.push(self.parse_sequence_item()?),
292 _ => {
293 let span = self.peek()?.span;
294 return Err(Error::new(ErrorKind::UnexpectedToken("token in sequence"), span));
295 }
296 }
297 }
298
299 let span = container_span(start_token.span, children.first(), children.last());
300 Ok(Content::Sequence(self.alloc(Sequence { span, props, children })))
301 }
302
303 fn parse_indentless_sequence(&mut self, props: Props) -> ParseResult<Content<'a>> {
308 let mut children = Vec::new_in(&self.allocator);
309 let first = self.peek()?.span;
310
311 while self.peek_kind()? == TokenKind::BlockEntry {
312 children.push(self.parse_sequence_item()?);
313 }
314
315 let span = container_span(Span::empty(first.start), children.first(), children.last());
316 Ok(Content::Sequence(self.alloc(Sequence { span, props, children })))
317 }
318
319 fn parse_block_mapping(&mut self, props: Props) -> ParseResult<Content<'a>> {
320 let start_token = self.next()?; let mut children = Vec::new_in(&self.allocator);
322
323 loop {
324 match self.peek_kind()? {
325 TokenKind::BlockEnd => {
326 self.next()?;
327 break;
328 }
329 TokenKind::Key | TokenKind::Value => {
330 children.push(self.parse_mapping_item()?);
331 }
332 _ => {
333 let span = self.peek()?.span;
334 return Err(Error::new(ErrorKind::UnexpectedToken("token in mapping"), span));
335 }
336 }
337 }
338
339 let span = container_span(start_token.span, children.first(), children.last());
340 Ok(Content::Mapping(self.alloc(Mapping { span, props, children })))
341 }
342
343 fn parse_mapping_item(&mut self) -> ParseResult<MappingItem<'a>> {
346 let key = if let Some(key_token) = self.eat(TokenKind::Key)? {
347 let explicit = !key_token.synthesized;
350 let content = self.parse_optional_node(true)?;
351 let span = match (&content, explicit) {
354 (Some(content), true) => Span::new(key_token.span.start, content.span().end),
355 (Some(content), false) => content.span(),
356 (None, true) => key_token.span,
357 (None, false) => Span::empty(key_token.span.start),
358 };
359 MappingKey { span, content, explicit }
360 } else {
361 let at = self.peek()?.span.start;
363 MappingKey { span: Span::empty(at), content: None, explicit: false }
364 };
365
366 let value = if let Some(value_token) = self.eat(TokenKind::Value)? {
367 let content = self.parse_optional_node(true)?;
368 let span = content.as_ref().map_or(Span::empty(value_token.span.end), Content::span);
369 MappingValue { span, content }
370 } else {
371 MappingValue { span: Span::empty(key.span.end), content: None }
374 };
375
376 let span = Span::new(key.span.start, value.span.end.max(key.span.end));
377 Ok(MappingItem { span, key, value })
378 }
379
380 fn parse_flow_sequence(&mut self, props: Props) -> ParseResult<Content<'a>> {
381 let start_token = self.next()?; let mut children = Vec::new_in(&self.allocator);
383
384 loop {
385 match self.peek_kind()? {
386 TokenKind::FlowSequenceEnd => {
387 let end_token = self.next()?;
388 let span = Span::new(start_token.span.start, end_token.span.end);
389 return Ok(Content::FlowSequence(self.alloc(FlowSequence {
390 span,
391 props,
392 children,
393 })));
394 }
395 TokenKind::FlowEntry => {
396 self.next()?;
397 }
398 TokenKind::Key | TokenKind::Value => {
399 let item = self.parse_mapping_item()?;
402 children.push(FlowSequenceEntry::Pair(self.alloc(item)));
403 }
404 _ => {
405 let is_synthesized_pair = {
408 let token = self.peek()?;
409 token.kind == TokenKind::FlowMappingStart && token.synthesized
410 };
411 let content = self.parse_node(false)?;
412 if is_synthesized_pair {
413 if let Content::FlowMapping(mapping) = content {
414 let mut mapping = mapping.unbox();
415 debug_assert!(mapping.children.len() == 1);
416 if let Some(item) = mapping.children.pop() {
417 children.push(FlowSequenceEntry::Pair(self.alloc(item)));
418 }
419 continue;
420 }
421 unreachable!("synthesized FlowMappingStart must produce a FlowMapping");
422 }
423 let span = content.span();
424 children.push(FlowSequenceEntry::Item(FlowSequenceItem { span, content }));
425 }
426 }
427 }
428 }
429
430 fn parse_flow_mapping(&mut self, props: Props) -> ParseResult<Content<'a>> {
431 let start_token = self.next()?; let mut children = Vec::new_in(&self.allocator);
433
434 loop {
435 match self.peek_kind()? {
436 TokenKind::FlowMappingEnd => {
437 let end_token = self.next()?;
438 let span = if end_token.synthesized {
439 container_span(start_token.span, children.first(), children.last())
441 } else {
442 Span::new(start_token.span.start, end_token.span.end)
443 };
444 return Ok(Content::FlowMapping(self.alloc(FlowMapping {
445 span,
446 props,
447 children,
448 })));
449 }
450 TokenKind::FlowEntry => {
451 self.next()?;
452 }
453 TokenKind::Key | TokenKind::Value => {
454 children.push(self.parse_mapping_item()?);
455 }
456 _ if self.peek_kind()?.starts_node() => {
457 let content = self.parse_node(false)?;
459 let span = content.span();
460 children.push(MappingItem {
461 span,
462 key: MappingKey { span, content: Some(content), explicit: false },
463 value: MappingValue { span: Span::empty(span.end), content: None },
464 });
465 }
466 _ => {
467 let span = self.peek()?.span;
468 return Err(Error::new(
469 ErrorKind::UnexpectedToken("token in flow mapping"),
470 span,
471 ));
472 }
473 }
474 }
475 }
476}
477
478fn container_span<T: HasSpan>(start: Span, first: Option<&T>, last: Option<&T>) -> Span {
481 let start_pos = first.map_or(start.start, |c| c.span().start.min(start.start));
482 let end_pos = last.map_or(start.end, |c| c.span().end.max(start.end));
483 Span::new(start_pos, end_pos)
484}
485
486trait HasSpan {
488 fn span(&self) -> Span;
489}
490
491impl HasSpan for SequenceItem<'_> {
492 fn span(&self) -> Span {
493 self.span
494 }
495}
496
497impl HasSpan for MappingItem<'_> {
498 fn span(&self) -> Span {
499 self.span
500 }
501}