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::Colon) {
361 Some(self.type_expr()?)
362 } else if matches!(self.peek(), Tok::Arrow | Tok::Ident(_)) {
363 let found = self.peek().describe();
366 let span = self.span();
367 self.error(span, format!("expected `:` before the return type, found {found}"))
368 .help("a function's return type follows a `:`, like a variable's: `fn name(…): int { … }`");
369 self.eat(&Tok::Arrow);
370 Some(self.type_expr()?)
371 } else {
372 None
373 };
374 let body = self.block()?;
375 let span = lo.to(body.span);
376 Ok(FnDecl {
377 name,
378 params,
379 ret,
380 body,
381 span,
382 })
383 }
384
385 fn type_decl(&mut self) -> PResult<TypeDecl> {
386 let lo = self.bump().span; let name = self.ident("a type name")?;
388 self.expect(&Tok::Assign, "after the type name")?;
389 let ty = self.type_expr()?;
390 let span = lo.to(self.prev_span());
391 Ok(TypeDecl { name, ty, span })
392 }
393
394 fn enum_decl(&mut self) -> PResult<EnumDecl> {
395 let lo = self.bump().span; let name = self.ident("an enum name")?;
397 self.expect(&Tok::LBrace, "after the enum name")?;
398 let mut variants = Vec::new();
399 self.skip_newlines();
400 while !self.at(&Tok::RBrace) {
401 variants.push(self.ident("a variant name")?);
402 self.skip_newlines();
403 if !self.eat(&Tok::Comma) {
404 break;
405 }
406 self.skip_newlines();
407 }
408 self.skip_newlines();
409 let hi = self.expect(&Tok::RBrace, "to close the enum")?;
410 Ok(EnumDecl {
411 name,
412 variants,
413 span: lo.to(hi),
414 })
415 }
416
417 fn type_expr(&mut self) -> PResult<TypeExpr> {
418 self.nested(|p| p.type_expr_inner())
419 }
420
421 fn type_expr_inner(&mut self) -> PResult<TypeExpr> {
422 if self.at(&Tok::LBrace) {
423 let lo = self.bump().span;
424 let mut fields = Vec::new();
425 self.skip_newlines();
426 while !self.at(&Tok::RBrace) {
427 let name = self.ident("a field name")?;
428 self.expect(&Tok::Colon, "after the field name")?;
429 let ty = self.type_expr()?;
430 fields.push((name, ty));
431 self.skip_newlines();
432 if !self.eat(&Tok::Comma) {
433 break;
434 }
435 self.skip_newlines();
436 }
437 self.skip_newlines();
438 let hi = self.expect(&Tok::RBrace, "to close the record type")?;
439 return Ok(TypeExpr::Record {
440 fields,
441 span: lo.to(hi),
442 });
443 }
444 let name = self.ident("a type")?;
445 let mut args = Vec::new();
446 if self.eat(&Tok::LBracket) {
447 loop {
448 args.push(self.type_expr()?);
449 if !self.eat(&Tok::Comma) {
450 break;
451 }
452 }
453 self.expect(&Tok::RBracket, "to close the type arguments")?;
454 }
455 Ok(TypeExpr::Named { name, args })
456 }
457
458 fn block(&mut self) -> PResult<Block> {
461 self.nested(|p| p.block_inner())
462 }
463
464 fn block_inner(&mut self) -> PResult<Block> {
465 let lo = self.expect(&Tok::LBrace, "to start a block")?;
466 self.with_restriction(false, |p| {
467 let mut stmts = Vec::new();
468 loop {
469 p.skip_separators();
470 match p.peek() {
471 Tok::RBrace => break,
472 Tok::Eof => {
473 p.error(lo, "this `{` is never closed");
474 return Err(Failed);
475 }
476 _ => {}
477 }
478 match p.stmt() {
479 Ok(stmt) => {
480 stmts.push(stmt);
481 if p.end_of_statement().is_err() {
482 p.recover();
483 }
484 }
485 Err(Failed) => p.recover(),
486 }
487 }
488 let hi = p.bump().span; Ok(Block { stmts, span: lo.to(hi) })
490 })
491 }
492
493 fn stmt(&mut self) -> PResult<Stmt> {
494 let lo = self.span();
495 let kind = match self.peek() {
496 Tok::Let | Tok::Var => {
497 let mutable = self.bump().tok == Tok::Var;
498 let pattern = self.pattern()?;
499 let ty = if self.eat(&Tok::Colon) {
500 Some(self.type_expr()?)
501 } else {
502 None
503 };
504 let op = match self.peek() {
505 Tok::Assign => BindOp::Assign,
506 Tok::Tilde => BindOp::Draw,
507 other => {
508 let found = other.describe();
509 let span = self.span();
510 self.error(span, format!("expected `=` or `~` in the binding, found {found}"))
511 .help("`=` keeps a value; `~` draws one from a distribution");
512 return Err(Failed);
513 }
514 };
515 self.bump();
516 let value = self.expr()?;
517 StmtKind::Let {
518 mutable,
519 pattern,
520 ty,
521 op,
522 value,
523 }
524 }
525 Tok::For => {
526 self.bump();
527 let pattern = self.pattern()?;
528 self.expect(&Tok::In, "after the loop variable")?;
529 let iter = self.with_restriction(true, |p| p.expr())?;
530 let body = self.block()?;
531 StmtKind::For { pattern, iter, body }
532 }
533 Tok::While => {
534 self.bump();
535 let cond = self.with_restriction(true, |p| p.expr())?;
536 let body = self.block()?;
537 StmtKind::While { cond, body }
538 }
539 Tok::Repeat => {
540 self.bump();
541 let count = self.with_restriction(true, |p| p.expr())?;
542 let body = self.block()?;
543 StmtKind::Repeat { count, body }
544 }
545 Tok::Loop => {
546 self.bump();
547 let body = self.block()?;
548 StmtKind::Loop { body }
549 }
550 Tok::Break => {
551 self.bump();
552 StmtKind::Break
553 }
554 Tok::Continue => {
555 self.bump();
556 StmtKind::Continue
557 }
558 Tok::Return => {
559 self.bump();
560 if matches!(
561 self.peek(),
562 Tok::Newline | Tok::Semi | Tok::RBrace | Tok::Eof | Tok::Comma
563 ) {
564 StmtKind::Return(None)
565 } else {
566 StmtKind::Return(Some(self.expr()?))
567 }
568 }
569 Tok::Observe => {
570 self.bump();
571 let value = self.expr()?;
572 let from = if self.peek().is_ident("from") {
573 self.bump();
574 Some(self.expr()?)
575 } else {
576 None
577 };
578 StmtKind::Observe { value, from }
579 }
580 Tok::Score => {
581 self.bump();
582 StmtKind::Score(self.expr()?)
583 }
584 Tok::Report => {
585 self.bump();
586 let value = self.expr()?;
587 let by = if self.peek().is_ident("by") {
588 self.bump();
589 Some(self.expr()?)
590 } else {
591 None
592 };
593 let label = if self.peek().is_ident("as") {
594 self.bump();
595 match self.peek().clone() {
596 Tok::Str(parts) => {
597 let span = self.bump().span;
598 match plain_string(&parts) {
599 Some(text) => Some((text, span)),
600 None => {
601 self.error(span, "a report label can't contain `{…}`");
602 return Err(Failed);
603 }
604 }
605 }
606 other => {
607 let span = self.span();
608 self.error(
609 span,
610 format!("expected a label string after `as`, found {}", other.describe()),
611 );
612 return Err(Failed);
613 }
614 }
615 } else {
616 None
617 };
618 StmtKind::Report { value, by, label }
619 }
620 Tok::Fn | Tok::Type | Tok::Enum | Tok::Import => {
621 let span = self.span();
622 let what = self.peek().text();
623 self.error(span, format!("`{what}` declarations are only allowed at the top level"));
624 return Err(Failed);
625 }
626 _ => {
627 let target = self.expr()?;
628 let op = match self.peek() {
629 Tok::Assign => Some(AssignOp::Set),
630 Tok::Tilde => Some(AssignOp::Draw),
631 Tok::PlusAssign => Some(AssignOp::Add),
632 Tok::MinusAssign => Some(AssignOp::Sub),
633 Tok::StarAssign => Some(AssignOp::Mul),
634 Tok::SlashAssign => Some(AssignOp::Div),
635 _ => None,
636 };
637 match op {
638 None => StmtKind::Expr(target),
639 Some(op) => {
640 self.bump();
641 if !is_place(&target) {
642 self.error(target.span, "can't assign to this")
643 .help("only variables, fields (`a.b`) and elements (`a[i]`) can be assigned");
644 return Err(Failed);
645 }
646 let value = self.expr()?;
647 StmtKind::Assign { target, op, value }
648 }
649 }
650 }
651 };
652 Ok(Stmt {
653 kind,
654 span: lo.to(self.prev_span()),
655 })
656 }
657
658 fn pattern(&mut self) -> PResult<Pattern> {
661 self.nested(|p| p.pattern_inner())
662 }
663
664 fn pattern_inner(&mut self) -> PResult<Pattern> {
665 let first = self.pattern_alt()?;
666 if !self.at(&Tok::Pipe) {
667 return Ok(first);
668 }
669 let mut alts = vec![first];
671 while self.eat(&Tok::Pipe) {
672 self.deeper()?;
673 alts.push(self.pattern_alt()?);
674 }
675 let span = alts[0].span.to(alts.last().unwrap().span);
676 Ok(Pattern {
677 kind: PatternKind::Or(alts),
678 span,
679 })
680 }
681
682 fn pattern_alt(&mut self) -> PResult<Pattern> {
683 let span = self.span();
684 let kind = match self.peek().clone() {
685 Tok::Underscore => {
686 self.bump();
687 PatternKind::Wildcard
688 }
689 Tok::Ident(name) => {
690 self.bump();
691 PatternKind::Name(name)
692 }
693 Tok::Int(_) | Tok::Float(_) | Tok::Percent(_) | Tok::Str(_) | Tok::True | Tok::False => {
694 PatternKind::Literal(self.primary()?)
695 }
696 Tok::Minus if matches!(self.peek_at(1), Tok::Int(_) | Tok::Float(_) | Tok::Percent(_)) => {
697 self.bump();
698 let inner = self.primary()?;
699 PatternKind::Literal(Expr {
700 span: span.to(inner.span),
701 kind: ExprKind::Unary {
702 op: UnOp::Neg,
703 expr: Box::new(inner),
704 },
705 })
706 }
707 Tok::LBracket => {
708 self.bump();
709 let mut items = Vec::new();
711 while !self.at(&Tok::RBracket) {
712 self.deeper()?;
713 items.push(self.pattern()?);
714 if !self.eat(&Tok::Comma) {
715 break;
716 }
717 }
718 self.expect(&Tok::RBracket, "to close the list pattern")?;
719 PatternKind::List(items)
720 }
721 other => {
722 self.error(span, format!("expected a pattern, found {}", other.describe()));
723 return Err(Failed);
724 }
725 };
726 Ok(Pattern {
727 kind,
728 span: span.to(self.prev_span()),
729 })
730 }
731
732 fn expr(&mut self) -> PResult<Expr> {
735 if let Some(lambda) = self.lambda()? {
736 return Ok(lambda);
737 }
738 self.expr_bp(0)
739 }
740
741 fn lambda(&mut self) -> PResult<Option<Expr>> {
743 let lo = self.span();
744 let params = match (self.peek(), self.peek_at(1)) {
745 (Tok::Ident(_), Tok::Arrow) => {
746 let param = self.ident("a parameter")?;
747 vec![param]
748 }
749 (Tok::LParen, _) => {
750 let mut i = 1;
752 let mut expect_ident = true;
753 loop {
754 match (self.peek_at(i), expect_ident) {
755 (Tok::RParen, _) => break,
756 (Tok::Ident(_), true) => expect_ident = false,
757 (Tok::Comma, false) => expect_ident = true,
758 _ => return Ok(None),
759 }
760 i += 1;
761 }
762 if *self.peek_at(i + 1) != Tok::Arrow {
763 return Ok(None);
764 }
765 self.bump(); let mut params = Vec::new();
767 while !self.at(&Tok::RParen) {
768 params.push(self.ident("a parameter")?);
769 self.eat(&Tok::Comma);
770 }
771 self.bump(); params
773 }
774 _ => return Ok(None),
775 };
776 self.expect(&Tok::Arrow, "")?;
777 let body = self.nested(|p| p.expr())?;
778 let span = lo.to(body.span);
779 Ok(Some(Expr {
780 kind: ExprKind::Lambda {
781 params,
782 body: Box::new(body),
783 },
784 span,
785 }))
786 }
787
788 fn expr_bp(&mut self, min: u8) -> PResult<Expr> {
789 self.nested(|p| p.expr_bp_inner(min))
790 }
791
792 fn expr_bp_inner(&mut self, min: u8) -> PResult<Expr> {
793 let lo = self.span();
794 let mut lhs = match self.peek() {
795 Tok::Typeof | Tok::Not | Tok::Minus | Tok::Tilde => {
796 let (op, precedence) = match self.peek() {
797 Tok::Typeof => (Some(UnOp::Typeof), PREC_TYPEOF),
798 Tok::Not => (Some(UnOp::Not), PREC_NOT),
799 Tok::Minus => (Some(UnOp::Neg), PREC_NEG),
800 _ => (None, PREC_TYPEOF),
801 };
802 self.bump();
803 let operand = self.expr_bp(precedence)?;
804 Expr {
805 span: lo.to(operand.span),
806 kind: match op {
807 Some(op) => ExprKind::Unary {
808 op,
809 expr: Box::new(operand),
810 },
811 None => ExprKind::Draw(Box::new(operand)),
812 },
813 }
814 }
815 _ => self.postfix()?,
816 };
817 while let Some((op, prec, len)) = self.binary_op() {
818 if prec < min {
819 break;
820 }
821 self.deeper()?;
822 for _ in 0..len {
823 self.bump();
824 }
825 let rhs = match prec {
826 PREC_POW => self.expr_bp(PREC_POW)?, _ => self.expr_bp(prec + 1)?,
828 };
829 if prec == PREC_CMP || prec == PREC_RANGE {
830 if let Some((next, next_prec, _)) = self.binary_op() {
831 if next_prec == prec {
832 let span = self.span();
833 let msg = if prec == PREC_CMP {
834 format!(
835 "comparisons can't be chained: `{}` after `{}`",
836 next.symbol(),
837 op.symbol()
838 )
839 } else {
840 format!("`{}` can't follow `{}` directly", next.symbol(), op.symbol())
841 };
842 self.error(span, msg)
843 .help("add parentheses, or combine the tests with `and`");
844 return Err(Failed);
845 }
846 }
847 }
848 let span = lhs.span.to(rhs.span);
849 lhs = Expr {
850 kind: ExprKind::Binary {
851 op,
852 lhs: Box::new(lhs),
853 rhs: Box::new(rhs),
854 },
855 span,
856 };
857 }
858 Ok(lhs)
859 }
860
861 fn binary_op(&self) -> Option<(BinOp, u8, usize)> {
863 Some(match self.peek() {
864 Tok::Or => (BinOp::Or, PREC_OR, 1),
865 Tok::And => (BinOp::And, PREC_AND, 1),
866 Tok::EqEq => (BinOp::Eq, PREC_CMP, 1),
867 Tok::NotEq => (BinOp::Ne, PREC_CMP, 1),
868 Tok::Lt => (BinOp::Lt, PREC_CMP, 1),
869 Tok::Le => (BinOp::Le, PREC_CMP, 1),
870 Tok::Gt => (BinOp::Gt, PREC_CMP, 1),
871 Tok::Ge => (BinOp::Ge, PREC_CMP, 1),
872 Tok::In => (BinOp::In, PREC_CMP, 1),
873 Tok::Not if *self.peek_at(1) == Tok::In => (BinOp::NotIn, PREC_CMP, 2),
874 Tok::DotDot => (BinOp::Range, PREC_RANGE, 1),
875 Tok::DotDotLt => (BinOp::RangeExcl, PREC_RANGE, 1),
876 Tok::Ident(word) if word == "to" => (BinOp::To, PREC_RANGE, 1),
877 Tok::Plus => (BinOp::Add, PREC_ADD, 1),
878 Tok::Minus => (BinOp::Sub, PREC_ADD, 1),
879 Tok::Star => (BinOp::Mul, PREC_MUL, 1),
880 Tok::Slash => (BinOp::Div, PREC_MUL, 1),
881 Tok::Div => (BinOp::IntDiv, PREC_MUL, 1),
882 Tok::Mod => (BinOp::Mod, PREC_MUL, 1),
883 Tok::Caret => (BinOp::Pow, PREC_POW, 1),
884 _ => return None,
885 })
886 }
887
888 fn postfix(&mut self) -> PResult<Expr> {
889 let mut expr = self.primary()?;
890 loop {
891 if matches!(self.peek(), Tok::Dot | Tok::LParen | Tok::LBracket | Tok::With) {
892 self.deeper()?;
893 }
894 match self.peek() {
895 Tok::Dot => {
896 self.bump();
897 let name = self.ident("a field or method name after `.`")?;
898 if self.at(&Tok::LParen) {
899 let args = self.call_args()?;
900 let span = expr.span.to(self.prev_span());
901 expr = Expr {
902 kind: ExprKind::Method {
903 receiver: Box::new(expr),
904 name,
905 args,
906 },
907 span,
908 };
909 } else {
910 let span = expr.span.to(name.span);
911 expr = Expr {
912 kind: ExprKind::Field {
913 expr: Box::new(expr),
914 name,
915 },
916 span,
917 };
918 }
919 }
920 Tok::LParen => {
921 let args = self.call_args()?;
922 let span = expr.span.to(self.prev_span());
923 expr = Expr {
924 kind: ExprKind::Call {
925 callee: Box::new(expr),
926 args,
927 },
928 span,
929 };
930 }
931 Tok::LBracket => {
932 self.bump();
933 let index = self.with_restriction(false, |p| p.expr())?;
934 let hi = self.expect(&Tok::RBracket, "to close the index")?;
935 let span = expr.span.to(hi);
936 expr = Expr {
937 kind: ExprKind::Index {
938 expr: Box::new(expr),
939 index: Box::new(index),
940 },
941 span,
942 };
943 }
944 Tok::With => {
945 self.bump();
946 self.expect(&Tok::LBrace, "after `with`")?;
947 let fields = self.record_fields()?;
948 let span = expr.span.to(self.prev_span());
949 expr = Expr {
950 kind: ExprKind::With {
951 expr: Box::new(expr),
952 fields,
953 },
954 span,
955 };
956 }
957 _ => return Ok(expr),
958 }
959 }
960 }
961
962 fn call_args(&mut self) -> PResult<Vec<Arg>> {
963 self.expect(&Tok::LParen, "")?;
964 self.with_restriction(false, |p| {
965 let mut args = Vec::new();
966 while !p.at(&Tok::RParen) {
967 let name = if matches!(p.peek(), Tok::Ident(_)) && *p.peek_at(1) == Tok::Colon {
968 let name = p.ident("an argument name")?;
969 p.bump(); Some(name)
971 } else {
972 None
973 };
974 let value = p.expr()?;
975 args.push(Arg { name, value });
976 if !p.eat(&Tok::Comma) {
977 break;
978 }
979 }
980 p.expect(&Tok::RParen, "to close the arguments")?;
981 Ok(args)
982 })
983 }
984
985 fn record_fields(&mut self) -> PResult<Vec<Field>> {
987 self.with_restriction(false, |p| {
988 let mut fields = Vec::new();
989 p.skip_newlines();
990 while !p.at(&Tok::RBrace) {
991 let name = p.ident("a field name")?;
992 let value = if p.eat(&Tok::Colon) {
993 p.expr()?
994 } else {
995 Expr {
996 kind: ExprKind::Name(name.name.clone()),
997 span: name.span,
998 }
999 };
1000 fields.push(Field { name, value });
1001 p.skip_newlines();
1002 if !p.eat(&Tok::Comma) {
1003 break;
1004 }
1005 p.skip_newlines();
1006 }
1007 p.skip_newlines();
1008 p.expect(&Tok::RBrace, "to close the record")?;
1009 Ok(fields)
1010 })
1011 }
1012
1013 fn record_ahead(&self, offset: usize, allow_empty: bool) -> bool {
1015 let mut i = offset + 1;
1016 while *self.peek_at(i) == Tok::Newline {
1017 i += 1;
1018 }
1019 match (self.peek_at(i), self.peek_at(i + 1)) {
1020 (Tok::RBrace, _) => allow_empty,
1021 (Tok::Ident(_), Tok::Colon | Tok::Comma) => true,
1022 (Tok::Ident(_), Tok::RBrace) => allow_empty,
1023 _ => false,
1024 }
1025 }
1026
1027 fn primary(&mut self) -> PResult<Expr> {
1028 let lo = self.span();
1029 let kind = match self.peek().clone() {
1030 Tok::Int(v) => {
1031 self.bump();
1032 ExprKind::Int(v)
1033 }
1034 Tok::Float(v) => {
1035 self.bump();
1036 ExprKind::Float(v)
1037 }
1038 Tok::Percent(v) => {
1039 self.bump();
1040 ExprKind::Percent(v)
1041 }
1042 Tok::Dice { count, sides } => {
1043 self.bump();
1044 ExprKind::Dice { count, sides }
1045 }
1046 Tok::True => {
1047 self.bump();
1048 ExprKind::Bool(true)
1049 }
1050 Tok::False => {
1051 self.bump();
1052 ExprKind::Bool(false)
1053 }
1054 Tok::Str(parts) => {
1055 self.bump();
1056 ExprKind::Str(self.string_segments(parts))
1057 }
1058 Tok::Ident(name) => {
1059 if !self.restricted && *self.peek_at(1) == Tok::LBrace && self.record_ahead(1, true) {
1061 let ident = self.ident("")?;
1062 self.bump(); let fields = self.record_fields()?;
1064 ExprKind::Record {
1065 name: Some(ident),
1066 fields,
1067 }
1068 } else {
1069 self.bump();
1070 ExprKind::Name(name)
1071 }
1072 }
1073 Tok::LParen => {
1074 self.bump();
1075 let inner = self.with_restriction(false, |p| p.expr())?;
1076 self.expect(&Tok::RParen, "to close the parenthesis")?;
1077 let span = lo.to(self.prev_span());
1078 return Ok(Expr { span, ..inner });
1079 }
1080 Tok::LBracket => return self.list_or_map(),
1081 Tok::LBrace => {
1082 if self.restricted {
1083 self.error(lo, "expected an expression before `{`");
1084 return Err(Failed);
1085 }
1086 if self.record_ahead(0, false) {
1087 self.bump();
1088 let fields = self.record_fields()?;
1089 ExprKind::Record { name: None, fields }
1090 } else {
1091 ExprKind::Block(self.block()?)
1092 }
1093 }
1094 Tok::If => return self.if_expr(),
1095 Tok::Try => return self.try_expr(),
1096 Tok::Chance => return self.chance_expr(),
1097 Tok::Match => return self.match_expr(),
1098 Tok::Simulate => {
1099 self.bump();
1100 ExprKind::Simulate(self.block()?)
1101 }
1102 Tok::Underscore => {
1103 self.error(lo, "`_` can only be used in patterns");
1104 return Err(Failed);
1105 }
1106 other => {
1107 self.error(lo, format!("expected an expression, found {}", other.describe()));
1108 return Err(Failed);
1109 }
1110 };
1111 Ok(Expr {
1112 kind,
1113 span: lo.to(self.prev_span()),
1114 })
1115 }
1116
1117 fn string_segments(&mut self, parts: Vec<StrPart>) -> Vec<StrSegment> {
1118 let mut segments = Vec::new();
1119 for part in parts {
1120 match part {
1121 StrPart::Lit(text) => segments.push(StrSegment::Lit(text)),
1122 StrPart::Expr { src, offset } => {
1123 let (expr, mut diags) = parse_nested_expr(&src, offset, self.depth + 1);
1124 self.diags.append(&mut diags);
1125 if let Some(expr) = expr {
1126 segments.push(StrSegment::Expr(expr));
1127 }
1128 }
1129 }
1130 }
1131 segments
1132 }
1133
1134 fn list_or_map(&mut self) -> PResult<Expr> {
1135 let lo = self.bump().span; self.with_restriction(false, |p| {
1137 if p.at(&Tok::Colon) && *p.peek_at(1) == Tok::RBracket {
1138 p.bump();
1139 let hi = p.bump().span;
1140 return Ok(Expr {
1141 kind: ExprKind::Map(Vec::new()),
1142 span: lo.to(hi),
1143 });
1144 }
1145 if p.at(&Tok::RBracket) {
1146 let hi = p.bump().span;
1147 return Ok(Expr {
1148 kind: ExprKind::List(Vec::new()),
1149 span: lo.to(hi),
1150 });
1151 }
1152 let first = p.expr()?;
1153 if p.eat(&Tok::Colon) {
1154 let value = p.expr()?;
1155 let mut entries = vec![(first, value)];
1156 while p.eat(&Tok::Comma) {
1157 if p.at(&Tok::RBracket) {
1158 break;
1159 }
1160 let key = p.expr()?;
1161 p.expect(&Tok::Colon, "between a key and its value")?;
1162 let value = p.expr()?;
1163 entries.push((key, value));
1164 }
1165 let hi = p.expect(&Tok::RBracket, "to close the map")?;
1166 Ok(Expr {
1167 kind: ExprKind::Map(entries),
1168 span: lo.to(hi),
1169 })
1170 } else {
1171 let mut items = vec![first];
1172 while p.eat(&Tok::Comma) {
1173 if p.at(&Tok::RBracket) {
1174 break;
1175 }
1176 items.push(p.expr()?);
1177 }
1178 let hi = p.expect(&Tok::RBracket, "to close the list")?;
1179 Ok(Expr {
1180 kind: ExprKind::List(items),
1181 span: lo.to(hi),
1182 })
1183 }
1184 })
1185 }
1186
1187 fn if_expr(&mut self) -> PResult<Expr> {
1188 let lo = self.bump().span; let cond = self.with_restriction(true, |p| p.expr())?;
1190 let then = self.block()?;
1191 let mut ahead = 0;
1194 while *self.peek_at(ahead) == Tok::Newline {
1195 ahead += 1;
1196 }
1197 if ahead > 0 && *self.peek_at(ahead) == Tok::Else && matches!(self.peek_at(ahead + 1), Tok::LBrace | Tok::If) {
1198 self.skip_newlines();
1199 }
1200 let otherwise = if self.eat(&Tok::Else) {
1201 if self.at(&Tok::If) {
1202 Some(Box::new(self.nested(|p| p.if_expr())?))
1203 } else {
1204 let block = self.block()?;
1205 Some(Box::new(Expr {
1206 span: block.span,
1207 kind: ExprKind::Block(block),
1208 }))
1209 }
1210 } else {
1211 None
1212 };
1213 Ok(Expr {
1214 kind: ExprKind::If {
1215 cond: Box::new(cond),
1216 then,
1217 otherwise,
1218 },
1219 span: lo.to(self.prev_span()),
1220 })
1221 }
1222
1223 fn try_expr(&mut self) -> PResult<Expr> {
1224 let lo = self.bump().span; let body = self.block()?;
1226 let mut catches: Vec<Catch> = Vec::new();
1227 loop {
1228 let mut ahead = 0;
1230 while *self.peek_at(ahead) == Tok::Newline {
1231 ahead += 1;
1232 }
1233 if *self.peek_at(ahead) != Tok::Catch {
1234 break;
1235 }
1236 self.skip_newlines();
1237 let start = self.bump().span; let fault = match self.peek() {
1239 Tok::Ident(_) => Some(self.ident("a fault")?),
1240 _ => None,
1241 };
1242 let body = self.block()?;
1243 let span = start.to(self.prev_span());
1244 if catches.last().is_some_and(|c| c.fault.is_none()) {
1245 self.error(span, "a `catch` after one that catches every fault never runs");
1246 }
1247 catches.push(Catch { fault, body, span });
1248 }
1249 if catches.is_empty() {
1250 self.error(
1251 lo,
1252 "`try` needs a `catch`, like `try { 1 / x } catch DivisionByZero { 0 }`",
1253 );
1254 return Err(Failed);
1255 }
1256 Ok(Expr {
1257 kind: ExprKind::Try { body, catches },
1258 span: lo.to(self.prev_span()),
1259 })
1260 }
1261
1262 fn arms<T>(&mut self, mut arm: impl FnMut(&mut Parser) -> PResult<T>) -> PResult<Vec<T>> {
1264 self.expect(&Tok::LBrace, "to start the arms")?;
1265 self.with_restriction(false, |p| {
1266 let mut arms = Vec::new();
1267 loop {
1268 while matches!(p.peek(), Tok::Newline | Tok::Comma) {
1269 p.bump();
1270 }
1271 if p.at(&Tok::RBrace) {
1272 break;
1273 }
1274 let start = p.pos;
1275 match arm(p) {
1276 Ok(a) => arms.push(a),
1277 Err(Failed) => {
1278 let mut open = p.tokens[start..p.pos].iter().fold(0usize, |open, t| match t.tok {
1283 Tok::LParen | Tok::LBracket | Tok::LBrace => open + 1,
1284 Tok::RParen | Tok::RBracket | Tok::RBrace => open.saturating_sub(1),
1285 _ => open,
1286 });
1287 loop {
1288 match p.peek() {
1289 Tok::Eof => return Err(Failed),
1290 Tok::Newline | Tok::Comma | Tok::RBrace if open == 0 => break,
1291 Tok::LParen | Tok::LBracket | Tok::LBrace => open += 1,
1292 Tok::RParen | Tok::RBracket | Tok::RBrace => open = open.saturating_sub(1),
1293 _ => {}
1294 }
1295 p.bump();
1296 }
1297 continue;
1298 }
1299 }
1300 match p.peek() {
1301 Tok::Newline | Tok::Comma | Tok::RBrace => {}
1302 other => {
1303 let found = other.describe();
1304 let span = p.span();
1305 p.error(span, format!("expected `,` or a new line between arms, found {found}"));
1306 return Err(Failed);
1307 }
1308 }
1309 }
1310 p.bump(); Ok(arms)
1312 })
1313 }
1314
1315 fn chance_expr(&mut self) -> PResult<Expr> {
1316 let lo = self.bump().span; let arms = self.arms(|p| {
1318 let arm_lo = p.span();
1319 let weight = if p.eat(&Tok::Else) { None } else { Some(p.expr()?) };
1320 p.expect(&Tok::FatArrow, "after the arm's probability")?;
1321 let body = p.stmt()?;
1322 Ok(ChanceArm {
1323 weight,
1324 span: arm_lo.to(body.span),
1325 body,
1326 })
1327 })?;
1328 Ok(Expr {
1329 kind: ExprKind::Chance { arms },
1330 span: lo.to(self.prev_span()),
1331 })
1332 }
1333
1334 fn match_expr(&mut self) -> PResult<Expr> {
1335 let lo = self.bump().span; let scrutinee = self.with_restriction(true, |p| p.expr())?;
1337 let arms = self.arms(|p| {
1338 let pattern = p.pattern()?;
1339 let guard = if p.eat(&Tok::If) { Some(p.expr()?) } else { None };
1340 p.expect(&Tok::FatArrow, "after the pattern")?;
1341 let body = p.stmt()?;
1342 Ok(MatchArm {
1343 span: pattern.span.to(body.span),
1344 pattern,
1345 guard,
1346 body,
1347 })
1348 })?;
1349 Ok(Expr {
1350 kind: ExprKind::Match {
1351 scrutinee: Box::new(scrutinee),
1352 arms,
1353 },
1354 span: lo.to(self.prev_span()),
1355 })
1356 }
1357}
1358
1359fn plain_string(parts: &[StrPart]) -> Option<String> {
1361 let mut text = String::new();
1362 for part in parts {
1363 match part {
1364 StrPart::Lit(s) => text.push_str(s),
1365 StrPart::Expr { .. } => return None,
1366 }
1367 }
1368 Some(text)
1369}
1370
1371fn is_place(expr: &Expr) -> bool {
1372 match &expr.kind {
1373 ExprKind::Name(_) => true,
1374 ExprKind::Field { expr, .. } | ExprKind::Index { expr, .. } => is_place(expr),
1375 _ => false,
1376 }
1377}