1#[cfg(feature = "no_std")]
2use alloc::{boxed::Box, format, string::{String, ToString}, vec, vec::Vec};
3
4use crate::error::BopError;
5use crate::lexer::{SpannedToken, StringPart, Token};
6use crate::naming;
7
8fn ident_shape_error(site: &str, expected: &str, actual: &str, line: u32) -> BopError {
18 let actual_label = naming::kind_label(naming::classify(actual));
19 let message = format!(
20 "{} `{}` looks like a {}, but a {} name is required here",
21 site, actual, actual_label, expected
22 );
23 let mut err = BopError::runtime(message, line);
24 err.friendly_hint = Some(naming::hint_for(expected, actual));
25 err
26}
27
28fn ensure_value_name(name: &str, site: &str, line: u32) -> Result<(), BopError> {
32 if naming::is_value_name(name) {
33 Ok(())
34 } else {
35 Err(ident_shape_error(site, "value", name, line))
36 }
37}
38
39fn ensure_type_name(name: &str, site: &str, line: u32) -> Result<(), BopError> {
44 if naming::is_type_name(name) {
45 Ok(())
46 } else {
47 Err(ident_shape_error(site, "type", name, line))
48 }
49}
50
51fn ensure_constant_name(name: &str, site: &str, line: u32) -> Result<(), BopError> {
53 if naming::is_constant_name(name) {
54 Ok(())
55 } else {
56 Err(ident_shape_error(site, "constant", name, line))
57 }
58}
59
60#[derive(Debug, Clone)]
63pub struct Expr {
64 pub kind: ExprKind,
65 pub line: u32,
66 pub column: Option<core::num::NonZeroU32>,
73}
74
75impl Expr {
76 pub fn line(kind: ExprKind, line: u32) -> Self {
81 Self { kind, line, column: None }
82 }
83
84 pub fn at(kind: ExprKind, line: u32, column: Option<core::num::NonZeroU32>) -> Self {
87 Self { kind, line, column }
88 }
89}
90
91#[derive(Debug, Clone)]
92pub enum ExprKind {
93 Int(i64),
97 Number(f64),
98 Str(String),
99 StringInterp(Vec<StringPart>),
100 Bool(bool),
101 None,
102 Ident(String),
103 BinaryOp {
104 left: Box<Expr>,
105 op: BinOp,
106 right: Box<Expr>,
107 },
108 UnaryOp {
109 op: UnaryOp,
110 expr: Box<Expr>,
111 },
112 Call {
113 callee: Box<Expr>,
114 args: Vec<Expr>,
115 },
116 MethodCall {
117 object: Box<Expr>,
118 method: String,
119 args: Vec<Expr>,
120 },
121 FieldAccess {
124 object: Box<Expr>,
125 field: String,
126 },
127 StructConstruct {
132 namespace: Option<String>,
139 type_name: String,
140 fields: Vec<(String, Expr)>,
141 },
142 EnumConstruct {
147 namespace: Option<String>,
151 type_name: String,
152 variant: String,
153 payload: VariantPayload,
154 },
155 Index {
156 object: Box<Expr>,
157 index: Box<Expr>,
158 },
159 Array(Vec<Expr>),
160 Dict(Vec<(String, Expr)>),
161 IfExpr {
162 condition: Box<Expr>,
163 then_expr: Box<Expr>,
164 else_expr: Box<Expr>,
165 },
166 Lambda {
170 params: Vec<String>,
171 body: Vec<Stmt>,
172 },
173 Match {
178 scrutinee: Box<Expr>,
179 arms: Vec<MatchArm>,
180 },
181
182 Try(Box<Expr>),
200}
201
202#[derive(Debug, Clone)]
203pub struct MatchArm {
204 pub pattern: Pattern,
205 pub guard: Option<Expr>,
208 pub body: Expr,
209 pub line: u32,
210}
211
212#[derive(Debug, Clone)]
217pub enum Pattern {
218 Literal(LiteralPattern),
221 Wildcard,
223 Binding(String),
226 EnumVariant {
229 namespace: Option<String>,
230 type_name: String,
231 variant: String,
232 payload: VariantPatternPayload,
233 },
234 Struct {
237 namespace: Option<String>,
238 type_name: String,
239 fields: Vec<(String, Pattern)>,
240 rest: bool,
241 },
242 Array {
244 elements: Vec<Pattern>,
245 rest: Option<ArrayRest>,
246 },
247 Or(Vec<Pattern>),
250}
251
252#[derive(Debug, Clone)]
253pub enum LiteralPattern {
254 Int(i64),
257 Number(f64),
258 Str(String),
259 Bool(bool),
260 None,
261}
262
263#[derive(Debug, Clone)]
264pub enum VariantPatternPayload {
265 Unit,
266 Tuple(Vec<Pattern>),
267 Struct {
268 fields: Vec<(String, Pattern)>,
269 rest: bool,
270 },
271}
272
273#[derive(Debug, Clone)]
275pub enum ArrayRest {
276 Ignored,
278 Named(String),
280}
281
282#[derive(Debug, Clone, Copy)]
283pub enum BinOp {
284 Add,
285 Sub,
286 Mul,
287 Div,
288 Mod,
289 Eq,
290 NotEq,
291 Lt,
292 Gt,
293 LtEq,
294 GtEq,
295 And,
296 Or,
297}
298
299#[derive(Debug, Clone, Copy)]
300pub enum UnaryOp {
301 Neg,
302 Not,
303}
304
305#[derive(Debug, Clone)]
306pub struct Stmt {
307 pub kind: StmtKind,
308 pub line: u32,
309 pub column: Option<core::num::NonZeroU32>,
313}
314
315impl Stmt {
316 pub fn line(kind: StmtKind, line: u32) -> Self {
320 Self { kind, line, column: None }
321 }
322
323 pub fn at(kind: StmtKind, line: u32, column: Option<core::num::NonZeroU32>) -> Self {
325 Self { kind, line, column }
326 }
327}
328
329#[derive(Debug, Clone)]
330pub enum StmtKind {
331 Let {
338 name: String,
339 value: Expr,
340 is_const: bool,
341 },
342 Assign {
343 target: AssignTarget,
344 op: AssignOp,
345 value: Expr,
346 },
347 If {
348 condition: Expr,
349 body: Vec<Stmt>,
350 else_ifs: Vec<(Expr, Vec<Stmt>)>,
351 else_body: Option<Vec<Stmt>>,
352 },
353 While {
354 condition: Expr,
355 body: Vec<Stmt>,
356 },
357 Repeat {
358 count: Expr,
359 body: Vec<Stmt>,
360 },
361 ForIn {
362 var: String,
363 iterable: Expr,
364 body: Vec<Stmt>,
365 },
366 FnDecl {
367 name: String,
368 params: Vec<String>,
369 body: Vec<Stmt>,
370 },
371 MethodDecl {
377 type_name: String,
378 method_name: String,
379 params: Vec<String>,
380 body: Vec<Stmt>,
381 },
382 Return {
383 value: Option<Expr>,
384 },
385 Break,
386 Continue,
387 Use {
408 path: String,
409 items: Option<Vec<String>>,
413 alias: Option<String>,
417 },
418 StructDecl {
422 name: String,
423 fields: Vec<String>,
424 },
425 EnumDecl {
428 name: String,
429 variants: Vec<VariantDecl>,
430 },
431 ExprStmt(Expr),
432}
433
434#[derive(Debug, Clone, PartialEq)]
436pub struct VariantDecl {
437 pub name: String,
438 pub kind: VariantKind,
439}
440
441#[derive(Debug, Clone, PartialEq)]
443pub enum VariantKind {
444 Unit,
446 Tuple(Vec<String>),
448 Struct(Vec<String>),
450}
451
452#[derive(Debug, Clone)]
454pub enum VariantPayload {
455 Unit,
456 Tuple(Vec<Expr>),
457 Struct(Vec<(String, Expr)>),
458}
459
460#[derive(Debug, Clone)]
461pub enum AssignTarget {
462 Variable(String),
463 Index { object: Expr, index: Expr },
464 Field { object: Expr, field: String },
469}
470
471#[derive(Debug, Clone, Copy)]
472pub enum AssignOp {
473 Eq,
474 AddEq,
475 SubEq,
476 MulEq,
477 DivEq,
478 ModEq,
479}
480
481const MAX_PARSE_DEPTH: usize = 128;
484
485pub fn parse(tokens: Vec<SpannedToken>) -> Result<Vec<Stmt>, BopError> {
486 let mut parser = Parser::new(tokens);
487 parser.parse_program()
488}
489
490struct Parser {
491 tokens: Vec<SpannedToken>,
492 pos: usize,
493 depth: usize,
494 allow_struct_literal: bool,
500}
501
502impl Parser {
503 fn new(tokens: Vec<SpannedToken>) -> Self {
504 Self {
505 tokens,
506 pos: 0,
507 depth: 0,
508 allow_struct_literal: true,
509 }
510 }
511
512 fn enter(&mut self) -> Result<(), BopError> {
513 self.depth += 1;
514 if self.depth > MAX_PARSE_DEPTH {
515 Err(self.error(self.peek_line(), "Code is nested too deeply"))
516 } else {
517 Ok(())
518 }
519 }
520
521 fn leave(&mut self) {
522 self.depth -= 1;
523 }
524
525 fn peek(&self) -> &Token {
526 self.tokens
527 .get(self.pos)
528 .map(|t| &t.token)
529 .unwrap_or(&Token::Eof)
530 }
531
532 fn peek_line(&self) -> u32 {
533 self.tokens.get(self.pos).map(|t| t.line).unwrap_or(0)
534 }
535
536 fn peek_column(&self) -> u32 {
540 self.tokens.get(self.pos).map(|t| t.column).unwrap_or(0)
541 }
542
543 fn peek_pos(&self) -> (u32, Option<core::num::NonZeroU32>) {
549 let tok = self.tokens.get(self.pos);
550 let line = tok.map(|t| t.line).unwrap_or(0);
551 let column = tok
552 .map(|t| t.column)
553 .and_then(core::num::NonZeroU32::new);
554 (line, column)
555 }
556
557 fn peek_at(&self, offset: usize) -> &Token {
558 self.tokens
559 .get(self.pos + offset)
560 .map(|t| &t.token)
561 .unwrap_or(&Token::Eof)
562 }
563
564 fn without_struct_literal<F, R>(&mut self, f: F) -> R
569 where
570 F: FnOnce(&mut Self) -> R,
571 {
572 let saved = self.allow_struct_literal;
573 self.allow_struct_literal = false;
574 let result = f(self);
575 self.allow_struct_literal = saved;
576 result
577 }
578
579 fn advance(&mut self) -> &Token {
580 let tok = self
581 .tokens
582 .get(self.pos)
583 .map(|t| &t.token)
584 .unwrap_or(&Token::Eof);
585 if self.pos < self.tokens.len() {
586 self.pos += 1;
587 }
588 tok
589 }
590
591 fn is_at_end(&self) -> bool {
592 matches!(self.peek(), Token::Eof)
593 }
594
595 fn expect(&mut self, expected: &Token) -> Result<u32, BopError> {
596 let (line, _column) = self.peek_pos();
597 if self.peek() == expected {
598 self.advance();
599 Ok(line)
600 } else {
601 Err(self.error(
602 line,
603 format!(
604 "Expected `{}` but found `{}`",
605 fmt_token(expected),
606 fmt_token(self.peek())
607 ),
608 ))
609 }
610 }
611
612 fn expect_ident(&mut self) -> Result<(String, u32), BopError> {
613 let (line, _column) = self.peek_pos();
614 if let Token::Ident(name) = self.peek().clone() {
615 self.advance();
616 Ok((name, line))
617 } else {
618 Err(self.error(
619 line,
620 format!("Expected a name but found `{}`", fmt_token(self.peek())),
621 ))
622 }
623 }
624
625 fn skip_semicolons(&mut self) {
626 while matches!(self.peek(), Token::Semicolon) {
627 self.advance();
628 }
629 }
630
631 fn error(&self, line: u32, message: impl Into<String>) -> BopError {
632 let column = if self.tokens.get(self.pos).map(|t| t.line) == Some(line) {
637 Some(self.peek_column())
638 } else {
639 None
640 };
641 BopError {
642 line: Some(line),
643 column,
644 message: message.into(),
645 friendly_hint: None,
646 is_fatal: false,
647 is_try_return: false,
648 }
649 }
650
651 fn parse_program(&mut self) -> Result<Vec<Stmt>, BopError> {
654 let mut stmts = Vec::new();
655 self.skip_semicolons();
656 while !self.is_at_end() {
657 stmts.push(self.parse_statement()?);
658 self.skip_semicolons();
659 }
660 Ok(stmts)
661 }
662
663 fn parse_block(&mut self) -> Result<Vec<Stmt>, BopError> {
664 self.enter()?;
665 self.expect(&Token::LBrace)?;
666 let mut stmts = Vec::new();
667 self.skip_semicolons();
668 while !matches!(self.peek(), Token::RBrace | Token::Eof) {
669 stmts.push(self.parse_statement()?);
670 self.skip_semicolons();
671 }
672 self.expect(&Token::RBrace)?;
673 self.leave();
674 Ok(stmts)
675 }
676
677 fn parse_statement(&mut self) -> Result<Stmt, BopError> {
680 let (line, column) = self.peek_pos();
681 match self.peek() {
682 Token::Let => self.parse_let(),
683 Token::Const => self.parse_const(),
684 Token::If => self.parse_if_stmt(),
685 Token::While => self.parse_while(),
686 Token::For => self.parse_for(),
687 Token::Repeat => self.parse_repeat(),
688 Token::Fn if matches!(self.peek_at(1), Token::Ident(_)) => self.parse_fn_decl(),
692 Token::Return => self.parse_return(),
693 Token::Break => {
694 self.advance();
695 Ok(Stmt {
696 kind: StmtKind::Break,
697 line,
698 column,
699 })
700 }
701 Token::Continue => {
702 self.advance();
703 Ok(Stmt {
704 kind: StmtKind::Continue,
705 line,
706 column,
707 })
708 }
709 Token::Use => self.parse_use(),
710 Token::Struct => self.parse_struct_decl(),
711 Token::Enum => self.parse_enum_decl(),
712 _ => self.parse_expr_or_assign(),
713 }
714 }
715
716 fn parse_struct_decl(&mut self) -> Result<Stmt, BopError> {
717 let (line, column) = self.peek_pos();
718 self.advance(); let (name, name_line) = self.expect_ident()?;
720 ensure_type_name(&name, "`struct` declaration", name_line)?;
721 self.expect(&Token::LBrace)?;
722 let mut fields = Vec::new();
723 if !matches!(self.peek(), Token::RBrace) {
724 let (f, f_line) = self.expect_ident()?;
725 ensure_value_name(&f, "struct field", f_line)?;
726 fields.push(f);
727 while matches!(self.peek(), Token::Comma) {
728 self.advance();
729 if matches!(self.peek(), Token::RBrace) {
730 break; }
732 let (f, f_line) = self.expect_ident()?;
733 ensure_value_name(&f, "struct field", f_line)?;
734 fields.push(f);
735 }
736 }
737 self.expect(&Token::RBrace)?;
738 Ok(Stmt {
739 kind: StmtKind::StructDecl { name, fields },
740 line,
741 column,
742 })
743 }
744
745 fn parse_enum_decl(&mut self) -> Result<Stmt, BopError> {
746 let (line, column) = self.peek_pos();
747 self.advance(); let (name, name_line) = self.expect_ident()?;
749 ensure_type_name(&name, "`enum` declaration", name_line)?;
750 self.expect(&Token::LBrace)?;
751 let mut variants: Vec<VariantDecl> = Vec::new();
752 if !matches!(self.peek(), Token::RBrace) {
753 variants.push(self.parse_variant_decl()?);
754 while matches!(self.peek(), Token::Comma) {
755 self.advance();
756 if matches!(self.peek(), Token::RBrace) {
757 break; }
759 variants.push(self.parse_variant_decl()?);
760 }
761 }
762 self.expect(&Token::RBrace)?;
763 Ok(Stmt {
764 kind: StmtKind::EnumDecl { name, variants },
765 line,
766 column,
767 })
768 }
769
770 fn parse_variant_decl(&mut self) -> Result<VariantDecl, BopError> {
771 let (name, name_line) = self.expect_ident()?;
772 ensure_type_name(&name, "enum variant", name_line)?;
773 let kind = match self.peek() {
774 Token::LParen => {
775 self.advance();
776 let mut fields: Vec<String> = Vec::new();
777 if !matches!(self.peek(), Token::RParen) {
778 let (f, f_line) = self.expect_ident()?;
779 ensure_value_name(&f, "variant payload field", f_line)?;
780 fields.push(f);
781 while matches!(self.peek(), Token::Comma) {
782 self.advance();
783 if matches!(self.peek(), Token::RParen) {
784 break;
785 }
786 let (f, f_line) = self.expect_ident()?;
787 ensure_value_name(&f, "variant payload field", f_line)?;
788 fields.push(f);
789 }
790 }
791 self.expect(&Token::RParen)?;
792 VariantKind::Tuple(fields)
793 }
794 Token::LBrace => {
795 self.advance();
796 let mut fields: Vec<String> = Vec::new();
797 if !matches!(self.peek(), Token::RBrace) {
798 let (f, f_line) = self.expect_ident()?;
799 ensure_value_name(&f, "variant payload field", f_line)?;
800 fields.push(f);
801 while matches!(self.peek(), Token::Comma) {
802 self.advance();
803 if matches!(self.peek(), Token::RBrace) {
804 break;
805 }
806 let (f, f_line) = self.expect_ident()?;
807 ensure_value_name(&f, "variant payload field", f_line)?;
808 fields.push(f);
809 }
810 }
811 self.expect(&Token::RBrace)?;
812 VariantKind::Struct(fields)
813 }
814 _ => VariantKind::Unit,
815 };
816 Ok(VariantDecl { name, kind })
817 }
818
819 fn parse_use(&mut self) -> Result<Stmt, BopError> {
820 let (line, column) = self.peek_pos();
821 self.advance(); let (first, first_line) = self.expect_ident()?;
823 ensure_value_name(&first, "module path segment", first_line)?;
824 let mut path = first;
825
826 loop {
829 if !matches!(self.peek(), Token::Dot) {
830 break;
831 }
832 if matches!(self.peek_at(1), Token::LBrace) {
835 break;
836 }
837 self.advance(); let (seg, seg_line) = self.expect_ident()?;
839 ensure_value_name(&seg, "module path segment", seg_line)?;
840 path.push('.');
841 path.push_str(&seg);
842 }
843
844 let items = if matches!(self.peek(), Token::Dot) {
846 self.advance(); self.expect(&Token::LBrace)?;
848 let mut list: Vec<String> = Vec::new();
849 if !matches!(self.peek(), Token::RBrace) {
850 let (name, _) = self.expect_ident()?;
851 list.push(name);
852 while matches!(self.peek(), Token::Comma) {
853 self.advance();
854 if matches!(self.peek(), Token::RBrace) {
855 break; }
857 let (name, _) = self.expect_ident()?;
858 list.push(name);
859 }
860 }
861 self.expect(&Token::RBrace)?;
862 Some(list)
863 } else {
864 None
865 };
866
867 let alias = if matches!(self.peek(), Token::As) {
869 self.advance();
870 let (name, name_line) = self.expect_ident()?;
871 ensure_value_name(&name, "`use` alias", name_line)?;
872 Some(name)
873 } else {
874 None
875 };
876
877 Ok(Stmt {
878 kind: StmtKind::Use { path, items, alias },
879 line,
880 column,
881 })
882 }
883
884 fn parse_let(&mut self) -> Result<Stmt, BopError> {
885 let (line, column) = self.peek_pos();
886 self.advance(); let (name, _) = self.expect_ident()?;
888 ensure_value_name(&name, "`let` binding", line)?;
889 self.expect(&Token::Eq)?;
890 let value = self.parse_expr()?;
891 Ok(Stmt {
892 kind: StmtKind::Let { name, value, is_const: false },
893 line,
894 column,
895 })
896 }
897
898 fn parse_const(&mut self) -> Result<Stmt, BopError> {
905 let (line, column) = self.peek_pos();
906 self.advance(); let (name, _) = self.expect_ident()?;
908 ensure_constant_name(&name, "`const` declaration", line)?;
909 self.expect(&Token::Eq)?;
910 let value = self.parse_expr()?;
911 Ok(Stmt {
912 kind: StmtKind::Let { name, value, is_const: true },
913 line,
914 column,
915 })
916 }
917
918 fn parse_if_stmt(&mut self) -> Result<Stmt, BopError> {
919 let (line, column) = self.peek_pos();
920 self.advance(); let condition = self.without_struct_literal(|p| p.parse_expr())?;
922 let body = self.parse_block()?;
923
924 let mut else_ifs = Vec::new();
925 let mut else_body = None;
926
927 while matches!(self.peek(), Token::Else) {
928 self.advance(); if matches!(self.peek(), Token::If) {
930 self.advance(); let cond = self.without_struct_literal(|p| p.parse_expr())?;
932 let block = self.parse_block()?;
933 else_ifs.push((cond, block));
934 } else {
935 else_body = Some(self.parse_block()?);
936 break;
937 }
938 }
939
940 Ok(Stmt {
941 kind: StmtKind::If {
942 condition,
943 body,
944 else_ifs,
945 else_body,
946 },
947 line,
948 column,
949 })
950 }
951
952 fn parse_while(&mut self) -> Result<Stmt, BopError> {
953 let (line, column) = self.peek_pos();
954 self.advance(); let condition = self.without_struct_literal(|p| p.parse_expr())?;
956 let body = self.parse_block()?;
957 Ok(Stmt {
958 kind: StmtKind::While { condition, body },
959 line,
960 column,
961 })
962 }
963
964 fn parse_for(&mut self) -> Result<Stmt, BopError> {
965 let (line, column) = self.peek_pos();
966 self.advance(); let (var, var_line) = self.expect_ident()?;
968 ensure_value_name(&var, "`for` loop variable", var_line)?;
969 self.expect(&Token::In)?;
970 let iterable = self.without_struct_literal(|p| p.parse_expr())?;
971 let body = self.parse_block()?;
972 Ok(Stmt {
973 kind: StmtKind::ForIn {
974 var,
975 iterable,
976 body,
977 },
978 line,
979 column,
980 })
981 }
982
983 fn parse_repeat(&mut self) -> Result<Stmt, BopError> {
984 let (line, column) = self.peek_pos();
985 self.advance(); let count = self.without_struct_literal(|p| p.parse_expr())?;
987 let body = self.parse_block()?;
988 Ok(Stmt {
989 kind: StmtKind::Repeat { count, body },
990 line,
991 column,
992 })
993 }
994
995 fn parse_fn_decl(&mut self) -> Result<Stmt, BopError> {
996 let (line, column) = self.peek_pos();
997 self.advance(); let (name, name_line) = self.expect_ident()?;
999
1000 if matches!(self.peek(), Token::Dot) {
1005 ensure_type_name(&name, "method receiver", name_line)?;
1006 self.advance();
1007 let (method_name, method_line) = self.expect_ident()?;
1008 ensure_value_name(&method_name, "method name", method_line)?;
1009 self.expect(&Token::LParen)?;
1010 let mut params = Vec::new();
1011 if !matches!(self.peek(), Token::RParen) {
1012 let (p, p_line) = self.expect_ident()?;
1013 ensure_value_name(&p, "method parameter", p_line)?;
1014 params.push(p);
1015 while matches!(self.peek(), Token::Comma) {
1016 self.advance();
1017 let (p, p_line) = self.expect_ident()?;
1018 ensure_value_name(&p, "method parameter", p_line)?;
1019 params.push(p);
1020 }
1021 }
1022 self.expect(&Token::RParen)?;
1023 let body = self.parse_block()?;
1024 return Ok(Stmt {
1025 kind: StmtKind::MethodDecl {
1026 type_name: name,
1027 method_name,
1028 params,
1029 body,
1030 },
1031 line,
1032 column,
1033 });
1034 }
1035
1036 ensure_value_name(&name, "`fn` declaration", name_line)?;
1037 self.expect(&Token::LParen)?;
1038
1039 let mut params = Vec::new();
1040 if !matches!(self.peek(), Token::RParen) {
1041 let (p, p_line) = self.expect_ident()?;
1042 ensure_value_name(&p, "function parameter", p_line)?;
1043 params.push(p);
1044 while matches!(self.peek(), Token::Comma) {
1045 self.advance();
1046 let (p, p_line) = self.expect_ident()?;
1047 ensure_value_name(&p, "function parameter", p_line)?;
1048 params.push(p);
1049 }
1050 }
1051 self.expect(&Token::RParen)?;
1052 let body = self.parse_block()?;
1053 Ok(Stmt {
1054 kind: StmtKind::FnDecl { name, params, body },
1055 line,
1056 column,
1057 })
1058 }
1059
1060 fn parse_return(&mut self) -> Result<Stmt, BopError> {
1061 let (line, column) = self.peek_pos();
1062 self.advance(); let value = if matches!(self.peek(), Token::Semicolon | Token::RBrace | Token::Eof) {
1064 None
1065 } else {
1066 Some(self.parse_expr()?)
1067 };
1068 Ok(Stmt {
1069 kind: StmtKind::Return { value },
1070 line,
1071 column,
1072 })
1073 }
1074
1075 fn parse_expr_or_assign(&mut self) -> Result<Stmt, BopError> {
1076 let (line, column) = self.peek_pos();
1077 let expr = self.parse_expr()?;
1078
1079 let op = match self.peek() {
1080 Token::Eq => Some(AssignOp::Eq),
1081 Token::PlusEq => Some(AssignOp::AddEq),
1082 Token::MinusEq => Some(AssignOp::SubEq),
1083 Token::StarEq => Some(AssignOp::MulEq),
1084 Token::SlashEq => Some(AssignOp::DivEq),
1085 Token::PercentEq => Some(AssignOp::ModEq),
1086 _ => None,
1087 };
1088
1089 if let Some(op) = op {
1090 self.advance(); let target = expr_to_assign_target(expr, line)?;
1092 let value = self.parse_expr()?;
1093 Ok(Stmt {
1094 kind: StmtKind::Assign { target, op, value },
1095 line,
1096 column,
1097 })
1098 } else {
1099 Ok(Stmt {
1100 kind: StmtKind::ExprStmt(expr),
1101 line,
1102 column,
1103 })
1104 }
1105 }
1106
1107 fn parse_expr(&mut self) -> Result<Expr, BopError> {
1110 self.parse_or()
1111 }
1112
1113 fn parse_or(&mut self) -> Result<Expr, BopError> {
1114 let mut left = self.parse_and()?;
1115 while matches!(self.peek(), Token::PipePipe) {
1116 let (line, column) = self.peek_pos();
1117 self.advance();
1118 let right = self.parse_and()?;
1119 left = Expr {
1120 kind: ExprKind::BinaryOp {
1121 left: Box::new(left),
1122 op: BinOp::Or,
1123 right: Box::new(right),
1124 },
1125 line,
1126 column,
1127 };
1128 }
1129 Ok(left)
1130 }
1131
1132 fn parse_and(&mut self) -> Result<Expr, BopError> {
1133 let mut left = self.parse_equality()?;
1134 while matches!(self.peek(), Token::AmpAmp) {
1135 let (line, column) = self.peek_pos();
1136 self.advance();
1137 let right = self.parse_equality()?;
1138 left = Expr {
1139 kind: ExprKind::BinaryOp {
1140 left: Box::new(left),
1141 op: BinOp::And,
1142 right: Box::new(right),
1143 },
1144 line,
1145 column,
1146 };
1147 }
1148 Ok(left)
1149 }
1150
1151 fn parse_equality(&mut self) -> Result<Expr, BopError> {
1152 let mut left = self.parse_comparison()?;
1153 while matches!(self.peek(), Token::EqEq | Token::BangEq) {
1154 let (line, column) = self.peek_pos();
1155 let op = if matches!(self.peek(), Token::EqEq) {
1156 BinOp::Eq
1157 } else {
1158 BinOp::NotEq
1159 };
1160 self.advance();
1161 let right = self.parse_comparison()?;
1162 left = Expr {
1163 kind: ExprKind::BinaryOp {
1164 left: Box::new(left),
1165 op,
1166 right: Box::new(right),
1167 },
1168 line,
1169 column,
1170 };
1171 }
1172 Ok(left)
1173 }
1174
1175 fn parse_comparison(&mut self) -> Result<Expr, BopError> {
1176 let mut left = self.parse_addition()?;
1177 while matches!(
1178 self.peek(),
1179 Token::Lt | Token::Gt | Token::LtEq | Token::GtEq
1180 ) {
1181 let (line, column) = self.peek_pos();
1182 let op = match self.peek() {
1183 Token::Lt => BinOp::Lt,
1184 Token::Gt => BinOp::Gt,
1185 Token::LtEq => BinOp::LtEq,
1186 _ => BinOp::GtEq,
1187 };
1188 self.advance();
1189 let right = self.parse_addition()?;
1190 left = Expr {
1191 kind: ExprKind::BinaryOp {
1192 left: Box::new(left),
1193 op,
1194 right: Box::new(right),
1195 },
1196 line,
1197 column,
1198 };
1199 }
1200 Ok(left)
1201 }
1202
1203 fn parse_addition(&mut self) -> Result<Expr, BopError> {
1204 let mut left = self.parse_multiply()?;
1205 while matches!(self.peek(), Token::Plus | Token::Minus) {
1206 let (line, column) = self.peek_pos();
1207 let op = if matches!(self.peek(), Token::Plus) {
1208 BinOp::Add
1209 } else {
1210 BinOp::Sub
1211 };
1212 self.advance();
1213 let right = self.parse_multiply()?;
1214 left = Expr {
1215 kind: ExprKind::BinaryOp {
1216 left: Box::new(left),
1217 op,
1218 right: Box::new(right),
1219 },
1220 line,
1221 column,
1222 };
1223 }
1224 Ok(left)
1225 }
1226
1227 fn parse_multiply(&mut self) -> Result<Expr, BopError> {
1228 let mut left = self.parse_unary()?;
1229 while matches!(
1230 self.peek(),
1231 Token::Star | Token::Slash | Token::Percent
1232 ) {
1233 let (line, column) = self.peek_pos();
1234 let op = match self.peek() {
1235 Token::Star => BinOp::Mul,
1236 Token::Slash => BinOp::Div,
1237 _ => BinOp::Mod,
1238 };
1239 self.advance();
1240 let right = self.parse_unary()?;
1241 left = Expr {
1242 kind: ExprKind::BinaryOp {
1243 left: Box::new(left),
1244 op,
1245 right: Box::new(right),
1246 },
1247 line,
1248 column,
1249 };
1250 }
1251 Ok(left)
1252 }
1253
1254 fn parse_unary(&mut self) -> Result<Expr, BopError> {
1255 self.enter()?;
1256 let (line, column) = self.peek_pos();
1257 let result = match self.peek() {
1258 Token::Bang => {
1259 self.advance();
1260 let expr = self.parse_unary()?;
1261 Ok(Expr {
1262 kind: ExprKind::UnaryOp {
1263 op: UnaryOp::Not,
1264 expr: Box::new(expr),
1265 },
1266 line,
1267 column,
1268 })
1269 }
1270 Token::Minus => {
1271 self.advance();
1272 let expr = self.parse_unary()?;
1273 Ok(Expr {
1274 kind: ExprKind::UnaryOp {
1275 op: UnaryOp::Neg,
1276 expr: Box::new(expr),
1277 },
1278 line,
1279 column,
1280 })
1281 }
1282 Token::Try => {
1283 self.advance();
1289 let expr = self.parse_unary()?;
1290 Ok(Expr {
1291 kind: ExprKind::Try(Box::new(expr)),
1292 line,
1293 column,
1294 })
1295 }
1296 _ => self.parse_postfix(),
1297 };
1298 self.leave();
1299 result
1300 }
1301
1302 fn parse_postfix(&mut self) -> Result<Expr, BopError> {
1303 let mut expr = self.parse_primary()?;
1304
1305 loop {
1306 match self.peek() {
1307 Token::LParen => {
1308 let (line, column) = self.peek_pos();
1309 self.advance();
1310 let args = self.parse_args()?;
1311 self.expect(&Token::RParen)?;
1312 expr = Expr {
1313 kind: ExprKind::Call {
1314 callee: Box::new(expr),
1315 args,
1316 },
1317 line,
1318 column,
1319 };
1320 }
1321 Token::LBracket => {
1322 let (line, column) = self.peek_pos();
1323 self.advance();
1324 let index = self.parse_expr()?;
1325 self.expect(&Token::RBracket)?;
1326 expr = Expr {
1327 kind: ExprKind::Index {
1328 object: Box::new(expr),
1329 index: Box::new(index),
1330 },
1331 line,
1332 column,
1333 };
1334 }
1335 Token::Dot => {
1336 let (line, column) = self.peek_pos();
1337 self.advance();
1338 let (name, _) = self.expect_ident()?;
1339
1340 if let ExprKind::Ident(ns) = &expr.kind {
1347 if naming::is_type_name(&name) {
1348 match self.peek() {
1349 Token::ColonColon => {
1350 let ns_owned = ns.clone();
1351 expr = self.parse_enum_variant_tail(
1352 name,
1353 Some(ns_owned),
1354 line,
1355 expr.column,
1356 )?;
1357 continue;
1358 }
1359 Token::LBrace if self.allow_struct_literal => {
1360 let ns_owned = ns.clone();
1361 expr = self.parse_struct_literal(
1362 name,
1363 Some(ns_owned),
1364 line,
1365 expr.column,
1366 )?;
1367 continue;
1368 }
1369 _ => {}
1370 }
1371 }
1372 }
1373
1374 if matches!(self.peek(), Token::LParen) {
1375 self.advance();
1377 let args = self.parse_args()?;
1378 self.expect(&Token::RParen)?;
1379 expr = Expr {
1380 kind: ExprKind::MethodCall {
1381 object: Box::new(expr),
1382 method: name,
1383 args,
1384 },
1385 line,
1386 column,
1387 };
1388 } else {
1389 expr = Expr {
1391 kind: ExprKind::FieldAccess {
1392 object: Box::new(expr),
1393 field: name,
1394 },
1395 line,
1396 column,
1397 };
1398 }
1399 }
1400 _ => break,
1401 }
1402 }
1403
1404 Ok(expr)
1405 }
1406
1407 fn parse_args(&mut self) -> Result<Vec<Expr>, BopError> {
1408 let mut args = Vec::new();
1409 if !matches!(self.peek(), Token::RParen) {
1410 args.push(self.parse_expr()?);
1411 while matches!(self.peek(), Token::Comma) {
1412 self.advance();
1413 args.push(self.parse_expr()?);
1414 }
1415 }
1416 Ok(args)
1417 }
1418
1419 fn parse_primary(&mut self) -> Result<Expr, BopError> {
1420 let (line, column) = self.peek_pos();
1421
1422 match self.peek().clone() {
1423 Token::Int(n) => {
1424 self.advance();
1425 Ok(Expr {
1426 kind: ExprKind::Int(n),
1427 line,
1428 column,
1429 })
1430 }
1431 Token::Number(n) => {
1432 self.advance();
1433 Ok(Expr {
1434 kind: ExprKind::Number(n),
1435 line,
1436 column,
1437 })
1438 }
1439 Token::Str(s) => {
1440 self.advance();
1441 Ok(Expr {
1442 kind: ExprKind::Str(s),
1443 line,
1444 column,
1445 })
1446 }
1447 Token::StringInterp(parts) => {
1448 self.advance();
1449 Ok(Expr {
1450 kind: ExprKind::StringInterp(parts),
1451 line,
1452 column,
1453 })
1454 }
1455 Token::True => {
1456 self.advance();
1457 Ok(Expr {
1458 kind: ExprKind::Bool(true),
1459 line,
1460 column,
1461 })
1462 }
1463 Token::False => {
1464 self.advance();
1465 Ok(Expr {
1466 kind: ExprKind::Bool(false),
1467 line,
1468 column,
1469 })
1470 }
1471 Token::None => {
1472 self.advance();
1473 Ok(Expr {
1474 kind: ExprKind::None,
1475 line,
1476 column,
1477 })
1478 }
1479 Token::Ident(name) => {
1480 self.advance();
1481 if (name == "Ok" || name == "Err")
1490 && matches!(self.peek(), Token::LParen)
1491 {
1492 return self.parse_result_shorthand(name, line, column);
1493 }
1494 if matches!(self.peek(), Token::ColonColon) {
1499 return self.parse_enum_variant_tail(name, None, line, column);
1500 }
1501 if self.allow_struct_literal && matches!(self.peek(), Token::LBrace) {
1507 return self.parse_struct_literal(name, None, line, column);
1508 }
1509 Ok(Expr {
1510 kind: ExprKind::Ident(name),
1511 line,
1512 column,
1513 })
1514 }
1515 Token::LParen => {
1516 self.enter()?;
1517 self.advance();
1518 let expr = self.parse_expr()?;
1519 self.expect(&Token::RParen)?;
1520 self.leave();
1521 Ok(expr)
1522 }
1523 Token::LBracket => self.parse_array_literal(),
1524 Token::LBrace => self.parse_dict_literal(),
1525 Token::If => self.parse_if_expr(),
1526 Token::Fn => self.parse_lambda(),
1527 Token::Match => self.parse_match_expr(),
1528 _ => Err(self.error(
1529 line,
1530 format!("I didn't expect `{}` here", fmt_token(self.peek())),
1531 )),
1532 }
1533 }
1534
1535 fn parse_enum_variant_tail(
1536 &mut self,
1537 type_name: String,
1538 namespace: Option<String>,
1539 line: u32,
1540 column: Option<core::num::NonZeroU32>,
1541 ) -> Result<Expr, BopError> {
1542 self.advance(); let (variant, _) = self.expect_ident()?;
1544 let payload = match self.peek() {
1545 Token::LParen => {
1546 self.enter()?;
1547 self.advance();
1548 let mut args: Vec<Expr> = Vec::new();
1549 if !matches!(self.peek(), Token::RParen) {
1550 args.push(self.parse_expr()?);
1551 while matches!(self.peek(), Token::Comma) {
1552 self.advance();
1553 if matches!(self.peek(), Token::RParen) {
1554 break;
1555 }
1556 args.push(self.parse_expr()?);
1557 }
1558 }
1559 self.expect(&Token::RParen)?;
1560 self.leave();
1561 VariantPayload::Tuple(args)
1562 }
1563 Token::LBrace if self.allow_struct_literal => {
1564 self.enter()?;
1565 self.advance();
1566 let mut fields: Vec<(String, Expr)> = Vec::new();
1567 if !matches!(self.peek(), Token::RBrace) {
1568 let (fname, _) = self.expect_ident()?;
1569 self.expect(&Token::Colon)?;
1570 let fvalue = self.parse_expr()?;
1571 fields.push((fname, fvalue));
1572 while matches!(self.peek(), Token::Comma) {
1573 self.advance();
1574 if matches!(self.peek(), Token::RBrace) {
1575 break;
1576 }
1577 let (fname, _) = self.expect_ident()?;
1578 self.expect(&Token::Colon)?;
1579 let fvalue = self.parse_expr()?;
1580 fields.push((fname, fvalue));
1581 }
1582 }
1583 self.expect(&Token::RBrace)?;
1584 self.leave();
1585 VariantPayload::Struct(fields)
1586 }
1587 _ => VariantPayload::Unit,
1588 };
1589 Ok(Expr {
1590 kind: ExprKind::EnumConstruct {
1591 namespace,
1592 type_name,
1593 variant,
1594 payload,
1595 },
1596 line,
1597 column,
1598 })
1599 }
1600
1601 fn parse_result_shorthand(
1608 &mut self,
1609 variant: String,
1610 line: u32,
1611 column: Option<core::num::NonZeroU32>,
1612 ) -> Result<Expr, BopError> {
1613 debug_assert!(variant == "Ok" || variant == "Err");
1614 self.enter()?;
1615 self.expect(&Token::LParen)?;
1616 let mut args: Vec<Expr> = Vec::new();
1617 if !matches!(self.peek(), Token::RParen) {
1618 args.push(self.parse_expr()?);
1619 while matches!(self.peek(), Token::Comma) {
1620 self.advance();
1621 if matches!(self.peek(), Token::RParen) {
1622 break;
1623 }
1624 args.push(self.parse_expr()?);
1625 }
1626 }
1627 self.expect(&Token::RParen)?;
1628 self.leave();
1629 Ok(Expr {
1630 kind: ExprKind::EnumConstruct {
1631 namespace: None,
1632 type_name: String::from("Result"),
1633 variant,
1634 payload: VariantPayload::Tuple(args),
1635 },
1636 line,
1637 column,
1638 })
1639 }
1640
1641 fn parse_struct_literal(
1642 &mut self,
1643 type_name: String,
1644 namespace: Option<String>,
1645 line: u32,
1646 column: Option<core::num::NonZeroU32>,
1647 ) -> Result<Expr, BopError> {
1648 self.enter()?;
1649 self.expect(&Token::LBrace)?;
1650 let mut fields: Vec<(String, Expr)> = Vec::new();
1651 if !matches!(self.peek(), Token::RBrace) {
1652 let (fname, _) = self.expect_ident()?;
1653 self.expect(&Token::Colon)?;
1654 let fvalue = self.parse_expr()?;
1655 fields.push((fname, fvalue));
1656 while matches!(self.peek(), Token::Comma) {
1657 self.advance();
1658 if matches!(self.peek(), Token::RBrace) {
1659 break; }
1661 let (fname, _) = self.expect_ident()?;
1662 self.expect(&Token::Colon)?;
1663 let fvalue = self.parse_expr()?;
1664 fields.push((fname, fvalue));
1665 }
1666 }
1667 self.expect(&Token::RBrace)?;
1668 self.leave();
1669 Ok(Expr {
1670 kind: ExprKind::StructConstruct {
1671 namespace,
1672 type_name,
1673 fields,
1674 },
1675 line,
1676 column,
1677 })
1678 }
1679
1680 fn parse_array_literal(&mut self) -> Result<Expr, BopError> {
1681 let (line, column) = self.peek_pos();
1682 self.advance(); let mut elements = Vec::new();
1684 if !matches!(self.peek(), Token::RBracket) {
1685 elements.push(self.parse_expr()?);
1686 while matches!(self.peek(), Token::Comma) {
1687 self.advance();
1688 if matches!(self.peek(), Token::RBracket) {
1689 break; }
1691 elements.push(self.parse_expr()?);
1692 }
1693 }
1694 self.expect(&Token::RBracket)?;
1695 Ok(Expr {
1696 kind: ExprKind::Array(elements),
1697 line,
1698 column,
1699 })
1700 }
1701
1702 fn parse_dict_literal(&mut self) -> Result<Expr, BopError> {
1703 let (line, column) = self.peek_pos();
1704 self.advance(); let mut entries = Vec::new();
1706 if !matches!(self.peek(), Token::RBrace) {
1707 let key = self.expect_string_key()?;
1708 self.expect(&Token::Colon)?;
1709 let value = self.parse_expr()?;
1710 entries.push((key, value));
1711 while matches!(self.peek(), Token::Comma) {
1712 self.advance();
1713 if matches!(self.peek(), Token::RBrace) {
1714 break; }
1716 let key = self.expect_string_key()?;
1717 self.expect(&Token::Colon)?;
1718 let value = self.parse_expr()?;
1719 entries.push((key, value));
1720 }
1721 }
1722 self.expect(&Token::RBrace)?;
1723 Ok(Expr {
1724 kind: ExprKind::Dict(entries),
1725 line,
1726 column,
1727 })
1728 }
1729
1730 fn expect_string_key(&mut self) -> Result<String, BopError> {
1731 let (line, _column) = self.peek_pos();
1732 match self.peek().clone() {
1733 Token::Str(s) => {
1734 self.advance();
1735 Ok(s)
1736 }
1737 _ => Err(self.error(line, "Dict keys must be strings (in quotes)")),
1738 }
1739 }
1740
1741 fn parse_match_expr(&mut self) -> Result<Expr, BopError> {
1742 let (line, column) = self.peek_pos();
1743 self.advance(); let scrutinee = self.without_struct_literal(|p| p.parse_expr())?;
1748 self.expect(&Token::LBrace)?;
1749 let mut arms: Vec<MatchArm> = Vec::new();
1750 self.skip_semicolons();
1751 while !matches!(self.peek(), Token::RBrace | Token::Eof) {
1752 arms.push(self.parse_match_arm()?);
1753 while matches!(self.peek(), Token::Comma | Token::Semicolon) {
1757 self.advance();
1758 }
1759 }
1760 self.expect(&Token::RBrace)?;
1761 Ok(Expr {
1762 kind: ExprKind::Match {
1763 scrutinee: Box::new(scrutinee),
1764 arms,
1765 },
1766 line,
1767 column,
1768 })
1769 }
1770
1771 fn parse_match_arm(&mut self) -> Result<MatchArm, BopError> {
1772 let (line, _column) = self.peek_pos();
1773 let pattern = self.parse_pattern()?;
1774 let guard = if matches!(self.peek(), Token::If) {
1775 self.advance();
1776 Some(self.without_struct_literal(|p| p.parse_expr())?)
1777 } else {
1778 None
1779 };
1780 self.expect(&Token::FatArrow)?;
1781 let body = self.parse_expr()?;
1782 Ok(MatchArm {
1783 pattern,
1784 guard,
1785 body,
1786 line,
1787 })
1788 }
1789
1790 fn parse_pattern(&mut self) -> Result<Pattern, BopError> {
1791 let first = self.parse_pattern_single()?;
1792 if matches!(self.peek(), Token::Pipe) {
1796 let mut alts = vec![first];
1797 while matches!(self.peek(), Token::Pipe) {
1798 self.advance();
1799 alts.push(self.parse_pattern_single()?);
1800 }
1801 Ok(Pattern::Or(alts))
1802 } else {
1803 Ok(first)
1804 }
1805 }
1806
1807 fn parse_pattern_single(&mut self) -> Result<Pattern, BopError> {
1808 self.enter()?;
1809 let (line, _column) = self.peek_pos();
1810 let result = match self.peek().clone() {
1811 Token::Int(n) => {
1812 self.advance();
1813 Ok(Pattern::Literal(LiteralPattern::Int(n)))
1814 }
1815 Token::Number(n) => {
1816 self.advance();
1817 Ok(Pattern::Literal(LiteralPattern::Number(n)))
1818 }
1819 Token::Str(s) => {
1820 self.advance();
1821 Ok(Pattern::Literal(LiteralPattern::Str(s)))
1822 }
1823 Token::True => {
1824 self.advance();
1825 Ok(Pattern::Literal(LiteralPattern::Bool(true)))
1826 }
1827 Token::False => {
1828 self.advance();
1829 Ok(Pattern::Literal(LiteralPattern::Bool(false)))
1830 }
1831 Token::None => {
1832 self.advance();
1833 Ok(Pattern::Literal(LiteralPattern::None))
1834 }
1835 Token::Minus => {
1836 self.advance();
1838 match self.peek().clone() {
1839 Token::Int(n) => {
1840 self.advance();
1841 match n.checked_neg() {
1846 Some(neg) => Ok(Pattern::Literal(LiteralPattern::Int(neg))),
1847 None => Err(self.error(
1848 line,
1849 format!(
1850 "Integer literal `-{}` is out of range for i64",
1851 n
1852 ),
1853 )),
1854 }
1855 }
1856 Token::Number(n) => {
1857 self.advance();
1858 Ok(Pattern::Literal(LiteralPattern::Number(-n)))
1859 }
1860 other => Err(self.error(
1861 line,
1862 format!(
1863 "Expected a number after `-` in pattern, got `{}`",
1864 fmt_token(&other)
1865 ),
1866 )),
1867 }
1868 }
1869 Token::LBracket => self.parse_pattern_array(),
1870 Token::Ident(name) if name == "_" => {
1871 self.advance();
1872 Ok(Pattern::Wildcard)
1873 }
1874 Token::Ident(name) => {
1875 self.advance();
1876 if (name == "Ok" || name == "Err")
1881 && matches!(self.peek(), Token::LParen)
1882 {
1883 return self.parse_result_shorthand_pattern(name);
1884 }
1885 if matches!(self.peek(), Token::ColonColon) {
1887 self.parse_pattern_variant_tail(name, None)
1888 } else if matches!(self.peek(), Token::LBrace) {
1889 self.parse_pattern_struct(name, None)
1894 } else if matches!(self.peek(), Token::Dot)
1895 && naming::is_value_name(&name)
1896 {
1897 self.advance(); let (type_name, type_line) = self.expect_ident()?;
1904 if !naming::is_type_name(&type_name) {
1905 return Err(self.error(
1906 type_line,
1907 format!(
1908 "Expected a type name after `{}.` in pattern, got `{}`",
1909 name, type_name
1910 ),
1911 ));
1912 }
1913 if matches!(self.peek(), Token::ColonColon) {
1914 self.parse_pattern_variant_tail(type_name, Some(name))
1915 } else if matches!(self.peek(), Token::LBrace) {
1916 self.parse_pattern_struct(type_name, Some(name))
1917 } else {
1918 Err(self.error(
1919 type_line,
1920 format!(
1921 "Expected `::Variant(...)` or `{{...}}` after `{}.{}` in pattern",
1922 name, type_name
1923 ),
1924 ))
1925 }
1926 } else {
1927 Ok(Pattern::Binding(name))
1930 }
1931 }
1932 other => Err(self.error(
1933 line,
1934 format!("Expected a pattern, got `{}`", fmt_token(&other)),
1935 )),
1936 };
1937 self.leave();
1938 result
1939 }
1940
1941 fn parse_pattern_array(&mut self) -> Result<Pattern, BopError> {
1942 self.advance(); let mut elements: Vec<Pattern> = Vec::new();
1944 let mut rest: Option<ArrayRest> = None;
1945 if !matches!(self.peek(), Token::RBracket) {
1946 loop {
1947 if matches!(self.peek(), Token::DotDot) {
1948 self.advance();
1949 let captured = match self.peek().clone() {
1951 Token::Ident(n) if n != "_" => {
1952 self.advance();
1953 ArrayRest::Named(n)
1954 }
1955 _ => ArrayRest::Ignored,
1956 };
1957 rest = Some(captured);
1958 break;
1962 }
1963 elements.push(self.parse_pattern()?);
1964 if matches!(self.peek(), Token::Comma) {
1965 self.advance();
1966 if matches!(self.peek(), Token::RBracket) {
1967 break; }
1969 } else {
1970 break;
1971 }
1972 }
1973 }
1974 self.expect(&Token::RBracket)?;
1975 Ok(Pattern::Array { elements, rest })
1976 }
1977
1978 fn parse_pattern_variant_tail(
1979 &mut self,
1980 type_name: String,
1981 namespace: Option<String>,
1982 ) -> Result<Pattern, BopError> {
1983 self.advance(); let (variant, _) = self.expect_ident()?;
1985 let payload = match self.peek() {
1986 Token::LParen => {
1987 self.advance();
1988 let mut items: Vec<Pattern> = Vec::new();
1989 if !matches!(self.peek(), Token::RParen) {
1990 items.push(self.parse_pattern()?);
1991 while matches!(self.peek(), Token::Comma) {
1992 self.advance();
1993 if matches!(self.peek(), Token::RParen) {
1994 break;
1995 }
1996 items.push(self.parse_pattern()?);
1997 }
1998 }
1999 self.expect(&Token::RParen)?;
2000 VariantPatternPayload::Tuple(items)
2001 }
2002 Token::LBrace => {
2003 let (fields, rest) = self.parse_pattern_field_list()?;
2004 VariantPatternPayload::Struct { fields, rest }
2005 }
2006 _ => VariantPatternPayload::Unit,
2007 };
2008 Ok(Pattern::EnumVariant {
2009 namespace,
2010 type_name,
2011 variant,
2012 payload,
2013 })
2014 }
2015
2016 fn parse_result_shorthand_pattern(
2022 &mut self,
2023 variant: String,
2024 ) -> Result<Pattern, BopError> {
2025 debug_assert!(variant == "Ok" || variant == "Err");
2026 self.expect(&Token::LParen)?;
2027 let mut items: Vec<Pattern> = Vec::new();
2028 if !matches!(self.peek(), Token::RParen) {
2029 items.push(self.parse_pattern()?);
2030 while matches!(self.peek(), Token::Comma) {
2031 self.advance();
2032 if matches!(self.peek(), Token::RParen) {
2033 break;
2034 }
2035 items.push(self.parse_pattern()?);
2036 }
2037 }
2038 self.expect(&Token::RParen)?;
2039 Ok(Pattern::EnumVariant {
2040 namespace: None,
2041 type_name: String::from("Result"),
2042 variant,
2043 payload: VariantPatternPayload::Tuple(items),
2044 })
2045 }
2046
2047 fn parse_pattern_struct(
2048 &mut self,
2049 type_name: String,
2050 namespace: Option<String>,
2051 ) -> Result<Pattern, BopError> {
2052 let (fields, rest) = self.parse_pattern_field_list()?;
2053 Ok(Pattern::Struct {
2054 namespace,
2055 type_name,
2056 fields,
2057 rest,
2058 })
2059 }
2060
2061 fn parse_pattern_field_list(
2062 &mut self,
2063 ) -> Result<(Vec<(String, Pattern)>, bool), BopError> {
2064 self.expect(&Token::LBrace)?;
2065 let mut fields: Vec<(String, Pattern)> = Vec::new();
2066 let mut rest = false;
2067 if !matches!(self.peek(), Token::RBrace) {
2068 loop {
2069 if matches!(self.peek(), Token::DotDot) {
2070 self.advance();
2071 rest = true;
2072 break;
2073 }
2074 let (fname, _) = self.expect_ident()?;
2075 let sub = if matches!(self.peek(), Token::Colon) {
2079 self.advance();
2080 self.parse_pattern()?
2081 } else {
2082 Pattern::Binding(fname.clone())
2083 };
2084 fields.push((fname, sub));
2085 if matches!(self.peek(), Token::Comma) {
2086 self.advance();
2087 if matches!(self.peek(), Token::RBrace) {
2088 break;
2089 }
2090 } else {
2091 break;
2092 }
2093 }
2094 }
2095 self.expect(&Token::RBrace)?;
2096 Ok((fields, rest))
2097 }
2098
2099 fn parse_lambda(&mut self) -> Result<Expr, BopError> {
2100 let (line, column) = self.peek_pos();
2101 self.advance(); self.expect(&Token::LParen)?;
2103
2104 let mut params = Vec::new();
2105 if !matches!(self.peek(), Token::RParen) {
2106 let (p, _) = self.expect_ident()?;
2107 params.push(p);
2108 while matches!(self.peek(), Token::Comma) {
2109 self.advance();
2110 let (p, _) = self.expect_ident()?;
2111 params.push(p);
2112 }
2113 }
2114 self.expect(&Token::RParen)?;
2115 let body = self.parse_block()?;
2116 Ok(Expr {
2117 kind: ExprKind::Lambda { params, body },
2118 line,
2119 column,
2120 })
2121 }
2122
2123 fn parse_if_expr(&mut self) -> Result<Expr, BopError> {
2124 let (line, column) = self.peek_pos();
2125 self.advance(); let condition = self.without_struct_literal(|p| p.parse_expr())?;
2127 self.expect(&Token::LBrace)?;
2128 let then_expr = self.parse_expr()?;
2129 self.expect(&Token::RBrace)?;
2130 self.expect(&Token::Else)?;
2131 self.expect(&Token::LBrace)?;
2132 let else_expr = self.parse_expr()?;
2133 self.expect(&Token::RBrace)?;
2134 Ok(Expr {
2135 kind: ExprKind::IfExpr {
2136 condition: Box::new(condition),
2137 then_expr: Box::new(then_expr),
2138 else_expr: Box::new(else_expr),
2139 },
2140 line,
2141 column,
2142 })
2143 }
2144}
2145
2146pub fn count_instructions(stmts: &[Stmt]) -> u32 {
2154 let mut count = 0u32;
2155 for stmt in stmts {
2156 count += 1; match &stmt.kind {
2158 StmtKind::If {
2159 body,
2160 else_ifs,
2161 else_body,
2162 ..
2163 } => {
2164 count += count_instructions(body);
2165 for (_, branch_body) in else_ifs {
2166 count += count_instructions(branch_body);
2167 }
2168 if let Some(eb) = else_body {
2169 count += count_instructions(eb);
2170 }
2171 }
2172 StmtKind::While { body, .. }
2173 | StmtKind::Repeat { body, .. }
2174 | StmtKind::ForIn { body, .. } => {
2175 count += count_instructions(body);
2176 }
2177 StmtKind::FnDecl { .. } => {
2178 }
2180 _ => {}
2181 }
2182 }
2183 count
2184}
2185
2186fn expr_to_assign_target(expr: Expr, line: u32) -> Result<AssignTarget, BopError> {
2189 match expr.kind {
2190 ExprKind::Ident(name) => {
2191 if naming::is_constant_name(&name) {
2199 let mut err = BopError::runtime(
2200 format!("can't reassign `{}` — it's a constant", name),
2201 line,
2202 );
2203 err.friendly_hint = Some(
2204 "constants are immutable. Use `let` if you want a mutable binding."
2205 .to_string(),
2206 );
2207 return Err(err);
2208 }
2209 Ok(AssignTarget::Variable(name))
2210 }
2211 ExprKind::Index { object, index } => Ok(AssignTarget::Index {
2212 object: *object,
2213 index: *index,
2214 }),
2215 ExprKind::FieldAccess { object, field } => Ok(AssignTarget::Field {
2216 object: *object,
2217 field,
2218 }),
2219 _ => Err(BopError {
2220 line: Some(line),
2221 column: None,
2222 message:
2223 "You can only assign to a variable, an index (`arr[0]`), or a struct field (`point.x`)"
2224 .to_string(),
2225 friendly_hint: None,
2226 is_fatal: false,
2227 is_try_return: false,
2228 }),
2229 }
2230}
2231
2232pub fn fmt_token(token: &Token) -> &'static str {
2233 match token {
2234 Token::Int(_) => "an integer",
2235 Token::Number(_) => "a number",
2236 Token::Str(_) | Token::StringInterp(_) => "a string",
2237 Token::True => "true",
2238 Token::False => "false",
2239 Token::None => "none",
2240 Token::Ident(_) => "a name",
2241 Token::Let => "let",
2242 Token::Const => "const",
2243 Token::Fn => "fn",
2244 Token::Return => "return",
2245 Token::If => "if",
2246 Token::Else => "else",
2247 Token::While => "while",
2248 Token::For => "for",
2249 Token::In => "in",
2250 Token::Repeat => "repeat",
2251 Token::Break => "break",
2252 Token::Continue => "continue",
2253 Token::Use => "use",
2254 Token::As => "as",
2255 Token::Struct => "struct",
2256 Token::Enum => "enum",
2257 Token::Match => "match",
2258 Token::Try => "try",
2259 Token::ColonColon => "::",
2260 Token::DotDot => "..",
2261 Token::FatArrow => "=>",
2262 Token::Pipe => "|",
2263 Token::Plus => "+",
2264 Token::Minus => "-",
2265 Token::Star => "*",
2266 Token::Slash => "/",
2267 Token::Percent => "%",
2268 Token::EqEq => "==",
2269 Token::BangEq => "!=",
2270 Token::Lt => "<",
2271 Token::Gt => ">",
2272 Token::LtEq => "<=",
2273 Token::GtEq => ">=",
2274 Token::AmpAmp => "&&",
2275 Token::PipePipe => "||",
2276 Token::Bang => "!",
2277 Token::Eq => "=",
2278 Token::PlusEq => "+=",
2279 Token::MinusEq => "-=",
2280 Token::StarEq => "*=",
2281 Token::SlashEq => "/=",
2282 Token::PercentEq => "%=",
2283 Token::LParen => "(",
2284 Token::RParen => ")",
2285 Token::LBracket => "[",
2286 Token::RBracket => "]",
2287 Token::LBrace => "{",
2288 Token::RBrace => "}",
2289 Token::Comma => ",",
2290 Token::Colon => ":",
2291 Token::Dot => ".",
2292 Token::Semicolon => ";",
2293 Token::Newline => "newline",
2294 Token::Eof => "end of code",
2295 }
2296}