1use beck_diag::depth::Nesting;
19use beck_diag::{Diagnostic, Diagnostics, FileId, Span};
20
21use crate::lexer::{lex, Raw, Tok, Token};
22use crate::node::{sym, Head, Lit, Node, Symbol};
23
24pub struct Parser<'a> {
25 toks: Vec<Token>,
26 pos: usize,
27 diags: &'a mut Diagnostics,
28 file: FileId,
29 poisoned: bool,
32 attached_block: bool,
34 nesting: Nesting,
38 in_test: usize,
42}
43
44pub fn parse_module(file: FileId, name: &str, src: &str, diags: &mut Diagnostics) -> Node {
46 let toks = lex(file, src, diags);
47 let mut p = Parser {
48 toks,
49 pos: 0,
50 diags,
51 file,
52 poisoned: false,
53 attached_block: false,
54 nesting: Nesting::new(),
55 in_test: 0,
56 };
57 let mut items = vec![Node::sym(name, Span::new(file, 0..0))];
58 while !p.at_eof() {
59 p.skip_newlines();
60 if p.at_eof() {
61 break;
62 }
63 match p.item() {
64 Some(item) => items.push(item),
65 None => p.recover_to_next_item(),
66 }
67 }
68 Node::form(sym::MODULE, items, Span::new(file, 0..src.len()))
69}
70
71pub fn parse_expr_str(file: FileId, src: &str, diags: &mut Diagnostics) -> Option<Node> {
73 let toks = lex(file, src, diags);
74 let mut p = Parser {
75 toks,
76 pos: 0,
77 diags,
78 file,
79 poisoned: false,
80 attached_block: false,
81 nesting: Nesting::new(),
82 in_test: 0,
83 };
84 p.skip_newlines();
85 p.expr()
86}
87
88impl<'a> Parser<'a> {
89 fn cur(&self) -> &Token {
92 &self.toks[self.pos.min(self.toks.len() - 1)]
93 }
94
95 fn at_eof(&self) -> bool {
96 matches!(self.cur().tok, Tok::Eof)
97 }
98
99 fn span(&self) -> Span {
100 self.cur().span
101 }
102
103 fn bump(&mut self) -> Token {
104 let t = self.cur().clone();
105 if self.pos < self.toks.len() - 1 {
106 self.pos += 1;
107 }
108 t
109 }
110
111 fn at(&self, r: &Raw) -> bool {
112 self.cur().raw() == Some(r)
113 }
114
115 fn at_kw(&self, name: &str) -> bool {
116 self.cur().is_ident(name)
117 }
118
119 fn eat(&mut self, r: &Raw) -> bool {
120 if self.at(r) {
121 self.bump();
122 true
123 } else {
124 false
125 }
126 }
127
128 fn eat_kw(&mut self, name: &str) -> bool {
129 if self.at_kw(name) {
130 self.bump();
131 true
132 } else {
133 false
134 }
135 }
136
137 fn expect(&mut self, r: &Raw, what: &str) -> bool {
138 if self.eat(r) {
139 return true;
140 }
141 self.error(format!("expected {what}, found {}", self.cur().describe()));
142 false
143 }
144
145 fn error(&mut self, msg: impl Into<String>) {
146 if self.poisoned {
147 return;
148 }
149 self.poisoned = true;
150 let span = self.span();
151 self.diags.push(
152 Diagnostic::error("B0120", msg.into(), span).with_primary_label("unexpected here"),
153 );
154 }
155
156 fn skip_newlines(&mut self) {
157 while matches!(self.cur().tok, Tok::Newline) {
158 self.bump();
159 }
160 }
161
162 fn recover_to_next_item(&mut self) {
165 self.poisoned = false;
166 let mut depth = 0i32;
167 loop {
168 match &self.cur().tok {
169 Tok::Eof => return,
170 Tok::Indent => {
171 depth += 1;
172 self.bump();
173 }
174 Tok::Dedent => {
175 depth -= 1;
176 self.bump();
177 if depth <= 0 {
178 return;
179 }
180 }
181 Tok::Newline if depth <= 0 => {
182 self.bump();
183 return;
184 }
185 _ => {
186 self.bump();
187 }
188 }
189 }
190 }
191
192 fn ident(&mut self, what: &str) -> Option<(String, Span)> {
193 let span = self.span();
194 match self.cur().raw() {
195 Some(Raw::Ident(s)) => {
196 let s = s.clone();
197 self.bump();
198 Some((s, span))
199 }
200 _ => {
201 self.error(format!("expected {what}, found {}", self.cur().describe()));
202 None
203 }
204 }
205 }
206
207 fn item(&mut self) -> Option<Node> {
210 if self.at(&Raw::At) {
211 return self.decorated();
212 }
213 let start = self.span();
214 if self.at_kw("def") {
215 return self.def_item();
216 }
217 if self.at_kw("row") {
222 self.bump();
223 let (name, name_span) = self.ident("a row name")?;
224 self.expect(&Raw::Eq, "`=`");
225 let mut atoms = Vec::new();
226 loop {
227 atoms.push(self.expr()?);
228 if !self.eat(&Raw::Comma) {
229 break;
230 }
231 }
232 let span = start.to(atoms.last().map(|a| a.span()).unwrap_or(name_span));
233 self.end_of_line();
234 let mut items = vec![Node::sym(name, name_span)];
235 items.extend(atoms);
236 return Some(Node::form(sym::ROW, items, span));
237 }
238 if self.at_kw("identity") && matches!(self.peek_raw(1), Some(Raw::Eq)) {
245 self.bump();
246 self.expect(&Raw::Eq, "`=`");
247 let provider = self.expr()?;
248 let span = start.to(provider.span());
249 self.end_of_line();
250 return Some(Node::form(sym::IDENTITY, vec![provider], span));
251 }
252 if self.at_kw("macro") {
253 return self.macro_item();
254 }
255 if self.at_kw("model") {
256 return self.model_item();
257 }
258 if self.at_kw("union") {
259 return self.union_item();
260 }
261 if self.at_kw("trait") {
262 return self.trait_item();
263 }
264 if self.at_kw("impl") {
265 return self.impl_item();
266 }
267 if self.at_kw("type") {
268 return self.type_item();
269 }
270 if self.at_kw("import") {
271 self.bump();
272 let (name, s) = self.ident("a module name")?;
273 let mut path = name;
274 let mut span = start.to(s);
275 while self.at(&Raw::Dot) {
276 self.bump();
277 let (seg, s2) = self.ident("a module name")?;
278 path.push('.');
279 path.push_str(&seg);
280 span = span.to(s2);
281 }
282 self.end_of_line();
283 return Some(Node::form(sym::IMPORT, vec![Node::sym(path, span)], span));
284 }
285 if self.at_kw("test") {
286 self.bump();
287 let (name, name_span) = self.quoted_name("a test name")?;
288 self.expect(&Raw::Colon, "`:`");
289 let body = self.test_body()?;
290 let span = start.to(body.span());
291 return Some(Node::form(
292 sym::TEST,
293 vec![Node::lit(Lit::Str(name.into()), name_span), body],
294 span,
295 ));
296 }
297 if self.at_kw("property") && matches!(self.peek_raw(1), Some(Raw::Str(_))) {
300 self.bump();
301 let (name, name_span) = self.quoted_name("a property name")?;
302 let params = self.params()?;
303 self.expect(&Raw::Colon, "`:`");
304 let body = self.test_body()?;
305 let span = start.to(body.span());
306 return Some(Node::form(
307 sym::PROPERTY,
308 vec![Node::lit(Lit::Str(name.into()), name_span), params, body],
309 span,
310 ));
311 }
312 self.statement()
314 }
315
316 fn decorated(&mut self) -> Option<Node> {
317 let start = self.span();
318 self.bump(); let deco = self.postfix(false)?;
320 self.end_of_line();
321 self.skip_newlines();
322 let inner = self.item()?;
323 let span = start.to(inner.span());
324 Some(Node::form(sym::DECORATE, vec![deco, inner], span))
325 }
326
327 fn def_item(&mut self) -> Option<Node> {
329 let start = self.span();
330 self.bump(); let (name, name_span) = self.ident("a function name")?;
332 let typarams = self.typarams(name_span);
336 let params = self.params()?;
337 let returns = if self.eat(&Raw::Arrow) {
338 let t = self.type_expr()?;
339 let s = t.span();
340 Node::form(sym::RETURNS, vec![t], s)
341 } else {
342 Node::form(sym::RETURNS, vec![], name_span)
343 };
344
345 let mut uses = Vec::new();
348 if self.eat_kw("uses") {
349 loop {
350 uses.push(self.expr()?);
351 if !self.eat(&Raw::Comma) {
352 break;
353 }
354 }
355 }
356 let uses_span = uses.first().map(|n| n.span()).unwrap_or(name_span);
357 let uses = Node::form("uses", uses, uses_span);
358
359 if !self.at(&Raw::Colon) {
364 let span = start.to(uses.span());
365 return Some(Node::form(
366 sym::DEF,
367 vec![Node::sym(name, name_span), typarams, params, returns, uses],
368 span,
369 ));
370 }
371 self.expect(&Raw::Colon, "`:` before the function body");
372 let body = self.block()?;
373 let span = start.to(body.span());
374 Some(Node::form(
375 sym::DEF,
376 vec![
377 Node::sym(name, name_span),
378 typarams,
379 params,
380 returns,
381 uses,
382 body,
383 ],
384 span,
385 ))
386 }
387
388 fn macro_item(&mut self) -> Option<Node> {
389 let start = self.span();
390 self.bump(); let (name, name_span) = self.ident("a macro name")?;
392 let params = self.params()?;
393 self.expect(&Raw::Colon, "`:` before the macro body");
394 let body = self.block()?;
395 let span = start.to(body.span());
396 Some(Node::form(
397 sym::MACRO,
398 vec![Node::sym(name, name_span), params, body],
399 span,
400 ))
401 }
402
403 fn typarams(&mut self, at: Span) -> Node {
412 let start = self.span();
413 if !self.at(&Raw::LBracket) {
414 return Node::form(sym::TYPARAMS, Vec::new(), at);
415 }
416 self.bump();
417 let mut out = Vec::new();
418 while !self.at(&Raw::RBracket) && !self.at_eof() {
419 let Some((name, span)) = self.ident("a type parameter") else {
420 break;
421 };
422 if self.eat(&Raw::Colon) {
423 let mut parts = vec![Node::sym(name, span)];
424 while let Some((t, tspan)) = self.ident("a trait name") {
425 parts.push(Node::sym(t, tspan));
426 if !self.eat(&Raw::Plus) {
427 break;
428 }
429 }
430 let end = self.span();
431 out.push(Node::form(sym::ANNOT, parts, span.to(end)));
432 } else {
433 out.push(Node::sym(name, span));
434 }
435 if !self.eat(&Raw::Comma) {
436 break;
437 }
438 }
439 let end = self.span();
440 self.expect(&Raw::RBracket, "`]`");
441 Node::form(sym::TYPARAMS, out, start.to(end))
442 }
443
444 fn params(&mut self) -> Option<Node> {
445 let start = self.span();
446 self.expect(&Raw::LParen, "`(`");
447 let mut out = Vec::new();
448 while !self.at(&Raw::RParen) && !self.at_eof() {
449 let (name, name_span) = self.ident("a parameter name")?;
450 let ty = if self.eat(&Raw::Colon) {
451 Some(self.type_expr()?)
452 } else {
453 None
454 };
455 let span = ty
456 .as_ref()
457 .map(|t| name_span.to(t.span()))
458 .unwrap_or(name_span);
459 out.push(match ty {
460 Some(t) => Node::form(sym::ANNOT, vec![Node::sym(name, name_span), t], span),
461 None => Node::sym(name, name_span),
462 });
463 if !self.eat(&Raw::Comma) {
464 break;
465 }
466 }
467 let end = self.span();
468 self.expect(&Raw::RParen, "`)`");
469 Some(Node::form(sym::PARAMS, out, start.to(end)))
470 }
471
472 fn model_item(&mut self) -> Option<Node> {
473 let start = self.span();
474 self.bump(); let (name, name_span) = self.ident("a model name")?;
476 let typarams = self.typarams(name_span);
477 self.expect(&Raw::Colon, "`:`");
478 let mut fields = vec![Node::sym(name, name_span), typarams];
479 for line in self.indented_lines()? {
480 let mut p = self.sub(line);
481 if let Some(f) = p.field_decl() {
482 fields.push(f);
483 }
484 }
485 Some(Node::form(sym::MODEL, fields, start))
486 }
487
488 fn union_item(&mut self) -> Option<Node> {
489 let start = self.span();
490 self.bump(); let (name, name_span) = self.ident("a union name")?;
492 let typarams = self.typarams(name_span);
493 self.expect(&Raw::Colon, "`:`");
494 let mut variants = vec![Node::sym(name, name_span), typarams];
495 for line in self.indented_lines()? {
496 let mut p = self.sub(line);
497 if let Some(v) = p.variant_decl() {
498 variants.push(v);
499 }
500 }
501 Some(Node::form(sym::UNION, variants, start))
502 }
503
504 fn trait_item(&mut self) -> Option<Node> {
505 let start = self.span();
506 self.bump(); let (name, name_span) = self.ident("a trait name")?;
508 self.expect(&Raw::Colon, "`:`");
509 let body = self.block()?;
510 let mut items = vec![Node::sym(name, name_span)];
511 items.extend(body.args);
512 Some(Node::form(sym::TRAIT, items, start))
513 }
514
515 fn impl_item(&mut self) -> Option<Node> {
520 let start = self.span();
521 self.bump(); let typarams = self.typarams(start);
523 let (trait_name, tspan) = self.ident("a trait name")?;
524 if !self.eat_kw("for") {
525 self.error("expected `for` in an impl declaration");
526 return None;
527 }
528 let ty = self.type_expr()?;
529 let mut items = vec![Node::sym(trait_name, tspan), typarams, ty];
530 if self.eat(&Raw::Colon) {
534 let body = self.block()?;
535 items.extend(body.args);
536 } else {
537 self.end_of_line();
538 }
539 Some(Node::form(sym::IMPL, items, start))
540 }
541
542 fn type_item(&mut self) -> Option<Node> {
543 let start = self.span();
544 self.bump(); let (name, name_span) = self.ident("a type name")?;
546 let typarams = self.typarams(name_span);
547 self.expect(&Raw::Eq, "`=`");
548 if self.at_kw("newtype") {
550 self.bump();
551 self.expect(&Raw::LBracket, "`[`");
552 let inner = self.type_expr()?;
553 self.expect(&Raw::RBracket, "`]`");
554 self.end_of_line();
555 return Some(Node::form(
556 sym::NEWTYPE,
557 vec![Node::sym(name, name_span), typarams, inner],
558 start,
559 ));
560 }
561 let ty = self.type_expr()?;
562 self.end_of_line();
563 Some(Node::form(
564 sym::TYPE,
565 vec![Node::sym(name, name_span), typarams, ty],
566 start,
567 ))
568 }
569
570 fn field_decl(&mut self) -> Option<Node> {
571 let (name, name_span) = self.ident("a field name")?;
572 self.expect(&Raw::Colon, "`:`");
573 let ty = self.type_expr()?;
574 let span = name_span.to(ty.span());
575 Some(Node::form(
576 sym::FIELD,
577 vec![Node::sym(name, name_span), ty],
578 span,
579 ))
580 }
581
582 fn variant_decl(&mut self) -> Option<Node> {
583 let (name, name_span) = self.ident("a variant name")?;
584 let mut items = vec![Node::sym(name, name_span)];
585 if self.eat(&Raw::LParen) {
586 while !self.at(&Raw::RParen) && !self.at_eof() {
587 items.push(self.field_decl()?);
588 if !self.eat(&Raw::Comma) {
589 break;
590 }
591 }
592 self.expect(&Raw::RParen, "`)`");
593 }
594 Some(Node::form(sym::VARIANT, items, name_span))
595 }
596
597 fn peek_raw(&self, n: usize) -> Option<&Raw> {
600 self.toks
601 .get((self.pos + n).min(self.toks.len() - 1))?
602 .raw()
603 }
604
605 fn quoted_name(&mut self, what: &str) -> Option<(String, Span)> {
606 let span = self.span();
607 match self.cur().raw() {
608 Some(Raw::Str(s)) => {
609 let s = s.clone();
610 self.bump();
611 Some((s, span))
612 }
613 _ => {
614 self.error(format!("expected {what} in quotes"));
615 None
616 }
617 }
618 }
619
620 fn test_body(&mut self) -> Option<Node> {
622 self.in_test += 1;
623 let out = self.block();
624 self.in_test -= 1;
625 out
626 }
627
628 fn given_clause(&mut self) -> Option<Node> {
636 let start = self.span();
637 self.bump(); let events = self.expr()?;
639 let mut args = vec![events];
640 if self.eat_kw("by") {
641 let (actor, span) = self.quoted_name("an actor name")?;
642 args.push(Node::lit(Lit::Str(actor.into()), span));
643 }
644 let span = start.to(args.last().map(|a| a.span()).unwrap_or(start));
645 self.end_of_line();
646 Some(Node::form(sym::GIVEN, args, span))
647 }
648
649 fn when_clause(&mut self) -> Option<Node> {
656 let start = self.span();
657 self.bump(); let session = if self.at_kw("session") && self.line_has_ident("sends") {
661 let (actor, span) = self.session_actor()?;
662 if !self.eat_kw("sends") {
663 self.error("expected `sends` after the session");
664 return None;
665 }
666 Node::lit(Lit::Str(actor.into()), span)
667 } else {
668 Node::sym(sym::WILDCARD, start)
669 };
670 let mut args = vec![session];
671 loop {
672 args.push(self.expr()?);
673 if !self.eat(&Raw::Comma) {
674 break;
675 }
676 }
677 let span = start.to(args.last().map(|a| a.span()).unwrap_or(start));
678 self.end_of_line();
679 Some(Node::form(sym::WHEN, args, span))
680 }
681
682 fn stub_clause(&mut self) -> Option<Node> {
698 let start = self.span();
699 self.bump(); let (atom, atom_span) = self.effect_atom()?;
701 self.expect(&Raw::Colon, "`:`");
702
703 let value = if matches!(self.cur().tok, Tok::Newline) {
704 if self.block_starts_with("case") {
707 self.skip_newlines();
708 self.bump(); let arms = self.case_arms()?;
710 Node::form(sym::STUB_ARMS, arms, start.to(self.span()))
711 } else {
712 self.block()?
713 }
714 } else {
715 let e = self.expr()?;
716 self.end_of_line();
717 e
718 };
719
720 let span = start.to(value.span());
721 Some(Node::form(
722 sym::STUB,
723 vec![Node::lit(Lit::Str(atom.into()), atom_span), value],
724 span,
725 ))
726 }
727
728 fn expect_clause(&mut self) -> Option<Node> {
731 let start = self.span();
732 self.bump(); if self.at_kw("no") {
736 self.bump();
737 let (atom, _) = self.effect_atom()?;
738 let span = start.to(self.span());
739 self.end_of_line();
740 return Some(Node::form(
741 sym::EXPECT_EFFECT,
742 vec![
743 Node::lit(Lit::Str(atom.into()), span),
744 Node::sym("none", span),
745 ],
746 span,
747 ));
748 }
749
750 if self.at_kw("wire_compatible_with") {
753 self.bump();
754 let (path, pspan) = self.quoted_name("a `.becki` path")?;
755 let span = start.to(pspan);
756 self.end_of_line();
757 return Some(Node::form(
758 sym::EXPECT_WIRE,
759 vec![Node::lit(Lit::Str(path.into()), pspan)],
760 span,
761 ));
762 }
763
764 if self.at_kw("place") && matches!(self.peek_raw(1), Some(Raw::LParen)) {
766 self.bump();
767 self.expect(&Raw::LParen, "`(`");
768 let (name, nspan) = self.ident("a definition or signal name")?;
769 self.expect(&Raw::RParen, "`)`");
770 if !self.eat(&Raw::EqEq) {
771 self.error("expected `==` and a tier");
772 return None;
773 }
774 let (tier, tspan) = self.ident("a tier")?;
775 let span = start.to(tspan);
776 self.end_of_line();
777 return Some(Node::form(
778 sym::EXPECT_PLACE,
779 vec![Node::sym(name, nspan), Node::sym(tier, tspan)],
780 span,
781 ));
782 }
783
784 if self.at_kw("flow") && matches!(self.peek_raw(1), Some(Raw::LParen)) {
786 self.bump();
787 self.expect(&Raw::LParen, "`(`");
788 let (name, nspan) = self.ident("a type name")?;
789 self.expect(&Raw::RParen, "`)`");
790 if !(self.eat_kw("reaches") && self.eat_kw("nothing") && self.eat_kw("on")) {
791 self.error("expected `reaches nothing on <tier>`");
792 return None;
793 }
794 let (tier, tspan) = self.ident("a tier")?;
795 let span = start.to(tspan);
796 self.end_of_line();
797 return Some(Node::form(
798 sym::EXPECT_FLOW,
799 vec![Node::sym(name, nspan), Node::sym(tier, tspan)],
800 span,
801 ));
802 }
803
804 if self.at_effect_atom() {
806 let (atom, aspan) = self.effect_atom()?;
807 let how = if self.eat_kw("once") {
808 Node::form(
809 "times",
810 vec![Node::lit(Lit::Int(1), self.span())],
811 self.span(),
812 )
813 } else if self.eat_kw("times") {
814 let span = self.span();
815 match self.cur().raw() {
816 Some(Raw::Int(n)) => {
817 let n = *n;
818 self.bump();
819 Node::form("times", vec![Node::lit(Lit::Int(n), span)], span)
820 }
821 _ => {
822 self.error("expected a count after `times`");
823 return None;
824 }
825 }
826 } else if self.eat_kw("with") {
827 let e = self.expr()?;
828 let s = e.span();
829 Node::form("with", vec![e], s)
830 } else {
831 self.error("expected `once`, `times <n>` or `with <value>` after an effect atom");
832 return None;
833 };
834 let span = start.to(how.span());
835 self.end_of_line();
836 return Some(Node::form(
837 sym::EXPECT_EFFECT,
838 vec![Node::lit(Lit::Str(atom.into()), aspan), how],
839 span,
840 ));
841 }
842
843 if self.at_kw("page") {
847 self.bump();
848 let mut args = Vec::new();
849 if self.at(&Raw::LParen) {
850 self.bump();
851 if !self.eat_kw("session") {
852 self.error("expected `session(\"actor\")`");
853 return None;
854 }
855 let (actor, aspan) = self.parenthesised_string("an actor name")?;
856 self.expect(&Raw::RParen, "`)`");
857 args.push(Node::lit(Lit::Str(actor.into()), aspan));
858 }
859 if self.eat_kw("matches") {
864 if !self.eat_kw("snapshot") {
865 self.error("expected `snapshot`");
866 return None;
867 }
868 let mut span = start.to(self.span());
869 let name = if matches!(self.peek_raw(0), Some(Raw::Str(_))) {
873 let (name, nspan) = self.quoted_name("a snapshot name")?;
874 span = start.to(nspan);
875 Node::lit(Lit::Str(name.into()), nspan)
876 } else {
877 Node::sym("none", span)
878 };
879 let actor = args.pop().unwrap_or_else(|| Node::sym("none", span));
880 self.end_of_line();
881 return Some(Node::form(sym::EXPECT_SNAPSHOT, vec![name, actor], span));
882 }
883 if !self.eat_kw("contains") {
884 self.error("expected `contains` or `matches snapshot`");
885 return None;
886 }
887 let needle = self.expr()?;
888 let span = start.to(needle.span());
889 self.end_of_line();
890 args.insert(0, needle);
891 return Some(Node::form(sym::EXPECT_CONTAINS, args, span));
892 }
893
894 if self.at_kw("state")
897 && matches!(self.peek_raw(1), Some(Raw::EqEq))
898 && matches!(self.peek_raw(2), Some(Raw::Ident(s)) if s == "fold_of")
899 {
900 self.bump(); self.bump(); self.bump(); let events = self.expr()?;
904 let mut args = vec![events];
905 if self.eat_kw("by") {
906 let (actor, span) = self.quoted_name("an actor name")?;
907 args.push(Node::lit(Lit::Str(actor.into()), span));
908 }
909 let span = start.to(args.last().map(|a| a.span()).unwrap_or(start));
910 self.end_of_line();
911 return Some(Node::form(sym::EXPECT_FOLD, args, span));
912 }
913
914 let e = self.expr()?;
917 let e = match e.head_name() {
918 Some("Ok" | "Err") if e.applied => {
919 let span = e.span();
920 Node::form("==", vec![Node::sym("result", span), e], span)
921 }
922 _ => e,
923 };
924 let span = start.to(e.span());
925 self.end_of_line();
926 Some(Node::form(sym::EXPECT, vec![e], span))
927 }
928
929 const EFFECT_HEADS: &'static [&'static str] = &[
932 "ingress", "durable", "dom", "nondet", "net", "fs", "env", "spawn", "cap", "partial",
933 "external", "log", "metrics",
934 ];
935
936 fn at_effect_atom(&self) -> bool {
937 match self.cur().raw() {
938 Some(Raw::Ident(s)) => Self::EFFECT_HEADS.contains(&s.as_str()),
939 _ => false,
940 }
941 }
942
943 fn effect_atom(&mut self) -> Option<(String, Span)> {
948 let start = self.span();
949 let (head, _) = self.ident("an effect atom")?;
950 let mut out = head;
951 while self.at(&Raw::Dot) {
952 self.bump();
953 let (seg, _) = self.ident("an effect atom")?;
954 out.push('.');
955 out.push_str(&seg);
956 }
957 let mut end = self.span();
958 if self.at(&Raw::LParen) {
959 self.bump();
960 out.push('(');
961 let mut depth = 1;
962 loop {
963 match self.cur().raw() {
964 Some(Raw::LParen) => depth += 1,
965 Some(Raw::RParen) => {
966 depth -= 1;
967 if depth == 0 {
968 end = self.span();
969 self.bump();
970 break;
971 }
972 }
973 None => {
974 self.error("unterminated effect atom");
975 return None;
976 }
977 _ => {}
978 }
979 out.push_str(&token_text(self.cur()));
980 self.bump();
981 }
982 out.push(')');
983 }
984 Some((out, start.to(end)))
985 }
986
987 fn block_starts_with(&self, kw: &str) -> bool {
992 let mut i = self.pos;
993 while matches!(self.toks.get(i).map(|t| &t.tok), Some(Tok::Newline)) {
994 i += 1;
995 }
996 if !matches!(self.toks.get(i).map(|t| &t.tok), Some(Tok::Indent)) {
997 return false;
998 }
999 matches!(self.toks.get(i + 1).and_then(|t| t.raw()), Some(Raw::Ident(s)) if s == kw)
1000 }
1001
1002 fn session_actor(&mut self) -> Option<(String, Span)> {
1004 self.bump(); self.parenthesised_string("an actor name")
1006 }
1007
1008 fn parenthesised_string(&mut self, what: &str) -> Option<(String, Span)> {
1010 self.expect(&Raw::LParen, "`(`");
1011 let out = self.quoted_name(what)?;
1012 self.expect(&Raw::RParen, "`)`");
1013 Some(out)
1014 }
1015
1016 fn line_has_ident(&self, name: &str) -> bool {
1018 let mut depth = 0i32;
1019 for t in &self.toks[self.pos..] {
1020 match &t.tok {
1021 Tok::Newline | Tok::Indent | Tok::Dedent | Tok::Eof if depth == 0 => return false,
1022 Tok::Raw(Raw::LParen | Raw::LBracket | Raw::LBrace) => depth += 1,
1023 Tok::Raw(Raw::RParen | Raw::RBracket | Raw::RBrace) => depth -= 1,
1024 Tok::Raw(Raw::Ident(s)) if depth == 0 && s == name => return true,
1025 _ => {}
1026 }
1027 }
1028 false
1029 }
1030
1031 fn enter(&mut self) -> bool {
1038 if self.nesting.enter() {
1039 return true;
1040 }
1041 if self.nesting.should_report() {
1042 let span = self.span();
1043 let note = self.nesting.note();
1044 self.diags.push(
1045 Diagnostic::error("B0121", "nesting is too deep to read", span)
1046 .with_primary_label("the parser gave up here")
1047 .with_note(note),
1048 );
1049 }
1050 self.poisoned = true;
1051 false
1052 }
1053
1054 fn block(&mut self) -> Option<Node> {
1055 if !self.enter() {
1056 return None;
1057 }
1058 let out = self.block_inner();
1059 self.nesting.leave();
1060 out
1061 }
1062
1063 fn block_inner(&mut self) -> Option<Node> {
1064 let start = self.span();
1065 if !matches!(self.cur().tok, Tok::Newline) {
1067 let e = self.statement()?;
1068 let s = e.span();
1069 return Some(Node::form(sym::DO, vec![e], start.to(s)));
1070 }
1071 self.skip_newlines();
1072 if !matches!(self.cur().tok, Tok::Indent) {
1073 self.error("expected an indented block");
1074 return None;
1075 }
1076 self.bump(); let mut stmts = Vec::new();
1078 loop {
1079 self.skip_newlines();
1080 match self.cur().tok {
1081 Tok::Dedent => {
1082 self.bump();
1083 break;
1084 }
1085 Tok::Eof => break,
1086 _ => match self.statement() {
1087 Some(s) => stmts.push(s),
1088 None => {
1089 self.recover_in_block();
1090 if matches!(self.cur().tok, Tok::Dedent) {
1091 self.bump();
1092 break;
1093 }
1094 if self.at_eof() {
1095 break;
1096 }
1097 }
1098 },
1099 }
1100 }
1101 let end = self.span();
1102 Some(Node::form(sym::DO, stmts, start.to(end)))
1103 }
1104
1105 fn recover_in_block(&mut self) {
1106 self.poisoned = false;
1107 let mut depth = 0i32;
1108 loop {
1109 match &self.cur().tok {
1110 Tok::Eof => return,
1111 Tok::Indent => {
1112 depth += 1;
1113 self.bump();
1114 }
1115 Tok::Dedent if depth > 0 => {
1116 depth -= 1;
1117 self.bump();
1118 }
1119 Tok::Dedent => return,
1120 Tok::Newline if depth == 0 => {
1121 self.bump();
1122 return;
1123 }
1124 _ => {
1125 self.bump();
1126 }
1127 }
1128 }
1129 }
1130
1131 fn indented_lines(&mut self) -> Option<Vec<Vec<Token>>> {
1134 self.skip_newlines();
1135 if !matches!(self.cur().tok, Tok::Indent) {
1136 self.error("expected an indented block");
1137 return None;
1138 }
1139 self.bump();
1140 let mut lines = Vec::new();
1141 let mut cur: Vec<Token> = Vec::new();
1142 let mut depth = 0i32;
1143 loop {
1144 match &self.cur().tok {
1145 Tok::Eof => break,
1146 Tok::Dedent if depth == 0 => {
1147 self.bump();
1148 break;
1149 }
1150 Tok::Dedent => {
1151 depth -= 1;
1152 cur.push(self.bump());
1153 }
1154 Tok::Indent => {
1155 depth += 1;
1156 cur.push(self.bump());
1157 }
1158 Tok::Newline if depth == 0 => {
1159 self.bump();
1160 if !cur.is_empty() {
1161 lines.push(std::mem::take(&mut cur));
1162 }
1163 }
1164 _ => cur.push(self.bump()),
1165 }
1166 }
1167 if !cur.is_empty() {
1168 lines.push(cur);
1169 }
1170 Some(lines)
1171 }
1172
1173 fn sub(&mut self, mut toks: Vec<Token>) -> Parser<'_> {
1175 let end = toks.last().map(|t| t.span).unwrap_or(Span::NONE);
1176 toks.push(Token {
1177 tok: Tok::Eof,
1178 span: end,
1179 });
1180 Parser {
1181 toks,
1182 pos: 0,
1183 diags: self.diags,
1184 file: self.file,
1185 poisoned: false,
1186 attached_block: false,
1187 nesting: self.nesting.resumed(),
1188 in_test: self.in_test,
1189 }
1190 }
1191
1192 fn line_has_assignment(&self) -> bool {
1197 let mut depth = 0i32;
1198 for t in &self.toks[self.pos..] {
1199 match &t.tok {
1200 Tok::Newline | Tok::Indent | Tok::Dedent | Tok::Eof if depth == 0 => return false,
1201 Tok::Raw(Raw::LParen | Raw::LBracket | Raw::LBrace) => depth += 1,
1202 Tok::Raw(Raw::RParen | Raw::RBracket | Raw::RBrace) => depth -= 1,
1203 Tok::Raw(Raw::Eq) if depth == 0 => return true,
1204 _ => {}
1205 }
1206 }
1207 false
1208 }
1209
1210 fn end_of_line(&mut self) {
1211 if matches!(self.cur().tok, Tok::Newline) {
1212 self.bump();
1213 }
1214 }
1215
1216 fn statement(&mut self) -> Option<Node> {
1217 let start = self.span();
1218
1219 if self.in_test > 0 {
1221 if self.at_kw("given") {
1222 return self.given_clause();
1223 }
1224 if self.at_kw("when") {
1225 return self.when_clause();
1226 }
1227 if self.at_kw("expect") {
1228 return self.expect_clause();
1229 }
1230 if self.at_kw("stub") {
1231 return self.stub_clause();
1232 }
1233 }
1234
1235 if self.at(&Raw::At) {
1236 return self.decorated();
1237 }
1238 if self.at_kw("def") {
1239 return self.def_item();
1240 }
1241 if self.at_kw("return") {
1242 self.bump();
1243 if matches!(self.cur().tok, Tok::Newline | Tok::Dedent | Tok::Eof) {
1244 self.end_of_line();
1245 return Some(Node::form(sym::RETURN, vec![], start));
1246 }
1247 let e = self.expr_stmt()?;
1248 let span = start.to(e.span());
1249 self.end_of_line();
1250 return Some(Node::form(sym::RETURN, vec![e], span));
1251 }
1252 if self.at_kw("if") {
1253 return self.if_stmt();
1254 }
1255 if self.at_kw("for") {
1256 self.bump();
1257 let (name, name_span) = self.ident("a loop variable")?;
1258 if !self.eat_kw("in") {
1259 self.error("expected `in`");
1260 return None;
1261 }
1262 let seq = self.expr()?;
1263 self.expect(&Raw::Colon, "`:`");
1264 let body = self.block()?;
1265 let span = start.to(body.span());
1266 return Some(Node::form(
1267 sym::FOR,
1268 vec![Node::sym(name, name_span), seq, body],
1269 span,
1270 ));
1271 }
1272 if self.at_kw("while") {
1273 self.bump();
1274 let c = self.expr()?;
1275 self.expect(&Raw::Colon, "`:`");
1276 let body = self.block()?;
1277 let span = start.to(body.span());
1278 return Some(Node::form(sym::WHILE, vec![c, body], span));
1279 }
1280 if self.at_kw("match") {
1281 return self.match_stmt();
1282 }
1283 if self.at_kw("var") {
1284 self.bump();
1285 let (name, name_span) = self.ident("a variable name")?;
1286 let ty = if self.eat(&Raw::Colon) {
1287 Some(self.type_expr()?)
1288 } else {
1289 None
1290 };
1291 self.expect(&Raw::Eq, "`=`");
1292 let e = self.expr_stmt()?;
1293 let span = start.to(e.span());
1294 self.end_of_line();
1295 let target = match ty {
1296 Some(t) => Node::form(sym::ANNOT, vec![Node::sym(name, name_span), t], name_span),
1297 None => Node::sym(name, name_span),
1298 };
1299 return Some(Node::form(sym::VAR, vec![target, e], span));
1300 }
1301 if self.at_kw("quote") {
1302 }
1304
1305 let save = self.pos;
1311 if self.line_has_assignment() {
1312 if let Some(Raw::Ident(name)) = self.cur().raw().cloned() {
1313 let name_span = self.span();
1314 self.bump();
1315 let ty = if self.at(&Raw::Colon) {
1316 self.bump();
1317 match self.type_expr() {
1318 Some(t) => Some(t),
1319 None => {
1320 self.pos = save;
1321 self.poisoned = false;
1322 None
1323 }
1324 }
1325 } else {
1326 None
1327 };
1328 if self.at(&Raw::Eq) {
1329 self.bump();
1330 let e = self.expr_stmt()?;
1331 let span = start.to(e.span());
1332 self.end_of_line();
1333 let target = match ty {
1334 Some(t) => {
1335 Node::form(sym::ANNOT, vec![Node::sym(&name, name_span), t], name_span)
1336 }
1337 None => Node::sym(&name, name_span),
1338 };
1339 return Some(Node::form(sym::LET, vec![target, e], span));
1340 }
1341 self.pos = save;
1342 self.poisoned = false;
1343 }
1344 }
1345
1346 let e = self.expr_stmt()?;
1347 self.end_of_line();
1348 Some(e)
1349 }
1350
1351 fn if_stmt(&mut self) -> Option<Node> {
1352 let start = self.span();
1353 self.bump(); let cond = self.expr()?;
1355 self.expect(&Raw::Colon, "`:`");
1356 let then = self.block()?;
1357 self.skip_newlines();
1358 let mut args = vec![cond, then];
1359 if self.at_kw("elif") {
1360 let e = self.if_stmt()?;
1361 let s = e.span();
1362 args.push(Node::form(sym::DO, vec![e], s));
1363 } else if self.at_kw("else") {
1364 self.bump();
1365 self.expect(&Raw::Colon, "`:`");
1366 args.push(self.block()?);
1367 }
1368 let span = start.to(args.last().map(|n| n.span()).unwrap_or(start));
1369 Some(Node::form(sym::IF, args, span))
1370 }
1371
1372 fn match_stmt(&mut self) -> Option<Node> {
1373 let start = self.span();
1374 self.bump(); let scrutinee = self.expr()?;
1376 self.expect(&Raw::Colon, "`:`");
1377 self.skip_newlines();
1378 if !matches!(self.cur().tok, Tok::Indent) {
1379 self.error("expected an indented block of `case` arms");
1380 return None;
1381 }
1382 self.bump();
1383 let mut arms = vec![scrutinee];
1384 arms.extend(self.case_arms()?);
1385 let span = start.to(self.span());
1386 Some(Node::form(sym::MATCH, arms, span))
1387 }
1388
1389 fn case_arms(&mut self) -> Option<Vec<Node>> {
1394 let mut arms = Vec::new();
1395 loop {
1396 self.skip_newlines();
1397 match self.cur().tok {
1398 Tok::Dedent => {
1399 self.bump();
1400 break;
1401 }
1402 Tok::Eof => break,
1403 _ => {}
1404 }
1405 let arm_start = self.span();
1406 if !self.eat_kw("case") {
1407 self.error("expected `case`");
1408 self.recover_in_block();
1409 continue;
1410 }
1411 let pat = self.expr_bp(1)?;
1419 let guard = if self.eat_kw("if") {
1420 Some(self.expr()?)
1421 } else {
1422 None
1423 };
1424 self.expect(&Raw::Colon, "`:`");
1425 let body = self.block()?;
1426 let span = arm_start.to(body.span());
1427 let mut args = vec![pat, body];
1428 args.extend(guard);
1429 arms.push(Node::form(sym::CASE, args, span));
1430 }
1431 Some(arms)
1432 }
1433
1434 pub fn expr(&mut self) -> Option<Node> {
1437 self.expr_bp(0)
1438 }
1439
1440 fn expr_stmt(&mut self) -> Option<Node> {
1448 if self.at_kw("not")
1449 || self.at(&Raw::Minus)
1450 || self.at(&Raw::Dollar)
1451 || self.at(&Raw::DollarStar)
1452 {
1453 return self.expr();
1454 }
1455 let first = self.postfix(true)?;
1456 if self.attached_block {
1457 self.attached_block = false;
1458 return Some(first);
1459 }
1460 self.expr_bp_from(first, 0)
1461 }
1462
1463 fn expr_bp(&mut self, min_bp: u8) -> Option<Node> {
1464 let lhs = self.unary()?;
1465 self.expr_bp_from(lhs, min_bp)
1466 }
1467
1468 fn expr_bp_from(&mut self, lhs: Node, min_bp: u8) -> Option<Node> {
1481 let mut lhs = lhs;
1482 let mut chain: u32 = 0;
1483
1484 loop {
1485 chain += 1;
1486 if chain > beck_diag::depth::MAX_BLOCK {
1487 if self.nesting.should_report() {
1488 let span = lhs.span();
1489 let note = self.nesting.note_about("operators in one chain").replace(
1490 &format!("{} operators", self.nesting.limit()),
1491 &format!("{} operators", beck_diag::depth::MAX_BLOCK),
1492 );
1493 self.diags.push(
1494 beck_diag::Diagnostic::error(
1495 "B0122",
1496 "this expression chains too many operators to read",
1497 span,
1498 )
1499 .with_primary_label("the reader gave up here")
1500 .with_note(note),
1501 );
1502 }
1503 return None;
1504 }
1505 if self.at_kw("if") && min_bp == 0 {
1508 self.bump();
1509 let cond = self.expr_bp(1)?;
1510 if !self.eat_kw("else") {
1511 self.error("expected `else` in a conditional expression");
1512 return None;
1513 }
1514 let alt = self.expr_bp(0)?;
1515 let span = lhs.span().to(alt.span());
1516 lhs = Node::form(sym::IF, vec![cond, lhs, alt], span);
1517 continue;
1518 }
1519
1520 let (op, lbp, rbp) = match self.infix_op() {
1521 Some(x) => x,
1522 None => break,
1523 };
1524 if lbp < min_bp {
1525 break;
1526 }
1527 self.bump();
1528 let rhs = self.expr_bp(rbp)?;
1529 let span = lhs.span().to(rhs.span());
1530 lhs = Node::form(op, vec![lhs, rhs], span);
1531 }
1532 Some(lhs)
1533 }
1534
1535 fn infix_op(&self) -> Option<(&'static str, u8, u8)> {
1538 if self.at_kw("or") {
1539 return Some(("or", 1, 2));
1540 }
1541 if self.at_kw("and") {
1542 return Some(("and", 3, 4));
1543 }
1544 if self.at_kw("in") {
1545 return Some(("contains", 5, 6));
1546 }
1547 let r = self.cur().raw()?;
1548 Some(match r {
1549 Raw::Pipe => ("|", 1, 2),
1555 Raw::At => ("@", 3, 4),
1559 Raw::EqEq => ("==", 5, 6),
1560 Raw::NotEq => ("!=", 5, 6),
1561 Raw::Lt => ("<", 5, 6),
1562 Raw::LtEq => ("<=", 5, 6),
1563 Raw::Gt => (">", 5, 6),
1564 Raw::GtEq => (">=", 5, 6),
1565 Raw::Plus => ("+", 7, 8),
1566 Raw::Minus => ("-", 7, 8),
1567 Raw::Star => ("*", 9, 10),
1568 Raw::Slash => ("/", 9, 10),
1569 Raw::Percent => ("%", 9, 10),
1570 _ => return None,
1571 })
1572 }
1573
1574 fn unary(&mut self) -> Option<Node> {
1575 let start = self.span();
1576 if self.at_kw("not") {
1577 self.bump();
1578 let e = self.unary()?;
1579 let span = start.to(e.span());
1580 return Some(Node::form("not", vec![e], span));
1581 }
1582 if self.at(&Raw::Minus) {
1583 self.bump();
1584 let e = self.unary()?;
1585 let span = start.to(e.span());
1586 return Some(Node::form("negate", vec![e], span));
1587 }
1588 if self.at(&Raw::Dollar) {
1589 self.bump();
1590 let e = self.unary()?;
1591 let span = start.to(e.span());
1592 return Some(Node::form(sym::UNQUOTE, vec![e], span));
1593 }
1594 if self.at(&Raw::DollarStar) {
1595 self.bump();
1596 let e = self.unary()?;
1597 let span = start.to(e.span());
1598 return Some(Node::form(sym::SPLICE, vec![e], span));
1599 }
1600 self.postfix(false)
1601 }
1602
1603 fn postfix(&mut self, allow_block: bool) -> Option<Node> {
1619 if !self.enter() {
1620 return None;
1621 }
1622 let out = self.postfix_inner(allow_block);
1623 self.nesting.leave();
1624 out
1625 }
1626
1627 fn postfix_inner(&mut self, allow_block: bool) -> Option<Node> {
1628 let mut e = self.primary()?;
1629 loop {
1630 if self.at(&Raw::Dot) {
1631 self.bump();
1632 let (name, name_span) = self.ident("a field or method name")?;
1633 let span = e.span().to(name_span);
1634 if self.at(&Raw::LParen) {
1637 let (args, aspan) = self.call_args()?;
1638 let mut items = vec![e, Node::sym(name, name_span)];
1639 items.extend(args);
1640 e = Node::form(sym::DOT, items, span.to(aspan));
1641 } else {
1642 e = Node::form(sym::DOT, vec![e, Node::sym(name, name_span)], span);
1643 }
1644 continue;
1645 }
1646 if self.at(&Raw::LParen) {
1647 let (args, aspan) = self.call_args()?;
1648 let span = e.span().to(aspan);
1649 e = match e.head {
1650 Head::Sym(s) if e.args.is_empty() => Node::form_sym(s, args, span),
1652 _ => {
1653 let mut items = vec![e];
1654 items.extend(args);
1655 Node::form(sym::CALL, items, span)
1656 }
1657 };
1658 if allow_block && self.at(&Raw::Colon) {
1661 e = self.attach_block(e)?;
1662 break;
1663 }
1664 continue;
1665 }
1666 if self.at(&Raw::LBracket) {
1667 self.bump();
1668 let idx = self.expr()?;
1669 let end = self.span();
1670 self.expect(&Raw::RBracket, "`]`");
1671 let span = e.span().to(end);
1672 e = Node::form("index", vec![e, idx], span);
1673 continue;
1674 }
1675 if allow_block && self.at(&Raw::Colon) && e.as_var().is_some() {
1677 e = self.attach_block(e)?;
1678 break;
1679 }
1680 break;
1681 }
1682 Some(e)
1683 }
1684
1685 fn attach_block(&mut self, callee: Node) -> Option<Node> {
1687 let colon = self.span();
1688 self.bump(); let body = self.block()?;
1690 let bspan = body.span();
1691 let quoted = Node::form(sym::QUOTE, vec![body], bspan);
1692 let kw = Node::form(
1693 sym::KW_ARG,
1694 vec![Node::sym("do", colon), quoted],
1695 colon.to(bspan),
1696 );
1697 let span = callee.span().to(bspan);
1698 let mut n = callee;
1699 n.args.push(kw);
1700 n.applied = true;
1701 n.meta.span = span;
1702 self.attached_block = true;
1703 Some(n)
1704 }
1705
1706 fn call_args(&mut self) -> Option<(Vec<Node>, Span)> {
1707 let start = self.span();
1708 self.expect(&Raw::LParen, "`(`");
1709 let mut args = Vec::new();
1710 while !self.at(&Raw::RParen) && !self.at_eof() {
1711 let save = self.pos;
1713 if let Some(Raw::Ident(name)) = self.cur().raw().cloned() {
1714 let nspan = self.span();
1715 self.bump();
1716 if self.at(&Raw::Eq) {
1717 self.bump();
1718 let v = self.expr()?;
1719 let span = nspan.to(v.span());
1720 args.push(Node::form(
1721 sym::KW_ARG,
1722 vec![Node::sym(&name, nspan), v],
1723 span,
1724 ));
1725 if !self.eat(&Raw::Comma) {
1726 break;
1727 }
1728 continue;
1729 }
1730 self.pos = save;
1731 }
1732 args.push(self.expr()?);
1733 if !self.eat(&Raw::Comma) {
1734 break;
1735 }
1736 }
1737 let end = self.span();
1738 self.expect(&Raw::RParen, "`)`");
1739 Some((args, start.to(end)))
1740 }
1741
1742 fn primary(&mut self) -> Option<Node> {
1743 if !self.enter() {
1744 return None;
1745 }
1746 let out = self.primary_inner();
1747 self.nesting.leave();
1748 out
1749 }
1750
1751 fn primary_inner(&mut self) -> Option<Node> {
1752 let span = self.span();
1753 if self.at_kw("lambda") {
1754 self.bump();
1755 let mut params = Vec::new();
1756 while !self.at(&Raw::Colon) && !self.at_eof() {
1757 let (name, nspan) = self.ident("a parameter name")?;
1758 params.push(Node::sym(name, nspan));
1759 if !self.eat(&Raw::Comma) {
1760 break;
1761 }
1762 }
1763 self.expect(&Raw::Colon, "`:`");
1764 let body = self.expr()?;
1765 let bspan = body.span();
1766 return Some(Node::form(
1767 sym::FN,
1768 vec![
1769 Node::form(sym::PARAMS, params, span),
1770 Node::form(sym::DO, vec![body], bspan),
1771 ],
1772 span.to(bspan),
1773 ));
1774 }
1775 if self.at_kw("raise") {
1779 self.bump();
1780 let e = self.expr()?;
1781 let espan = e.span();
1782 return Some(Node::form(sym::RAISE, vec![e], span.to(espan)));
1783 }
1784 if self.at_kw("try") {
1785 self.bump();
1786 self.expect(&Raw::Colon, "`:` after `try`");
1787 let body = self.block()?;
1788 let bspan = body.span();
1789 return Some(Node::form(sym::TRY, vec![body], span.to(bspan)));
1790 }
1791 if self.at_kw("parallel") {
1792 self.bump();
1793 self.expect(&Raw::Colon, "`:` after `parallel`");
1794 let body = self.block()?;
1795 let bspan = body.span();
1796 return Some(Node::form(sym::PARALLEL, vec![body], span.to(bspan)));
1797 }
1798 if self.at_kw("quote") {
1799 self.bump();
1800 self.expect(&Raw::Colon, "`:` after `quote`");
1801 let body = self.block()?;
1802 let bspan = body.span();
1803 return Some(Node::form(sym::QUOTE, vec![body], span.to(bspan)));
1804 }
1805
1806 match self.cur().raw().cloned() {
1807 Some(Raw::Int(n)) => {
1808 self.bump();
1809 Some(Node::lit(Lit::Int(n), span))
1810 }
1811 Some(Raw::Float(n)) => {
1812 self.bump();
1813 Some(Node::lit(Lit::Float(n), span))
1814 }
1815 Some(Raw::Str(s)) => {
1816 self.bump();
1817 Some(Node::lit(Lit::Str(s.into()), span))
1818 }
1819 Some(Raw::Keyword(k)) => {
1820 self.bump();
1821 Some(Node::lit(Lit::Keyword(k.into()), span))
1822 }
1823 Some(Raw::Ident(name)) => {
1824 self.bump();
1825 match name.as_str() {
1826 "True" | "true" => Some(Node::lit(Lit::Bool(true), span)),
1827 "False" | "false" => Some(Node::lit(Lit::Bool(false), span)),
1828 _ => Some(Node::symbol(Symbol::new(&name), span)),
1829 }
1830 }
1831 Some(Raw::LParen) => {
1832 self.bump();
1833 if self.at(&Raw::RParen) {
1834 let end = self.span();
1835 self.bump();
1836 return Some(Node::sym("unit", span.to(end)));
1837 }
1838 let e = self.expr()?;
1839 self.expect(&Raw::RParen, "`)`");
1840 Some(e)
1841 }
1842 Some(Raw::LBracket) => {
1843 self.bump();
1844 let mut items = Vec::new();
1845 while !self.at(&Raw::RBracket) && !self.at_eof() {
1846 if self.at(&Raw::Star) {
1852 let star = self.span();
1853 self.bump();
1854 let e = self.postfix(false)?;
1855 let sp = star.to(e.span());
1856 items.push(Node::form(sym::REST, vec![e], sp));
1857 } else {
1858 items.push(self.expr()?);
1859 }
1860 if !self.eat(&Raw::Comma) {
1861 break;
1862 }
1863 }
1864 let end = self.span();
1865 self.expect(&Raw::RBracket, "`]`");
1866 Some(Node::form(sym::LIST, items, span.to(end)))
1867 }
1868 Some(Raw::LBrace) => {
1869 self.bump();
1870 let mut items = Vec::new();
1874 let mut is_record = true;
1875 while !self.at(&Raw::RBrace) && !self.at_eof() {
1876 let key_span = self.span();
1877 let key = match self.cur().raw().cloned() {
1878 Some(Raw::Ident(name))
1879 if self.toks.get(self.pos + 1).map(|t| t.raw())
1880 == Some(Some(&Raw::Colon)) =>
1881 {
1882 self.bump();
1883 Node::lit(Lit::Keyword(name.into()), key_span)
1884 }
1885 _ => {
1886 is_record = false;
1887 self.expr()?
1888 }
1889 };
1890 self.expect(&Raw::Colon, "`:`");
1891 let value = self.expr()?;
1892 items.push(key);
1893 items.push(value);
1894 if !self.eat(&Raw::Comma) {
1895 break;
1896 }
1897 }
1898 let end = self.span();
1899 self.expect(&Raw::RBrace, "`}`");
1900 let head = if is_record { sym::RECORD } else { sym::MAP };
1901 Some(Node::form(head, items, span.to(end)))
1902 }
1903 _ => {
1904 self.error(format!(
1905 "expected an expression, found {}",
1906 self.cur().describe()
1907 ));
1908 None
1909 }
1910 }
1911 }
1912
1913 fn type_expr(&mut self) -> Option<Node> {
1926 if !self.enter() {
1927 return None;
1928 }
1929 let out = self.type_expr_inner();
1930 self.nesting.leave();
1931 out
1932 }
1933
1934 fn type_expr_inner(&mut self) -> Option<Node> {
1935 let start = self.span();
1936 if self.at(&Raw::LParen) {
1937 self.bump();
1938 let mut params = Vec::new();
1939 while !self.at(&Raw::RParen) && !self.at_eof() {
1940 params.push(self.type_expr()?);
1941 if !self.eat(&Raw::Comma) {
1942 break;
1943 }
1944 }
1945 self.expect(&Raw::RParen, "`)`");
1946 if self.eat(&Raw::Arrow) {
1947 let ret = self.type_expr()?;
1948 let span = start.to(ret.span());
1949 let mut items = params;
1950 items.push(ret);
1951 return Some(Node::form("fn-type", items, span));
1952 }
1953 if params.len() == 1 {
1955 return params.pop();
1956 }
1957 let span = start.to(self.span());
1958 return Some(Node::form("tuple-type", params, span));
1959 }
1960
1961 let (name, name_span) = self.ident("a type")?;
1962 let mut node = Node::sym(&name, name_span);
1963 if self.at(&Raw::LBracket) {
1964 self.bump();
1965 let mut args = Vec::new();
1966 while !self.at(&Raw::RBracket) && !self.at_eof() {
1967 args.push(self.type_expr()?);
1968 if !self.eat(&Raw::Comma) {
1969 break;
1970 }
1971 }
1972 let end = self.span();
1973 self.expect(&Raw::RBracket, "`]`");
1974 node = Node::form(&name, args, name_span.to(end));
1975 }
1976 if self.eat(&Raw::Arrow) {
1978 let ret = self.type_expr()?;
1979 let span = node.span().to(ret.span());
1980 return Some(Node::form("fn-type", vec![node, ret], span));
1981 }
1982 Some(node)
1983 }
1984}
1985
1986fn token_text(t: &Token) -> String {
1989 match &t.tok {
1990 Tok::Raw(Raw::Ident(s)) => s.clone(),
1991 Tok::Raw(Raw::Str(s)) => s.clone(),
1992 Tok::Raw(Raw::Keyword(s)) => format!(":{s}"),
1993 Tok::Raw(Raw::Int(n)) => n.to_string(),
1994 Tok::Raw(Raw::Float(n)) => n.to_string(),
1995 Tok::Raw(Raw::Dot) => ".".into(),
1996 Tok::Raw(Raw::Slash) => "/".into(),
1997 Tok::Raw(Raw::Minus) => "-".into(),
1998 Tok::Raw(Raw::Star) => "*".into(),
1999 Tok::Raw(Raw::Comma) => ",".into(),
2000 Tok::Raw(Raw::Colon) => ":".into(),
2001 _ => String::new(),
2002 }
2003}
2004
2005#[cfg(test)]
2006mod tests {
2007 use super::*;
2008 use crate::print;
2009
2010 fn parse(src: &str) -> (Node, beck_diag::SourceMap) {
2011 let mut map = beck_diag::SourceMap::new();
2012 let f = map.add("t.beck", src);
2013 let mut d = Diagnostics::new();
2014 let n = parse_module(f, "t", src, &mut d);
2015 assert!(!d.has_errors(), "{}", d.render(&map));
2016 (n, map)
2017 }
2018
2019 fn sx(src: &str) -> String {
2020 let (n, _) = parse(src);
2021 print::to_sexpr(&n.args[1])
2023 }
2024
2025 #[test]
2026 fn a_def_carries_params_returns_and_effects() {
2027 assert_eq!(
2028 sx("def toggle(t: Todo) -> Todo uses durable:\n return t\n"),
2029 "(def toggle (typarams) (params (: t Todo)) (returns Todo) (uses durable) (do (return t)))"
2030 );
2031 }
2032
2033 #[test]
2034 fn the_doc_example_produces_the_documented_tree() {
2035 assert_eq!(
2037 sx("def toggle(todos: Map[Id, Todo], e: Toggled) -> Map[Id, Todo]:\n\
2038 \x20 return todos.update(e.id, lambda t: t.with(done=not t.done))\n"),
2039 "(def toggle (typarams) (params (: todos (Map Id Todo)) (: e Toggled)) (returns (Map Id Todo)) \
2040 (uses) (do (return (. todos update (. e id) (fn (params t) (do (. t with (kw done (not (. t done)))))))))) "
2041 .trim_end()
2042 );
2043 }
2044
2045 #[test]
2046 fn precedence_is_conventional() {
2047 let (n, _) = parse("x = 1 + 2 * 3 < 4 and not b\n");
2048 assert_eq!(
2049 print::to_sexpr(&n.args[1]),
2050 "(let x (and (< (+ 1 (* 2 3)) 4) (not b)))"
2051 );
2052 }
2053
2054 #[test]
2055 fn the_block_rule_passes_the_body_as_a_quoted_argument() {
2056 assert_eq!(
2057 sx("retry(times=3):\n charge(card)\n"),
2058 "(retry (kw times 3) (kw do (quote (do (charge card)))))"
2059 );
2060 assert_eq!(
2062 sx("main:\n h1: \"todos\"\n"),
2063 "(main (kw do (quote (do (h1 (kw do (quote (do \"todos\"))))))))"
2064 );
2065 }
2066
2067 #[test]
2068 fn decorators_receive_the_definitions_ast() {
2069 assert_eq!(
2070 sx("@on(server)\ndef f() -> Int:\n return 1\n"),
2071 "(decorate (on server) (def f (typarams) (params) (returns Int) (uses) (do (return 1))))"
2072 );
2073 }
2074
2075 #[test]
2076 fn models_unions_and_newtypes() {
2077 assert_eq!(
2078 sx("model Todo:\n id: Id\n done: Bool\n"),
2079 "(model Todo (typarams) (field id Id) (field done Bool))"
2080 );
2081 assert_eq!(
2082 sx("union Event:\n Added(id: Id, text: Str)\n Toggled(id: Id)\n"),
2083 "(union Event (typarams) (variant Added (field id Id) (field text Str)) \
2084 (variant Toggled (field id Id)))"
2085 );
2086 assert_eq!(
2087 sx("type Id = newtype[Uuid]\n"),
2088 "(newtype Id (typarams) Uuid)"
2089 );
2090 assert_eq!(
2091 sx("type Ids = list[Id]\n"),
2092 "(type Ids (typarams) (list Id))"
2093 );
2094 }
2095
2096 #[test]
2097 fn match_arms_are_ordinary_nodes() {
2098 assert_eq!(
2099 sx("match e:\n case Added(id, text):\n return 1\n case _:\n return 2\n"),
2100 "(match e (case (Added id text) (do (return 1))) (case _ (do (return 2))))"
2101 );
2102 }
2103
2104 #[test]
2105 fn conditional_expressions_and_collections() {
2106 assert_eq!(sx("x = 1 if c else 2\n"), "(let x (if c 1 2))");
2107 assert_eq!(sx("x = [1, 2]\n"), "(let x (list 1 2))");
2108 assert_eq!(sx("x = {id: 1}\n"), "(let x (record :id 1))");
2109 assert_eq!(sx("x = {k: 1}[k]\n"), "(let x (index (record :k 1) k))");
2110 }
2111
2112 #[test]
2113 fn quote_and_unquote() {
2114 assert_eq!(
2115 sx("macro unless(cond, do):\n return quote:\n if not $cond:\n $do\n"),
2116 "(macro unless (params cond do) (do (return (quote (do (if (not (unquote cond)) (do (unquote do))))))))"
2117 );
2118 }
2119
2120 #[test]
2121 fn errors_recover_so_later_items_still_parse() {
2122 let src = "def a(x: Int y: Int) -> Int:\n return 1\n\ndef b() -> Int:\n return 2\n";
2127 let mut map = beck_diag::SourceMap::new();
2128 let f = map.add("t.beck", src);
2129 let mut d = Diagnostics::new();
2130 let n = parse_module(f, "t", src, &mut d);
2131 assert!(d.has_errors());
2132 let names: Vec<String> = n
2133 .args
2134 .iter()
2135 .skip(1)
2136 .filter(|i| i.is_form(sym::DEF))
2137 .map(|i| i.args[0].as_var().unwrap().as_str().to_string())
2138 .collect();
2139 assert!(
2140 names.contains(&"b".to_string()),
2141 "the definition after the error must still be parsed, got {names:?}"
2142 );
2143 }
2144}
2145
2146#[cfg(test)]
2147mod test_clause_tests {
2148 use super::*;
2149
2150 fn sx(src: &str) -> String {
2151 let mut map = beck_diag::SourceMap::new();
2152 let f = map.add("t.beck", src);
2153 let mut d = Diagnostics::new();
2154 let n = parse_module(f, "t", src, &mut d);
2155 assert!(!d.has_errors(), "{}", d.render(&map));
2156 crate::print::to_sexpr(&n.args[1])
2157 }
2158
2159 #[test]
2160 fn the_four_clauses_read_as_forms() {
2161 assert_eq!(
2162 sx("test \"x\":\n given []\n"),
2163 "(test \"x\" (do (given (list))))"
2164 );
2165 assert_eq!(
2166 sx("test \"x\":\n given [a] by \"ana\"\n"),
2167 "(test \"x\" (do (given (list a) \"ana\")))"
2168 );
2169 assert_eq!(
2170 sx("test \"x\":\n when A(id=1), B(id=2)\n"),
2171 "(test \"x\" (do (when _ (A (kw id 1)) (B (kw id 2)))))"
2172 );
2173 assert_eq!(
2174 sx("test \"x\":\n when session(\"ana\") sends A(id=1)\n"),
2175 "(test \"x\" (do (when \"ana\" (A (kw id 1)))))"
2176 );
2177 assert_eq!(
2178 sx("test \"x\":\n stub net.out(payments.example.com): Declined\n"),
2179 "(test \"x\" (do (stub \"net.out(payments.example.com)\" Declined)))"
2180 );
2181 }
2182
2183 #[test]
2184 fn expect_has_six_shapes_and_they_are_decided_without_backtracking() {
2185 assert_eq!(
2186 sx("test \"x\":\n expect page contains \"milk\"\n"),
2187 "(test \"x\" (do (expect-contains \"milk\")))"
2188 );
2189 assert_eq!(
2190 sx("test \"x\":\n expect place(charge) == server\n"),
2191 "(test \"x\" (do (expect-place charge server)))"
2192 );
2193 assert_eq!(
2194 sx("test \"x\":\n expect flow(ApiKey) reaches nothing on client\n"),
2195 "(test \"x\" (do (expect-flow ApiKey client)))"
2196 );
2197 assert_eq!(
2198 sx("test \"x\":\n expect wire_compatible_with \"o.becki\"\n"),
2199 "(test \"x\" (do (expect-wire \"o.becki\")))"
2200 );
2201 assert_eq!(
2202 sx("test \"x\":\n expect no net.out\n"),
2203 "(test \"x\" (do (expect-effect \"net.out\" none)))"
2204 );
2205 assert_eq!(
2206 sx("test \"x\":\n expect net.out(h.example.com) once\n"),
2207 "(test \"x\" (do (expect-effect \"net.out(h.example.com)\" (times 1))))"
2208 );
2209 assert_eq!(
2211 sx("test \"x\":\n expect list_len(events) == 1\n"),
2212 "(test \"x\" (do (expect (== (list_len events) 1))))"
2213 );
2214 assert_eq!(
2216 sx("test \"x\":\n expect Err(error=BlankText)\n"),
2217 "(test \"x\" (do (expect (== result (Err (kw error BlankText))))))"
2218 );
2219 }
2220
2221 #[test]
2222 fn the_clause_keywords_are_not_reserved_outside_a_test() {
2223 assert_eq!(
2226 sx("def f() -> Int:\n return expect(1)\n"),
2227 "(def f (typarams) (params) (returns Int) (uses) (do (return (expect 1))))"
2228 );
2229 }
2230
2231 #[test]
2232 fn a_property_carries_its_generated_parameters() {
2233 assert_eq!(
2234 sx("property \"p\"(events: list[Event]):\n given events\n"),
2235 "(property \"p\" (params (: events (list Event))) (do (given events)))"
2236 );
2237 }
2238}
2239
2240#[cfg(test)]
2246mod nesting_tests {
2247 use super::*;
2248 use beck_diag::depth::{MAX_NESTING, STACK_BYTES};
2249
2250 fn nested_parens(n: usize) -> String {
2252 format!(
2253 "def f() -> Int:\n return {}1{}\n",
2254 "(".repeat(n),
2255 ")".repeat(n)
2256 )
2257 }
2258
2259 fn diagnose(src: &str) -> Vec<String> {
2262 beck_diag::depth::on_the_front_end_stack(|| {
2263 let mut map = beck_diag::SourceMap::new();
2264 let f = map.add("deep.beck", src);
2265 let mut d = Diagnostics::new();
2266 let _ = parse_module(f, "deep", src, &mut d);
2267 d.iter().map(|x| x.code.to_string()).collect()
2268 })
2269 }
2270
2271 #[test]
2272 fn one_level_past_the_ceiling_is_a_diagnostic_rather_than_an_abort() {
2273 let codes = diagnose(&nested_parens(MAX_NESTING as usize + 8));
2277 assert!(
2278 codes.contains(&"B0121".to_string()),
2279 "a program past the ceiling should be refused with B0121, got {codes:?}"
2280 );
2281 }
2282
2283 #[test]
2284 fn the_refusal_is_one_diagnostic_and_not_one_per_level() {
2285 let codes = diagnose(&nested_parens(MAX_NESTING as usize + 8));
2286 assert_eq!(
2287 codes.iter().filter(|c| *c == "B0121").count(),
2288 1,
2289 "got {codes:?}"
2290 );
2291 }
2292
2293 #[test]
2294 fn nesting_a_person_would_write_is_still_read() {
2295 let mut map = beck_diag::SourceMap::new();
2296 let src = nested_parens(64);
2297 let f = map.add("ok.beck", &src);
2298 let mut d = Diagnostics::new();
2299 let _ = parse_module(f, "ok", &src, &mut d);
2300 assert!(!d.has_errors(), "{}", d.render(&map));
2301 }
2302
2303 #[test]
2306 fn the_ceiling_fits_the_declared_stack() {
2307 const PROBE_DEPTH: usize = 200;
2308 let spent = std::thread::Builder::new()
2311 .stack_size(256 * 1024 * 1024)
2312 .spawn(|| {
2313 let src = nested_parens(PROBE_DEPTH);
2314 beck_diag::depth::probe::stack_spent(|| {
2315 let mut map = beck_diag::SourceMap::new();
2316 let f = map.add("probe.beck", &src);
2317 let mut d = Diagnostics::new();
2318 parse_module(f, "probe", &src, &mut d)
2319 })
2320 })
2321 .expect("a thread")
2322 .join()
2323 .expect("the probe parses");
2324
2325 let per_level = spent / PROBE_DEPTH;
2326 println!("parser: {spent} bytes for {PROBE_DEPTH} levels ({per_level} per level)");
2327 let needed = MAX_NESTING as usize * per_level * 2;
2330 assert!(
2331 needed < STACK_BYTES,
2332 "a ceiling of {MAX_NESTING} levels at {per_level} bytes each needs {needed} bytes \
2333 with the margin, against a declared STACK_BYTES of {STACK_BYTES} — raise the \
2334 declaration or lower the ceiling"
2335 );
2336 }
2337}