1use crate::ast::*;
4use crate::diagnostic::Diagnostic;
5use crate::lexer::lex;
6use crate::span::Span;
7use crate::token::{StrPart, Tok, Token};
8
9pub fn parse_program(src: &str) -> (Program, Vec<Diagnostic>) {
12 let (tokens, mut diags) = lex(src, 0);
13 let mut parser = Parser::new(tokens);
14 let program = parser.program();
15 diags.append(&mut parser.diags);
16 diags.sort_by_key(|d| d.span.lo);
17 (program, diags)
18}
19
20pub fn parse_expr(src: &str, base: u32) -> (Option<Expr>, Vec<Diagnostic>) {
22 parse_nested_expr(src, base, 0)
23}
24
25pub const MAX_NESTING: u32 = 200;
29
30fn parse_nested_expr(src: &str, base: u32, depth: u32) -> (Option<Expr>, Vec<Diagnostic>) {
31 let (tokens, mut diags) = lex(src, base);
32 let mut parser = Parser::new(tokens);
33 parser.depth = depth;
34 let expr = parser.expr().ok();
35 if expr.is_some() && !parser.at(&Tok::Eof) {
36 let tok = parser.peek().clone();
37 parser.error(
38 parser.span(),
39 format!("unexpected {} after the expression", tok.describe()),
40 );
41 }
42 diags.append(&mut parser.diags);
43 (expr, diags)
44}
45
46#[derive(Debug)]
48pub struct Failed;
49
50type PResult<T> = Result<T, Failed>;
51
52const PREC_OR: u8 = 1;
54const PREC_AND: u8 = 2;
55const PREC_NOT: u8 = 3;
56const PREC_CMP: u8 = 4;
57const PREC_RANGE: u8 = 5;
58const PREC_ADD: u8 = 6;
59const PREC_MUL: u8 = 7;
60const PREC_NEG: u8 = 8;
61const PREC_POW: u8 = 9;
62const PREC_TYPEOF: u8 = 10;
63
64struct Parser {
65 tokens: Vec<Token>,
66 pos: usize,
67 diags: Vec<Diagnostic>,
68 depth: u32,
70 restricted: bool,
73}
74
75impl Parser {
76 fn new(tokens: Vec<Token>) -> Parser {
77 Parser {
78 tokens,
79 pos: 0,
80 diags: Vec::new(),
81 depth: 0,
82 restricted: false,
83 }
84 }
85
86 fn peek(&self) -> &Tok {
89 &self.tokens[self.pos].tok
90 }
91
92 fn peek_at(&self, ahead: usize) -> &Tok {
93 let i = (self.pos + ahead).min(self.tokens.len() - 1);
94 &self.tokens[i].tok
95 }
96
97 fn span(&self) -> Span {
98 self.tokens[self.pos].span
99 }
100
101 fn prev_span(&self) -> Span {
102 if self.pos == 0 {
103 self.span()
104 } else {
105 self.tokens[self.pos - 1].span
106 }
107 }
108
109 fn at(&self, tok: &Tok) -> bool {
110 self.peek() == tok
111 }
112
113 fn bump(&mut self) -> Token {
114 let token = self.tokens[self.pos].clone();
115 if self.pos < self.tokens.len() - 1 {
116 self.pos += 1;
117 }
118 token
119 }
120
121 fn eat(&mut self, tok: &Tok) -> bool {
122 if self.at(tok) {
123 self.bump();
124 true
125 } else {
126 false
127 }
128 }
129
130 fn error(&mut self, span: Span, message: impl Into<String>) -> &mut Diagnostic {
131 self.diags.push(Diagnostic::error(span, message));
132 self.diags.last_mut().unwrap()
133 }
134
135 fn expect(&mut self, tok: &Tok, context: &str) -> PResult<Span> {
136 if self.at(tok) {
137 Ok(self.bump().span)
138 } else {
139 let found = self.peek().describe();
140 let span = self.span();
141 self.error(span, format!("expected `{}` {context}, found {found}", tok.text()));
142 Err(Failed)
143 }
144 }
145
146 fn ident(&mut self, what: &str) -> PResult<Ident> {
147 match self.peek().clone() {
148 Tok::Ident(name) => {
149 let span = self.bump().span;
150 Ok(Ident { name, span })
151 }
152 other => {
153 let span = self.span();
154 self.error(span, format!("expected {what}, found {}", other.describe()));
155 Err(Failed)
156 }
157 }
158 }
159
160 fn skip_newlines(&mut self) {
161 while self.at(&Tok::Newline) {
162 self.bump();
163 }
164 }
165
166 fn skip_separators(&mut self) {
167 while matches!(self.peek(), Tok::Newline | Tok::Semi) {
168 self.bump();
169 }
170 }
171
172 fn end_of_statement(&mut self) -> PResult<()> {
174 match self.peek() {
175 Tok::Newline | Tok::Semi => {
176 self.bump();
177 Ok(())
178 }
179 Tok::RBrace | Tok::Eof => Ok(()),
180 other => {
181 let found = other.describe();
182 let span = self.span();
183 self.error(span, format!("expected the end of the statement, found {found}"))
184 .help("put each statement on its own line, or separate them with `;`");
185 Err(Failed)
186 }
187 }
188 }
189
190 fn recover(&mut self) {
192 let mut depth = 0usize;
193 loop {
194 match self.peek() {
195 Tok::Eof => return,
196 Tok::LParen | Tok::LBracket | Tok::LBrace => depth += 1,
197 Tok::RParen | Tok::RBracket => depth = depth.saturating_sub(1),
198 Tok::RBrace => {
199 if depth == 0 {
200 return;
201 }
202 depth -= 1;
203 }
204 Tok::Newline | Tok::Semi if depth == 0 => {
205 self.bump();
206 return;
207 }
208 _ => {}
209 }
210 self.bump();
211 }
212 }
213
214 fn nested<T>(&mut self, f: impl FnOnce(&mut Parser) -> PResult<T>) -> PResult<T> {
217 let saved = self.depth;
218 self.deeper()?;
219 let result = f(self);
220 self.depth = saved;
221 result
222 }
223
224 fn deeper(&mut self) -> PResult<()> {
230 if self.depth >= MAX_NESTING {
231 let span = self.span();
232 self.error(span, "this is nested too deeply").help(format!(
233 "expressions, blocks and patterns can nest at most {MAX_NESTING} levels, \
234 and each operator or `.` in a chain like `a + b + c` counts as one"
235 ));
236 return Err(Failed);
237 }
238 self.depth += 1;
239 Ok(())
240 }
241
242 fn with_restriction<T>(&mut self, restricted: bool, f: impl FnOnce(&mut Parser) -> T) -> T {
243 let saved = std::mem::replace(&mut self.restricted, restricted);
244 let result = f(self);
245 self.restricted = saved;
246 result
247 }
248
249 fn program(&mut self) -> Program {
252 let mut pragmas = Vec::new();
253 let mut items = Vec::new();
254 self.skip_separators();
255 while self.at(&Tok::At) {
256 match self.pragma() {
257 Ok(p) => {
258 pragmas.push(p);
259 if self.end_of_statement().is_err() {
260 self.recover();
261 }
262 }
263 Err(Failed) => self.recover(),
264 }
265 self.skip_separators();
266 }
267 while !self.at(&Tok::Eof) {
268 if self.at(&Tok::RBrace) {
269 let span = self.span();
270 self.error(span, "unexpected `}`")
271 .help("there is no open `{` for it to close");
272 self.bump();
273 self.skip_separators();
274 continue;
275 }
276 match self.item() {
277 Ok(item) => {
278 items.push(item);
279 if self.end_of_statement().is_err() {
280 self.recover();
281 }
282 }
283 Err(Failed) => self.recover(),
284 }
285 self.skip_separators();
286 }
287 Program { pragmas, items }
288 }
289
290 fn pragma(&mut self) -> PResult<Pragma> {
291 let lo = self.expect(&Tok::At, "")?;
292 let name = self.ident("a pragma name after `@`")?;
293 let arg = if matches!(self.peek(), Tok::Newline | Tok::Semi | Tok::Eof) {
294 None
295 } else {
296 Some(self.expr()?)
297 };
298 let span = lo.to(self.prev_span());
299 Ok(Pragma { name, arg, span })
300 }
301
302 fn item(&mut self) -> PResult<Item> {
303 match self.peek() {
304 Tok::Fn => self.fn_decl().map(Item::Fn),
305 Tok::Type => self.type_decl().map(Item::Type),
306 Tok::Enum => self.enum_decl().map(Item::Enum),
307 Tok::Import => {
308 let lo = self.bump().span;
309 match self.peek().clone() {
310 Tok::Str(parts) => {
311 let span = self.bump().span;
312 match plain_string(&parts) {
313 Some(path) => Ok(Item::Import(Import {
314 path,
315 span: lo.to(span),
316 })),
317 None => {
318 self.error(span, "an import path can't contain `{…}`");
319 Err(Failed)
320 }
321 }
322 }
323 other => {
324 let span = self.span();
325 self.error(
326 span,
327 format!("expected a file path after `import`, found {}", other.describe()),
328 );
329 Err(Failed)
330 }
331 }
332 }
333 Tok::At => {
334 let span = self.span();
335 self.error(span, "pragmas must come before everything else in the file");
336 Err(Failed)
337 }
338 _ => self.stmt().map(Item::Stmt),
339 }
340 }
341
342 fn fn_decl(&mut self) -> PResult<FnDecl> {
343 let lo = self.bump().span; let name = self.ident("a function name")?;
345 self.expect(&Tok::LParen, "after the function name")?;
346 let mut params = Vec::new();
347 while !self.at(&Tok::RParen) {
348 let pname = self.ident("a parameter name")?;
349 let ty = if self.eat(&Tok::Colon) {
350 Some(self.type_expr()?)
351 } else {
352 None
353 };
354 params.push(Param { name: pname, ty });
355 if !self.eat(&Tok::Comma) {
356 break;
357 }
358 }
359 self.expect(&Tok::RParen, "after the parameters")?;
360 let ret = if self.eat(&Tok::Arrow) {
361 Some(self.type_expr()?)
362 } else {
363 None
364 };
365 let body = self.block()?;
366 let span = lo.to(body.span);
367 Ok(FnDecl {
368 name,
369 params,
370 ret,
371 body,
372 span,
373 })
374 }
375
376 fn type_decl(&mut self) -> PResult<TypeDecl> {
377 let lo = self.bump().span; let name = self.ident("a type name")?;
379 self.expect(&Tok::Assign, "after the type name")?;
380 let ty = self.type_expr()?;
381 let span = lo.to(self.prev_span());
382 Ok(TypeDecl { name, ty, span })
383 }
384
385 fn enum_decl(&mut self) -> PResult<EnumDecl> {
386 let lo = self.bump().span; let name = self.ident("an enum name")?;
388 self.expect(&Tok::LBrace, "after the enum name")?;
389 let mut variants = Vec::new();
390 self.skip_newlines();
391 while !self.at(&Tok::RBrace) {
392 variants.push(self.ident("a variant name")?);
393 self.skip_newlines();
394 if !self.eat(&Tok::Comma) {
395 break;
396 }
397 self.skip_newlines();
398 }
399 self.skip_newlines();
400 let hi = self.expect(&Tok::RBrace, "to close the enum")?;
401 Ok(EnumDecl {
402 name,
403 variants,
404 span: lo.to(hi),
405 })
406 }
407
408 fn type_expr(&mut self) -> PResult<TypeExpr> {
409 self.nested(|p| p.type_expr_inner())
410 }
411
412 fn type_expr_inner(&mut self) -> PResult<TypeExpr> {
413 if self.at(&Tok::LBrace) {
414 let lo = self.bump().span;
415 let mut fields = Vec::new();
416 self.skip_newlines();
417 while !self.at(&Tok::RBrace) {
418 let name = self.ident("a field name")?;
419 self.expect(&Tok::Colon, "after the field name")?;
420 let ty = self.type_expr()?;
421 fields.push((name, ty));
422 self.skip_newlines();
423 if !self.eat(&Tok::Comma) {
424 break;
425 }
426 self.skip_newlines();
427 }
428 self.skip_newlines();
429 let hi = self.expect(&Tok::RBrace, "to close the record type")?;
430 return Ok(TypeExpr::Record {
431 fields,
432 span: lo.to(hi),
433 });
434 }
435 let name = self.ident("a type")?;
436 let mut args = Vec::new();
437 if self.eat(&Tok::LBracket) {
438 loop {
439 args.push(self.type_expr()?);
440 if !self.eat(&Tok::Comma) {
441 break;
442 }
443 }
444 self.expect(&Tok::RBracket, "to close the type arguments")?;
445 }
446 Ok(TypeExpr::Named { name, args })
447 }
448
449 fn block(&mut self) -> PResult<Block> {
452 self.nested(|p| p.block_inner())
453 }
454
455 fn block_inner(&mut self) -> PResult<Block> {
456 let lo = self.expect(&Tok::LBrace, "to start a block")?;
457 self.with_restriction(false, |p| {
458 let mut stmts = Vec::new();
459 loop {
460 p.skip_separators();
461 match p.peek() {
462 Tok::RBrace => break,
463 Tok::Eof => {
464 p.error(lo, "this `{` is never closed");
465 return Err(Failed);
466 }
467 _ => {}
468 }
469 match p.stmt() {
470 Ok(stmt) => {
471 stmts.push(stmt);
472 if p.end_of_statement().is_err() {
473 p.recover();
474 }
475 }
476 Err(Failed) => p.recover(),
477 }
478 }
479 let hi = p.bump().span; Ok(Block { stmts, span: lo.to(hi) })
481 })
482 }
483
484 fn stmt(&mut self) -> PResult<Stmt> {
485 let lo = self.span();
486 let kind = match self.peek() {
487 Tok::Let | Tok::Var => {
488 let mutable = self.bump().tok == Tok::Var;
489 let pattern = self.pattern()?;
490 let ty = if self.eat(&Tok::Colon) {
491 Some(self.type_expr()?)
492 } else {
493 None
494 };
495 let op = match self.peek() {
496 Tok::Assign => BindOp::Assign,
497 Tok::Tilde => BindOp::Draw,
498 other => {
499 let found = other.describe();
500 let span = self.span();
501 self.error(span, format!("expected `=` or `~` in the binding, found {found}"))
502 .help("`=` keeps a value; `~` draws one from a distribution");
503 return Err(Failed);
504 }
505 };
506 self.bump();
507 let value = self.expr()?;
508 StmtKind::Let {
509 mutable,
510 pattern,
511 ty,
512 op,
513 value,
514 }
515 }
516 Tok::For => {
517 self.bump();
518 let pattern = self.pattern()?;
519 self.expect(&Tok::In, "after the loop variable")?;
520 let iter = self.with_restriction(true, |p| p.expr())?;
521 let body = self.block()?;
522 StmtKind::For { pattern, iter, body }
523 }
524 Tok::While => {
525 self.bump();
526 let cond = self.with_restriction(true, |p| p.expr())?;
527 let body = self.block()?;
528 StmtKind::While { cond, body }
529 }
530 Tok::Repeat => {
531 self.bump();
532 let count = self.with_restriction(true, |p| p.expr())?;
533 let body = self.block()?;
534 StmtKind::Repeat { count, body }
535 }
536 Tok::Loop => {
537 self.bump();
538 let body = self.block()?;
539 StmtKind::Loop { body }
540 }
541 Tok::Break => {
542 self.bump();
543 StmtKind::Break
544 }
545 Tok::Continue => {
546 self.bump();
547 StmtKind::Continue
548 }
549 Tok::Return => {
550 self.bump();
551 if matches!(
552 self.peek(),
553 Tok::Newline | Tok::Semi | Tok::RBrace | Tok::Eof | Tok::Comma
554 ) {
555 StmtKind::Return(None)
556 } else {
557 StmtKind::Return(Some(self.expr()?))
558 }
559 }
560 Tok::Observe => {
561 self.bump();
562 let value = self.expr()?;
563 let from = if self.peek().is_ident("from") {
564 self.bump();
565 Some(self.expr()?)
566 } else {
567 None
568 };
569 StmtKind::Observe { value, from }
570 }
571 Tok::Score => {
572 self.bump();
573 StmtKind::Score(self.expr()?)
574 }
575 Tok::Report => {
576 self.bump();
577 let value = self.expr()?;
578 let by = if self.peek().is_ident("by") {
579 self.bump();
580 Some(self.expr()?)
581 } else {
582 None
583 };
584 let label = if self.peek().is_ident("as") {
585 self.bump();
586 match self.peek().clone() {
587 Tok::Str(parts) => {
588 let span = self.bump().span;
589 match plain_string(&parts) {
590 Some(text) => Some((text, span)),
591 None => {
592 self.error(span, "a report label can't contain `{…}`");
593 return Err(Failed);
594 }
595 }
596 }
597 other => {
598 let span = self.span();
599 self.error(
600 span,
601 format!("expected a label string after `as`, found {}", other.describe()),
602 );
603 return Err(Failed);
604 }
605 }
606 } else {
607 None
608 };
609 StmtKind::Report { value, by, label }
610 }
611 Tok::Fn | Tok::Type | Tok::Enum | Tok::Import => {
612 let span = self.span();
613 let what = self.peek().text();
614 self.error(span, format!("`{what}` declarations are only allowed at the top level"));
615 return Err(Failed);
616 }
617 _ => {
618 let target = self.expr()?;
619 let op = match self.peek() {
620 Tok::Assign => Some(AssignOp::Set),
621 Tok::Tilde => Some(AssignOp::Draw),
622 Tok::PlusAssign => Some(AssignOp::Add),
623 Tok::MinusAssign => Some(AssignOp::Sub),
624 Tok::StarAssign => Some(AssignOp::Mul),
625 Tok::SlashAssign => Some(AssignOp::Div),
626 _ => None,
627 };
628 match op {
629 None => StmtKind::Expr(target),
630 Some(op) => {
631 self.bump();
632 if !is_place(&target) {
633 self.error(target.span, "can't assign to this")
634 .help("only variables, fields (`a.b`) and elements (`a[i]`) can be assigned");
635 return Err(Failed);
636 }
637 let value = self.expr()?;
638 StmtKind::Assign { target, op, value }
639 }
640 }
641 }
642 };
643 Ok(Stmt {
644 kind,
645 span: lo.to(self.prev_span()),
646 })
647 }
648
649 fn pattern(&mut self) -> PResult<Pattern> {
652 self.nested(|p| p.pattern_inner())
653 }
654
655 fn pattern_inner(&mut self) -> PResult<Pattern> {
656 let first = self.pattern_alt()?;
657 if !self.at(&Tok::Pipe) {
658 return Ok(first);
659 }
660 let mut alts = vec![first];
662 while self.eat(&Tok::Pipe) {
663 self.deeper()?;
664 alts.push(self.pattern_alt()?);
665 }
666 let span = alts[0].span.to(alts.last().unwrap().span);
667 Ok(Pattern {
668 kind: PatternKind::Or(alts),
669 span,
670 })
671 }
672
673 fn pattern_alt(&mut self) -> PResult<Pattern> {
674 let span = self.span();
675 let kind = match self.peek().clone() {
676 Tok::Underscore => {
677 self.bump();
678 PatternKind::Wildcard
679 }
680 Tok::Ident(name) => {
681 self.bump();
682 PatternKind::Name(name)
683 }
684 Tok::Int(_) | Tok::Float(_) | Tok::Percent(_) | Tok::Str(_) | Tok::True | Tok::False => {
685 PatternKind::Literal(self.primary()?)
686 }
687 Tok::Minus if matches!(self.peek_at(1), Tok::Int(_) | Tok::Float(_) | Tok::Percent(_)) => {
688 self.bump();
689 let inner = self.primary()?;
690 PatternKind::Literal(Expr {
691 span: span.to(inner.span),
692 kind: ExprKind::Unary {
693 op: UnOp::Neg,
694 expr: Box::new(inner),
695 },
696 })
697 }
698 Tok::LBracket => {
699 self.bump();
700 let mut items = Vec::new();
702 while !self.at(&Tok::RBracket) {
703 self.deeper()?;
704 items.push(self.pattern()?);
705 if !self.eat(&Tok::Comma) {
706 break;
707 }
708 }
709 self.expect(&Tok::RBracket, "to close the list pattern")?;
710 PatternKind::List(items)
711 }
712 other => {
713 self.error(span, format!("expected a pattern, found {}", other.describe()));
714 return Err(Failed);
715 }
716 };
717 Ok(Pattern {
718 kind,
719 span: span.to(self.prev_span()),
720 })
721 }
722
723 fn expr(&mut self) -> PResult<Expr> {
726 if let Some(lambda) = self.lambda()? {
727 return Ok(lambda);
728 }
729 self.expr_bp(0)
730 }
731
732 fn lambda(&mut self) -> PResult<Option<Expr>> {
734 let lo = self.span();
735 let params = match (self.peek(), self.peek_at(1)) {
736 (Tok::Ident(_), Tok::Arrow) => {
737 let param = self.ident("a parameter")?;
738 vec![param]
739 }
740 (Tok::LParen, _) => {
741 let mut i = 1;
743 let mut expect_ident = true;
744 loop {
745 match (self.peek_at(i), expect_ident) {
746 (Tok::RParen, _) => break,
747 (Tok::Ident(_), true) => expect_ident = false,
748 (Tok::Comma, false) => expect_ident = true,
749 _ => return Ok(None),
750 }
751 i += 1;
752 }
753 if *self.peek_at(i + 1) != Tok::Arrow {
754 return Ok(None);
755 }
756 self.bump(); let mut params = Vec::new();
758 while !self.at(&Tok::RParen) {
759 params.push(self.ident("a parameter")?);
760 self.eat(&Tok::Comma);
761 }
762 self.bump(); params
764 }
765 _ => return Ok(None),
766 };
767 self.expect(&Tok::Arrow, "")?;
768 let body = self.nested(|p| p.expr())?;
769 let span = lo.to(body.span);
770 Ok(Some(Expr {
771 kind: ExprKind::Lambda {
772 params,
773 body: Box::new(body),
774 },
775 span,
776 }))
777 }
778
779 fn expr_bp(&mut self, min: u8) -> PResult<Expr> {
780 self.nested(|p| p.expr_bp_inner(min))
781 }
782
783 fn expr_bp_inner(&mut self, min: u8) -> PResult<Expr> {
784 let lo = self.span();
785 let mut lhs = match self.peek() {
786 Tok::Typeof | Tok::Not | Tok::Minus | Tok::Tilde => {
787 let (op, precedence) = match self.peek() {
788 Tok::Typeof => (Some(UnOp::Typeof), PREC_TYPEOF),
789 Tok::Not => (Some(UnOp::Not), PREC_NOT),
790 Tok::Minus => (Some(UnOp::Neg), PREC_NEG),
791 _ => (None, PREC_TYPEOF),
792 };
793 self.bump();
794 let operand = self.expr_bp(precedence)?;
795 Expr {
796 span: lo.to(operand.span),
797 kind: match op {
798 Some(op) => ExprKind::Unary {
799 op,
800 expr: Box::new(operand),
801 },
802 None => ExprKind::Draw(Box::new(operand)),
803 },
804 }
805 }
806 _ => self.postfix()?,
807 };
808 while let Some((op, prec, len)) = self.binary_op() {
809 if prec < min {
810 break;
811 }
812 self.deeper()?;
813 for _ in 0..len {
814 self.bump();
815 }
816 let rhs = match prec {
817 PREC_POW => self.expr_bp(PREC_POW)?, _ => self.expr_bp(prec + 1)?,
819 };
820 if prec == PREC_CMP || prec == PREC_RANGE {
821 if let Some((next, next_prec, _)) = self.binary_op() {
822 if next_prec == prec {
823 let span = self.span();
824 let msg = if prec == PREC_CMP {
825 format!(
826 "comparisons can't be chained: `{}` after `{}`",
827 next.symbol(),
828 op.symbol()
829 )
830 } else {
831 format!("`{}` can't follow `{}` directly", next.symbol(), op.symbol())
832 };
833 self.error(span, msg)
834 .help("add parentheses, or combine the tests with `and`");
835 return Err(Failed);
836 }
837 }
838 }
839 let span = lhs.span.to(rhs.span);
840 lhs = Expr {
841 kind: ExprKind::Binary {
842 op,
843 lhs: Box::new(lhs),
844 rhs: Box::new(rhs),
845 },
846 span,
847 };
848 }
849 Ok(lhs)
850 }
851
852 fn binary_op(&self) -> Option<(BinOp, u8, usize)> {
854 Some(match self.peek() {
855 Tok::Or => (BinOp::Or, PREC_OR, 1),
856 Tok::And => (BinOp::And, PREC_AND, 1),
857 Tok::EqEq => (BinOp::Eq, PREC_CMP, 1),
858 Tok::NotEq => (BinOp::Ne, PREC_CMP, 1),
859 Tok::Lt => (BinOp::Lt, PREC_CMP, 1),
860 Tok::Le => (BinOp::Le, PREC_CMP, 1),
861 Tok::Gt => (BinOp::Gt, PREC_CMP, 1),
862 Tok::Ge => (BinOp::Ge, PREC_CMP, 1),
863 Tok::In => (BinOp::In, PREC_CMP, 1),
864 Tok::Not if *self.peek_at(1) == Tok::In => (BinOp::NotIn, PREC_CMP, 2),
865 Tok::DotDot => (BinOp::Range, PREC_RANGE, 1),
866 Tok::DotDotLt => (BinOp::RangeExcl, PREC_RANGE, 1),
867 Tok::Ident(word) if word == "to" => (BinOp::To, PREC_RANGE, 1),
868 Tok::Plus => (BinOp::Add, PREC_ADD, 1),
869 Tok::Minus => (BinOp::Sub, PREC_ADD, 1),
870 Tok::Star => (BinOp::Mul, PREC_MUL, 1),
871 Tok::Slash => (BinOp::Div, PREC_MUL, 1),
872 Tok::Div => (BinOp::IntDiv, PREC_MUL, 1),
873 Tok::Mod => (BinOp::Mod, PREC_MUL, 1),
874 Tok::Caret => (BinOp::Pow, PREC_POW, 1),
875 _ => return None,
876 })
877 }
878
879 fn postfix(&mut self) -> PResult<Expr> {
880 let mut expr = self.primary()?;
881 loop {
882 if matches!(self.peek(), Tok::Dot | Tok::LParen | Tok::LBracket | Tok::With) {
883 self.deeper()?;
884 }
885 match self.peek() {
886 Tok::Dot => {
887 self.bump();
888 let name = self.ident("a field or method name after `.`")?;
889 if self.at(&Tok::LParen) {
890 let args = self.call_args()?;
891 let span = expr.span.to(self.prev_span());
892 expr = Expr {
893 kind: ExprKind::Method {
894 receiver: Box::new(expr),
895 name,
896 args,
897 },
898 span,
899 };
900 } else {
901 let span = expr.span.to(name.span);
902 expr = Expr {
903 kind: ExprKind::Field {
904 expr: Box::new(expr),
905 name,
906 },
907 span,
908 };
909 }
910 }
911 Tok::LParen => {
912 let args = self.call_args()?;
913 let span = expr.span.to(self.prev_span());
914 expr = Expr {
915 kind: ExprKind::Call {
916 callee: Box::new(expr),
917 args,
918 },
919 span,
920 };
921 }
922 Tok::LBracket => {
923 self.bump();
924 let index = self.with_restriction(false, |p| p.expr())?;
925 let hi = self.expect(&Tok::RBracket, "to close the index")?;
926 let span = expr.span.to(hi);
927 expr = Expr {
928 kind: ExprKind::Index {
929 expr: Box::new(expr),
930 index: Box::new(index),
931 },
932 span,
933 };
934 }
935 Tok::With => {
936 self.bump();
937 self.expect(&Tok::LBrace, "after `with`")?;
938 let fields = self.record_fields()?;
939 let span = expr.span.to(self.prev_span());
940 expr = Expr {
941 kind: ExprKind::With {
942 expr: Box::new(expr),
943 fields,
944 },
945 span,
946 };
947 }
948 _ => return Ok(expr),
949 }
950 }
951 }
952
953 fn call_args(&mut self) -> PResult<Vec<Arg>> {
954 self.expect(&Tok::LParen, "")?;
955 self.with_restriction(false, |p| {
956 let mut args = Vec::new();
957 while !p.at(&Tok::RParen) {
958 let name = if matches!(p.peek(), Tok::Ident(_)) && *p.peek_at(1) == Tok::Colon {
959 let name = p.ident("an argument name")?;
960 p.bump(); Some(name)
962 } else {
963 None
964 };
965 let value = p.expr()?;
966 args.push(Arg { name, value });
967 if !p.eat(&Tok::Comma) {
968 break;
969 }
970 }
971 p.expect(&Tok::RParen, "to close the arguments")?;
972 Ok(args)
973 })
974 }
975
976 fn record_fields(&mut self) -> PResult<Vec<Field>> {
978 self.with_restriction(false, |p| {
979 let mut fields = Vec::new();
980 p.skip_newlines();
981 while !p.at(&Tok::RBrace) {
982 let name = p.ident("a field name")?;
983 let value = if p.eat(&Tok::Colon) {
984 p.expr()?
985 } else {
986 Expr {
987 kind: ExprKind::Name(name.name.clone()),
988 span: name.span,
989 }
990 };
991 fields.push(Field { name, value });
992 p.skip_newlines();
993 if !p.eat(&Tok::Comma) {
994 break;
995 }
996 p.skip_newlines();
997 }
998 p.skip_newlines();
999 p.expect(&Tok::RBrace, "to close the record")?;
1000 Ok(fields)
1001 })
1002 }
1003
1004 fn record_ahead(&self, offset: usize, allow_empty: bool) -> bool {
1006 let mut i = offset + 1;
1007 while *self.peek_at(i) == Tok::Newline {
1008 i += 1;
1009 }
1010 match (self.peek_at(i), self.peek_at(i + 1)) {
1011 (Tok::RBrace, _) => allow_empty,
1012 (Tok::Ident(_), Tok::Colon | Tok::Comma) => true,
1013 (Tok::Ident(_), Tok::RBrace) => allow_empty,
1014 _ => false,
1015 }
1016 }
1017
1018 fn primary(&mut self) -> PResult<Expr> {
1019 let lo = self.span();
1020 let kind = match self.peek().clone() {
1021 Tok::Int(v) => {
1022 self.bump();
1023 ExprKind::Int(v)
1024 }
1025 Tok::Float(v) => {
1026 self.bump();
1027 ExprKind::Float(v)
1028 }
1029 Tok::Percent(v) => {
1030 self.bump();
1031 ExprKind::Percent(v)
1032 }
1033 Tok::Dice { count, sides } => {
1034 self.bump();
1035 ExprKind::Dice { count, sides }
1036 }
1037 Tok::True => {
1038 self.bump();
1039 ExprKind::Bool(true)
1040 }
1041 Tok::False => {
1042 self.bump();
1043 ExprKind::Bool(false)
1044 }
1045 Tok::Str(parts) => {
1046 self.bump();
1047 ExprKind::Str(self.string_segments(parts))
1048 }
1049 Tok::Ident(name) => {
1050 if !self.restricted && *self.peek_at(1) == Tok::LBrace && self.record_ahead(1, true) {
1052 let ident = self.ident("")?;
1053 self.bump(); let fields = self.record_fields()?;
1055 ExprKind::Record {
1056 name: Some(ident),
1057 fields,
1058 }
1059 } else {
1060 self.bump();
1061 ExprKind::Name(name)
1062 }
1063 }
1064 Tok::LParen => {
1065 self.bump();
1066 let inner = self.with_restriction(false, |p| p.expr())?;
1067 self.expect(&Tok::RParen, "to close the parenthesis")?;
1068 let span = lo.to(self.prev_span());
1069 return Ok(Expr { span, ..inner });
1070 }
1071 Tok::LBracket => return self.list_or_map(),
1072 Tok::LBrace => {
1073 if self.restricted {
1074 self.error(lo, "expected an expression before `{`");
1075 return Err(Failed);
1076 }
1077 if self.record_ahead(0, false) {
1078 self.bump();
1079 let fields = self.record_fields()?;
1080 ExprKind::Record { name: None, fields }
1081 } else {
1082 ExprKind::Block(self.block()?)
1083 }
1084 }
1085 Tok::If => return self.if_expr(),
1086 Tok::Try => return self.try_expr(),
1087 Tok::Chance => return self.chance_expr(),
1088 Tok::Match => return self.match_expr(),
1089 Tok::Simulate => {
1090 self.bump();
1091 ExprKind::Simulate(self.block()?)
1092 }
1093 Tok::Underscore => {
1094 self.error(lo, "`_` can only be used in patterns");
1095 return Err(Failed);
1096 }
1097 other => {
1098 self.error(lo, format!("expected an expression, found {}", other.describe()));
1099 return Err(Failed);
1100 }
1101 };
1102 Ok(Expr {
1103 kind,
1104 span: lo.to(self.prev_span()),
1105 })
1106 }
1107
1108 fn string_segments(&mut self, parts: Vec<StrPart>) -> Vec<StrSegment> {
1109 let mut segments = Vec::new();
1110 for part in parts {
1111 match part {
1112 StrPart::Lit(text) => segments.push(StrSegment::Lit(text)),
1113 StrPart::Expr { src, offset } => {
1114 let (expr, mut diags) = parse_nested_expr(&src, offset, self.depth + 1);
1115 self.diags.append(&mut diags);
1116 if let Some(expr) = expr {
1117 segments.push(StrSegment::Expr(expr));
1118 }
1119 }
1120 }
1121 }
1122 segments
1123 }
1124
1125 fn list_or_map(&mut self) -> PResult<Expr> {
1126 let lo = self.bump().span; self.with_restriction(false, |p| {
1128 if p.at(&Tok::Colon) && *p.peek_at(1) == Tok::RBracket {
1129 p.bump();
1130 let hi = p.bump().span;
1131 return Ok(Expr {
1132 kind: ExprKind::Map(Vec::new()),
1133 span: lo.to(hi),
1134 });
1135 }
1136 if p.at(&Tok::RBracket) {
1137 let hi = p.bump().span;
1138 return Ok(Expr {
1139 kind: ExprKind::List(Vec::new()),
1140 span: lo.to(hi),
1141 });
1142 }
1143 let first = p.expr()?;
1144 if p.eat(&Tok::Colon) {
1145 let value = p.expr()?;
1146 let mut entries = vec![(first, value)];
1147 while p.eat(&Tok::Comma) {
1148 if p.at(&Tok::RBracket) {
1149 break;
1150 }
1151 let key = p.expr()?;
1152 p.expect(&Tok::Colon, "between a key and its value")?;
1153 let value = p.expr()?;
1154 entries.push((key, value));
1155 }
1156 let hi = p.expect(&Tok::RBracket, "to close the map")?;
1157 Ok(Expr {
1158 kind: ExprKind::Map(entries),
1159 span: lo.to(hi),
1160 })
1161 } else {
1162 let mut items = vec![first];
1163 while p.eat(&Tok::Comma) {
1164 if p.at(&Tok::RBracket) {
1165 break;
1166 }
1167 items.push(p.expr()?);
1168 }
1169 let hi = p.expect(&Tok::RBracket, "to close the list")?;
1170 Ok(Expr {
1171 kind: ExprKind::List(items),
1172 span: lo.to(hi),
1173 })
1174 }
1175 })
1176 }
1177
1178 fn if_expr(&mut self) -> PResult<Expr> {
1179 let lo = self.bump().span; let cond = self.with_restriction(true, |p| p.expr())?;
1181 let then = self.block()?;
1182 let mut ahead = 0;
1185 while *self.peek_at(ahead) == Tok::Newline {
1186 ahead += 1;
1187 }
1188 if ahead > 0 && *self.peek_at(ahead) == Tok::Else && matches!(self.peek_at(ahead + 1), Tok::LBrace | Tok::If) {
1189 self.skip_newlines();
1190 }
1191 let otherwise = if self.eat(&Tok::Else) {
1192 if self.at(&Tok::If) {
1193 Some(Box::new(self.nested(|p| p.if_expr())?))
1194 } else {
1195 let block = self.block()?;
1196 Some(Box::new(Expr {
1197 span: block.span,
1198 kind: ExprKind::Block(block),
1199 }))
1200 }
1201 } else {
1202 None
1203 };
1204 Ok(Expr {
1205 kind: ExprKind::If {
1206 cond: Box::new(cond),
1207 then,
1208 otherwise,
1209 },
1210 span: lo.to(self.prev_span()),
1211 })
1212 }
1213
1214 fn try_expr(&mut self) -> PResult<Expr> {
1215 let lo = self.bump().span; let body = self.block()?;
1217 let mut catches: Vec<Catch> = Vec::new();
1218 loop {
1219 let mut ahead = 0;
1221 while *self.peek_at(ahead) == Tok::Newline {
1222 ahead += 1;
1223 }
1224 if *self.peek_at(ahead) != Tok::Catch {
1225 break;
1226 }
1227 self.skip_newlines();
1228 let start = self.bump().span; let fault = match self.peek() {
1230 Tok::Ident(_) => Some(self.ident("a fault")?),
1231 _ => None,
1232 };
1233 let body = self.block()?;
1234 let span = start.to(self.prev_span());
1235 if catches.last().is_some_and(|c| c.fault.is_none()) {
1236 self.error(span, "a `catch` after one that catches every fault never runs");
1237 }
1238 catches.push(Catch { fault, body, span });
1239 }
1240 if catches.is_empty() {
1241 self.error(
1242 lo,
1243 "`try` needs a `catch`, like `try { 1 / x } catch DivisionByZero { 0 }`",
1244 );
1245 return Err(Failed);
1246 }
1247 Ok(Expr {
1248 kind: ExprKind::Try { body, catches },
1249 span: lo.to(self.prev_span()),
1250 })
1251 }
1252
1253 fn arms<T>(&mut self, mut arm: impl FnMut(&mut Parser) -> PResult<T>) -> PResult<Vec<T>> {
1255 self.expect(&Tok::LBrace, "to start the arms")?;
1256 self.with_restriction(false, |p| {
1257 let mut arms = Vec::new();
1258 loop {
1259 while matches!(p.peek(), Tok::Newline | Tok::Comma) {
1260 p.bump();
1261 }
1262 if p.at(&Tok::RBrace) {
1263 break;
1264 }
1265 let start = p.pos;
1266 match arm(p) {
1267 Ok(a) => arms.push(a),
1268 Err(Failed) => {
1269 let mut open = p.tokens[start..p.pos].iter().fold(0usize, |open, t| match t.tok {
1274 Tok::LParen | Tok::LBracket | Tok::LBrace => open + 1,
1275 Tok::RParen | Tok::RBracket | Tok::RBrace => open.saturating_sub(1),
1276 _ => open,
1277 });
1278 loop {
1279 match p.peek() {
1280 Tok::Eof => return Err(Failed),
1281 Tok::Newline | Tok::Comma | Tok::RBrace if open == 0 => break,
1282 Tok::LParen | Tok::LBracket | Tok::LBrace => open += 1,
1283 Tok::RParen | Tok::RBracket | Tok::RBrace => open = open.saturating_sub(1),
1284 _ => {}
1285 }
1286 p.bump();
1287 }
1288 continue;
1289 }
1290 }
1291 match p.peek() {
1292 Tok::Newline | Tok::Comma | Tok::RBrace => {}
1293 other => {
1294 let found = other.describe();
1295 let span = p.span();
1296 p.error(span, format!("expected `,` or a new line between arms, found {found}"));
1297 return Err(Failed);
1298 }
1299 }
1300 }
1301 p.bump(); Ok(arms)
1303 })
1304 }
1305
1306 fn chance_expr(&mut self) -> PResult<Expr> {
1307 let lo = self.bump().span; let arms = self.arms(|p| {
1309 let arm_lo = p.span();
1310 let weight = if p.eat(&Tok::Else) { None } else { Some(p.expr()?) };
1311 p.expect(&Tok::FatArrow, "after the arm's probability")?;
1312 let body = p.stmt()?;
1313 Ok(ChanceArm {
1314 weight,
1315 span: arm_lo.to(body.span),
1316 body,
1317 })
1318 })?;
1319 Ok(Expr {
1320 kind: ExprKind::Chance { arms },
1321 span: lo.to(self.prev_span()),
1322 })
1323 }
1324
1325 fn match_expr(&mut self) -> PResult<Expr> {
1326 let lo = self.bump().span; let scrutinee = self.with_restriction(true, |p| p.expr())?;
1328 let arms = self.arms(|p| {
1329 let pattern = p.pattern()?;
1330 let guard = if p.eat(&Tok::If) { Some(p.expr()?) } else { None };
1331 p.expect(&Tok::FatArrow, "after the pattern")?;
1332 let body = p.stmt()?;
1333 Ok(MatchArm {
1334 span: pattern.span.to(body.span),
1335 pattern,
1336 guard,
1337 body,
1338 })
1339 })?;
1340 Ok(Expr {
1341 kind: ExprKind::Match {
1342 scrutinee: Box::new(scrutinee),
1343 arms,
1344 },
1345 span: lo.to(self.prev_span()),
1346 })
1347 }
1348}
1349
1350fn plain_string(parts: &[StrPart]) -> Option<String> {
1352 let mut text = String::new();
1353 for part in parts {
1354 match part {
1355 StrPart::Lit(s) => text.push_str(s),
1356 StrPart::Expr { .. } => return None,
1357 }
1358 }
1359 Some(text)
1360}
1361
1362fn is_place(expr: &Expr) -> bool {
1363 match &expr.kind {
1364 ExprKind::Name(_) => true,
1365 ExprKind::Field { expr, .. } | ExprKind::Index { expr, .. } => is_place(expr),
1366 _ => false,
1367 }
1368}