1use crate::ast::*;
20use crate::errors::QalaError;
21use crate::span::Span;
22use crate::token::{Token, TokenKind};
23
24pub const MAX_DEPTH: u32 = 256;
31
32pub struct Parser<'t> {
41 tokens: &'t [Token],
43 pos: usize,
46 depth: u32,
49 open_delims: Vec<(TokenKind, Span)>,
53}
54
55impl<'t> Parser<'t> {
56 pub fn parse(tokens: &'t [Token]) -> Result<Ast, QalaError> {
65 let mut p = Parser {
66 tokens,
67 pos: 0,
68 depth: 0,
69 open_delims: Vec::new(),
70 };
71 let mut items: Ast = Vec::new();
72 while !matches!(p.peek(), TokenKind::Eof) {
73 items.push(p.parse_item()?);
74 }
75 Ok(items)
76 }
77
78 fn peek(&self) -> &TokenKind {
83 &self.tokens[self.pos].kind
84 }
85
86 fn peek_span(&self) -> Span {
88 self.tokens[self.pos].span
89 }
90
91 #[allow(dead_code)] fn peek2(&self) -> &TokenKind {
97 self.tokens
98 .get(self.pos + 1)
99 .map(|t| &t.kind)
100 .unwrap_or(&TokenKind::Eof)
101 }
102
103 fn advance(&mut self) -> &Token {
108 let tok = &self.tokens[self.pos];
109 if !matches!(tok.kind, TokenKind::Eof) {
110 self.pos += 1;
111 }
112 &self.tokens[self.pos.saturating_sub(1).min(self.tokens.len() - 1)]
115 }
116
117 fn check(&self, k: &TokenKind) -> bool {
120 self.peek() == k
121 }
122
123 fn eat(&mut self, k: &TokenKind) -> bool {
126 if self.check(k) {
127 self.advance();
128 true
129 } else {
130 false
131 }
132 }
133
134 fn expect(&mut self, k: &TokenKind) -> Result<Span, QalaError> {
137 if self.check(k) {
138 Ok(self.advance().span)
139 } else {
140 Err(self.unexpected(std::slice::from_ref(k)))
141 }
142 }
143
144 fn expect_ident(&mut self) -> Result<(String, Span), QalaError> {
147 match self.peek().clone() {
148 TokenKind::Ident(name) => {
149 let span = self.advance().span;
150 Ok((name, span))
151 }
152 _ => Err(self.unexpected(&[TokenKind::Ident(String::new())])),
153 }
154 }
155
156 fn unexpected(&self, expected: &[TokenKind]) -> QalaError {
166 if matches!(self.peek(), TokenKind::Eof) {
167 let span = if self.pos > 0 {
172 let prev = &self.tokens[self.pos - 1];
173 Span::new(prev.span.end(), 0)
174 } else {
175 Span::new(0, 0)
176 };
177 QalaError::UnexpectedEof {
178 span,
179 expected: expected.to_vec(),
180 }
181 } else {
182 QalaError::UnexpectedToken {
183 span: self.peek_span(),
184 expected: expected.to_vec(),
185 found: self.peek().clone(),
186 }
187 }
188 }
189
190 fn enter(&mut self) -> Result<(), QalaError> {
199 self.depth = self.depth.saturating_add(1);
200 if self.depth > MAX_DEPTH {
201 return Err(QalaError::Parse {
202 span: self.peek_span(),
203 message: "expression nests too deeply".to_string(),
204 });
205 }
206 Ok(())
207 }
208
209 fn exit(&mut self) {
212 self.depth = self.depth.saturating_sub(1);
213 }
214
215 fn delimited_list<T>(
228 &mut self,
229 open: TokenKind,
230 close: TokenKind,
231 sep: TokenKind,
232 mut parse_one: impl FnMut(&mut Self) -> Result<T, QalaError>,
233 ) -> Result<(Vec<T>, Span), QalaError> {
234 let open_span = self.expect(&open)?;
235 self.open_delims.push((open.clone(), open_span));
236 let mut items: Vec<T> = Vec::new();
237 loop {
238 if self.check(&close) {
239 break;
240 }
241 items.push(parse_one(self)?);
244 if !self.eat(&sep) {
245 break;
246 }
247 }
248 if self.check(&close) {
249 let close_span = self.advance().span;
250 self.open_delims.pop();
251 Ok((items, close_span))
252 } else {
253 self.open_delims.pop();
255 Err(QalaError::UnclosedDelimiter {
256 span: open_span,
257 opener: open,
258 found: self.peek().clone(),
259 })
260 }
261 }
262
263 fn parse_type(&mut self) -> Result<TypeExpr, QalaError> {
284 self.enter()?;
285 let result = self.parse_type_inner();
286 self.exit();
287 result
288 }
289
290 fn parse_type_inner(&mut self) -> Result<TypeExpr, QalaError> {
291 match self.peek().clone() {
292 TokenKind::I64Ty => {
294 let span = self.advance().span;
295 Ok(TypeExpr::Primitive {
296 kind: PrimType::I64,
297 span,
298 })
299 }
300 TokenKind::F64Ty => {
301 let span = self.advance().span;
302 Ok(TypeExpr::Primitive {
303 kind: PrimType::F64,
304 span,
305 })
306 }
307 TokenKind::BoolTy => {
308 let span = self.advance().span;
309 Ok(TypeExpr::Primitive {
310 kind: PrimType::Bool,
311 span,
312 })
313 }
314 TokenKind::StrTy => {
315 let span = self.advance().span;
316 Ok(TypeExpr::Primitive {
317 kind: PrimType::Str,
318 span,
319 })
320 }
321 TokenKind::ByteTy => {
322 let span = self.advance().span;
323 Ok(TypeExpr::Primitive {
324 kind: PrimType::Byte,
325 span,
326 })
327 }
328 TokenKind::VoidTy => {
329 let span = self.advance().span;
330 Ok(TypeExpr::Primitive {
331 kind: PrimType::Void,
332 span,
333 })
334 }
335 TokenKind::Ident(name) => {
339 let name_span = self.advance().span;
340 if self.check(&TokenKind::Lt) {
341 let (args, close) =
342 self.delimited_list(TokenKind::Lt, TokenKind::Gt, TokenKind::Comma, |p| {
343 p.parse_type()
344 })?;
345 Ok(TypeExpr::Generic {
346 name,
347 args,
348 span: name_span.to(close),
349 })
350 } else {
351 Ok(TypeExpr::Named {
352 name,
353 span: name_span,
354 })
355 }
356 }
357 TokenKind::LBracket => self.parse_bracket_type(),
361 TokenKind::LParen => self.parse_paren_type(),
365 TokenKind::Fn => self.parse_fn_type(),
367 _ => Err(self.unexpected(&[
368 TokenKind::I64Ty,
369 TokenKind::F64Ty,
370 TokenKind::BoolTy,
371 TokenKind::StrTy,
372 TokenKind::ByteTy,
373 TokenKind::VoidTy,
374 TokenKind::Ident(String::new()),
375 TokenKind::LBracket,
376 TokenKind::LParen,
377 TokenKind::Fn,
378 ])),
379 }
380 }
381
382 fn parse_bracket_type(&mut self) -> Result<TypeExpr, QalaError> {
384 let open_span = self.expect(&TokenKind::LBracket)?;
385 self.open_delims.push((TokenKind::LBracket, open_span));
386 let elem = self.parse_type()?;
387 if self.eat(&TokenKind::Semi) {
388 let size = match self.peek().clone() {
390 TokenKind::Int(v) if v >= 0 => {
391 self.advance();
392 v as u64
393 }
394 _ => {
395 self.open_delims.pop();
396 return Err(self.unexpected(&[TokenKind::Int(0)]));
397 }
398 };
399 if !self.check(&TokenKind::RBracket) {
400 self.open_delims.pop();
401 return Err(QalaError::UnclosedDelimiter {
402 span: open_span,
403 opener: TokenKind::LBracket,
404 found: self.peek().clone(),
405 });
406 }
407 let close = self.advance().span;
408 self.open_delims.pop();
409 Ok(TypeExpr::Array {
410 elem: Box::new(elem),
411 size,
412 span: open_span.to(close),
413 })
414 } else {
415 if !self.check(&TokenKind::RBracket) {
417 self.open_delims.pop();
418 return Err(QalaError::UnclosedDelimiter {
419 span: open_span,
420 opener: TokenKind::LBracket,
421 found: self.peek().clone(),
422 });
423 }
424 let close = self.advance().span;
425 self.open_delims.pop();
426 Ok(TypeExpr::DynArray {
427 elem: Box::new(elem),
428 span: open_span.to(close),
429 })
430 }
431 }
432
433 fn parse_paren_type(&mut self) -> Result<TypeExpr, QalaError> {
437 let open_span = self.expect(&TokenKind::LParen)?;
438 self.open_delims.push((TokenKind::LParen, open_span));
439 if self.check(&TokenKind::RParen) {
441 let close = self.advance().span;
442 self.open_delims.pop();
443 return Ok(TypeExpr::Tuple {
444 elems: Vec::new(),
445 span: open_span.to(close),
446 });
447 }
448 let first = self.parse_type()?;
449 if self.check(&TokenKind::RParen) {
453 self.advance();
454 self.open_delims.pop();
455 return Ok(first);
456 }
457 if !self.eat(&TokenKind::Comma) {
459 self.open_delims.pop();
460 return Err(QalaError::UnclosedDelimiter {
461 span: open_span,
462 opener: TokenKind::LParen,
463 found: self.peek().clone(),
464 });
465 }
466 let mut elems = vec![first];
467 loop {
468 if self.check(&TokenKind::RParen) {
469 break;
470 }
471 elems.push(self.parse_type()?);
472 if !self.eat(&TokenKind::Comma) {
473 break;
474 }
475 }
476 if !self.check(&TokenKind::RParen) {
477 self.open_delims.pop();
478 return Err(QalaError::UnclosedDelimiter {
479 span: open_span,
480 opener: TokenKind::LParen,
481 found: self.peek().clone(),
482 });
483 }
484 let close = self.advance().span;
485 self.open_delims.pop();
486 Ok(TypeExpr::Tuple {
487 elems,
488 span: open_span.to(close),
489 })
490 }
491
492 fn parse_fn_type(&mut self) -> Result<TypeExpr, QalaError> {
496 let fn_span = self.expect(&TokenKind::Fn)?;
497 let (params, _close) = self.delimited_list(
498 TokenKind::LParen,
499 TokenKind::RParen,
500 TokenKind::Comma,
501 |p| p.parse_type(),
502 )?;
503 self.expect(&TokenKind::Arrow)?;
504 let ret = self.parse_type()?;
505 let ret_span = ret.span();
506 Ok(TypeExpr::Fn {
507 params,
508 ret: Box::new(ret),
509 span: fn_span.to(ret_span),
510 })
511 }
512
513 fn parse_item(&mut self) -> Result<Item, QalaError> {
517 match self.peek() {
518 TokenKind::Fn => self.parse_fn_item(),
519 TokenKind::Struct => Ok(Item::Struct(self.parse_struct_item()?)),
520 TokenKind::Enum => Ok(Item::Enum(self.parse_enum_item()?)),
521 TokenKind::Interface => Ok(Item::Interface(self.parse_interface_item()?)),
522 _ => Err(self.unexpected(&[
523 TokenKind::Fn,
524 TokenKind::Struct,
525 TokenKind::Enum,
526 TokenKind::Interface,
527 ])),
528 }
529 }
530
531 fn parse_fn_item(&mut self) -> Result<Item, QalaError> {
535 let fn_span = self.expect(&TokenKind::Fn)?;
536 let (first_name, _first_span) = self.expect_ident()?;
537 let (type_name, name) = if self.eat(&TokenKind::Dot) {
540 let (method, _) = self.expect_ident()?;
541 (Some(first_name), method)
542 } else {
543 (None, first_name)
544 };
545 let params = self.parse_fn_params(type_name.is_some())?;
546 let ret_ty = if self.eat(&TokenKind::Arrow) {
547 Some(self.parse_type()?)
548 } else {
549 None
550 };
551 let effect = self.parse_optional_effect()?.map(|(e, _span)| e);
552 let body = self.parse_block()?;
553 let span = fn_span.to(body.span);
554 Ok(Item::Fn(FnDecl {
555 type_name,
556 name,
557 params,
558 ret_ty,
559 effect,
560 body,
561 span,
562 }))
563 }
564
565 fn parse_fn_params(&mut self, is_method: bool) -> Result<Vec<Param>, QalaError> {
572 let open_span = self.expect(&TokenKind::LParen)?;
573 self.open_delims.push((TokenKind::LParen, open_span));
574 let mut params: Vec<Param> = Vec::new();
575 if !self.check(&TokenKind::RParen) {
578 params.push(self.parse_fn_param(true, is_method)?);
579 while self.eat(&TokenKind::Comma) {
580 if self.check(&TokenKind::RParen) {
581 break;
582 }
583 params.push(self.parse_fn_param(false, is_method)?);
584 }
585 }
586 if !self.check(&TokenKind::RParen) {
587 self.open_delims.pop();
588 return Err(QalaError::UnclosedDelimiter {
589 span: open_span,
590 opener: TokenKind::LParen,
591 found: self.peek().clone(),
592 });
593 }
594 self.advance();
595 self.open_delims.pop();
596 Ok(params)
597 }
598
599 fn parse_fn_param(&mut self, is_first: bool, is_method: bool) -> Result<Param, QalaError> {
603 if self.check(&TokenKind::SelfKw) {
604 let span = self.advance().span;
605 if is_first && is_method {
606 return Ok(Param {
607 is_self: true,
608 name: "self".to_string(),
609 ty: None,
610 default: None,
611 span,
612 });
613 }
614 return Err(QalaError::Parse {
618 span,
619 message: "`self` is only legal as the first parameter of a method".to_string(),
620 });
621 }
622 let (name, name_span) = self.expect_ident()?;
623 self.expect(&TokenKind::Colon)?;
624 let ty = self.parse_type()?;
625 let ty_span = ty.span();
626 let default = if self.eat(&TokenKind::Eq) {
627 Some(self.parse_expr()?)
628 } else {
629 None
630 };
631 let end_span = match &default {
632 Some(e) => e.span(),
633 None => ty_span,
634 };
635 Ok(Param {
636 is_self: false,
637 name,
638 ty: Some(ty),
639 default,
640 span: name_span.to(end_span),
641 })
642 }
643
644 fn parse_optional_effect(&mut self) -> Result<Option<(Effect, Span)>, QalaError> {
649 if !self.eat(&TokenKind::Is) {
650 return Ok(None);
651 }
652 let effect = match self.peek() {
653 TokenKind::Pure => Effect::Pure,
654 TokenKind::Io => Effect::Io,
655 TokenKind::Alloc => Effect::Alloc,
656 TokenKind::Panic => Effect::Panic,
657 _ => {
658 return Err(self.unexpected(&[
659 TokenKind::Pure,
660 TokenKind::Io,
661 TokenKind::Alloc,
662 TokenKind::Panic,
663 ]));
664 }
665 };
666 let kw_span = self.advance().span;
667 Ok(Some((effect, kw_span)))
668 }
669
670 fn parse_struct_item(&mut self) -> Result<StructDecl, QalaError> {
673 let kw_span = self.expect(&TokenKind::Struct)?;
674 let (name, _) = self.expect_ident()?;
675 let (fields, close) = self.delimited_list(
676 TokenKind::LBrace,
677 TokenKind::RBrace,
678 TokenKind::Comma,
679 |p| {
680 let (fname, fname_span) = p.expect_ident()?;
681 p.expect(&TokenKind::Colon)?;
682 let fty = p.parse_type()?;
683 let fty_span = fty.span();
684 Ok(Field {
685 name: fname,
686 ty: fty,
687 span: fname_span.to(fty_span),
688 })
689 },
690 )?;
691 Ok(StructDecl {
692 name,
693 fields,
694 span: kw_span.to(close),
695 })
696 }
697
698 fn parse_enum_item(&mut self) -> Result<EnumDecl, QalaError> {
702 let kw_span = self.expect(&TokenKind::Enum)?;
703 let (name, _) = self.expect_ident()?;
704 let (variants, close) = self.delimited_list(
705 TokenKind::LBrace,
706 TokenKind::RBrace,
707 TokenKind::Comma,
708 |p| {
709 let (vname, vname_span) = p.expect_ident()?;
710 if p.check(&TokenKind::LParen) {
711 let (fields, close) = p.delimited_list(
712 TokenKind::LParen,
713 TokenKind::RParen,
714 TokenKind::Comma,
715 |q| q.parse_type(),
716 )?;
717 Ok(Variant {
718 name: vname,
719 fields,
720 span: vname_span.to(close),
721 })
722 } else {
723 Ok(Variant {
724 name: vname,
725 fields: Vec::new(),
726 span: vname_span,
727 })
728 }
729 },
730 )?;
731 Ok(EnumDecl {
732 name,
733 variants,
734 span: kw_span.to(close),
735 })
736 }
737
738 fn parse_interface_item(&mut self) -> Result<InterfaceDecl, QalaError> {
743 let kw_span = self.expect(&TokenKind::Interface)?;
744 let (name, _) = self.expect_ident()?;
745 let (methods, close) = self.delimited_list(
746 TokenKind::LBrace,
747 TokenKind::RBrace,
748 TokenKind::Comma,
749 |p| {
750 let fn_span = p.expect(&TokenKind::Fn)?;
751 let (mname, _mname_span) = p.expect_ident()?;
752 let params = p.parse_fn_params(true)?;
754 let ret_ty = if p.eat(&TokenKind::Arrow) {
755 Some(p.parse_type()?)
756 } else {
757 None
758 };
759 let effect_with_span = p.parse_optional_effect()?;
760 let end = match (&ret_ty, &effect_with_span) {
764 (Some(ret), _) => ret.span(),
765 (None, Some((_e, effect_span))) => *effect_span,
766 (None, None) => fn_span,
767 };
768 let effect = effect_with_span.map(|(e, _span)| e);
769 Ok(MethodSig {
770 name: mname,
771 params,
772 ret_ty,
773 effect,
774 span: fn_span.to(end),
775 })
776 },
777 )?;
778 Ok(InterfaceDecl {
779 name,
780 methods,
781 span: kw_span.to(close),
782 })
783 }
784
785 pub fn parse_expr(&mut self) -> Result<Expr, QalaError> {
799 self.expr_bp(0, ExprCtx::Normal)
800 }
801
802 fn expr_bp(&mut self, min_bp: u8, ctx: ExprCtx) -> Result<Expr, QalaError> {
818 self.enter()?;
819 let result = self.expr_bp_inner(min_bp, ctx);
820 self.exit();
821 result
822 }
823
824 fn expr_bp_inner(&mut self, min_bp: u8, ctx: ExprCtx) -> Result<Expr, QalaError> {
825 let mut lhs = self.parse_primary(ctx)?;
827
828 loop {
830 let op = self.peek().clone();
831 if let Some((lbp, ())) = postfix_bp(&op) {
834 if lbp < min_bp {
835 break;
836 }
837 lhs = self.fold_postfix(lhs, &op)?;
838 continue;
839 }
840 if let Some((lbp, rbp)) = infix_bp(&op) {
845 if lbp < min_bp {
846 break;
847 }
848 let op_tok = self.advance().clone();
849 lhs = self.fold_infix(lhs, op_tok, rbp, ctx)?;
850 continue;
851 }
852 break;
853 }
854 Ok(lhs)
855 }
856
857 fn parse_primary(&mut self, ctx: ExprCtx) -> Result<Expr, QalaError> {
862 match self.peek().clone() {
863 TokenKind::Int(v) => {
865 let span = self.advance().span;
866 Ok(Expr::Int { value: v, span })
867 }
868 TokenKind::Float(v) => {
869 let span = self.advance().span;
870 Ok(Expr::Float { value: v, span })
871 }
872 TokenKind::Byte(v) => {
873 let span = self.advance().span;
874 Ok(Expr::Byte { value: v, span })
875 }
876 TokenKind::Str(s) => {
877 let span = self.advance().span;
878 Ok(Expr::Str { value: s, span })
879 }
880 TokenKind::True => {
881 let span = self.advance().span;
882 Ok(Expr::Bool { value: true, span })
883 }
884 TokenKind::False => {
885 let span = self.advance().span;
886 Ok(Expr::Bool { value: false, span })
887 }
888 TokenKind::Ident(name) => self.parse_ident_or_struct_literal(name, ctx),
893 TokenKind::LParen => self.parse_paren_or_tuple(),
896 TokenKind::LBracket => self.parse_array_literal(),
898 TokenKind::LBrace => self.parse_block_expr(),
900 TokenKind::StrStart(_) => self.parse_interpolation(),
903 TokenKind::Match => self.parse_match(),
905 TokenKind::SelfKw => {
909 let span = self.advance().span;
910 Ok(Expr::Ident {
911 name: "self".to_string(),
912 span,
913 })
914 }
915 TokenKind::Bang | TokenKind::Minus | TokenKind::Comptime => self.parse_prefix(),
917 _ => Err(self.unexpected(&[
919 TokenKind::Int(0),
920 TokenKind::Float(0.0),
921 TokenKind::Byte(0),
922 TokenKind::Str(String::new()),
923 TokenKind::StrStart(String::new()),
924 TokenKind::True,
925 TokenKind::False,
926 TokenKind::Ident(String::new()),
927 TokenKind::LParen,
928 TokenKind::LBracket,
929 TokenKind::LBrace,
930 TokenKind::Match,
931 TokenKind::Bang,
932 TokenKind::Minus,
933 TokenKind::Comptime,
934 ])),
935 }
936 }
937
938 fn parse_ident_or_struct_literal(
948 &mut self,
949 name: String,
950 ctx: ExprCtx,
951 ) -> Result<Expr, QalaError> {
952 let name_span = self.advance().span;
953 if matches!(ctx, ExprCtx::Normal) && self.check(&TokenKind::LBrace) {
954 let (fields, close) = self.delimited_list(
955 TokenKind::LBrace,
956 TokenKind::RBrace,
957 TokenKind::Comma,
958 |p| p.parse_field_init(),
959 )?;
960 Ok(Expr::StructLit {
961 name,
962 fields,
963 span: name_span.to(close),
964 })
965 } else {
966 Ok(Expr::Ident {
967 name,
968 span: name_span,
969 })
970 }
971 }
972
973 fn parse_field_init(&mut self) -> Result<FieldInit, QalaError> {
975 let (name, name_span) = self.expect_ident()?;
976 self.expect(&TokenKind::Colon)?;
977 let value = self.parse_expr()?;
978 let span = name_span.to(value.span());
979 Ok(FieldInit { name, value, span })
980 }
981
982 fn parse_paren_or_tuple(&mut self) -> Result<Expr, QalaError> {
990 let open_span = self.expect(&TokenKind::LParen)?;
991 self.open_delims.push((TokenKind::LParen, open_span));
992 if self.check(&TokenKind::RParen) {
994 let close = self.advance().span;
995 self.open_delims.pop();
996 return Ok(Expr::Tuple {
997 elems: Vec::new(),
998 span: open_span.to(close),
999 });
1000 }
1001 let first = self.parse_expr()?;
1002 if self.check(&TokenKind::RParen) {
1004 let close = self.advance().span;
1005 self.open_delims.pop();
1006 return Ok(Expr::Paren {
1007 inner: Box::new(first),
1008 span: open_span.to(close),
1009 });
1010 }
1011 if !self.eat(&TokenKind::Comma) {
1013 self.open_delims.pop();
1014 return Err(QalaError::UnclosedDelimiter {
1015 span: open_span,
1016 opener: TokenKind::LParen,
1017 found: self.peek().clone(),
1018 });
1019 }
1020 let mut elems = vec![first];
1021 loop {
1022 if self.check(&TokenKind::RParen) {
1023 break;
1024 }
1025 elems.push(self.parse_expr()?);
1026 if !self.eat(&TokenKind::Comma) {
1027 break;
1028 }
1029 }
1030 if !self.check(&TokenKind::RParen) {
1031 self.open_delims.pop();
1032 return Err(QalaError::UnclosedDelimiter {
1033 span: open_span,
1034 opener: TokenKind::LParen,
1035 found: self.peek().clone(),
1036 });
1037 }
1038 let close = self.advance().span;
1039 self.open_delims.pop();
1040 Ok(Expr::Tuple {
1041 elems,
1042 span: open_span.to(close),
1043 })
1044 }
1045
1046 fn parse_array_literal(&mut self) -> Result<Expr, QalaError> {
1052 let open_span = self.expect(&TokenKind::LBracket)?;
1053 self.open_delims.push((TokenKind::LBracket, open_span));
1054 if self.check(&TokenKind::RBracket) {
1056 let close = self.advance().span;
1057 self.open_delims.pop();
1058 return Ok(Expr::ArrayLit {
1059 elems: Vec::new(),
1060 span: open_span.to(close),
1061 });
1062 }
1063 let first = self.parse_expr()?;
1064 if self.eat(&TokenKind::Semi) {
1066 let count = self.parse_expr()?;
1067 if !self.check(&TokenKind::RBracket) {
1068 self.open_delims.pop();
1069 return Err(QalaError::UnclosedDelimiter {
1070 span: open_span,
1071 opener: TokenKind::LBracket,
1072 found: self.peek().clone(),
1073 });
1074 }
1075 let close = self.advance().span;
1076 self.open_delims.pop();
1077 return Ok(Expr::ArrayRepeat {
1078 value: Box::new(first),
1079 count: Box::new(count),
1080 span: open_span.to(close),
1081 });
1082 }
1083 let mut elems = vec![first];
1085 if self.eat(&TokenKind::Comma) {
1086 loop {
1087 if self.check(&TokenKind::RBracket) {
1088 break;
1089 }
1090 elems.push(self.parse_expr()?);
1091 if !self.eat(&TokenKind::Comma) {
1092 break;
1093 }
1094 }
1095 }
1096 if !self.check(&TokenKind::RBracket) {
1097 self.open_delims.pop();
1098 return Err(QalaError::UnclosedDelimiter {
1099 span: open_span,
1100 opener: TokenKind::LBracket,
1101 found: self.peek().clone(),
1102 });
1103 }
1104 let close = self.advance().span;
1105 self.open_delims.pop();
1106 Ok(Expr::ArrayLit {
1107 elems,
1108 span: open_span.to(close),
1109 })
1110 }
1111
1112 fn parse_block_expr(&mut self) -> Result<Expr, QalaError> {
1114 let block = self.parse_block()?;
1115 let span = block.span;
1116 Ok(Expr::Block { block, span })
1117 }
1118
1119 fn parse_block(&mut self) -> Result<Block, QalaError> {
1135 self.enter()?;
1136 let result = self.parse_block_inner();
1137 self.exit();
1138 result
1139 }
1140
1141 fn parse_block_inner(&mut self) -> Result<Block, QalaError> {
1142 let open_span = self.expect(&TokenKind::LBrace)?;
1143 self.open_delims.push((TokenKind::LBrace, open_span));
1144 let mut stmts: Vec<Stmt> = Vec::new();
1145 let mut value: Option<Box<Expr>> = None;
1146 loop {
1147 if self.check(&TokenKind::RBrace) {
1148 break;
1149 }
1150 if is_stmt_head(self.peek()) {
1151 let stmt = self.parse_stmt()?;
1155 stmts.push(stmt);
1156 self.eat(&TokenKind::Semi);
1157 continue;
1158 }
1159 let expr = self.parse_expr()?;
1163 let expr_span = expr.span();
1164 if self.eat(&TokenKind::Semi) {
1165 stmts.push(Stmt::Expr {
1167 expr,
1168 span: expr_span,
1169 });
1170 continue;
1171 }
1172 if self.check(&TokenKind::RBrace) {
1173 value = Some(Box::new(expr));
1176 break;
1177 }
1178 stmts.push(Stmt::Expr {
1182 expr,
1183 span: expr_span,
1184 });
1185 }
1186 if !self.check(&TokenKind::RBrace) {
1187 self.open_delims.pop();
1188 return Err(QalaError::UnclosedDelimiter {
1189 span: open_span,
1190 opener: TokenKind::LBrace,
1191 found: self.peek().clone(),
1192 });
1193 }
1194 let close = self.advance().span;
1195 self.open_delims.pop();
1196 Ok(Block {
1197 stmts,
1198 value,
1199 span: open_span.to(close),
1200 })
1201 }
1202
1203 fn parse_stmt(&mut self) -> Result<Stmt, QalaError> {
1214 self.enter()?;
1215 let result = self.parse_stmt_inner();
1216 self.exit();
1217 result
1218 }
1219
1220 fn parse_stmt_inner(&mut self) -> Result<Stmt, QalaError> {
1221 match self.peek() {
1222 TokenKind::Let => self.parse_let_stmt(),
1223 TokenKind::If => self.parse_if_stmt(),
1224 TokenKind::While => self.parse_while_stmt(),
1225 TokenKind::For => self.parse_for_stmt(),
1226 TokenKind::Return => self.parse_return_stmt(),
1227 TokenKind::Break => {
1228 let span = self.advance().span;
1229 Ok(Stmt::Break { span })
1230 }
1231 TokenKind::Continue => {
1232 let span = self.advance().span;
1233 Ok(Stmt::Continue { span })
1234 }
1235 TokenKind::Defer => self.parse_defer_stmt(),
1236 _ => Err(self.unexpected(&[
1239 TokenKind::Let,
1240 TokenKind::If,
1241 TokenKind::While,
1242 TokenKind::For,
1243 TokenKind::Return,
1244 TokenKind::Break,
1245 TokenKind::Continue,
1246 TokenKind::Defer,
1247 ])),
1248 }
1249 }
1250
1251 fn parse_let_stmt(&mut self) -> Result<Stmt, QalaError> {
1255 let kw_span = self.expect(&TokenKind::Let)?;
1256 let is_mut = self.eat(&TokenKind::Mut);
1257 let (name, _name_span) = self.expect_ident()?;
1258 let ty = if self.eat(&TokenKind::Colon) {
1259 Some(self.parse_type()?)
1260 } else {
1261 None
1262 };
1263 self.expect(&TokenKind::Eq)?;
1265 let init = self.parse_expr()?;
1266 let span = kw_span.to(init.span());
1267 Ok(Stmt::Let {
1268 is_mut,
1269 name,
1270 ty,
1271 init,
1272 span,
1273 })
1274 }
1275
1276 fn parse_if_stmt(&mut self) -> Result<Stmt, QalaError> {
1281 let kw_span = self.expect(&TokenKind::If)?;
1282 let cond = self.parse_expr_no_struct()?;
1283 let then_block = self.parse_block()?;
1284 let mut tail_span = then_block.span;
1285 let else_branch = if self.eat(&TokenKind::Else) {
1286 if self.check(&TokenKind::If) {
1287 let inner = self.parse_stmt()?;
1290 tail_span = tail_span.to(inner.span());
1291 Some(ElseBranch::If(Box::new(inner)))
1292 } else {
1293 let block = self.parse_block()?;
1294 tail_span = tail_span.to(block.span);
1295 Some(ElseBranch::Block(block))
1296 }
1297 } else {
1298 None
1299 };
1300 Ok(Stmt::If {
1301 cond,
1302 then_block,
1303 else_branch,
1304 span: kw_span.to(tail_span),
1305 })
1306 }
1307
1308 fn parse_while_stmt(&mut self) -> Result<Stmt, QalaError> {
1310 let kw_span = self.expect(&TokenKind::While)?;
1311 let cond = self.parse_expr_no_struct()?;
1312 let body = self.parse_block()?;
1313 let span = kw_span.to(body.span);
1314 Ok(Stmt::While { cond, body, span })
1315 }
1316
1317 fn parse_for_stmt(&mut self) -> Result<Stmt, QalaError> {
1322 let kw_span = self.expect(&TokenKind::For)?;
1323 let (var, _) = self.expect_ident()?;
1324 self.expect(&TokenKind::In)?;
1325 let iter = self.parse_expr_no_struct()?;
1326 let body = self.parse_block()?;
1327 let span = kw_span.to(body.span);
1328 Ok(Stmt::For {
1329 var,
1330 iter,
1331 body,
1332 span,
1333 })
1334 }
1335
1336 fn parse_return_stmt(&mut self) -> Result<Stmt, QalaError> {
1340 let kw_span = self.expect(&TokenKind::Return)?;
1341 if self.check(&TokenKind::RBrace)
1345 || matches!(self.peek(), TokenKind::Eof)
1346 || is_stmt_head(self.peek())
1347 {
1348 return Ok(Stmt::Return {
1349 value: None,
1350 span: kw_span,
1351 });
1352 }
1353 let value = self.parse_expr()?;
1354 let span = kw_span.to(value.span());
1355 Ok(Stmt::Return {
1356 value: Some(value),
1357 span,
1358 })
1359 }
1360
1361 fn parse_defer_stmt(&mut self) -> Result<Stmt, QalaError> {
1365 let kw_span = self.expect(&TokenKind::Defer)?;
1366 let expr = self.parse_expr()?;
1367 let span = kw_span.to(expr.span());
1368 Ok(Stmt::Defer { expr, span })
1369 }
1370
1371 fn parse_expr_no_struct(&mut self) -> Result<Expr, QalaError> {
1375 self.expr_bp(0, ExprCtx::NoStructLiteral)
1376 }
1377
1378 fn parse_interpolation(&mut self) -> Result<Expr, QalaError> {
1383 let (start_text, start_span) = match self.peek().clone() {
1385 TokenKind::StrStart(s) => {
1386 let span = self.advance().span;
1387 (s, span)
1388 }
1389 _ => return Err(self.unexpected(&[TokenKind::StrStart(String::new())])),
1390 };
1391 let mut parts: Vec<InterpPart> = vec![InterpPart::Literal(start_text)];
1392 let end_span: Span;
1393 loop {
1394 self.expect(&TokenKind::InterpStart)?;
1398 let inner = self.parse_expr()?;
1399 parts.push(InterpPart::Expr(inner));
1400 self.expect(&TokenKind::InterpEnd)?;
1401 match self.peek().clone() {
1402 TokenKind::StrMid(t) => {
1403 let _span = self.advance().span;
1404 parts.push(InterpPart::Literal(t));
1405 }
1407 TokenKind::StrEnd(t) => {
1408 let span = self.advance().span;
1409 parts.push(InterpPart::Literal(t));
1410 end_span = span;
1411 break;
1412 }
1413 _ => {
1414 return Err(self.unexpected(&[
1415 TokenKind::StrMid(String::new()),
1416 TokenKind::StrEnd(String::new()),
1417 ]));
1418 }
1419 }
1420 }
1421 Ok(Expr::Interpolation {
1422 parts,
1423 span: start_span.to(end_span),
1424 })
1425 }
1426
1427 fn parse_match(&mut self) -> Result<Expr, QalaError> {
1434 let kw_span = self.expect(&TokenKind::Match)?;
1435 let scrutinee = self.expr_bp(0, ExprCtx::NoStructLiteral)?;
1436 let open_span = self.expect(&TokenKind::LBrace)?;
1437 self.open_delims.push((TokenKind::LBrace, open_span));
1438 let mut arms: Vec<MatchArm> = Vec::new();
1439 loop {
1440 if self.check(&TokenKind::RBrace) {
1441 break;
1442 }
1443 let pattern = self.parse_pattern()?;
1444 let pattern_span = pattern.span();
1445 let guard = if self.eat(&TokenKind::If) {
1449 Some(self.parse_expr_no_struct()?)
1450 } else {
1451 None
1452 };
1453 self.expect(&TokenKind::FatArrow)?;
1454 let body = if self.check(&TokenKind::LBrace) {
1455 MatchArmBody::Block(self.parse_block()?)
1456 } else {
1457 MatchArmBody::Expr(Box::new(self.parse_expr()?))
1458 };
1459 let body_span = match &body {
1460 MatchArmBody::Expr(e) => e.span(),
1461 MatchArmBody::Block(b) => b.span,
1462 };
1463 arms.push(MatchArm {
1464 pattern,
1465 guard,
1466 body,
1467 span: pattern_span.to(body_span),
1468 });
1469 if !self.eat(&TokenKind::Comma) {
1473 break;
1474 }
1475 }
1476 if arms.is_empty() {
1477 let close_span = self.peek_span();
1480 self.open_delims.pop();
1481 return Err(QalaError::Parse {
1482 span: kw_span.to(close_span),
1483 message: "match needs at least one arm".to_string(),
1484 });
1485 }
1486 if !self.check(&TokenKind::RBrace) {
1487 self.open_delims.pop();
1488 return Err(QalaError::UnclosedDelimiter {
1489 span: open_span,
1490 opener: TokenKind::LBrace,
1491 found: self.peek().clone(),
1492 });
1493 }
1494 let close_span = self.advance().span;
1495 self.open_delims.pop();
1496 Ok(Expr::Match {
1497 scrutinee: Box::new(scrutinee),
1498 arms,
1499 span: kw_span.to(close_span),
1500 })
1501 }
1502
1503 fn parse_pattern(&mut self) -> Result<Pattern, QalaError> {
1513 match self.peek().clone() {
1514 TokenKind::Ident(name) => {
1515 let name_span = self.advance().span;
1516 if name == "_" {
1518 return Ok(Pattern::Wildcard { span: name_span });
1519 }
1520 if self.check(&TokenKind::LParen) {
1522 let (sub, close) = self.delimited_list(
1523 TokenKind::LParen,
1524 TokenKind::RParen,
1525 TokenKind::Comma,
1526 |p| p.parse_pattern(),
1527 )?;
1528 return Ok(Pattern::Variant {
1529 name,
1530 sub,
1531 span: name_span.to(close),
1532 });
1533 }
1534 Ok(Pattern::Binding {
1537 name,
1538 span: name_span,
1539 })
1540 }
1541 TokenKind::Int(v) => {
1542 let span = self.advance().span;
1543 Ok(Pattern::Int { value: v, span })
1544 }
1545 TokenKind::Float(v) => {
1546 let span = self.advance().span;
1547 Ok(Pattern::Float { value: v, span })
1548 }
1549 TokenKind::Byte(v) => {
1550 let span = self.advance().span;
1551 Ok(Pattern::Byte { value: v, span })
1552 }
1553 TokenKind::Str(s) => {
1554 let span = self.advance().span;
1555 Ok(Pattern::Str { value: s, span })
1556 }
1557 TokenKind::True => {
1558 let span = self.advance().span;
1559 Ok(Pattern::Bool { value: true, span })
1560 }
1561 TokenKind::False => {
1562 let span = self.advance().span;
1563 Ok(Pattern::Bool { value: false, span })
1564 }
1565 _ => Err(self.unexpected(&[
1566 TokenKind::Ident(String::new()),
1567 TokenKind::Int(0),
1568 TokenKind::Float(0.0),
1569 TokenKind::Byte(0),
1570 TokenKind::Str(String::new()),
1571 TokenKind::True,
1572 TokenKind::False,
1573 ])),
1574 }
1575 }
1576
1577 fn parse_prefix(&mut self) -> Result<Expr, QalaError> {
1581 let op_tok = self.advance().clone();
1582 let ((), rbp) = prefix_bp(&op_tok.kind);
1583 let operand = self.expr_bp(rbp, ExprCtx::Normal)?;
1584 let span = op_tok.span.to(operand.span());
1585 match op_tok.kind {
1586 TokenKind::Bang => Ok(Expr::Unary {
1587 op: UnaryOp::Not,
1588 operand: Box::new(operand),
1589 span,
1590 }),
1591 TokenKind::Minus => Ok(Expr::Unary {
1592 op: UnaryOp::Neg,
1593 operand: Box::new(operand),
1594 span,
1595 }),
1596 TokenKind::Comptime => Ok(Expr::Comptime {
1597 body: Box::new(operand),
1598 span,
1599 }),
1600 _ => Err(QalaError::Parse {
1603 span: op_tok.span,
1604 message: "internal: prefix on a non-prefix token".to_string(),
1605 }),
1606 }
1607 }
1608
1609 fn fold_postfix(&mut self, lhs: Expr, op: &TokenKind) -> Result<Expr, QalaError> {
1612 match op {
1613 TokenKind::Dot => {
1614 self.advance(); let (name, name_span) = self.expect_ident()?;
1616 if self.check(&TokenKind::LParen) {
1619 let (args, close) = self.delimited_list(
1620 TokenKind::LParen,
1621 TokenKind::RParen,
1622 TokenKind::Comma,
1623 |p| p.parse_expr(),
1624 )?;
1625 let lhs_span = lhs.span();
1626 Ok(Expr::MethodCall {
1627 receiver: Box::new(lhs),
1628 name,
1629 args,
1630 span: lhs_span.to(close),
1631 })
1632 } else {
1633 let lhs_span = lhs.span();
1634 Ok(Expr::FieldAccess {
1635 obj: Box::new(lhs),
1636 name,
1637 span: lhs_span.to(name_span),
1638 })
1639 }
1640 }
1641 TokenKind::LParen => {
1642 let (args, close) = self.delimited_list(
1643 TokenKind::LParen,
1644 TokenKind::RParen,
1645 TokenKind::Comma,
1646 |p| p.parse_expr(),
1647 )?;
1648 let lhs_span = lhs.span();
1649 Ok(Expr::Call {
1650 callee: Box::new(lhs),
1651 args,
1652 span: lhs_span.to(close),
1653 })
1654 }
1655 TokenKind::LBracket => {
1656 let open_span = self.advance().span;
1657 self.open_delims.push((TokenKind::LBracket, open_span));
1658 let idx = self.parse_expr()?;
1659 if !self.check(&TokenKind::RBracket) {
1660 self.open_delims.pop();
1661 return Err(QalaError::UnclosedDelimiter {
1662 span: open_span,
1663 opener: TokenKind::LBracket,
1664 found: self.peek().clone(),
1665 });
1666 }
1667 let close = self.advance().span;
1668 self.open_delims.pop();
1669 let lhs_span = lhs.span();
1670 Ok(Expr::Index {
1671 obj: Box::new(lhs),
1672 index: Box::new(idx),
1673 span: lhs_span.to(close),
1674 })
1675 }
1676 TokenKind::Question => {
1677 let q_span = self.advance().span;
1678 let lhs_span = lhs.span();
1679 Ok(Expr::Try {
1680 expr: Box::new(lhs),
1681 span: lhs_span.to(q_span),
1682 })
1683 }
1684 _ => Err(QalaError::Parse {
1685 span: self.peek_span(),
1686 message: "internal: postfix_bp returned Some for a non-postfix token".to_string(),
1687 }),
1688 }
1689 }
1690
1691 fn fold_infix(
1697 &mut self,
1698 lhs: Expr,
1699 op_tok: Token,
1700 rbp: u8,
1701 ctx: ExprCtx,
1702 ) -> Result<Expr, QalaError> {
1703 match op_tok.kind {
1704 TokenKind::PipeGt => {
1705 let rhs = self.parse_pipeline_rhs(op_tok.span)?;
1710 let lhs_span = lhs.span();
1711 let rhs_span = rhs.span();
1712 Ok(Expr::Pipeline {
1713 lhs: Box::new(lhs),
1714 call: Box::new(rhs),
1715 span: lhs_span.to(rhs_span),
1716 })
1717 }
1718 TokenKind::Or => {
1719 let rhs = self.expr_bp(rbp, ctx)?;
1720 let lhs_span = lhs.span();
1721 let rhs_span = rhs.span();
1722 Ok(Expr::OrElse {
1723 expr: Box::new(lhs),
1724 fallback: Box::new(rhs),
1725 span: lhs_span.to(rhs_span),
1726 })
1727 }
1728 TokenKind::DotDot | TokenKind::DotDotEq => {
1729 if matches!(lhs, Expr::Range { .. }) {
1736 return Err(QalaError::Parse {
1737 span: op_tok.span,
1738 message: "range operators cannot be chained; use parentheses if nested ranges are intended".to_string(),
1739 });
1740 }
1741 let inclusive = matches!(op_tok.kind, TokenKind::DotDotEq);
1742 let rhs = self.expr_bp(rbp, ctx)?;
1743 let lhs_span = lhs.span();
1744 let rhs_span = rhs.span();
1745 Ok(Expr::Range {
1746 start: Some(Box::new(lhs)),
1747 end: Some(Box::new(rhs)),
1748 inclusive,
1749 span: lhs_span.to(rhs_span),
1750 })
1751 }
1752 ref k if binop_of(k).is_some() => {
1753 let bop = binop_of(k).expect("checked by the guard");
1754 let rhs = self.expr_bp(rbp, ctx)?;
1755 let lhs_span = lhs.span();
1756 let rhs_span = rhs.span();
1757 Ok(Expr::Binary {
1758 op: bop,
1759 lhs: Box::new(lhs),
1760 rhs: Box::new(rhs),
1761 span: lhs_span.to(rhs_span),
1762 })
1763 }
1764 _ => Err(QalaError::Parse {
1765 span: op_tok.span,
1766 message: "internal: infix_bp returned Some for an unhandled token".to_string(),
1767 }),
1768 }
1769 }
1770
1771 fn parse_pipeline_rhs(&mut self, pipe_span: Span) -> Result<Expr, QalaError> {
1779 if !matches!(self.peek(), TokenKind::Ident(_) | TokenKind::LParen) {
1787 return Err(QalaError::Parse {
1788 span: pipe_span,
1789 message: "expected a call after `|>`".to_string(),
1790 });
1791 }
1792 let rhs = self.expr_bp(infix_lbp_pipeline() + 1, ExprCtx::Normal)?;
1797 if !is_callable_shape(&rhs) {
1798 return Err(QalaError::Parse {
1799 span: pipe_span,
1800 message: "the right side of `|>` must be a call".to_string(),
1801 });
1802 }
1803 Ok(rhs)
1804 }
1805}
1806
1807#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1812enum ExprCtx {
1813 Normal,
1815 NoStructLiteral,
1818}
1819
1820fn postfix_bp(k: &TokenKind) -> Option<(u8, ())> {
1823 match k {
1824 TokenKind::Dot | TokenKind::LParen | TokenKind::LBracket | TokenKind::Question => {
1825 Some((100, ()))
1826 }
1827 _ => None,
1828 }
1829}
1830
1831fn prefix_bp(k: &TokenKind) -> ((), u8) {
1837 match k {
1838 TokenKind::Bang | TokenKind::Minus | TokenKind::Comptime => ((), 90),
1839 _ => ((), u8::MAX),
1844 }
1845}
1846
1847fn infix_bp(k: &TokenKind) -> Option<(u8, u8)> {
1859 Some(match k {
1860 TokenKind::Star | TokenKind::Slash | TokenKind::Percent => (80, 81),
1862 TokenKind::Plus | TokenKind::Minus => (70, 71),
1864 TokenKind::DotDot | TokenKind::DotDotEq => (60, 61),
1867 TokenKind::Lt
1869 | TokenKind::LtEq
1870 | TokenKind::Gt
1871 | TokenKind::GtEq
1872 | TokenKind::EqEq
1873 | TokenKind::BangEq => (50, 51),
1874 TokenKind::AmpAmp => (40, 41),
1876 TokenKind::PipePipe => (30, 31),
1877 TokenKind::PipeGt => (20, 21),
1879 TokenKind::Or => (10, 11),
1881 _ => return None,
1882 })
1883}
1884
1885fn infix_lbp_pipeline() -> u8 {
1888 20
1889}
1890
1891fn binop_of(k: &TokenKind) -> Option<BinOp> {
1895 Some(match k {
1896 TokenKind::Plus => BinOp::Add,
1897 TokenKind::Minus => BinOp::Sub,
1898 TokenKind::Star => BinOp::Mul,
1899 TokenKind::Slash => BinOp::Div,
1900 TokenKind::Percent => BinOp::Rem,
1901 TokenKind::EqEq => BinOp::Eq,
1902 TokenKind::BangEq => BinOp::Ne,
1903 TokenKind::Lt => BinOp::Lt,
1904 TokenKind::LtEq => BinOp::Le,
1905 TokenKind::Gt => BinOp::Gt,
1906 TokenKind::GtEq => BinOp::Ge,
1907 TokenKind::AmpAmp => BinOp::And,
1908 TokenKind::PipePipe => BinOp::Or,
1909 _ => return None,
1910 })
1911}
1912
1913fn is_callable_shape(e: &Expr) -> bool {
1920 matches!(
1921 e,
1922 Expr::Ident { .. } | Expr::Call { .. } | Expr::FieldAccess { .. } | Expr::MethodCall { .. }
1923 )
1924}
1925
1926fn is_stmt_head(k: &TokenKind) -> bool {
1934 matches!(
1935 k,
1936 TokenKind::Let
1937 | TokenKind::If
1938 | TokenKind::While
1939 | TokenKind::For
1940 | TokenKind::Return
1941 | TokenKind::Break
1942 | TokenKind::Continue
1943 | TokenKind::Defer
1944 )
1945}
1946
1947#[cfg(test)]
1948mod tests {
1949 use super::*;
1950 use crate::lexer::Lexer;
1951
1952 fn lex(src: &str) -> Vec<Token> {
1955 Lexer::tokenize(src).expect("expected successful tokenize")
1956 }
1957
1958 #[allow(dead_code)] fn parse_ok(src: &str) -> Ast {
1961 Parser::parse(&lex(src)).expect("expected a successful parse")
1962 }
1963
1964 fn parse_err(src: &str) -> QalaError {
1966 Parser::parse(&lex(src)).expect_err("expected a parse error")
1967 }
1968
1969 fn expr_of(src: &str) -> Expr {
1974 let toks = lex(src);
1975 let mut p = Parser {
1976 tokens: &toks,
1977 pos: 0,
1978 depth: 0,
1979 open_delims: Vec::new(),
1980 };
1981 let e = p
1982 .parse_expr()
1983 .expect("expected a successful expression parse");
1984 assert!(
1985 matches!(p.peek(), TokenKind::Eof),
1986 "expr_of left tokens unconsumed: next = {:?}",
1987 p.peek()
1988 );
1989 e
1990 }
1991
1992 fn expr_err(src: &str) -> QalaError {
1995 let toks = lex(src);
1996 let mut p = Parser {
1997 tokens: &toks,
1998 pos: 0,
1999 depth: 0,
2000 open_delims: Vec::new(),
2001 };
2002 p.parse_expr()
2003 .expect_err("expected an expression parse error")
2004 }
2005
2006 #[test]
2009 fn empty_program_parses_to_no_items() {
2010 let ast = parse_ok("");
2012 assert!(ast.is_empty());
2013 }
2014
2015 #[test]
2016 fn whitespace_and_comments_only_parses_to_no_items() {
2017 let ast = parse_ok(" \n// a comment\n ");
2019 assert!(ast.is_empty());
2020 }
2021
2022 #[test]
2023 fn a_program_with_a_non_item_token_at_the_top_level_is_a_clean_error() {
2024 let err = parse_err("let x = 5");
2027 match err {
2028 QalaError::UnexpectedToken {
2029 ref expected,
2030 ref found,
2031 ..
2032 } => {
2033 assert!(expected.contains(&TokenKind::Fn));
2034 assert!(expected.contains(&TokenKind::Struct));
2035 assert!(expected.contains(&TokenKind::Enum));
2036 assert!(expected.contains(&TokenKind::Interface));
2037 assert_eq!(found, &TokenKind::Let);
2038 }
2039 other => panic!("expected UnexpectedToken, got {other:?}"),
2040 }
2041 assert!(err.message().contains("expected"));
2042 }
2043
2044 fn type_of(src: &str) -> TypeExpr {
2050 let program = format!("fn f() -> {src} {{}}");
2051 let ast = parse_ok(&program);
2052 match ast.into_iter().next().expect("one item") {
2053 Item::Fn(d) => d.ret_ty.expect("a return type is present"),
2054 other => panic!("expected fn item, got {other:?}"),
2055 }
2056 }
2057
2058 #[test]
2059 fn primitive_type_names_parse_to_typeexpr_primitive() {
2060 let cases = [
2061 ("i64", PrimType::I64),
2062 ("f64", PrimType::F64),
2063 ("bool", PrimType::Bool),
2064 ("str", PrimType::Str),
2065 ("byte", PrimType::Byte),
2066 ("void", PrimType::Void),
2067 ];
2068 for (src, want) in cases {
2069 match type_of(src) {
2070 TypeExpr::Primitive { kind, .. } => assert_eq!(kind, want, "{src}"),
2071 other => panic!("expected Primitive for {src}, got {other:?}"),
2072 }
2073 }
2074 }
2075
2076 #[test]
2077 fn a_bare_ident_parses_to_typeexpr_named() {
2078 match type_of("Shape") {
2079 TypeExpr::Named { name, .. } => assert_eq!(name, "Shape"),
2080 other => panic!("expected Named, got {other:?}"),
2081 }
2082 }
2083
2084 #[test]
2085 fn a_fixed_array_type_carries_its_int_size() {
2086 match type_of("[i64; 5]") {
2087 TypeExpr::Array { elem, size, .. } => {
2088 assert!(matches!(
2089 *elem,
2090 TypeExpr::Primitive {
2091 kind: PrimType::I64,
2092 ..
2093 }
2094 ));
2095 assert_eq!(size, 5);
2096 }
2097 other => panic!("expected Array, got {other:?}"),
2098 }
2099 }
2100
2101 #[test]
2102 fn a_dyn_array_type_has_no_size() {
2103 match type_of("[i64]") {
2104 TypeExpr::DynArray { elem, .. } => {
2105 assert!(matches!(
2106 *elem,
2107 TypeExpr::Primitive {
2108 kind: PrimType::I64,
2109 ..
2110 }
2111 ));
2112 }
2113 other => panic!("expected DynArray, got {other:?}"),
2114 }
2115 }
2116
2117 #[test]
2118 fn tuple_versus_paren_type_distinguished_by_a_trailing_comma() {
2119 match type_of("(i64, str)") {
2121 TypeExpr::Tuple { elems, .. } => assert_eq!(elems.len(), 2),
2122 other => panic!("expected Tuple, got {other:?}"),
2123 }
2124 match type_of("(i64,)") {
2126 TypeExpr::Tuple { elems, .. } => assert_eq!(elems.len(), 1),
2127 other => panic!("expected Tuple, got {other:?}"),
2128 }
2129 match type_of("()") {
2131 TypeExpr::Tuple { elems, .. } => assert!(elems.is_empty()),
2132 other => panic!("expected zero-tuple, got {other:?}"),
2133 }
2134 match type_of("(i64)") {
2136 TypeExpr::Primitive {
2137 kind: PrimType::I64,
2138 ..
2139 } => {}
2140 other => panic!("expected unwrapped i64, got {other:?}"),
2141 }
2142 }
2143
2144 #[test]
2145 fn a_function_type_parses() {
2146 match type_of("fn(i64, bool) -> str") {
2147 TypeExpr::Fn { params, ret, .. } => {
2148 assert_eq!(params.len(), 2);
2149 assert!(matches!(
2150 params[0],
2151 TypeExpr::Primitive {
2152 kind: PrimType::I64,
2153 ..
2154 }
2155 ));
2156 assert!(matches!(
2157 params[1],
2158 TypeExpr::Primitive {
2159 kind: PrimType::Bool,
2160 ..
2161 }
2162 ));
2163 assert!(matches!(
2164 *ret,
2165 TypeExpr::Primitive {
2166 kind: PrimType::Str,
2167 ..
2168 }
2169 ));
2170 }
2171 other => panic!("expected Fn, got {other:?}"),
2172 }
2173 }
2174
2175 #[test]
2176 fn a_generic_type_parses_with_arguments() {
2177 match type_of("Result<str, str>") {
2178 TypeExpr::Generic { name, args, .. } => {
2179 assert_eq!(name, "Result");
2180 assert_eq!(args.len(), 2);
2181 }
2182 other => panic!("expected Generic, got {other:?}"),
2183 }
2184 }
2185
2186 #[test]
2187 fn nested_generics_use_two_gt_tokens_not_one_shift() {
2188 match type_of("Result<Option<i64>, str>") {
2192 TypeExpr::Generic { name, args, .. } => {
2193 assert_eq!(name, "Result");
2194 assert_eq!(args.len(), 2);
2195 match &args[0] {
2196 TypeExpr::Generic {
2197 name: inner_name,
2198 args: inner_args,
2199 ..
2200 } => {
2201 assert_eq!(inner_name, "Option");
2202 assert_eq!(inner_args.len(), 1);
2203 assert!(matches!(
2204 inner_args[0],
2205 TypeExpr::Primitive {
2206 kind: PrimType::I64,
2207 ..
2208 }
2209 ));
2210 }
2211 other => panic!("expected nested Generic, got {other:?}"),
2212 }
2213 assert!(matches!(
2214 args[1],
2215 TypeExpr::Primitive {
2216 kind: PrimType::Str,
2217 ..
2218 }
2219 ));
2220 }
2221 other => panic!("expected outer Generic, got {other:?}"),
2222 }
2223 }
2224
2225 #[test]
2228 fn a_minimal_fn_parses_with_no_params_no_return_no_effect() {
2229 let ast = parse_ok("fn g() {}");
2230 assert_eq!(ast.len(), 1);
2231 match &ast[0] {
2232 Item::Fn(d) => {
2233 assert_eq!(d.name, "g");
2234 assert!(d.type_name.is_none());
2235 assert!(d.params.is_empty());
2236 assert!(d.ret_ty.is_none());
2237 assert!(d.effect.is_none());
2238 assert!(d.body.stmts.is_empty());
2239 assert!(d.body.value.is_none());
2240 }
2241 other => panic!("expected Fn, got {other:?}"),
2242 }
2243 }
2244
2245 #[test]
2246 fn a_fn_parses_with_params_return_default_and_effect() {
2247 let ast = parse_ok("fn f(a: i64, b: i64 = 10) -> i64 is pure {}");
2248 match &ast[0] {
2249 Item::Fn(d) => {
2250 assert_eq!(d.name, "f");
2251 assert_eq!(d.params.len(), 2);
2252 assert_eq!(d.params[0].name, "a");
2253 assert!(d.params[0].default.is_none());
2254 assert_eq!(d.params[1].name, "b");
2255 match &d.params[1].default {
2256 Some(Expr::Int { value: 10, .. }) => {}
2257 other => panic!("expected default Int(10), got {other:?}"),
2258 }
2259 assert!(matches!(
2260 d.ret_ty,
2261 Some(TypeExpr::Primitive {
2262 kind: PrimType::I64,
2263 ..
2264 })
2265 ));
2266 assert_eq!(d.effect, Some(Effect::Pure));
2267 }
2268 other => panic!("expected Fn, got {other:?}"),
2269 }
2270 }
2271
2272 #[test]
2273 fn each_of_the_four_effect_keywords_parses() {
2274 for (src, want) in [
2275 ("fn f() is pure {}", Effect::Pure),
2276 ("fn f() is io {}", Effect::Io),
2277 ("fn f() is alloc {}", Effect::Alloc),
2278 ("fn f() is panic {}", Effect::Panic),
2279 ] {
2280 let ast = parse_ok(src);
2281 match &ast[0] {
2282 Item::Fn(d) => assert_eq!(d.effect, Some(want.clone()), "{src}"),
2283 other => panic!("expected Fn for {src}, got {other:?}"),
2284 }
2285 }
2286 }
2287
2288 #[test]
2289 fn a_method_definition_parses_with_self_as_the_first_param() {
2290 let ast = parse_ok("fn Point.area(self) -> f64 is pure { 3.14 }");
2291 match &ast[0] {
2292 Item::Fn(d) => {
2293 assert_eq!(d.type_name.as_deref(), Some("Point"));
2294 assert_eq!(d.name, "area");
2295 assert_eq!(d.params.len(), 1);
2296 assert!(d.params[0].is_self);
2297 assert_eq!(d.params[0].name, "self");
2298 assert!(d.params[0].ty.is_none());
2299 assert_eq!(d.effect, Some(Effect::Pure));
2300 }
2301 other => panic!("expected Fn, got {other:?}"),
2302 }
2303 }
2304
2305 #[test]
2306 fn self_on_a_free_function_is_a_parse_error() {
2307 let err = parse_err("fn f(self) {}");
2309 match err {
2310 QalaError::Parse { message, .. } => {
2311 assert!(message.contains("self"), "message was {message:?}");
2312 }
2313 other => panic!("expected QalaError::Parse, got {other:?}"),
2314 }
2315 }
2316
2317 #[test]
2318 fn self_outside_the_first_param_slot_of_a_method_is_a_parse_error() {
2319 let err = parse_err("fn Point.f(a: i64, self) {}");
2320 match err {
2321 QalaError::Parse { message, .. } => {
2322 assert!(message.contains("self"), "message was {message:?}");
2323 }
2324 other => panic!("expected QalaError::Parse, got {other:?}"),
2325 }
2326 }
2327
2328 #[test]
2329 fn self_in_method_body_parses_as_ident() {
2330 let ast = parse_ok("fn Point.area(self) -> f64 is pure { self.x }");
2334 match &ast[0] {
2335 Item::Fn(d) => {
2336 match d.body.value.as_deref() {
2338 Some(Expr::FieldAccess { obj, name, .. }) => {
2339 assert!(
2340 matches!(**obj, Expr::Ident { ref name, .. } if name == "self"),
2341 "expected Ident(\"self\"), got {:?}",
2342 obj
2343 );
2344 assert_eq!(name, "x");
2345 }
2346 other => panic!("expected FieldAccess on self, got {other:?}"),
2347 }
2348 }
2349 other => panic!("expected Fn, got {other:?}"),
2350 }
2351 }
2352
2353 #[test]
2354 fn self_method_call_in_body_parses() {
2355 let ast = parse_ok("fn Point.go(self) { self.foo() }");
2358 match &ast[0] {
2359 Item::Fn(d) => match d.body.value.as_deref() {
2360 Some(Expr::MethodCall { receiver, name, .. }) => {
2361 assert!(
2362 matches!(**receiver, Expr::Ident { ref name, .. } if name == "self"),
2363 "expected Ident(\"self\") as receiver, got {receiver:?}"
2364 );
2365 assert_eq!(name, "foo");
2366 }
2367 other => panic!("expected MethodCall trailing value, got {other:?}"),
2368 },
2369 other => panic!("expected Fn, got {other:?}"),
2370 }
2371 }
2372
2373 #[test]
2374 fn a_struct_with_typed_fields_parses() {
2375 let ast = parse_ok("struct Point { x: f64, y: f64 }");
2376 match &ast[0] {
2377 Item::Struct(d) => {
2378 assert_eq!(d.name, "Point");
2379 assert_eq!(d.fields.len(), 2);
2380 assert_eq!(d.fields[0].name, "x");
2381 assert!(matches!(
2382 d.fields[0].ty,
2383 TypeExpr::Primitive {
2384 kind: PrimType::F64,
2385 ..
2386 }
2387 ));
2388 assert_eq!(d.fields[1].name, "y");
2389 }
2390 other => panic!("expected Struct, got {other:?}"),
2391 }
2392 }
2393
2394 #[test]
2395 fn a_struct_with_a_trailing_comma_parses() {
2396 let ast = parse_ok("struct S { x: i64, y: i64, }");
2397 match &ast[0] {
2398 Item::Struct(d) => assert_eq!(d.fields.len(), 2),
2399 other => panic!("expected Struct, got {other:?}"),
2400 }
2401 }
2402
2403 #[test]
2404 fn an_enum_with_data_carrying_variants_parses() {
2405 let ast = parse_ok("enum Shape { Circle(f64), Rect(f64, f64), Triangle(f64, f64, f64) }");
2406 match &ast[0] {
2407 Item::Enum(d) => {
2408 assert_eq!(d.name, "Shape");
2409 assert_eq!(d.variants.len(), 3);
2410 assert_eq!(d.variants[0].name, "Circle");
2411 assert_eq!(d.variants[0].fields.len(), 1);
2412 assert_eq!(d.variants[1].name, "Rect");
2413 assert_eq!(d.variants[1].fields.len(), 2);
2414 assert_eq!(d.variants[2].name, "Triangle");
2415 assert_eq!(d.variants[2].fields.len(), 3);
2416 }
2417 other => panic!("expected Enum, got {other:?}"),
2418 }
2419 }
2420
2421 #[test]
2422 fn an_enum_with_a_no_data_variant_parses() {
2423 let ast = parse_ok("enum E { A, B(i64), }");
2424 match &ast[0] {
2425 Item::Enum(d) => {
2426 assert_eq!(d.variants.len(), 2);
2427 assert_eq!(d.variants[0].name, "A");
2428 assert!(d.variants[0].fields.is_empty());
2429 assert_eq!(d.variants[1].fields.len(), 1);
2430 }
2431 other => panic!("expected Enum, got {other:?}"),
2432 }
2433 }
2434
2435 #[test]
2436 fn an_interface_with_method_signatures_parses() {
2437 let ast = parse_ok("interface Printable { fn to_string(self) -> str }");
2438 match &ast[0] {
2439 Item::Interface(d) => {
2440 assert_eq!(d.name, "Printable");
2441 assert_eq!(d.methods.len(), 1);
2442 assert_eq!(d.methods[0].name, "to_string");
2443 assert_eq!(d.methods[0].params.len(), 1);
2444 assert!(d.methods[0].params[0].is_self);
2445 assert!(matches!(
2446 d.methods[0].ret_ty,
2447 Some(TypeExpr::Primitive {
2448 kind: PrimType::Str,
2449 ..
2450 })
2451 ));
2452 }
2453 other => panic!("expected Interface, got {other:?}"),
2454 }
2455 }
2456
2457 #[test]
2458 fn an_interface_with_a_trailing_comma_parses() {
2459 let ast = parse_ok("interface I { fn m(self) -> str, }");
2460 match &ast[0] {
2461 Item::Interface(d) => assert_eq!(d.methods.len(), 1),
2462 other => panic!("expected Interface, got {other:?}"),
2463 }
2464 }
2465
2466 #[test]
2467 fn interface_method_sig_span_covers_effect_when_no_return_type() {
2468 let src = "interface I { fn m(self) is io }";
2472 let ast = parse_ok(src);
2473 match &ast[0] {
2474 Item::Interface(d) => {
2475 let sig = &d.methods[0];
2476 assert_eq!(sig.effect, Some(Effect::Io));
2477 assert!(sig.ret_ty.is_none());
2478 assert!(
2483 sig.span.len > 2,
2484 "span covers only the fn keyword (len={}), expected full sig",
2485 sig.span.len
2486 );
2487 let sig_text = sig.span.slice(src);
2489 assert!(
2490 sig_text.ends_with("io"),
2491 "sig span text should end with 'io', got {sig_text:?}"
2492 );
2493 }
2494 other => panic!("expected Interface, got {other:?}"),
2495 }
2496 }
2497
2498 #[test]
2499 fn multiple_items_parse_in_source_order() {
2500 let ast = parse_ok("fn f() {} struct S { x: i64 } enum E { A } fn g() {}");
2501 assert_eq!(ast.len(), 4);
2502 assert!(matches!(ast[0], Item::Fn(_)));
2503 assert!(matches!(ast[1], Item::Struct(_)));
2504 assert!(matches!(ast[2], Item::Enum(_)));
2505 assert!(matches!(ast[3], Item::Fn(_)));
2506 }
2507
2508 #[test]
2511 fn advance_does_not_step_past_eof() {
2512 let toks = lex("");
2515 let mut p = Parser {
2516 tokens: &toks,
2517 pos: 0,
2518 depth: 0,
2519 open_delims: Vec::new(),
2520 };
2521 assert!(matches!(p.peek(), TokenKind::Eof));
2522 for _ in 0..10 {
2523 p.advance();
2524 }
2525 assert!(matches!(p.peek(), TokenKind::Eof));
2526 }
2527
2528 #[test]
2529 fn check_eat_and_expect_compose() {
2530 let toks = lex("+ - ;");
2533 let mut p = Parser {
2534 tokens: &toks,
2535 pos: 0,
2536 depth: 0,
2537 open_delims: Vec::new(),
2538 };
2539 assert!(p.check(&TokenKind::Plus));
2540 assert!(!p.check(&TokenKind::Minus));
2541 assert!(p.eat(&TokenKind::Plus));
2542 assert!(!p.eat(&TokenKind::Plus)); p.expect(&TokenKind::Minus)
2544 .expect("the `-` should be there");
2545 p.expect(&TokenKind::Semi).expect("the `;` should be there");
2546 assert!(matches!(p.peek(), TokenKind::Eof));
2547 }
2548
2549 #[test]
2550 fn expect_on_wrong_kind_returns_unexpected_token() {
2551 let toks = lex(",");
2554 let mut p = Parser {
2555 tokens: &toks,
2556 pos: 0,
2557 depth: 0,
2558 open_delims: Vec::new(),
2559 };
2560 match p.expect(&TokenKind::RParen) {
2561 Err(QalaError::UnexpectedToken {
2562 span,
2563 expected,
2564 found,
2565 }) => {
2566 assert_eq!(span, Span::new(0, 1));
2567 assert_eq!(expected, vec![TokenKind::RParen]);
2568 assert_eq!(found, TokenKind::Comma);
2569 }
2570 other => panic!("expected UnexpectedToken, got {other:?}"),
2571 }
2572 }
2573
2574 #[test]
2575 fn expect_at_eof_returns_unexpected_eof_with_a_zero_width_span() {
2576 let toks = lex("+");
2579 let mut p = Parser {
2580 tokens: &toks,
2581 pos: 0,
2582 depth: 0,
2583 open_delims: Vec::new(),
2584 };
2585 p.advance(); match p.expect(&TokenKind::Semi) {
2587 Err(QalaError::UnexpectedEof { span, expected }) => {
2588 assert_eq!(span, Span::new(1, 0));
2590 assert_eq!(expected, vec![TokenKind::Semi]);
2591 }
2592 other => panic!("expected UnexpectedEof, got {other:?}"),
2593 }
2594 }
2595
2596 #[test]
2597 fn unexpected_at_eof_of_empty_source_is_a_zero_zero_span() {
2598 let toks = lex("");
2601 let p = Parser {
2602 tokens: &toks,
2603 pos: 0,
2604 depth: 0,
2605 open_delims: Vec::new(),
2606 };
2607 match p.unexpected(&[TokenKind::Fn]) {
2608 QalaError::UnexpectedEof { span, .. } => {
2609 assert_eq!(span, Span::new(0, 0));
2610 }
2611 other => panic!("expected UnexpectedEof, got {other:?}"),
2612 }
2613 }
2614
2615 #[test]
2616 fn expect_ident_returns_name_and_span() {
2617 let toks = lex("foo");
2618 let mut p = Parser {
2619 tokens: &toks,
2620 pos: 0,
2621 depth: 0,
2622 open_delims: Vec::new(),
2623 };
2624 let (name, span) = p.expect_ident().expect("expected ident");
2625 assert_eq!(name, "foo");
2626 assert_eq!(span, Span::new(0, 3));
2627 match p.expect_ident() {
2629 Err(QalaError::UnexpectedEof { .. }) => {}
2630 other => panic!("expected UnexpectedEof, got {other:?}"),
2631 }
2632 }
2633
2634 #[test]
2635 fn expect_ident_on_a_keyword_returns_unexpected_token() {
2636 let toks = lex("fn");
2639 let mut p = Parser {
2640 tokens: &toks,
2641 pos: 0,
2642 depth: 0,
2643 open_delims: Vec::new(),
2644 };
2645 match p.expect_ident() {
2646 Err(QalaError::UnexpectedToken { found, .. }) => {
2647 assert_eq!(found, TokenKind::Fn);
2648 }
2649 other => panic!("expected UnexpectedToken, got {other:?}"),
2650 }
2651 }
2652
2653 #[test]
2656 fn the_depth_guard_returns_a_clean_error_past_the_limit() {
2657 let toks = lex("");
2660 let mut p = Parser {
2661 tokens: &toks,
2662 pos: 0,
2663 depth: 0,
2664 open_delims: Vec::new(),
2665 };
2666 for _ in 0..MAX_DEPTH {
2667 p.enter().expect("under the limit");
2668 }
2669 match p.enter() {
2670 Err(QalaError::Parse { message, .. }) => {
2671 assert!(message.contains("deeply"), "message was {message:?}");
2672 }
2673 other => panic!("expected QalaError::Parse, got {other:?}"),
2674 }
2675 }
2676
2677 #[test]
2678 fn exit_undoes_enter_so_balanced_pairs_reset_the_counter() {
2679 let toks = lex("");
2680 let mut p = Parser {
2681 tokens: &toks,
2682 pos: 0,
2683 depth: 0,
2684 open_delims: Vec::new(),
2685 };
2686 for _ in 0..(MAX_DEPTH / 2) {
2687 p.enter().expect("under the limit");
2688 p.exit();
2689 }
2690 assert_eq!(p.depth, 0);
2691 for _ in 0..(MAX_DEPTH * 10) {
2693 p.enter().expect("under the limit -- balanced");
2694 p.exit();
2695 }
2696 assert_eq!(p.depth, 0);
2697 }
2698
2699 #[test]
2708 fn delimited_list_handles_empty_and_trailing_separators() {
2709 let toks = lex("()");
2711 let mut p = Parser {
2712 tokens: &toks,
2713 pos: 0,
2714 depth: 0,
2715 open_delims: Vec::new(),
2716 };
2717 let (items, close): (Vec<(String, Span)>, Span) = p
2718 .delimited_list(
2719 TokenKind::LParen,
2720 TokenKind::RParen,
2721 TokenKind::Comma,
2722 |q| q.expect_ident(),
2723 )
2724 .expect("empty list parses");
2725 assert!(items.is_empty());
2726 assert_eq!(close, Span::new(1, 1));
2727
2728 let toks = lex("(a, b,)");
2730 let mut p = Parser {
2731 tokens: &toks,
2732 pos: 0,
2733 depth: 0,
2734 open_delims: Vec::new(),
2735 };
2736 let (items, _): (Vec<(String, Span)>, Span) = p
2737 .delimited_list(
2738 TokenKind::LParen,
2739 TokenKind::RParen,
2740 TokenKind::Comma,
2741 |q| q.expect_ident(),
2742 )
2743 .expect("trailing comma OK");
2744 assert_eq!(items.len(), 2);
2745 assert_eq!(items[0].0, "a");
2746 assert_eq!(items[1].0, "b");
2747 }
2748
2749 #[test]
2750 fn delimited_list_blames_the_opener_on_a_missing_closer() {
2751 let toks = lex("(a, b");
2753 let mut p = Parser {
2754 tokens: &toks,
2755 pos: 0,
2756 depth: 0,
2757 open_delims: Vec::new(),
2758 };
2759 match p.delimited_list(
2760 TokenKind::LParen,
2761 TokenKind::RParen,
2762 TokenKind::Comma,
2763 |q| q.expect_ident(),
2764 ) {
2765 Err(QalaError::UnclosedDelimiter {
2766 span,
2767 opener,
2768 found,
2769 }) => {
2770 assert_eq!(span, Span::new(0, 1));
2771 assert_eq!(opener, TokenKind::LParen);
2772 assert_eq!(found, TokenKind::Eof);
2773 }
2774 other => panic!("expected UnclosedDelimiter, got {other:?}"),
2775 }
2776 }
2777
2778 #[test]
2779 fn delimited_list_blames_the_opener_on_a_wrong_closer() {
2780 let toks = lex("(a]");
2782 let mut p = Parser {
2783 tokens: &toks,
2784 pos: 0,
2785 depth: 0,
2786 open_delims: Vec::new(),
2787 };
2788 match p.delimited_list(
2789 TokenKind::LParen,
2790 TokenKind::RParen,
2791 TokenKind::Comma,
2792 |q| q.expect_ident(),
2793 ) {
2794 Err(QalaError::UnclosedDelimiter {
2795 span,
2796 opener,
2797 found,
2798 }) => {
2799 assert_eq!(span, Span::new(0, 1));
2800 assert_eq!(opener, TokenKind::LParen);
2801 assert_eq!(found, TokenKind::RBracket);
2802 }
2803 other => panic!("expected UnclosedDelimiter, got {other:?}"),
2804 }
2805 }
2806
2807 #[test]
2810 fn parsing_is_deterministic() {
2811 let src = "";
2815 let a = Parser::parse(&lex(src));
2816 let b = Parser::parse(&lex(src));
2817 assert_eq!(a, b);
2818 let bad = "fn f("; assert_eq!(Parser::parse(&lex(bad)), Parser::parse(&lex(bad)));
2823 }
2824
2825 fn is_ident(e: &Expr, want: &str) -> bool {
2835 matches!(e, Expr::Ident { name, .. } if name == want)
2836 }
2837
2838 #[test]
2839 fn mul_binds_tighter_than_add() {
2840 let e = expr_of("1 + 2 * 3");
2842 match e {
2843 Expr::Binary {
2844 op: BinOp::Add,
2845 lhs,
2846 rhs,
2847 ..
2848 } => {
2849 assert!(matches!(*lhs, Expr::Int { value: 1, .. }));
2850 match *rhs {
2851 Expr::Binary {
2852 op: BinOp::Mul,
2853 lhs,
2854 rhs,
2855 ..
2856 } => {
2857 assert!(matches!(*lhs, Expr::Int { value: 2, .. }));
2858 assert!(matches!(*rhs, Expr::Int { value: 3, .. }));
2859 }
2860 other => panic!("expected mul-binary on the right, got {other:?}"),
2861 }
2862 }
2863 other => panic!("expected add-binary, got {other:?}"),
2864 }
2865 let e = expr_of("1 * 2 + 3");
2867 match e {
2868 Expr::Binary {
2869 op: BinOp::Add,
2870 lhs,
2871 rhs,
2872 ..
2873 } => {
2874 assert!(matches!(*lhs, Expr::Binary { op: BinOp::Mul, .. }));
2875 assert!(matches!(*rhs, Expr::Int { value: 3, .. }));
2876 }
2877 other => panic!("expected add-binary at the top, got {other:?}"),
2878 }
2879 }
2880
2881 #[test]
2882 fn and_binds_tighter_than_or() {
2883 let e = expr_of("a || b && c");
2885 match e {
2886 Expr::Binary {
2887 op: BinOp::Or,
2888 lhs,
2889 rhs,
2890 ..
2891 } => {
2892 assert!(is_ident(&lhs, "a"));
2893 match *rhs {
2894 Expr::Binary {
2895 op: BinOp::And,
2896 lhs,
2897 rhs,
2898 ..
2899 } => {
2900 assert!(is_ident(&lhs, "b"));
2901 assert!(is_ident(&rhs, "c"));
2902 }
2903 other => panic!("expected and-binary on the right, got {other:?}"),
2904 }
2905 }
2906 other => panic!("expected or-binary at the top, got {other:?}"),
2907 }
2908 let e = expr_of("a && b || c");
2910 match e {
2911 Expr::Binary {
2912 op: BinOp::Or,
2913 lhs,
2914 rhs,
2915 ..
2916 } => {
2917 assert!(matches!(*lhs, Expr::Binary { op: BinOp::And, .. }));
2918 assert!(is_ident(&rhs, "c"));
2919 }
2920 other => panic!("expected or-binary at the top, got {other:?}"),
2921 }
2922 }
2923
2924 #[test]
2925 fn comparison_binds_tighter_than_logical_and() {
2926 let e = expr_of("a == b && c");
2928 match e {
2929 Expr::Binary {
2930 op: BinOp::And,
2931 lhs,
2932 rhs,
2933 ..
2934 } => {
2935 assert!(matches!(*lhs, Expr::Binary { op: BinOp::Eq, .. }));
2936 assert!(is_ident(&rhs, "c"));
2937 }
2938 other => panic!("expected and-binary, got {other:?}"),
2939 }
2940 }
2941
2942 #[test]
2943 fn postfix_dot_binds_tighter_than_prefix_minus() {
2944 let e = expr_of("-a.b");
2946 match e {
2947 Expr::Unary {
2948 op: UnaryOp::Neg,
2949 operand,
2950 ..
2951 } => match *operand {
2952 Expr::FieldAccess { obj, name, .. } => {
2953 assert!(is_ident(&obj, "a"));
2954 assert_eq!(name, "b");
2955 }
2956 other => panic!("expected field access inside unary, got {other:?}"),
2957 },
2958 other => panic!("expected unary at the top, got {other:?}"),
2959 }
2960 }
2961
2962 #[test]
2963 fn comptime_is_a_prefix_at_unary_precedence() {
2964 let e = expr_of("comptime a + b");
2966 match e {
2967 Expr::Binary {
2968 op: BinOp::Add,
2969 lhs,
2970 rhs,
2971 ..
2972 } => {
2973 assert!(matches!(*lhs, Expr::Comptime { .. }));
2974 assert!(is_ident(&rhs, "b"));
2975 if let Expr::Comptime { body, .. } = *lhs {
2976 assert!(is_ident(&body, "a"));
2977 }
2978 }
2979 other => panic!("expected add-binary, got {other:?}"),
2980 }
2981 let e = expr_of("comptime (a + b)");
2983 match e {
2984 Expr::Comptime { body, .. } => match *body {
2985 Expr::Paren { inner, .. } => {
2986 assert!(matches!(*inner, Expr::Binary { op: BinOp::Add, .. }));
2987 }
2988 other => panic!("expected paren inside comptime, got {other:?}"),
2989 },
2990 other => panic!("expected comptime at the top, got {other:?}"),
2991 }
2992 let e = expr_of("comptime { 1 }");
2994 match e {
2995 Expr::Comptime { body, .. } => {
2996 assert!(matches!(*body, Expr::Block { .. }));
2997 }
2998 other => panic!("expected comptime at the top, got {other:?}"),
2999 }
3000 }
3001
3002 #[test]
3003 fn pipeline_is_left_associative_and_accepts_call_or_bare_callable() {
3004 let e = expr_of("a |> f() |> g()");
3006 match e {
3007 Expr::Pipeline { lhs, call, .. } => {
3008 assert!(matches!(*call, Expr::Call { .. }));
3009 match *lhs {
3010 Expr::Pipeline { lhs, call, .. } => {
3011 assert!(is_ident(&lhs, "a"));
3012 assert!(matches!(*call, Expr::Call { .. }));
3013 }
3014 other => panic!("expected nested pipeline on the left, got {other:?}"),
3015 }
3016 }
3017 other => panic!("expected pipeline at the top, got {other:?}"),
3018 }
3019 let e = expr_of("5 |> double");
3021 match e {
3022 Expr::Pipeline { lhs, call, .. } => {
3023 assert!(matches!(*lhs, Expr::Int { value: 5, .. }));
3024 assert!(is_ident(&call, "double"));
3025 }
3026 other => panic!("expected pipeline, got {other:?}"),
3027 }
3028 }
3029
3030 #[test]
3031 fn or_fallback_is_left_associative_and_loosest() {
3032 let e = expr_of("x or y or z");
3034 match e {
3035 Expr::OrElse { expr, fallback, .. } => {
3036 assert!(is_ident(&fallback, "z"));
3037 match *expr {
3038 Expr::OrElse { expr, fallback, .. } => {
3039 assert!(is_ident(&expr, "x"));
3040 assert!(is_ident(&fallback, "y"));
3041 }
3042 other => panic!("expected nested OrElse on the left, got {other:?}"),
3043 }
3044 }
3045 other => panic!("expected OrElse, got {other:?}"),
3046 }
3047 let e = expr_of("x |> f() or g");
3049 match e {
3050 Expr::OrElse { expr, fallback, .. } => {
3051 assert!(matches!(*expr, Expr::Pipeline { .. }));
3052 assert!(is_ident(&fallback, "g"));
3053 }
3054 other => panic!("expected OrElse at the top, got {other:?}"),
3055 }
3056 }
3057
3058 #[test]
3059 fn question_mark_is_postfix_at_tightest_tier() {
3060 let e = expr_of("f()?.g");
3062 match e {
3063 Expr::FieldAccess { obj, name, .. } => {
3064 assert_eq!(name, "g");
3065 match *obj {
3066 Expr::Try { expr, .. } => {
3067 assert!(matches!(*expr, Expr::Call { .. }));
3068 }
3069 other => panic!("expected Try on the obj, got {other:?}"),
3070 }
3071 }
3072 other => panic!("expected FieldAccess, got {other:?}"),
3073 }
3074 let e = expr_of("a + b?");
3076 match e {
3077 Expr::Binary {
3078 op: BinOp::Add,
3079 lhs,
3080 rhs,
3081 ..
3082 } => {
3083 assert!(is_ident(&lhs, "a"));
3084 match *rhs {
3085 Expr::Try { expr, .. } => assert!(is_ident(&expr, "b")),
3086 other => panic!("expected Try on the rhs, got {other:?}"),
3087 }
3088 }
3089 other => panic!("expected add-binary, got {other:?}"),
3090 }
3091 let e = expr_of("parse(s)?");
3093 match e {
3094 Expr::Try { expr, .. } => assert!(matches!(*expr, Expr::Call { .. })),
3095 other => panic!("expected Try, got {other:?}"),
3096 }
3097 }
3098
3099 #[test]
3100 fn ranges_are_infix_at_a_tier_above_plus() {
3101 let e = expr_of("1..n+1");
3103 match e {
3104 Expr::Range {
3105 start,
3106 end,
3107 inclusive,
3108 ..
3109 } => {
3110 assert!(!inclusive);
3111 let s = start.expect("start present");
3112 assert!(matches!(*s, Expr::Int { value: 1, .. }));
3113 let en = end.expect("end present");
3114 assert!(matches!(*en, Expr::Binary { op: BinOp::Add, .. }));
3115 }
3116 other => panic!("expected Range, got {other:?}"),
3117 }
3118 let e = expr_of("0..=15");
3120 match e {
3121 Expr::Range { inclusive, .. } => assert!(inclusive),
3122 other => panic!("expected Range, got {other:?}"),
3123 }
3124 }
3125
3126 #[test]
3127 fn chained_range_is_a_parse_error() {
3128 parse_err("fn f() { 0..1..2 }");
3133 }
3134
3135 #[test]
3136 fn additive_is_left_associative() {
3137 let e = expr_of("a + b - c");
3139 match e {
3140 Expr::Binary {
3141 op: BinOp::Sub,
3142 lhs,
3143 rhs,
3144 ..
3145 } => {
3146 assert!(matches!(*lhs, Expr::Binary { op: BinOp::Add, .. }));
3147 assert!(is_ident(&rhs, "c"));
3148 }
3149 other => panic!("expected sub-binary at the top, got {other:?}"),
3150 }
3151 }
3152
3153 #[test]
3156 fn literals_parse_to_their_decoded_variants() {
3157 assert!(matches!(expr_of("42"), Expr::Int { value: 42, .. }));
3158 assert!(matches!(expr_of("3.14"), Expr::Float { .. }));
3159 assert!(matches!(expr_of("b'A'"), Expr::Byte { value: 65, .. }));
3160 assert!(matches!(expr_of("\"hello\""), Expr::Str { .. }));
3161 assert!(matches!(expr_of("true"), Expr::Bool { value: true, .. }));
3162 assert!(matches!(expr_of("false"), Expr::Bool { value: false, .. }));
3163 assert!(is_ident(&expr_of("foo"), "foo"));
3164 }
3165
3166 #[test]
3167 fn calls_parse_with_args_and_trailing_comma() {
3168 match expr_of("f(1, 2)") {
3170 Expr::Call { callee, args, .. } => {
3171 assert!(is_ident(&callee, "f"));
3172 assert_eq!(args.len(), 2);
3173 }
3174 other => panic!("expected Call, got {other:?}"),
3175 }
3176 match expr_of("f(1, 2,)") {
3178 Expr::Call { args, .. } => assert_eq!(args.len(), 2),
3179 other => panic!("expected Call, got {other:?}"),
3180 }
3181 match expr_of("g()") {
3183 Expr::Call { args, .. } => assert!(args.is_empty()),
3184 other => panic!("expected Call, got {other:?}"),
3185 }
3186 }
3187
3188 #[test]
3189 fn method_call_is_distinct_from_field_access() {
3190 match expr_of("p.area()") {
3192 Expr::MethodCall {
3193 receiver,
3194 name,
3195 args,
3196 ..
3197 } => {
3198 assert!(is_ident(&receiver, "p"));
3199 assert_eq!(name, "area");
3200 assert!(args.is_empty());
3201 }
3202 other => panic!("expected MethodCall, got {other:?}"),
3203 }
3204 match expr_of("p.x") {
3206 Expr::FieldAccess { obj, name, .. } => {
3207 assert!(is_ident(&obj, "p"));
3208 assert_eq!(name, "x");
3209 }
3210 other => panic!("expected FieldAccess, got {other:?}"),
3211 }
3212 }
3213
3214 #[test]
3215 fn index_indexes_into_an_array() {
3216 match expr_of("xs[0]") {
3217 Expr::Index { obj, index, .. } => {
3218 assert!(is_ident(&obj, "xs"));
3219 assert!(matches!(*index, Expr::Int { value: 0, .. }));
3220 }
3221 other => panic!("expected Index, got {other:?}"),
3222 }
3223 }
3224
3225 #[test]
3226 fn postfix_chain_nests_correctly() {
3227 let e = expr_of("f()?.g(1)[2]?");
3230 match e {
3231 Expr::Try { expr, .. } => match *expr {
3232 Expr::Index { obj, index, .. } => {
3233 assert!(matches!(*index, Expr::Int { value: 2, .. }));
3234 match *obj {
3235 Expr::MethodCall {
3236 receiver,
3237 name,
3238 args,
3239 ..
3240 } => {
3241 assert_eq!(name, "g");
3242 assert_eq!(args.len(), 1);
3243 assert!(matches!(*receiver, Expr::Try { .. }));
3244 }
3245 other => panic!("expected MethodCall, got {other:?}"),
3246 }
3247 }
3248 other => panic!("expected Index, got {other:?}"),
3249 },
3250 other => panic!("expected Try at the top, got {other:?}"),
3251 }
3252 }
3253
3254 #[test]
3255 fn array_literal_parses_with_elements_and_trailing_comma() {
3256 match expr_of("[1, 2, 3]") {
3257 Expr::ArrayLit { elems, .. } => assert_eq!(elems.len(), 3),
3258 other => panic!("expected ArrayLit, got {other:?}"),
3259 }
3260 match expr_of("[1, 2, 3,]") {
3262 Expr::ArrayLit { elems, .. } => assert_eq!(elems.len(), 3),
3263 other => panic!("expected ArrayLit, got {other:?}"),
3264 }
3265 match expr_of("[]") {
3267 Expr::ArrayLit { elems, .. } => assert!(elems.is_empty()),
3268 other => panic!("expected ArrayLit, got {other:?}"),
3269 }
3270 }
3271
3272 #[test]
3273 fn array_repeat_parses_as_value_semi_count() {
3274 match expr_of("[0; 100]") {
3275 Expr::ArrayRepeat { value, count, .. } => {
3276 assert!(matches!(*value, Expr::Int { value: 0, .. }));
3277 assert!(matches!(*count, Expr::Int { value: 100, .. }));
3278 }
3279 other => panic!("expected ArrayRepeat, got {other:?}"),
3280 }
3281 }
3282
3283 #[test]
3284 fn paren_versus_tuple_distinguished_by_a_trailing_comma() {
3285 match expr_of("(1 + 2)") {
3287 Expr::Paren { inner, .. } => {
3288 assert!(matches!(*inner, Expr::Binary { op: BinOp::Add, .. }));
3289 }
3290 other => panic!("expected Paren, got {other:?}"),
3291 }
3292 match expr_of("(1, 2)") {
3294 Expr::Tuple { elems, .. } => assert_eq!(elems.len(), 2),
3295 other => panic!("expected Tuple, got {other:?}"),
3296 }
3297 match expr_of("(1,)") {
3299 Expr::Tuple { elems, .. } => assert_eq!(elems.len(), 1),
3300 other => panic!("expected Tuple, got {other:?}"),
3301 }
3302 match expr_of("()") {
3304 Expr::Tuple { elems, .. } => assert!(elems.is_empty()),
3305 other => panic!("expected Tuple, got {other:?}"),
3306 }
3307 }
3308
3309 #[test]
3310 fn struct_literal_parses_with_field_inits_and_trailing_comma() {
3311 match expr_of("Point { x: 1.0, y: 2.0 }") {
3313 Expr::StructLit { name, fields, .. } => {
3314 assert_eq!(name, "Point");
3315 assert_eq!(fields.len(), 2);
3316 assert_eq!(fields[0].name, "x");
3317 assert_eq!(fields[1].name, "y");
3318 }
3319 other => panic!("expected StructLit, got {other:?}"),
3320 }
3321 match expr_of("Point { x: 1.0, y: 2.0, }") {
3323 Expr::StructLit { fields, .. } => assert_eq!(fields.len(), 2),
3324 other => panic!("expected StructLit, got {other:?}"),
3325 }
3326 }
3327
3328 #[test]
3329 fn match_with_three_arms_two_expr_one_block() {
3330 let src = "match s { Circle(r) => 3.14159 * r * r, Rect(w, h) => w * h, Triangle(a, b, c) => { sqrt(s) } }";
3332 match expr_of(src) {
3333 Expr::Match { arms, .. } => {
3334 assert_eq!(arms.len(), 3);
3335 assert!(matches!(arms[0].body, MatchArmBody::Expr(_)));
3336 assert!(matches!(arms[1].body, MatchArmBody::Expr(_)));
3337 assert!(matches!(arms[2].body, MatchArmBody::Block(_)));
3338 for arm in &arms {
3340 assert!(
3341 matches!(arm.pattern, Pattern::Variant { .. }),
3342 "expected Variant pattern, got {:?}",
3343 arm.pattern
3344 );
3345 }
3346 }
3347 other => panic!("expected Match, got {other:?}"),
3348 }
3349 }
3350
3351 #[test]
3352 fn match_with_guards_and_wildcard() {
3353 let src =
3355 "match value { v if v > 0 => \"positive\", v if v < 0 => \"negative\", _ => \"zero\" }";
3356 match expr_of(src) {
3357 Expr::Match { arms, .. } => {
3358 assert_eq!(arms.len(), 3);
3359 assert!(arms[0].guard.is_some());
3360 assert!(arms[1].guard.is_some());
3361 assert!(arms[2].guard.is_none());
3362 assert!(matches!(arms[0].pattern, Pattern::Binding { .. }));
3363 assert!(matches!(arms[2].pattern, Pattern::Wildcard { .. }));
3364 }
3365 other => panic!("expected Match, got {other:?}"),
3366 }
3367 }
3368
3369 #[test]
3370 fn match_with_exactly_one_arm_and_no_trailing_comma() {
3371 match expr_of("match x { _ => 0 }") {
3373 Expr::Match { arms, .. } => assert_eq!(arms.len(), 1),
3374 other => panic!("expected Match, got {other:?}"),
3375 }
3376 }
3377
3378 #[test]
3379 fn interpolation_parses_embedded_expressions_into_parts() {
3380 match expr_of("\"fib({i}) = {fibonacci(i)}\"") {
3383 Expr::Interpolation { parts, .. } => {
3384 assert_eq!(parts.len(), 5);
3387 assert!(matches!(parts[0], InterpPart::Literal(_)));
3388 match &parts[1] {
3389 InterpPart::Expr(Expr::Ident { name, .. }) => assert_eq!(name, "i"),
3390 other => panic!("expected Ident(i), got {other:?}"),
3391 }
3392 assert!(matches!(parts[2], InterpPart::Literal(_)));
3393 match &parts[3] {
3394 InterpPart::Expr(Expr::Call { callee, args, .. }) => {
3395 assert!(is_ident(callee, "fibonacci"));
3396 assert_eq!(args.len(), 1);
3397 }
3398 other => panic!("expected Call(fibonacci, ...), got {other:?}"),
3399 }
3400 assert!(matches!(parts[4], InterpPart::Literal(_)));
3401 }
3402 other => panic!("expected Interpolation, got {other:?}"),
3403 }
3404 }
3405
3406 #[test]
3407 fn plain_string_with_no_interpolations_parses_to_expr_str() {
3408 match expr_of("\"hello\"") {
3411 Expr::Str { value, .. } => assert_eq!(value, "hello"),
3412 other => panic!("expected Str, got {other:?}"),
3413 }
3414 }
3415
3416 #[test]
3419 fn x_pipe_with_no_call_errors_on_the_pipe_span() {
3420 let err = expr_err("x |>");
3422 match err {
3423 QalaError::Parse { span, message } => {
3424 assert_eq!(span, Span::new(2, 2));
3426 assert!(message.contains("`|>`"), "message was {message:?}");
3427 }
3428 other => panic!("expected QalaError::Parse, got {other:?}"),
3429 }
3430 }
3431
3432 #[test]
3433 fn x_pipe_with_a_non_callable_rhs_errors_on_the_pipe_span() {
3434 let err = expr_err("x |> 5");
3436 match err {
3437 QalaError::Parse { span, message } => {
3438 assert_eq!(span, Span::new(2, 2));
3439 assert!(message.contains("`|>`"), "message was {message:?}");
3440 }
3441 other => panic!("expected QalaError::Parse, got {other:?}"),
3442 }
3443 }
3444
3445 #[test]
3446 fn match_arm_guard_ending_in_struct_literal_does_not_consume_arm_body_brace() {
3447 let e = expr_of("match v { x if x > 0 => { 1 }, _ => { 0 } }");
3455 match e {
3456 Expr::Match { arms, .. } => {
3457 assert_eq!(arms.len(), 2);
3458 assert!(arms[0].guard.is_some(), "expected guard on first arm");
3460 assert!(arms[1].guard.is_none());
3462 }
3463 other => panic!("expected Match, got {other:?}"),
3464 }
3465 let e = expr_of("match s { v if v => { 1 } }");
3468 match e {
3469 Expr::Match { arms, .. } => {
3470 assert_eq!(arms.len(), 1);
3471 assert!(matches!(arms[0].body, MatchArmBody::Block(_)));
3472 }
3473 other => panic!("expected Match, got {other:?}"),
3474 }
3475 }
3476
3477 #[test]
3478 fn match_with_zero_arms_errors() {
3479 let err = expr_err("match x { }");
3480 match err {
3481 QalaError::Parse { message, .. } => {
3482 assert!(
3483 message.contains("at least one arm"),
3484 "message was {message:?}"
3485 );
3486 }
3487 other => panic!("expected QalaError::Parse, got {other:?}"),
3488 }
3489 }
3490
3491 #[test]
3492 fn an_unclosed_paren_errors_on_the_open_paren() {
3493 let err = expr_err("(a + b");
3495 match err {
3496 QalaError::UnclosedDelimiter { span, opener, .. } => {
3497 assert_eq!(span, Span::new(0, 1));
3498 assert_eq!(opener, TokenKind::LParen);
3499 }
3500 other => panic!("expected UnclosedDelimiter, got {other:?}"),
3501 }
3502 }
3503
3504 #[test]
3505 fn an_unclosed_bracket_errors_on_the_open_bracket() {
3506 let err = expr_err("[1, 2");
3508 match err {
3509 QalaError::UnclosedDelimiter { span, opener, .. } => {
3510 assert_eq!(span, Span::new(0, 1));
3511 assert_eq!(opener, TokenKind::LBracket);
3512 }
3513 other => panic!("expected UnclosedDelimiter, got {other:?}"),
3514 }
3515 }
3516
3517 #[test]
3518 fn the_assignment_token_is_not_an_expression_operator() {
3519 let toks = lex("a = b");
3524 let mut p = Parser {
3525 tokens: &toks,
3526 pos: 0,
3527 depth: 0,
3528 open_delims: Vec::new(),
3529 };
3530 let lhs = p.parse_expr().expect("expected ident a to parse");
3531 assert!(is_ident(&lhs, "a"));
3532 assert!(matches!(p.peek(), TokenKind::Eq));
3534 }
3535
3536 #[test]
3537 fn the_binding_power_tables_omit_assignment() {
3538 assert_eq!(postfix_bp(&TokenKind::Eq), None);
3541 assert_eq!(infix_bp(&TokenKind::Eq), None);
3542 let ((), rbp) = prefix_bp(&TokenKind::Eq);
3547 assert_eq!(rbp, u8::MAX);
3548 }
3549
3550 #[test]
3551 fn postfix_bp_only_returns_some_for_dot_lparen_lbracket_question() {
3552 assert!(postfix_bp(&TokenKind::Dot).is_some());
3555 assert!(postfix_bp(&TokenKind::LParen).is_some());
3556 assert!(postfix_bp(&TokenKind::LBracket).is_some());
3557 assert!(postfix_bp(&TokenKind::Question).is_some());
3558 for k in [
3559 TokenKind::Plus,
3560 TokenKind::Minus,
3561 TokenKind::Star,
3562 TokenKind::PipeGt,
3563 TokenKind::Or,
3564 TokenKind::DotDot,
3565 TokenKind::DotDotEq,
3566 TokenKind::Eq,
3567 TokenKind::Comma,
3568 TokenKind::RBrace,
3569 ] {
3570 assert!(postfix_bp(&k).is_none(), "{k:?} should not be postfix");
3571 }
3572 }
3573
3574 #[test]
3575 fn infix_bp_includes_ranges_but_not_assignment() {
3576 assert!(infix_bp(&TokenKind::DotDot).is_some());
3578 assert!(infix_bp(&TokenKind::DotDotEq).is_some());
3579 assert!(infix_bp(&TokenKind::PipeGt).is_some());
3580 assert!(infix_bp(&TokenKind::Or).is_some());
3581 assert!(infix_bp(&TokenKind::Eq).is_none());
3583 assert!(infix_bp(&TokenKind::Question).is_none());
3585 }
3586
3587 #[test]
3588 fn or_keyword_is_looser_than_pipe_gt() {
3589 let (or_lbp, _) = infix_bp(&TokenKind::Or).unwrap();
3591 let (pipe_lbp, _) = infix_bp(&TokenKind::PipeGt).unwrap();
3592 assert!(
3593 or_lbp < pipe_lbp,
3594 "`or` ({or_lbp}) should be looser than `|>` ({pipe_lbp})"
3595 );
3596 }
3597
3598 #[test]
3599 fn comptime_prefix_bp_matches_other_unary_prefixes() {
3600 let ((), c) = prefix_bp(&TokenKind::Comptime);
3603 let ((), b) = prefix_bp(&TokenKind::Bang);
3604 let ((), m) = prefix_bp(&TokenKind::Minus);
3605 assert_eq!(c, b);
3606 assert_eq!(b, m);
3607 }
3608
3609 #[test]
3610 fn expression_parsing_is_deterministic_on_a_mixed_input() {
3611 let src = "1 + 2 * 3 |> f() or g()";
3614 assert_eq!(expr_of(src), expr_of(src));
3615 }
3616
3617 fn first_stmt_of(stmt_src: &str) -> Stmt {
3622 let program = format!("fn f() {{ {stmt_src} }}");
3623 let ast = parse_ok(&program);
3624 match ast.into_iter().next().expect("one item") {
3625 Item::Fn(d) => d.body.stmts.into_iter().next().expect("a statement"),
3626 other => panic!("expected fn item, got {other:?}"),
3627 }
3628 }
3629
3630 fn body_of(body_src: &str) -> Block {
3632 let program = format!("fn f() {{ {body_src} }}");
3633 let ast = parse_ok(&program);
3634 match ast.into_iter().next().expect("one item") {
3635 Item::Fn(d) => d.body,
3636 other => panic!("expected fn item, got {other:?}"),
3637 }
3638 }
3639
3640 #[test]
3641 fn let_without_mut_or_type_parses() {
3642 match first_stmt_of("let x = 5") {
3643 Stmt::Let {
3644 is_mut,
3645 name,
3646 ty,
3647 init,
3648 ..
3649 } => {
3650 assert!(!is_mut);
3651 assert_eq!(name, "x");
3652 assert!(ty.is_none());
3653 assert!(matches!(init, Expr::Int { value: 5, .. }));
3654 }
3655 other => panic!("expected Let, got {other:?}"),
3656 }
3657 }
3658
3659 #[test]
3660 fn let_mut_sets_is_mut_true() {
3661 match first_stmt_of("let mut y = 10") {
3662 Stmt::Let { is_mut, name, .. } => {
3663 assert!(is_mut);
3664 assert_eq!(name, "y");
3665 }
3666 other => panic!("expected Let, got {other:?}"),
3667 }
3668 }
3669
3670 #[test]
3671 fn let_with_an_explicit_type_records_it() {
3672 match first_stmt_of("let z: i64 = 0") {
3673 Stmt::Let { ty, init, .. } => {
3674 assert!(matches!(
3675 ty,
3676 Some(TypeExpr::Primitive {
3677 kind: PrimType::I64,
3678 ..
3679 })
3680 ));
3681 assert!(matches!(init, Expr::Int { value: 0, .. }));
3682 }
3683 other => panic!("expected Let, got {other:?}"),
3684 }
3685 }
3686
3687 #[test]
3688 fn let_with_no_initializer_is_a_parse_error() {
3689 let err = parse_err("fn f() { let x: i64 }");
3691 assert!(matches!(
3692 err,
3693 QalaError::UnexpectedToken { .. } | QalaError::UnexpectedEof { .. }
3694 ));
3695 assert!(
3696 err.message().contains("`=`"),
3697 "message was {}",
3698 err.message()
3699 );
3700 }
3701
3702 #[test]
3703 fn if_without_else_parses() {
3704 match first_stmt_of("if c { return 1 }") {
3705 Stmt::If { else_branch, .. } => assert!(else_branch.is_none()),
3706 other => panic!("expected If, got {other:?}"),
3707 }
3708 }
3709
3710 #[test]
3711 fn if_with_else_block_parses() {
3712 match first_stmt_of("if c { 1 } else { 2 }") {
3713 Stmt::If { else_branch, .. } => {
3714 assert!(matches!(else_branch, Some(ElseBranch::Block(_))));
3715 }
3716 other => panic!("expected If, got {other:?}"),
3717 }
3718 }
3719
3720 #[test]
3721 fn else_if_chain_parses_as_nested_if() {
3722 match first_stmt_of("if a { 1 } else if b { 2 } else { 3 }") {
3725 Stmt::If { else_branch, .. } => match else_branch {
3726 Some(ElseBranch::If(boxed)) => match *boxed {
3727 Stmt::If {
3728 else_branch: Some(ElseBranch::Block(_)),
3729 ..
3730 } => {}
3731 other => panic!("expected If with else-block, got {other:?}"),
3732 },
3733 other => panic!("expected else-if (ElseBranch::If), got {other:?}"),
3734 },
3735 other => panic!("expected If at the top, got {other:?}"),
3736 }
3737 }
3738
3739 #[test]
3740 fn while_loop_parses() {
3741 match first_stmt_of("while c { x }") {
3742 Stmt::While { cond, body, .. } => {
3743 assert!(matches!(cond, Expr::Ident { .. }));
3744 assert!(body.value.is_some());
3745 }
3746 other => panic!("expected While, got {other:?}"),
3747 }
3748 }
3749
3750 #[test]
3751 fn for_loop_over_a_range_iterable_parses() {
3752 match first_stmt_of("for i in 0..n { x }") {
3753 Stmt::For { var, iter, .. } => {
3754 assert_eq!(var, "i");
3755 assert!(matches!(iter, Expr::Range { .. }));
3756 }
3757 other => panic!("expected For, got {other:?}"),
3758 }
3759 }
3760
3761 #[test]
3762 fn for_loop_over_an_ident_iterable_parses() {
3763 match first_stmt_of("for s in shapes { x }") {
3766 Stmt::For { var, iter, .. } => {
3767 assert_eq!(var, "s");
3768 assert!(matches!(iter, Expr::Ident { name, .. } if name == "shapes"));
3769 }
3770 other => panic!("expected For, got {other:?}"),
3771 }
3772 }
3773
3774 #[test]
3775 fn return_bare_has_no_value() {
3776 match first_stmt_of("return") {
3777 Stmt::Return { value, .. } => assert!(value.is_none()),
3778 other => panic!("expected Return, got {other:?}"),
3779 }
3780 }
3781
3782 #[test]
3783 fn return_with_an_expression_carries_it() {
3784 match first_stmt_of("return n + 1") {
3785 Stmt::Return { value, .. } => {
3786 assert!(matches!(value, Some(Expr::Binary { op: BinOp::Add, .. })));
3787 }
3788 other => panic!("expected Return, got {other:?}"),
3789 }
3790 }
3791
3792 #[test]
3793 fn break_and_continue_have_no_value() {
3794 let body = body_of("break continue");
3795 assert_eq!(body.stmts.len(), 2);
3797 assert!(matches!(body.stmts[0], Stmt::Break { .. }));
3798 assert!(matches!(body.stmts[1], Stmt::Continue { .. }));
3799 }
3800
3801 #[test]
3802 fn defer_takes_an_arbitrary_expression() {
3803 match first_stmt_of("defer close(f)") {
3804 Stmt::Defer { expr, .. } => assert!(matches!(expr, Expr::Call { .. })),
3805 other => panic!("expected Defer, got {other:?}"),
3806 }
3807 }
3808
3809 #[test]
3810 fn a_block_with_a_trailing_value_has_some_value() {
3811 let body = body_of("let x = 1; x");
3812 assert_eq!(body.stmts.len(), 1);
3813 assert!(matches!(body.stmts[0], Stmt::Let { .. }));
3814 assert!(matches!(body.value.as_deref(), Some(Expr::Ident { .. })));
3815 }
3816
3817 #[test]
3818 fn an_empty_block_has_no_stmts_and_no_value() {
3819 let body = body_of("");
3820 assert!(body.stmts.is_empty());
3821 assert!(body.value.is_none());
3822 }
3823
3824 #[test]
3825 fn newline_separated_statements_with_no_semi_all_parse() {
3826 let body = body_of("let f = open(path) defer close(f) let g = 1");
3831 assert_eq!(body.stmts.len(), 3);
3832 assert!(matches!(body.stmts[0], Stmt::Let { .. }));
3833 assert!(matches!(body.stmts[1], Stmt::Defer { .. }));
3834 assert!(matches!(body.stmts[2], Stmt::Let { .. }));
3835 }
3836
3837 #[test]
3838 fn expression_statements_chain_without_semicolons() {
3839 let body = body_of("println(\"a\") println(\"b\")");
3845 assert_eq!(body.stmts.len(), 1);
3846 match &body.stmts[0] {
3847 Stmt::Expr { expr, .. } => assert!(matches!(expr, Expr::Call { .. })),
3848 other => panic!("expected Expr stmt, got {other:?}"),
3849 }
3850 assert!(matches!(body.value.as_deref(), Some(Expr::Call { .. })));
3851 }
3852
3853 #[test]
3854 fn let_x_eq_followed_by_eof_errors_with_a_zero_width_span_at_the_eq() {
3855 let err = parse_err("fn f() { let x =\n");
3857 match err {
3858 QalaError::UnexpectedEof { span, .. } => {
3859 assert_eq!(span.len, 0);
3861 assert!(err.message().contains("end of input"));
3863 }
3864 other => panic!("expected UnexpectedEof, got {other:?}"),
3865 }
3866 }
3867
3868 #[test]
3869 fn mismatched_paren_inside_a_block_blames_the_open_paren() {
3870 let err = parse_err("fn f() { let x = ( a + b } }");
3873 match err {
3874 QalaError::UnclosedDelimiter { span, opener, .. } => {
3875 assert_eq!(opener, TokenKind::LParen);
3876 assert_eq!(span.start, 17);
3878 assert_eq!(span.len, 1);
3879 }
3880 other => panic!("expected UnclosedDelimiter, got {other:?}"),
3881 }
3882 }
3883
3884 #[test]
3885 fn there_is_no_expr_if_in_the_parser() {
3886 let err = parse_err("fn f() { let x = if c { 1 } else { 2 } }");
3889 match err {
3890 QalaError::UnexpectedToken { found, .. } => {
3891 assert_eq!(found, TokenKind::If);
3892 }
3893 other => panic!("expected UnexpectedToken at `if`, got {other:?}"),
3894 }
3895 }
3896
3897 #[test]
3900 fn the_six_examples_parse_with_no_error() {
3901 for name in [
3906 "hello",
3907 "fibonacci",
3908 "effects",
3909 "pattern-matching",
3910 "pipeline",
3911 "defer-demo",
3912 ] {
3913 let path = format!(
3914 "{}/../../playground/public/examples/{}.qala",
3915 env!("CARGO_MANIFEST_DIR"),
3916 name
3917 );
3918 let src = std::fs::read_to_string(&path)
3919 .unwrap_or_else(|e| panic!("could not read example {path}: {e}"));
3920 let toks = crate::lexer::Lexer::tokenize(&src)
3921 .unwrap_or_else(|e| panic!("example {name}.qala failed to tokenize: {e:?}"));
3922 let ast = Parser::parse(&toks)
3923 .unwrap_or_else(|e| panic!("example {name}.qala failed to parse: {e:?}"));
3924 assert!(
3925 !ast.is_empty(),
3926 "example {name}.qala should produce top-level items"
3927 );
3928 }
3929 }
3930
3931 #[test]
3937 fn pipeline_with_no_rhs_call_blames_the_pipe_operator() {
3938 let err = parse_err("fn f() is io { let r = x |> }");
3940 match err {
3941 QalaError::Parse { message, span } => {
3942 assert!(message.contains("`|>`"), "message was {message:?}");
3943 assert_eq!(span.len, 2);
3945 }
3946 other => panic!("expected QalaError::Parse, got {other:?}"),
3947 }
3948 }
3949
3950 #[test]
3951 fn a_mismatched_delimiter_blames_the_opener() {
3952 let err = parse_err("fn f() { let x = ( a + b } }");
3955 let msg = err.message();
3956 match &err {
3957 QalaError::UnclosedDelimiter {
3958 span,
3959 opener,
3960 found,
3961 } => {
3962 assert_eq!(*opener, TokenKind::LParen);
3963 assert_eq!(span.len, 1, "the `(` span is one byte wide");
3964 assert_eq!(*found, TokenKind::RBrace);
3965 }
3966 other => panic!("expected UnclosedDelimiter, got {other:?}"),
3967 }
3968 assert!(msg.contains("`(`"), "msg was {msg:?}");
3970 assert!(msg.contains("`}`"), "msg was {msg:?}");
3971 }
3972
3973 #[test]
3974 fn unexpected_eof_reports_a_zero_width_span_after_the_last_token() {
3975 let err = parse_err("fn f() { let x =\n");
3978 match err {
3979 QalaError::UnexpectedEof { span, .. } => {
3980 assert_eq!(span.len, 0, "EOF span must be zero-width");
3981 assert!(err.message().contains("end of input"));
3982 }
3983 other => panic!("expected UnexpectedEof, got {other:?}"),
3984 }
3985 }
3986
3987 #[test]
3988 fn an_unexpected_token_says_expected_x_found_y() {
3989 let err = parse_err("fn f() { let 5 = 0 }");
3991 assert!(matches!(err, QalaError::UnexpectedToken { .. }));
3992 let msg = err.message();
3993 assert!(msg.contains("expected"), "{msg:?}");
3994 assert!(msg.contains("identifier"), "{msg:?}");
3995 assert!(msg.contains("found"), "{msg:?}");
3996 }
3997
3998 #[test]
3999 fn trailing_commas_are_accepted_everywhere() {
4000 assert!(Parser::parse(&lex("fn f(a: i64, b: i64,) {}")).is_ok());
4002 assert!(Parser::parse(&lex("struct S { x: i64, y: i64, }")).is_ok());
4003 assert!(Parser::parse(&lex("enum E { A, B(i64), }")).is_ok());
4004 assert!(Parser::parse(&lex("interface I { fn m(self) -> str, }")).is_ok());
4005 assert!(Parser::parse(&lex("fn g() is io { let xs = [1, 2, 3,] }")).is_ok());
4006 assert!(Parser::parse(&lex("fn h() is io { let t = (1, 2,) }")).is_ok());
4007 assert!(Parser::parse(&lex("fn k(x: Result<i64, str,>) {}")).is_ok());
4009 }
4010
4011 #[test]
4012 fn an_empty_function_body_is_legal() {
4013 let ast = parse_ok("fn f() {}");
4014 match &ast[0] {
4015 Item::Fn(d) => {
4016 assert!(d.body.stmts.is_empty());
4017 assert!(d.body.value.is_none());
4018 }
4019 other => panic!("expected Fn, got {other:?}"),
4020 }
4021 }
4022
4023 #[test]
4024 fn zero_match_arms_is_an_error_in_a_full_program() {
4025 let err = parse_err("fn f() is io { match x { } }");
4028 match err {
4029 QalaError::Parse { message, .. } => {
4030 assert!(message.contains("at least one arm"), "{message:?}");
4031 }
4032 other => panic!("expected QalaError::Parse, got {other:?}"),
4033 }
4034 }
4035
4036 #[test]
4037 fn self_outside_a_method_definition_is_an_error_in_a_full_program() {
4038 assert!(Parser::parse(&lex("fn f(self) {}")).is_err());
4040 assert!(Parser::parse(&lex("fn Point.f(a: i64, self) {}")).is_err());
4042 assert!(Parser::parse(&lex("fn Point.area(self) -> f64 is pure { 3.14 }")).is_ok());
4044 }
4045
4046 #[test]
4052 fn deeply_nested_input_fails_gracefully_not_with_a_stack_overflow() {
4053 let deep = format!(
4056 "fn f() is io {{ let x = {}1{} }}",
4057 "(".repeat(20000),
4058 ")".repeat(20000)
4059 );
4060 let err = Parser::parse(&lex(&deep))
4061 .expect_err("expected a clean depth-limit error, not a crash");
4062 assert!(
4063 matches!(err, QalaError::Parse { .. }),
4064 "expected a Parse error, got {err:?}"
4065 );
4066 assert!(
4067 err.message().contains("deeply") || err.message().contains("nest"),
4068 "message was {}",
4069 err.message()
4070 );
4071 let deep_blocks = format!(
4074 "fn f() is io {{ {}1{} }}",
4075 "{".repeat(5000),
4076 "}".repeat(5000)
4077 );
4078 assert!(
4079 Parser::parse(&lex(&deep_blocks)).is_err(),
4080 "deep block nesting should error, not crash"
4081 );
4082 let deep_types = format!("fn f(x: {}i64{}) {{}}", "[".repeat(5000), "]".repeat(5000));
4085 assert!(
4086 Parser::parse(&lex(&deep_types)).is_err(),
4087 "deep type nesting should error, not crash"
4088 );
4089 }
4090
4091 #[test]
4092 fn ast_node_spans_point_at_the_source_bytes_they_came_from() {
4093 let src = "fn add(a: i64, b: i64) -> i64 is pure { return a + b }";
4096 let toks = lex(src);
4097 let ast = Parser::parse(&toks).expect("parses");
4098 assert_eq!(ast.len(), 1);
4099 let item = &ast[0];
4100 assert_eq!(item.span().slice(src), src);
4103 match item {
4104 Item::Fn(d) => {
4105 let p0_text = d.params[0].span.slice(src);
4107 assert_eq!(p0_text, "a: i64");
4108 let p1_text = d.params[1].span.slice(src);
4109 assert_eq!(p1_text, "b: i64");
4110 let ret_text = d.ret_ty.as_ref().expect("ret").span().slice(src);
4112 assert_eq!(ret_text, "i64");
4113 assert_eq!(d.body.span.slice(src), "{ return a + b }");
4115 let ret_stmt = &d.body.stmts[0];
4117 assert_eq!(ret_stmt.span().slice(src), "return a + b");
4118 if let Stmt::Return {
4120 value: Some(value), ..
4121 } = ret_stmt
4122 {
4123 assert_eq!(value.span().slice(src), "a + b");
4124 } else {
4125 panic!("expected Stmt::Return with a value, got {ret_stmt:?}");
4126 }
4127 }
4128 other => panic!("expected Fn, got {other:?}"),
4129 }
4130 }
4131
4132 #[test]
4133 fn parsing_a_full_program_is_deterministic_byte_for_byte() {
4134 let src = "fn fib(n: i64) -> i64 is pure { if n <= 1 { return n } return fib(n - 1) + fib(n - 2) }";
4139 let a = Parser::parse(&lex(src)).expect("parses");
4140 let b = Parser::parse(&lex(src)).expect("parses");
4141 assert_eq!(a, b);
4142 let bad = "fn f() { let x = ( }";
4144 assert_eq!(Parser::parse(&lex(bad)), Parser::parse(&lex(bad)));
4145 }
4146}