1use super::*;
18use leo_errors::{ParserError, Result};
19
20use leo_span::sym;
21use snarkvm::{
22 console::account::Address,
23 prelude::{CanaryV0, MainnetV0, TestnetV0},
24};
25
26const INT_TYPES: &[Token] = &[
27 Token::I8,
28 Token::I16,
29 Token::I32,
30 Token::I64,
31 Token::I128,
32 Token::U8,
33 Token::U16,
34 Token::U32,
35 Token::U64,
36 Token::U128,
37 Token::Field,
38 Token::Group,
39 Token::Scalar,
40];
41
42impl ParserContext<'_> {
43 pub(crate) fn parse_expression(&mut self) -> Result<Expression> {
46 let prior_fuzzy_state = self.disallow_struct_construction;
48
49 self.disallow_struct_construction = false;
51
52 let result = self.parse_conditional_expression();
54
55 self.disallow_struct_construction = prior_fuzzy_state;
57
58 result
59 }
60
61 pub(super) fn parse_conditional_expression(&mut self) -> Result<Expression> {
66 let mut expr = self.parse_boolean_or_expression()?;
68
69 if self.eat(&Token::Question) {
71 let if_true = self.parse_expression()?;
72 self.expect(&Token::Colon)?;
73 let if_false = self.parse_expression()?;
74 expr = TernaryExpression {
75 span: expr.span() + if_false.span(),
76 condition: expr,
77 if_true,
78 if_false,
79 id: self.node_builder.next_id(),
80 }
81 .into();
82 }
83 Ok(expr)
84 }
85
86 fn bin_expr(node_builder: &NodeBuilder, left: Expression, right: Expression, op: BinaryOperation) -> Expression {
88 BinaryExpression { span: left.span() + right.span(), op, left, right, id: node_builder.next_id() }.into()
89 }
90
91 fn parse_bin_expr(
94 &mut self,
95 tokens: &[Token],
96 mut f: impl FnMut(&mut Self) -> Result<Expression>,
97 ) -> Result<Expression> {
98 let mut expr = f(self)?;
99 while let Some(op) = self.eat_bin_op(tokens) {
100 expr = Self::bin_expr(self.node_builder, expr, f(self)?, op);
101 }
102 Ok(expr)
103 }
104
105 fn parse_boolean_or_expression(&mut self) -> Result<Expression> {
110 self.parse_bin_expr(&[Token::Or], Self::parse_boolean_and_expression)
111 }
112
113 fn parse_boolean_and_expression(&mut self) -> Result<Expression> {
118 self.parse_bin_expr(&[Token::And], Self::parse_equality_expression)
119 }
120
121 fn eat_unary_op(&mut self) -> Option<UnaryOperation> {
122 self.eat_any(&[Token::Not, Token::Sub]).then(|| match &self.prev_token.token {
123 Token::Not => UnaryOperation::Not,
124 Token::Sub => UnaryOperation::Negate,
125 _ => panic!("Can't happen."),
126 })
127 }
128
129 fn eat_bin_op(&mut self, tokens: &[Token]) -> Option<BinaryOperation> {
131 self.eat_any(tokens).then(|| match &self.prev_token.token {
132 Token::Eq => BinaryOperation::Eq,
133 Token::NotEq => BinaryOperation::Neq,
134 Token::Lt => BinaryOperation::Lt,
135 Token::LtEq => BinaryOperation::Lte,
136 Token::Gt => BinaryOperation::Gt,
137 Token::GtEq => BinaryOperation::Gte,
138 Token::Add => BinaryOperation::Add,
139 Token::Sub => BinaryOperation::Sub,
140 Token::Mul => BinaryOperation::Mul,
141 Token::Div => BinaryOperation::Div,
142 Token::Rem => BinaryOperation::Rem,
143 Token::Or => BinaryOperation::Or,
144 Token::And => BinaryOperation::And,
145 Token::BitOr => BinaryOperation::BitwiseOr,
146 Token::BitAnd => BinaryOperation::BitwiseAnd,
147 Token::Pow => BinaryOperation::Pow,
148 Token::Shl => BinaryOperation::Shl,
149 Token::Shr => BinaryOperation::Shr,
150 Token::BitXor => BinaryOperation::Xor,
151 _ => unreachable!("`eat_bin_op` shouldn't produce this"),
152 })
153 }
154
155 fn parse_ordering_expression(&mut self) -> Result<Expression> {
160 let mut expr = self.parse_bitwise_exclusive_or_expression()?;
161 if let Some(op) = self.eat_bin_op(&[Token::Lt, Token::LtEq, Token::Gt, Token::GtEq]) {
162 let right = self.parse_bitwise_exclusive_or_expression()?;
163 expr = Self::bin_expr(self.node_builder, expr, right, op);
164 }
165 Ok(expr)
166 }
167
168 fn parse_equality_expression(&mut self) -> Result<Expression> {
173 let mut expr = self.parse_ordering_expression()?;
174 if let Some(op) = self.eat_bin_op(&[Token::Eq, Token::NotEq]) {
175 let right = self.parse_ordering_expression()?;
176 expr = Self::bin_expr(self.node_builder, expr, right, op);
177 }
178 Ok(expr)
179 }
180
181 fn parse_bitwise_exclusive_or_expression(&mut self) -> Result<Expression> {
186 self.parse_bin_expr(&[Token::BitXor], Self::parse_bitwise_inclusive_or_expression)
187 }
188
189 fn parse_bitwise_inclusive_or_expression(&mut self) -> Result<Expression> {
194 self.parse_bin_expr(&[Token::BitOr], Self::parse_bitwise_and_expression)
195 }
196
197 fn parse_bitwise_and_expression(&mut self) -> Result<Expression> {
202 self.parse_bin_expr(&[Token::BitAnd], Self::parse_shift_expression)
203 }
204
205 fn parse_shift_expression(&mut self) -> Result<Expression> {
210 self.parse_bin_expr(&[Token::Shl, Token::Shr], Self::parse_additive_expression)
211 }
212
213 fn parse_additive_expression(&mut self) -> Result<Expression> {
218 self.parse_bin_expr(&[Token::Add, Token::Sub], Self::parse_multiplicative_expression)
219 }
220
221 fn parse_multiplicative_expression(&mut self) -> Result<Expression> {
226 self.parse_bin_expr(&[Token::Mul, Token::Div, Token::Rem], Self::parse_exponential_expression)
227 }
228
229 fn parse_exponential_expression(&mut self) -> Result<Expression> {
234 self.parse_bin_expr(&[Token::Pow], Self::parse_cast_expression)
235 }
236
237 fn parse_cast_expression(&mut self) -> Result<Expression> {
242 let mut expr = self.parse_unary_expression()?;
243 if self.eat(&Token::As) {
244 let (type_, end_span) = self.parse_primitive_type()?;
245 let span = expr.span() + end_span;
246 expr = CastExpression { expression: expr, type_, span, id: self.node_builder.next_id() }.into();
247 }
248
249 Ok(expr)
250 }
251
252 pub(super) fn parse_unary_expression(&mut self) -> Result<Expression> {
257 let token_span = self.token.span;
258
259 let Some(op) = self.eat_unary_op() else {
260 return self.parse_postfix_expression();
261 };
262
263 let mut inner = self.parse_unary_expression()?;
264
265 if let UnaryOperation::Negate = op {
267 use LiteralVariant::*;
268 if let Expression::Literal(Literal {
269 variant: Integer(_, string) | Field(string) | Group(string) | Scalar(string),
270 span,
271 ..
272 }) = &mut inner
273 {
274 if !string.starts_with('-') {
275 string.insert(0, '-');
277 *span = token_span + *span;
278 return Ok(inner);
279 }
280 }
281 }
282
283 Ok(UnaryExpression { span: token_span + inner.span(), op, receiver: inner, id: self.node_builder.next_id() }
284 .into())
285 }
286
287 fn parse_method_call_expression(&mut self, receiver: Expression, method: Identifier) -> Result<Expression> {
291 let (mut args, _, span) = self.parse_expr_tuple()?;
293 let span = receiver.span() + span;
294
295 if let (true, Some(op)) = (args.is_empty(), UnaryOperation::from_symbol(method.name)) {
296 Ok(UnaryExpression { span, op, receiver, id: self.node_builder.next_id() }.into())
298 } else if let (1, Some(op)) = (args.len(), BinaryOperation::from_symbol(method.name)) {
299 Ok(BinaryExpression {
301 span,
302 op,
303 left: receiver,
304 right: args.swap_remove(0),
305 id: self.node_builder.next_id(),
306 }
307 .into())
308 } else if let (2, Some(CoreFunction::SignatureVerify)) =
309 (args.len(), CoreFunction::from_symbols(sym::signature, method.name))
310 {
311 Ok(AssociatedFunctionExpression {
312 variant: Identifier::new(sym::signature, self.node_builder.next_id()),
313 name: method,
314 arguments: std::iter::once(receiver).chain(args).collect(),
315 span,
316 id: self.node_builder.next_id(),
317 }
318 .into())
319 } else if let (0, Some(CoreFunction::FutureAwait)) =
320 (args.len(), CoreFunction::from_symbols(sym::Future, method.name))
321 {
322 Ok(AssociatedFunctionExpression {
323 variant: Identifier::new(sym::Future, self.node_builder.next_id()),
324 name: method,
325 arguments: vec![receiver],
326 span,
327 id: self.node_builder.next_id(),
328 }
329 .into())
330 } else {
331 match (args.len(), CoreFunction::from_symbols(sym::Mapping, method.name)) {
333 (1, Some(CoreFunction::MappingGet))
334 | (2, Some(CoreFunction::MappingGetOrUse))
335 | (2, Some(CoreFunction::MappingSet))
336 | (1, Some(CoreFunction::MappingRemove))
337 | (1, Some(CoreFunction::MappingContains)) => {
338 Ok(AssociatedFunctionExpression {
340 variant: Identifier::new(sym::Mapping, self.node_builder.next_id()),
341 name: method,
342 arguments: std::iter::once(receiver).chain(args).collect(),
343 span,
344 id: self.node_builder.next_id(),
345 }
346 .into())
347 }
348 _ => {
349 self.emit_err(ParserError::invalid_method_call(receiver, method, args.len(), span));
351 Ok(ErrExpression { span, id: self.node_builder.next_id() }.into())
352 }
353 }
354 }
355 }
356
357 fn parse_associated_access_expression(&mut self, module_name: Expression) -> Result<Expression> {
360 let Expression::Path(ref path) = module_name else {
362 return Err(ParserError::invalid_associated_access(&module_name, module_name.span()).into());
363 };
364
365 let variant = path.identifier();
366 if !path.qualifier().is_empty() {
367 return Err(ParserError::invalid_associated_access(&module_name, module_name.span()).into());
368 };
369
370 let member_name = self.expect_identifier()?;
372
373 let expression = if self.check(&Token::LeftParen) {
375 let (args, _, end) = self.parse_expr_tuple()?;
377
378 AssociatedFunctionExpression {
380 span: module_name.span() + end,
381 variant,
382 name: member_name,
383 arguments: args,
384 id: self.node_builder.next_id(),
385 }
386 .into()
387 } else if CoreConstant::from_symbols(variant.name, member_name.name).is_some() {
388 AssociatedConstantExpression {
390 span: module_name.span() + member_name.span(),
391 ty: Type::Identifier(variant),
392 name: member_name,
393 id: self.node_builder.next_id(),
394 }
395 .into()
396 } else {
397 Path::new(vec![variant], member_name, None, variant.span + member_name.span, self.node_builder.next_id())
398 .into()
399 };
400
401 Ok(expression)
402 }
403
404 pub(crate) fn parse_expr_tuple(&mut self) -> Result<(Vec<Expression>, bool, Span)> {
406 self.parse_paren_comma_list(|p| p.parse_expression().map(Some))
407 }
408
409 fn parse_external_resource(&mut self, expr: Expression, network_span: Span) -> Result<Expression> {
416 self.expect(&Token::Div)?;
418
419 let name = self.expect_identifier()?;
421
422 let Expression::Path(ref path) = expr else {
424 unreachable!("Function must be preceded by a program identifier.");
425 };
426
427 if !path.qualifier().is_empty() {
428 unreachable!("Function must be preceded by a single-segment path.");
429 };
430
431 let program = path.identifier();
432
433 if self.token.token == Token::LeftCurly {
435 return Err(ParserError::cannot_define_external_record(expr.span() + name.span()).into());
436 }
437
438 if self.token.token != Token::LeftParen {
440 return Ok(LocatorExpression {
442 program: ProgramId {
443 name: program,
444 network: Identifier { name: sym::aleo, span: network_span, id: self.node_builder.next_id() },
445 },
446 name: name.name,
447 span: expr.span() + name.span(),
448 id: self.node_builder.next_id(),
449 }
450 .into());
451 }
452
453 let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
455
456 Ok(CallExpression {
457 span: expr.span() + span,
458 function: name.into(),
459 program: Some(program.name),
460 const_arguments: vec![], arguments,
462 id: self.node_builder.next_id(),
463 }
464 .into())
465 }
466
467 fn parse_postfix_expression(&mut self) -> Result<Expression> {
476 let mut expr = self.parse_primary_expression()?;
480 loop {
481 if self.eat(&Token::Dot) {
482 if self.check_int() {
483 let (index, span) = self.eat_whole_number()?;
485 expr = TupleAccess { tuple: expr, index, span, id: self.node_builder.next_id() }.into();
486 } else if self.eat(&Token::Leo) {
487 return Err(ParserError::only_aleo_external_calls(expr.span()).into());
488 } else if self.eat(&Token::Aleo) {
489 if self.token.token == Token::Div {
490 expr = self.parse_external_resource(expr, self.prev_token.span)?;
491 } else {
492 if !matches!(expr, Expression::Path(ref path) if path.qualifier().is_empty()) {
494 self.emit_err(ParserError::unexpected(expr.to_string(), "an identifier", expr.span()));
495 }
496
497 expr =
498 Literal::address(format!("{expr}.aleo"), expr.span(), self.node_builder.next_id()).into();
499 }
500 } else {
501 if matches!(expr, Expression::Path(ref path) if path.identifier().name == sym::SelfLower && path.qualifier().is_empty())
504 && self.token.token == Token::Address
505 {
506 let span = self.expect(&Token::Address)?;
508 expr = MemberAccess {
510 span: expr.span() + span,
511 inner: expr,
512 name: Identifier { name: sym::address, span, id: self.node_builder.next_id() },
513 id: self.node_builder.next_id(),
514 }
515 .into();
516 continue;
517 }
518
519 let name = self.expect_identifier()?;
521
522 if self.check(&Token::LeftParen) {
523 expr = self.parse_method_call_expression(expr, name)?
525 } else {
526 let expr_span = expr.span();
528 expr = MemberAccess {
529 inner: expr,
530 name,
531 span: expr_span + name.span(),
532 id: self.node_builder.next_id(),
533 }
534 .into();
535 }
536 }
537 } else if self.eat(&Token::DoubleColon) {
538 if self.check(&Token::LeftSquare) {
541 let Expression::Path(path) = &expr else {
543 return Err(leo_errors::LeoError::ParserError(ParserError::unexpected(
544 expr.to_string(),
545 "a path",
546 expr.span(),
547 )));
548 };
549
550 let const_arguments = self.parse_bracket_comma_list(|p| p.parse_expression().map(Some))?.0;
552
553 if self.check(&Token::LeftParen) {
556 let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
558
559 expr = CallExpression {
561 span: expr.span() + span,
562 function: path.clone(),
563 program: self.program_name,
564 const_arguments,
565 arguments,
566 id: self.node_builder.next_id(),
567 }
568 .into();
569 } else if !self.disallow_struct_construction && self.check(&Token::LeftCurly) {
570 expr = self.parse_struct_init_expression(path.clone(), const_arguments)?;
573 } else {
574 self.emit_err(ParserError::unexpected(expr.to_string(), "( or {{", expr.span()))
575 }
576 } else {
577 expr = self.parse_associated_access_expression(expr)?;
579 }
580 } else if self.eat(&Token::LeftSquare) {
581 let index = self.parse_expression()?;
583 let span = self.expect(&Token::RightSquare)?;
585 let expr_span = expr.span();
586 expr =
587 ArrayAccess { array: expr, index, span: expr_span + span, id: self.node_builder.next_id() }.into();
588 } else if self.check(&Token::LeftParen) {
589 let Expression::Path(path) = &expr else {
591 return Err(leo_errors::LeoError::ParserError(ParserError::unexpected(
592 expr.to_string(),
593 "a path",
594 expr.span(),
595 )));
596 };
597
598 let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
600
601 expr = if path.qualifier().len() == 1
603 && CoreFunction::from_symbols(path.qualifier()[0].name, path.identifier().name).is_some()
604 {
605 AssociatedFunctionExpression {
606 variant: path.qualifier()[0],
607 name: path.identifier(),
608 arguments,
609 span: expr.span() + span,
610 id: self.node_builder.next_id(),
611 }
612 .into()
613 } else {
614 CallExpression {
615 span: expr.span() + span,
616 function: path.clone(),
617 program: self.program_name,
618 const_arguments: vec![],
619 arguments,
620 id: self.node_builder.next_id(),
621 }
622 .into()
623 };
624 }
625 if !(self.check(&Token::Dot) || self.check(&Token::LeftSquare)) {
627 break;
628 }
629 }
630 Ok(expr)
631 }
632
633 fn parse_tuple_expression(&mut self) -> Result<Expression> {
637 let (mut elements, trailing, span) = self.parse_expr_tuple()?;
638
639 match (elements.len(), trailing) {
640 (0, _) | (1, true) => {
641 Err(ParserError::tuple_must_have_at_least_two_elements("expression", span).into())
643 }
644 (1, false) => {
645 Ok(elements.remove(0))
647 }
648 _ => {
649 Ok(TupleExpression { elements, span, id: self.node_builder.next_id() }.into())
652 }
653 }
654 }
655
656 fn parse_array_or_repeat_expression(&mut self) -> Result<Expression> {
658 let (open, close) = Delimiter::Bracket.open_close_pair();
659 let open_span = self.expect(&open)?;
660
661 let Ok(first_expr) = self.parse_expression() else {
663 let close_span = self.expect(&close)?;
665 return Err(ParserError::array_must_have_at_least_one_element("expression", open_span + close_span).into());
666 };
667
668 if self.eat(&Token::Semicolon) {
670 let count = self.parse_expression()?;
671 let span = open_span + self.expect(&close)?;
672 return Ok(RepeatExpression { expr: first_expr, count, span, id: self.node_builder.next_id() }.into());
673 }
674
675 let mut elements = vec![first_expr];
678 while self.eat(&Token::Comma) && !self.check(&close) {
679 elements.push(self.parse_expression()?);
680 }
681 let span = open_span + self.expect(&close)?;
682 Ok(ArrayExpression { elements, span, id: self.node_builder.next_id() }.into())
683 }
684
685 fn parse_struct_member(&mut self) -> Result<StructVariableInitializer> {
686 let identifier = self.expect_identifier()?;
687
688 let (expression, span) = if self.eat(&Token::Colon) {
689 let expression = self.parse_expression()?;
691 let span = identifier.span + expression.span();
692 (Some(expression), span)
693 } else {
694 (None, identifier.span)
695 };
696
697 Ok(StructVariableInitializer { identifier, expression, id: self.node_builder.next_id(), span })
698 }
699
700 pub fn parse_struct_init_expression(&mut self, path: Path, const_arguments: Vec<Expression>) -> Result<Expression> {
704 let (members, _, end) =
705 self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| p.parse_struct_member().map(Some))?;
706
707 Ok(StructExpression { span: path.span + end, path, const_arguments, members, id: self.node_builder.next_id() }
708 .into())
709 }
710
711 fn parse_primary_expression(&mut self) -> Result<Expression> {
728 if let Token::LeftParen = self.token.token {
729 return self.parse_tuple_expression();
730 } else if let Token::LeftSquare = self.token.token {
731 return self.parse_array_or_repeat_expression();
732 } else if let Token::Async = self.token.token {
733 let async_keyword_span = self.expect(&Token::Async)?;
734 let block = self.parse_block()?;
735 let span = async_keyword_span + block.span;
736 return Ok(AsyncExpression { block, span, id: self.node_builder.next_id() }.into());
737 }
738
739 let SpannedToken { token, span } = self.token.clone();
740 self.bump();
741
742 Ok(match token {
743 Token::Integer(value) => {
744 let suffix_span = self.token.span;
745 let full_span = span + suffix_span;
746 let assert_no_whitespace = |x| assert_no_whitespace(span, suffix_span, &value, x);
747
748 match self.eat_any(INT_TYPES).then_some(&self.prev_token.token) {
749 Some(Token::Field) | Some(Token::Group) | Some(Token::Scalar)
751 if value.starts_with("0x")
752 || value.starts_with("0o")
753 || value.starts_with("0b")
754 || value.starts_with("-0x")
755 || value.starts_with("-0o")
756 || value.starts_with("-0b") =>
757 {
758 return Err(ParserError::hexbin_literal_nonintegers(span).into());
759 }
760 Some(Token::Field) => {
762 assert_no_whitespace("field")?;
763 Literal::field(value, full_span, self.node_builder.next_id()).into()
764 }
765 Some(Token::Group) => {
767 assert_no_whitespace("group")?;
768 Literal::group(value, full_span, self.node_builder.next_id()).into()
769 }
770 Some(Token::Scalar) => {
772 assert_no_whitespace("scalar")?;
773 Literal::scalar(value, full_span, self.node_builder.next_id()).into()
774 }
775 Some(suffix) => {
777 assert_no_whitespace(&suffix.to_string())?;
778 let int_ty = Self::token_to_int_type(suffix).expect("unknown int type token");
779 Literal::integer(int_ty, value, full_span, self.node_builder.next_id()).into()
780 }
781 None => {
782 Literal::unsuffixed(value, span, self.node_builder.next_id()).into()
785 }
786 }
787 }
788 Token::True => Literal::boolean(true, span, self.node_builder.next_id()).into(),
789 Token::False => Literal::boolean(false, span, self.node_builder.next_id()).into(),
790 Token::AddressLit(address_string) => {
791 if match self.network {
792 NetworkName::MainnetV0 => address_string.parse::<Address<MainnetV0>>().is_err(),
793 NetworkName::TestnetV0 => address_string.parse::<Address<TestnetV0>>().is_err(),
794 NetworkName::CanaryV0 => address_string.parse::<Address<CanaryV0>>().is_err(),
795 } {
796 self.emit_err(ParserError::invalid_address_lit(&address_string, span));
797 }
798 Literal::address(address_string, span, self.node_builder.next_id()).into()
799 }
800 Token::StaticString(value) => {
801 Literal { span, id: self.node_builder.next_id(), variant: LiteralVariant::String(value) }.into()
802 }
803 Token::Identifier(first_ident) => {
804 let mut path_span = span;
805 let identifier = Identifier { name: first_ident, span, id: self.node_builder.next_id() };
806 let mut segments = vec![identifier];
807
808 while self.check(&Token::DoubleColon) {
810 if self.look_ahead(1, |next| matches!(next.token, Token::LeftSquare)) {
812 break;
813 }
814
815 self.bump(); let next_ident = self.expect_identifier()?;
818 path_span = path_span + next_ident.span;
819 segments.push(next_ident);
820 }
821
822 let (identifier, qualifier) = segments.split_last().expect("guaranateed to have at least one segment");
823
824 let path = Path::new(qualifier.to_vec(), *identifier, None, path_span, self.node_builder.next_id());
825
826 if !self.disallow_struct_construction && self.check(&Token::LeftCurly) {
828 self.parse_struct_init_expression(path.clone(), Vec::new())?
831 } else {
832 path.into()
833 }
834 }
835 Token::SelfLower => Identifier { name: sym::SelfLower, span, id: self.node_builder.next_id() }.into(),
836 Token::Block => Identifier { name: sym::block, span, id: self.node_builder.next_id() }.into(),
837 Token::Future => Identifier { name: sym::Future, span, id: self.node_builder.next_id() }.into(),
838 Token::Network => Identifier { name: sym::network, span, id: self.node_builder.next_id() }.into(),
839 t if crate::type_::TYPE_TOKENS.contains(&t) => {
840 Identifier { name: t.keyword_to_symbol().unwrap(), span, id: self.node_builder.next_id() }.into()
841 }
842 token => {
843 return Err(ParserError::unexpected_str(token, "expression", span).into());
844 }
845 })
846 }
847}
848
849fn assert_no_whitespace(left_span: Span, right_span: Span, left: &str, right: &str) -> Result<()> {
850 if left_span.hi != right_span.lo {
851 let error_span = Span::new(left_span.hi, right_span.lo); return Err(ParserError::unexpected_whitespace(left, right, error_span).into());
853 }
854
855 Ok(())
856}