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 { children, comments, span: Span::new(0, source_len) })
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()?)) } 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 directives,
121 span: Span::new(head_start, directives_end_marker.map_or(head_end, |s| s.end)),
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 { content, span: body_span };
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 head,
152 body,
153 directives_end_marker,
154 document_end_marker,
155 span: Span::new(head_start, span_end),
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 { name, parameters, span: token.span }
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) -> ParseResult<Content<'a>> {
194 let props = self.parse_props()?;
195
196 let token = *self.peek()?;
197 match token.kind {
198 TokenKind::Alias => {
199 self.next()?;
200 if props.anchor.is_some() || props.tag.is_some() {
201 return Err(Error::new(ErrorKind::DuplicatedNodeProperty, token.span));
202 }
203 Ok(Content::Alias(self.alloc(Alias { props, span: token.span })))
204 }
205 TokenKind::Scalar(style, header_index) => {
206 self.next()?;
207 Ok(self.build_scalar(props, style, header_index, token.span))
208 }
209 TokenKind::FlowSequenceStart => self.parse_flow_sequence(props),
210 TokenKind::FlowMappingStart => self.parse_flow_mapping(props),
211 TokenKind::BlockSequenceStart => self.parse_block_sequence(props),
212 TokenKind::BlockMappingStart => self.parse_block_mapping(props),
213 TokenKind::BlockEntry => self.parse_indentless_sequence(props),
217 _ => {
218 if props.anchor.is_some() || props.tag.is_some() {
221 let at = props
222 .anchor
223 .map(|a| a.span.end)
224 .max(props.tag.map(|t| t.span.end))
225 .unwrap();
226 return Ok(Content::Plain(self.alloc(Plain { props, span: Span::empty(at) })));
227 }
228 Err(Error::new(ErrorKind::ExpectedNode, token.span))
229 }
230 }
231 }
232
233 fn build_scalar(
234 &self,
235 props: Props,
236 style: ScalarStyle,
237 header_index: Option<crate::scanner::BlockHeaderIndex>,
238 span: Span,
239 ) -> Content<'a> {
240 match style {
241 ScalarStyle::Plain => Content::Plain(self.alloc(Plain { props, span })),
242 ScalarStyle::SingleQuoted => {
243 Content::QuoteSingle(self.alloc(QuoteSingle { props, span }))
244 }
245 ScalarStyle::DoubleQuoted => {
246 Content::QuoteDouble(self.alloc(QuoteDouble { props, span }))
247 }
248 ScalarStyle::Literal | ScalarStyle::Folded => {
249 let index = header_index.expect("block scalar token must carry a header index");
250 let header = self.scanner.block_headers[index.get()];
251 let node = BlockScalar {
252 props,
253 chomping: header.chomping,
254 indent: header.indent,
255 content_start: header.content_start,
256 span,
257 };
258 if style == ScalarStyle::Literal {
259 Content::BlockLiteral(self.alloc(node))
260 } else {
261 Content::BlockFolded(self.alloc(node))
262 }
263 }
264 }
265 }
266
267 fn parse_sequence_item(&mut self) -> ParseResult<SequenceItem<'a>> {
269 let entry_token = self.next()?;
270 debug_assert!(entry_token.kind == TokenKind::BlockEntry);
271 let content = self.parse_optional_node(false)?;
272 let end = content.as_ref().map_or(entry_token.span.end, |c| c.span().end);
273 Ok(SequenceItem { content, span: Span::new(entry_token.span.start, end) })
274 }
275
276 fn parse_block_sequence(&mut self, props: Props) -> ParseResult<Content<'a>> {
277 let start_token = self.next()?; let mut children = Vec::new_in(&self.allocator);
279
280 loop {
281 match self.peek_kind()? {
282 TokenKind::BlockEnd => {
283 self.next()?;
284 break;
285 }
286 TokenKind::BlockEntry => children.push(self.parse_sequence_item()?),
287 _ => {
288 let span = self.peek()?.span;
289 return Err(Error::new(ErrorKind::UnexpectedToken("token in sequence"), span));
290 }
291 }
292 }
293
294 let span = container_span(start_token.span, children.first(), children.last());
295 Ok(Content::Sequence(self.alloc(Sequence { props, children, span })))
296 }
297
298 fn parse_indentless_sequence(&mut self, props: Props) -> ParseResult<Content<'a>> {
303 let mut children = Vec::new_in(&self.allocator);
304 let first = self.peek()?.span;
305
306 while self.peek_kind()? == TokenKind::BlockEntry {
307 children.push(self.parse_sequence_item()?);
308 }
309
310 let span = container_span(Span::empty(first.start), children.first(), children.last());
311 Ok(Content::Sequence(self.alloc(Sequence { props, children, span })))
312 }
313
314 fn parse_block_mapping(&mut self, props: Props) -> ParseResult<Content<'a>> {
315 let start_token = self.next()?; let mut children = Vec::new_in(&self.allocator);
317
318 loop {
319 match self.peek_kind()? {
320 TokenKind::BlockEnd => {
321 self.next()?;
322 break;
323 }
324 TokenKind::Key | TokenKind::Value => {
325 children.push(self.parse_mapping_item()?);
326 }
327 _ => {
328 let span = self.peek()?.span;
329 return Err(Error::new(ErrorKind::UnexpectedToken("token in mapping"), span));
330 }
331 }
332 }
333
334 let span = container_span(start_token.span, children.first(), children.last());
335 Ok(Content::Mapping(self.alloc(Mapping { props, children, span })))
336 }
337
338 fn parse_mapping_item(&mut self) -> ParseResult<MappingItem<'a>> {
341 let key = if let Some(key_token) = self.eat(TokenKind::Key)? {
342 let explicit = !key_token.synthesized;
345 let content = self.parse_optional_node(true)?;
346 let span = content.as_ref().map_or(Span::empty(key_token.span.start), Content::span);
347 MappingKey { content, explicit, span }
348 } else {
349 let at = self.peek()?.span.start;
351 MappingKey { content: None, explicit: false, span: Span::empty(at) }
352 };
353
354 let value = if let Some(value_token) = self.eat(TokenKind::Value)? {
355 let content = self.parse_optional_node(true)?;
356 let span = content.as_ref().map_or(Span::empty(value_token.span.end), Content::span);
357 MappingValue { content, span }
358 } else {
359 MappingValue { content: None, span: Span::empty(key.span.end) }
362 };
363
364 let span = Span::new(key.span.start, value.span.end.max(key.span.end));
365 Ok(MappingItem { key, value, span })
366 }
367
368 fn parse_flow_sequence(&mut self, props: Props) -> ParseResult<Content<'a>> {
369 let start_token = self.next()?; let mut children = Vec::new_in(&self.allocator);
371
372 loop {
373 match self.peek_kind()? {
374 TokenKind::FlowSequenceEnd => {
375 let end_token = self.next()?;
376 let span = Span::new(start_token.span.start, end_token.span.end);
377 return Ok(Content::FlowSequence(self.alloc(FlowSequence {
378 props,
379 children,
380 span,
381 })));
382 }
383 TokenKind::FlowEntry => {
384 self.next()?;
385 }
386 TokenKind::Key | TokenKind::Value => {
387 let item = self.parse_mapping_item()?;
390 children.push(FlowSequenceEntry::Pair(self.alloc(item)));
391 }
392 _ => {
393 let is_synthesized_pair = {
396 let token = self.peek()?;
397 token.kind == TokenKind::FlowMappingStart && token.synthesized
398 };
399 let content = self.parse_node()?;
400 if is_synthesized_pair {
401 if let Content::FlowMapping(mapping) = content {
402 let mut mapping = mapping.unbox();
403 debug_assert!(mapping.children.len() == 1);
404 if let Some(item) = mapping.children.pop() {
405 children.push(FlowSequenceEntry::Pair(self.alloc(item)));
406 }
407 continue;
408 }
409 unreachable!("synthesized FlowMappingStart must produce a FlowMapping");
410 }
411 let span = content.span();
412 children.push(FlowSequenceEntry::Item(FlowSequenceItem { content, span }));
413 }
414 }
415 }
416 }
417
418 fn parse_flow_mapping(&mut self, props: Props) -> ParseResult<Content<'a>> {
419 let start_token = self.next()?; let mut children = Vec::new_in(&self.allocator);
421
422 loop {
423 match self.peek_kind()? {
424 TokenKind::FlowMappingEnd => {
425 let end_token = self.next()?;
426 let span = if end_token.synthesized {
427 container_span(start_token.span, children.first(), children.last())
429 } else {
430 Span::new(start_token.span.start, end_token.span.end)
431 };
432 return Ok(Content::FlowMapping(self.alloc(FlowMapping {
433 props,
434 children,
435 span,
436 })));
437 }
438 TokenKind::FlowEntry => {
439 self.next()?;
440 }
441 TokenKind::Key | TokenKind::Value => {
442 children.push(self.parse_mapping_item()?);
443 }
444 _ if self.peek_kind()?.starts_node() => {
445 let content = self.parse_node()?;
447 let span = content.span();
448 children.push(MappingItem {
449 key: MappingKey { content: Some(content), explicit: false, span },
450 value: MappingValue { content: None, span: Span::empty(span.end) },
451 span,
452 });
453 }
454 _ => {
455 let span = self.peek()?.span;
456 return Err(Error::new(
457 ErrorKind::UnexpectedToken("token in flow mapping"),
458 span,
459 ));
460 }
461 }
462 }
463 }
464}
465
466fn container_span<T: HasSpan>(start: Span, first: Option<&T>, last: Option<&T>) -> Span {
469 let start_pos = first.map_or(start.start, |c| c.span().start.min(start.start));
470 let end_pos = last.map_or(start.end, |c| c.span().end.max(start.end));
471 Span::new(start_pos, end_pos)
472}
473
474trait HasSpan {
476 fn span(&self) -> Span;
477}
478
479impl HasSpan for SequenceItem<'_> {
480 fn span(&self) -> Span {
481 self.span
482 }
483}
484
485impl HasSpan for MappingItem<'_> {
486 fn span(&self) -> Span {
487 self.span
488 }
489}