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 items_here: bool,
53}
54
55pub fn parse_module(file: FileId, name: &str, src: &str, diags: &mut Diagnostics) -> Node {
57 let toks = lex(file, src, diags);
58 let mut p = Parser {
59 toks,
60 pos: 0,
61 diags,
62 file,
63 poisoned: false,
64 attached_block: false,
65 nesting: Nesting::new(),
66 in_test: 0,
67 items_here: false,
68 };
69 let mut items = vec![Node::sym(name, Span::new(file, 0..0))];
70 while !p.at_eof() {
71 p.skip_newlines();
72 if p.at_eof() {
73 break;
74 }
75 p.items_here = true;
76 match p.item() {
77 Some(item) => items.push(item),
78 None => p.recover_to_next_item(),
79 }
80 }
81 Node::form(sym::MODULE, items, Span::new(file, 0..src.len()))
82}
83
84impl<'a> Parser<'a> {
85 fn cur(&self) -> &Token {
88 &self.toks[self.pos.min(self.toks.len() - 1)]
89 }
90
91 fn at_eof(&self) -> bool {
92 matches!(self.cur().tok, Tok::Eof)
93 }
94
95 fn span(&self) -> Span {
96 self.cur().span
97 }
98
99 fn bump(&mut self) -> Token {
100 let t = self.cur().clone();
101 if self.pos < self.toks.len() - 1 {
102 self.pos += 1;
103 }
104 t
105 }
106
107 fn at(&self, r: &Raw) -> bool {
108 self.cur().raw() == Some(r)
109 }
110
111 fn at_kw(&self, name: &str) -> bool {
112 self.cur().is_ident(name)
113 }
114
115 fn eat(&mut self, r: &Raw) -> bool {
116 if self.at(r) {
117 self.bump();
118 true
119 } else {
120 false
121 }
122 }
123
124 fn eat_kw(&mut self, name: &str) -> bool {
125 if self.at_kw(name) {
126 self.bump();
127 true
128 } else {
129 false
130 }
131 }
132
133 fn expect(&mut self, r: &Raw, what: &str) -> bool {
134 if self.eat(r) {
135 return true;
136 }
137 self.error(format!("expected {what}, found {}", self.cur().describe()));
138 false
139 }
140
141 fn error(&mut self, msg: impl Into<String>) {
142 if self.poisoned {
143 return;
144 }
145 self.poisoned = true;
146 let span = self.span();
147 self.diags.push(
148 Diagnostic::error("B0120", msg.into(), span).with_primary_label("unexpected here"),
149 );
150 }
151
152 fn skip_newlines(&mut self) {
153 while matches!(self.cur().tok, Tok::Newline) {
154 self.bump();
155 }
156 }
157
158 fn recover_to_next_item(&mut self) {
161 self.poisoned = false;
162 let mut depth = 0i32;
163 loop {
164 match &self.cur().tok {
165 Tok::Eof => return,
166 Tok::Indent => {
167 depth += 1;
168 self.bump();
169 }
170 Tok::Dedent => {
171 depth -= 1;
172 self.bump();
173 if depth <= 0 {
174 return;
175 }
176 }
177 Tok::Newline if depth <= 0 => {
178 self.bump();
179 return;
180 }
181 _ => {
182 self.bump();
183 }
184 }
185 }
186 }
187
188 fn ident(&mut self, what: &str) -> Option<(String, Span)> {
189 let span = self.span();
190 match self.cur().raw() {
191 Some(Raw::Ident(s)) => {
192 let s = s.clone();
193 self.bump();
194 Some((s, span))
195 }
196 _ => {
197 self.error(format!("expected {what}, found {}", self.cur().describe()));
198 None
199 }
200 }
201 }
202
203 fn item(&mut self) -> Option<Node> {
206 if self.at(&Raw::At) {
207 return self.decorated();
208 }
209 let start = self.span();
210 if self.at_kw("def") {
211 return self.def_item();
212 }
213 if self.at_kw("row") {
218 self.bump();
219 let (name, name_span) = self.ident("a row name")?;
220 self.expect(&Raw::Eq, "`=`");
221 let mut atoms = Vec::new();
222 loop {
223 atoms.push(self.expr()?);
224 if !self.eat(&Raw::Comma) {
225 break;
226 }
227 }
228 let span = start.to(atoms.last().map(|a| a.span()).unwrap_or(name_span));
229 self.end_of_line();
230 let mut items = vec![Node::sym(name, name_span)];
231 items.extend(atoms);
232 return Some(Node::form(sym::ROW, items, span));
233 }
234 if self.at_kw("identity") && matches!(self.peek_raw(1), Some(Raw::Eq)) {
241 self.bump();
242 self.expect(&Raw::Eq, "`=`");
243 let provider = self.expr()?;
244 let span = start.to(provider.span());
245 self.end_of_line();
246 return Some(Node::form(sym::IDENTITY, vec![provider], span));
247 }
248 if self.at_kw("typed") && matches!(self.peek_raw(1), Some(Raw::Ident(w)) if w == "macro") {
252 return self.macro_item(sym::TYPED_MACRO);
253 }
254 if self.at_kw("macro") {
255 return self.macro_item(sym::MACRO);
256 }
257 if self.at_kw("model") {
258 return self.model_item();
259 }
260 if self.at_kw("union") {
261 return self.union_item();
262 }
263 if self.at_kw("trait") {
264 return self.trait_item();
265 }
266 if self.at_kw("impl") {
267 return self.impl_item();
268 }
269 if self.at_kw("type") {
270 return self.type_item();
271 }
272 if self.at_kw("import") {
273 self.bump();
274 let (name, s) = self.ident("a module name")?;
275 let mut path = name;
276 let mut span = start.to(s);
277 while self.at(&Raw::Dot) {
278 self.bump();
279 let (seg, s2) = self.ident("a module name")?;
280 path.push('.');
281 path.push_str(&seg);
282 span = span.to(s2);
283 }
284 self.end_of_line();
285 return Some(Node::form(sym::IMPORT, vec![Node::sym(path, span)], span));
286 }
287 if self.at_kw("test") {
288 self.bump();
289 let (name, name_span) = self.quoted_name("a test name")?;
290 self.expect(&Raw::Colon, "`:`");
291 let body = self.test_body()?;
292 let span = start.to(body.span());
293 return Some(Node::form(
294 sym::TEST,
295 vec![Node::lit(Lit::Str(name.into()), name_span), body],
296 span,
297 ));
298 }
299 if self.at_kw("property") && matches!(self.peek_raw(1), Some(Raw::Str(_))) {
302 self.bump();
303 let (name, name_span) = self.quoted_name("a property name")?;
304 let params = self.params()?;
305 self.expect(&Raw::Colon, "`:`");
306 let body = self.test_body()?;
307 let span = start.to(body.span());
308 return Some(Node::form(
309 sym::PROPERTY,
310 vec![Node::lit(Lit::Str(name.into()), name_span), params, body],
311 span,
312 ));
313 }
314 self.statement()
316 }
317
318 fn decorated(&mut self) -> Option<Node> {
319 let start = self.span();
320 self.bump(); let deco = self.postfix(false)?;
322 self.end_of_line();
323 self.skip_newlines();
324 let inner = self.item()?;
325 let span = start.to(inner.span());
326 Some(Node::form(sym::DECORATE, vec![deco, inner], span))
327 }
328
329 fn def_item(&mut self) -> Option<Node> {
331 let start = self.span();
332 self.bump(); let (name, name_span) = self.ident("a function name")?;
334 let typarams = self.typarams(name_span);
338 let params = self.params()?;
339 let returns = if self.eat(&Raw::Arrow) {
340 let t = self.type_expr()?;
341 let s = t.span();
342 Node::form(sym::RETURNS, vec![t], s)
343 } else {
344 Node::form(sym::RETURNS, vec![], name_span)
345 };
346
347 let mut uses = Vec::new();
350 if self.eat_kw("uses") {
351 loop {
352 uses.push(self.expr()?);
353 if !self.eat(&Raw::Comma) {
354 break;
355 }
356 }
357 }
358 let uses_span = uses.first().map(|n| n.span()).unwrap_or(name_span);
359 let uses = Node::form("uses", uses, uses_span);
360
361 if !self.at(&Raw::Colon) {
366 let span = start.to(uses.span());
367 return Some(Node::form(
368 sym::DEF,
369 vec![Node::sym(name, name_span), typarams, params, returns, uses],
370 span,
371 ));
372 }
373 self.expect(&Raw::Colon, "`:` before the function body");
374 let body = self.block()?;
375 let span = start.to(body.span());
376 Some(Node::form(
377 sym::DEF,
378 vec![
379 Node::sym(name, name_span),
380 typarams,
381 params,
382 returns,
383 uses,
384 body,
385 ],
386 span,
387 ))
388 }
389
390 fn macro_item(&mut self, head: &str) -> Option<Node> {
392 let start = self.span();
393 if head == sym::TYPED_MACRO {
394 self.bump(); }
396 self.bump(); let (name, name_span) = self.ident("a macro name")?;
398 let params = self.params()?;
399 self.expect(&Raw::Colon, "`:` before the macro body");
400 let body = self.block()?;
401 let span = start.to(body.span());
402 Some(Node::form(
403 head,
404 vec![Node::sym(name, name_span), params, body],
405 span,
406 ))
407 }
408
409 fn typarams(&mut self, at: Span) -> Node {
418 let start = self.span();
419 if !self.at(&Raw::LBracket) {
420 return Node::form(sym::TYPARAMS, Vec::new(), at);
421 }
422 self.bump();
423 let mut out = Vec::new();
424 while !self.at(&Raw::RBracket) && !self.at_eof() {
425 let Some((name, span)) = self.ident("a type parameter") else {
426 break;
427 };
428 if self.eat(&Raw::Colon) {
429 let mut parts = vec![Node::sym(name, span)];
430 while let Some((t, tspan)) = self.ident("a trait name") {
431 parts.push(Node::sym(t, tspan));
432 if !self.eat(&Raw::Plus) {
433 break;
434 }
435 }
436 let end = self.span();
437 out.push(Node::form(sym::ANNOT, parts, span.to(end)));
438 } else {
439 out.push(Node::sym(name, span));
440 }
441 if !self.eat(&Raw::Comma) {
442 break;
443 }
444 }
445 let end = self.span();
446 self.expect(&Raw::RBracket, "`]`");
447 Node::form(sym::TYPARAMS, out, start.to(end))
448 }
449
450 fn params(&mut self) -> Option<Node> {
451 let start = self.span();
452 self.expect(&Raw::LParen, "`(`");
453 let mut out = Vec::new();
454 while !self.at(&Raw::RParen) && !self.at_eof() {
455 let (name, name_span) = self.ident("a parameter name")?;
456 let ty = if self.eat(&Raw::Colon) {
457 Some(self.type_expr()?)
458 } else {
459 None
460 };
461 let span = ty
462 .as_ref()
463 .map(|t| name_span.to(t.span()))
464 .unwrap_or(name_span);
465 out.push(match ty {
466 Some(t) => Node::form(sym::ANNOT, vec![Node::sym(name, name_span), t], span),
467 None => Node::sym(name, name_span),
468 });
469 if !self.eat(&Raw::Comma) {
470 break;
471 }
472 }
473 let end = self.span();
474 self.expect(&Raw::RParen, "`)`");
475 Some(Node::form(sym::PARAMS, out, start.to(end)))
476 }
477
478 fn model_item(&mut self) -> Option<Node> {
479 let start = self.span();
480 self.bump(); let (name, name_span) = self.ident("a model name")?;
482 let typarams = self.typarams(name_span);
483 self.expect(&Raw::Colon, "`:`");
484 let mut fields = vec![Node::sym(name, name_span), typarams];
485 for line in self.indented_lines()? {
486 let mut p = self.sub(line);
487 if let Some(f) = p.field_decl() {
488 fields.push(f);
489 }
490 }
491 Some(Node::form(sym::MODEL, fields, start))
492 }
493
494 fn union_item(&mut self) -> Option<Node> {
495 let start = self.span();
496 self.bump(); let (name, name_span) = self.ident("a union name")?;
498 let typarams = self.typarams(name_span);
499 self.expect(&Raw::Colon, "`:`");
500 let mut variants = vec![Node::sym(name, name_span), typarams];
501 for line in self.indented_lines()? {
502 let mut p = self.sub(line);
503 if let Some(v) = p.variant_decl() {
504 variants.push(v);
505 }
506 }
507 Some(Node::form(sym::UNION, variants, start))
508 }
509
510 fn trait_item(&mut self) -> Option<Node> {
511 let start = self.span();
512 self.bump(); let (name, name_span) = self.ident("a trait name")?;
514 self.expect(&Raw::Colon, "`:`");
515 let body = self.block()?;
516 let mut items = vec![Node::sym(name, name_span)];
517 items.extend(body.args);
518 Some(Node::form(sym::TRAIT, items, start))
519 }
520
521 fn impl_item(&mut self) -> Option<Node> {
526 let start = self.span();
527 self.bump(); let typarams = self.typarams(start);
529 let (trait_name, tspan) = self.ident("a trait name")?;
530 if !self.eat_kw("for") {
531 self.error("expected `for` in an impl declaration");
532 return None;
533 }
534 let ty = self.type_expr()?;
535 let mut items = vec![Node::sym(trait_name, tspan), typarams, ty];
536 if self.eat(&Raw::Colon) {
540 let body = self.block()?;
541 items.extend(body.args);
542 } else {
543 self.end_of_line();
544 }
545 Some(Node::form(sym::IMPL, items, start))
546 }
547
548 fn type_item(&mut self) -> Option<Node> {
549 let start = self.span();
550 self.bump(); let (name, name_span) = self.ident("a type name")?;
552 let typarams = self.typarams(name_span);
553 self.expect(&Raw::Eq, "`=`");
554 if self.at_kw("newtype") {
556 self.bump();
557 self.expect(&Raw::LBracket, "`[`");
558 let inner = self.type_expr()?;
559 self.expect(&Raw::RBracket, "`]`");
560 self.end_of_line();
561 return Some(Node::form(
562 sym::NEWTYPE,
563 vec![Node::sym(name, name_span), typarams, inner],
564 start,
565 ));
566 }
567 let ty = self.type_expr()?;
568 self.end_of_line();
569 Some(Node::form(
570 sym::TYPE,
571 vec![Node::sym(name, name_span), typarams, ty],
572 start,
573 ))
574 }
575
576 fn field_decl(&mut self) -> Option<Node> {
577 let (name, name_span) = self.ident("a field name")?;
578 self.expect(&Raw::Colon, "`:`");
579 let ty = self.type_expr()?;
580 let span = name_span.to(ty.span());
581 Some(Node::form(
582 sym::FIELD,
583 vec![Node::sym(name, name_span), ty],
584 span,
585 ))
586 }
587
588 fn variant_decl(&mut self) -> Option<Node> {
589 let (name, name_span) = self.ident("a variant name")?;
590 let mut items = vec![Node::sym(name, name_span)];
591 if self.eat(&Raw::LParen) {
592 while !self.at(&Raw::RParen) && !self.at_eof() {
593 items.push(self.field_decl()?);
594 if !self.eat(&Raw::Comma) {
595 break;
596 }
597 }
598 self.expect(&Raw::RParen, "`)`");
599 }
600 Some(Node::form(sym::VARIANT, items, name_span))
601 }
602
603 fn peek_raw(&self, n: usize) -> Option<&Raw> {
606 self.toks
607 .get((self.pos + n).min(self.toks.len() - 1))?
608 .raw()
609 }
610
611 fn quoted_name(&mut self, what: &str) -> Option<(String, Span)> {
612 let span = self.span();
613 match self.cur().raw() {
614 Some(Raw::Str(s)) => {
615 let s = s.clone();
616 self.bump();
617 Some((s, span))
618 }
619 _ => {
620 self.error(format!("expected {what} in quotes"));
621 None
622 }
623 }
624 }
625
626 fn test_body(&mut self) -> Option<Node> {
628 self.in_test += 1;
629 let out = self.block();
630 self.in_test -= 1;
631 out
632 }
633
634 fn given_clause(&mut self) -> Option<Node> {
642 let start = self.span();
643 self.bump(); let events = self.expr()?;
645 let mut args = vec![events];
646 if self.eat_kw("by") {
647 let (actor, span) = self.quoted_name("an actor name")?;
648 args.push(Node::lit(Lit::Str(actor.into()), span));
649 }
650 let span = start.to(args.last().map(|a| a.span()).unwrap_or(start));
651 self.end_of_line();
652 Some(Node::form(sym::GIVEN, args, span))
653 }
654
655 fn when_clause(&mut self) -> Option<Node> {
662 let start = self.span();
663 self.bump(); let session = if self.at_kw("session") && self.line_has_ident("sends") {
667 let (who, _) = self.session_actor()?;
668 if !self.eat_kw("sends") {
669 self.error("expected `sends` after the session");
670 return None;
671 }
672 who
673 } else {
674 Node::sym(sym::WILDCARD, start)
675 };
676 let mut args = vec![session];
677 loop {
678 args.push(self.expr()?);
679 if !self.eat(&Raw::Comma) {
680 break;
681 }
682 }
683 let span = start.to(args.last().map(|a| a.span()).unwrap_or(start));
684 self.end_of_line();
685 Some(Node::form(sym::WHEN, args, span))
686 }
687
688 fn stub_clause(&mut self) -> Option<Node> {
704 let start = self.span();
705 self.bump(); let (atom, atom_span) = self.effect_atom()?;
707 self.expect(&Raw::Colon, "`:`");
708
709 let value = if matches!(self.cur().tok, Tok::Newline) {
710 if self.block_starts_with("case") {
713 self.skip_newlines();
714 self.bump(); let arms = self.case_arms()?;
716 Node::form(sym::STUB_ARMS, arms, start.to(self.span()))
717 } else {
718 self.block()?
719 }
720 } else {
721 let e = self.expr()?;
722 self.end_of_line();
723 e
724 };
725
726 let span = start.to(value.span());
727 Some(Node::form(
728 sym::STUB,
729 vec![Node::lit(Lit::Str(atom.into()), atom_span), value],
730 span,
731 ))
732 }
733
734 fn expect_clause(&mut self) -> Option<Node> {
737 let start = self.span();
738 self.bump(); if self.at_kw("no") {
742 self.bump();
743 let (atom, _) = self.effect_atom()?;
744 let span = start.to(self.span());
745 self.end_of_line();
746 return Some(Node::form(
747 sym::EXPECT_EFFECT,
748 vec![
749 Node::lit(Lit::Str(atom.into()), span),
750 Node::sym("none", span),
751 ],
752 span,
753 ));
754 }
755
756 if self.at_kw("wire_compatible_with") {
759 self.bump();
760 let (path, pspan) = self.quoted_name("a `.becki` path")?;
761 let span = start.to(pspan);
762 self.end_of_line();
763 return Some(Node::form(
764 sym::EXPECT_WIRE,
765 vec![Node::lit(Lit::Str(path.into()), pspan)],
766 span,
767 ));
768 }
769
770 if self.at_kw("place") && matches!(self.peek_raw(1), Some(Raw::LParen)) {
772 self.bump();
773 self.expect(&Raw::LParen, "`(`");
774 let (name, nspan) = self.ident("a definition or signal name")?;
775 self.expect(&Raw::RParen, "`)`");
776 if !self.eat(&Raw::EqEq) {
777 self.error("expected `==` and a tier");
778 return None;
779 }
780 let (tier, tspan) = self.ident("a tier")?;
781 let span = start.to(tspan);
782 self.end_of_line();
783 return Some(Node::form(
784 sym::EXPECT_PLACE,
785 vec![Node::sym(name, nspan), Node::sym(tier, tspan)],
786 span,
787 ));
788 }
789
790 if self.at_kw("flow") && matches!(self.peek_raw(1), Some(Raw::LParen)) {
792 self.bump();
793 self.expect(&Raw::LParen, "`(`");
794 let (name, nspan) = self.ident("a type name")?;
795 self.expect(&Raw::RParen, "`)`");
796 if !(self.eat_kw("reaches") && self.eat_kw("nothing") && self.eat_kw("on")) {
797 self.error("expected `reaches nothing on <tier>`");
798 return None;
799 }
800 let (tier, tspan) = self.ident("a tier")?;
801 let span = start.to(tspan);
802 self.end_of_line();
803 return Some(Node::form(
804 sym::EXPECT_FLOW,
805 vec![Node::sym(name, nspan), Node::sym(tier, tspan)],
806 span,
807 ));
808 }
809
810 if self.at_effect_atom() {
812 let (atom, aspan) = self.effect_atom()?;
813 let how = if self.eat_kw("once") {
814 Node::form(
815 "times",
816 vec![Node::lit(Lit::Int(1), self.span())],
817 self.span(),
818 )
819 } else if self.eat_kw("times") {
820 let span = self.span();
821 match self.cur().raw() {
822 Some(Raw::Int(n)) => {
823 let n = *n;
824 self.bump();
825 Node::form("times", vec![Node::lit(Lit::Int(n), span)], span)
826 }
827 _ => {
828 self.error("expected a count after `times`");
829 return None;
830 }
831 }
832 } else if self.eat_kw("with") {
833 let e = self.expr()?;
834 let s = e.span();
835 Node::form("with", vec![e], s)
836 } else {
837 self.error("expected `once`, `times <n>` or `with <value>` after an effect atom");
838 return None;
839 };
840 let span = start.to(how.span());
841 self.end_of_line();
842 return Some(Node::form(
843 sym::EXPECT_EFFECT,
844 vec![Node::lit(Lit::Str(atom.into()), aspan), how],
845 span,
846 ));
847 }
848
849 if self.at_kw("page") {
853 self.bump();
854 let mut args = Vec::new();
855 if self.at(&Raw::LParen) {
856 self.bump();
857 if !self.at_kw("session") {
858 self.error("expected `session(\"actor\")`");
859 return None;
860 }
861 let (who, _) = self.session_actor()?;
862 self.expect(&Raw::RParen, "`)`");
863 args.push(who);
864 }
865 if self.eat_kw("matches") {
870 if !self.eat_kw("snapshot") {
871 self.error("expected `snapshot`");
872 return None;
873 }
874 let mut span = start.to(self.span());
875 let name = if matches!(self.peek_raw(0), Some(Raw::Str(_))) {
879 let (name, nspan) = self.quoted_name("a snapshot name")?;
880 span = start.to(nspan);
881 Node::lit(Lit::Str(name.into()), nspan)
882 } else {
883 Node::sym("none", span)
884 };
885 let actor = args.pop().unwrap_or_else(|| Node::sym("none", span));
886 self.end_of_line();
887 return Some(Node::form(sym::EXPECT_SNAPSHOT, vec![name, actor], span));
888 }
889 if !self.eat_kw("contains") {
890 self.error("expected `contains` or `matches snapshot`");
891 return None;
892 }
893 let needle = self.expr()?;
894 let span = start.to(needle.span());
895 self.end_of_line();
896 args.insert(0, needle);
897 return Some(Node::form(sym::EXPECT_CONTAINS, args, span));
898 }
899
900 if self.at_kw("state")
903 && matches!(self.peek_raw(1), Some(Raw::EqEq))
904 && matches!(self.peek_raw(2), Some(Raw::Ident(s)) if s == "fold_of")
905 {
906 self.bump(); self.bump(); self.bump(); let events = self.expr()?;
910 let mut args = vec![events];
911 if self.eat_kw("by") {
912 let (actor, span) = self.quoted_name("an actor name")?;
913 args.push(Node::lit(Lit::Str(actor.into()), span));
914 }
915 let span = start.to(args.last().map(|a| a.span()).unwrap_or(start));
916 self.end_of_line();
917 return Some(Node::form(sym::EXPECT_FOLD, args, span));
918 }
919
920 let e = self.expr()?;
923 let e = match e.head_name() {
924 Some("Ok" | "Err") if e.applied => {
925 let span = e.span();
926 Node::form("==", vec![Node::sym("result", span), e], span)
927 }
928 _ => e,
929 };
930 let span = start.to(e.span());
931 self.end_of_line();
932 Some(Node::form(sym::EXPECT, vec![e], span))
933 }
934
935 const EFFECT_HEADS: &'static [&'static str] = &[
938 "ingress", "durable", "dom", "nondet", "net", "fs", "env", "spawn", "cap", "partial",
939 "external", "log", "metrics",
940 ];
941
942 fn at_effect_atom(&self) -> bool {
943 match self.cur().raw() {
944 Some(Raw::Ident(s)) => Self::EFFECT_HEADS.contains(&s.as_str()),
945 _ => false,
946 }
947 }
948
949 fn effect_atom(&mut self) -> Option<(String, Span)> {
954 let start = self.span();
955 let (head, _) = self.ident("an effect atom")?;
956 let mut out = head;
957 while self.at(&Raw::Dot) {
958 self.bump();
959 let (seg, _) = self.ident("an effect atom")?;
960 out.push('.');
961 out.push_str(&seg);
962 }
963 let mut end = self.span();
964 if self.at(&Raw::LParen) {
965 self.bump();
966 out.push('(');
967 let mut depth = 1;
968 loop {
969 match self.cur().raw() {
970 Some(Raw::LParen) => depth += 1,
971 Some(Raw::RParen) => {
972 depth -= 1;
973 if depth == 0 {
974 end = self.span();
975 self.bump();
976 break;
977 }
978 }
979 None => {
980 self.error("unterminated effect atom");
981 return None;
982 }
983 _ => {}
984 }
985 out.push_str(&token_text(self.cur()));
986 self.bump();
987 }
988 out.push(')');
989 }
990 Some((out, start.to(end)))
991 }
992
993 fn block_starts_with(&self, kw: &str) -> bool {
998 let mut i = self.pos;
999 while matches!(self.toks.get(i).map(|t| &t.tok), Some(Tok::Newline)) {
1000 i += 1;
1001 }
1002 if !matches!(self.toks.get(i).map(|t| &t.tok), Some(Tok::Indent)) {
1003 return false;
1004 }
1005 matches!(self.toks.get(i + 1).and_then(|t| t.raw()), Some(Raw::Ident(s)) if s == kw)
1006 }
1007
1008 fn session_actor(&mut self) -> Option<(Node, Span)> {
1015 self.bump(); self.expect(&Raw::LParen, "`(`");
1017 let (actor, aspan) = self.quoted_name("an actor name")?;
1018 let node = if self.eat(&Raw::Comma) {
1019 let (route, rspan) = self.quoted_name("a route")?;
1020 Node::form(
1021 sym::AT,
1022 vec![
1023 Node::lit(Lit::Str(actor.into()), aspan),
1024 Node::lit(Lit::Str(route.into()), rspan),
1025 ],
1026 aspan.to(rspan),
1027 )
1028 } else {
1029 Node::lit(Lit::Str(actor.into()), aspan)
1030 };
1031 let span = aspan.to(node.span());
1032 self.expect(&Raw::RParen, "`)`");
1033 Some((node, span))
1034 }
1035
1036 fn line_has_ident(&self, name: &str) -> bool {
1038 let mut depth = 0i32;
1039 for t in &self.toks[self.pos..] {
1040 match &t.tok {
1041 Tok::Newline | Tok::Indent | Tok::Dedent | Tok::Eof if depth == 0 => return false,
1042 Tok::Raw(Raw::LParen | Raw::LBracket | Raw::LBrace) => depth += 1,
1043 Tok::Raw(Raw::RParen | Raw::RBracket | Raw::RBrace) => depth -= 1,
1044 Tok::Raw(Raw::Ident(s)) if depth == 0 && s == name => return true,
1045 _ => {}
1046 }
1047 }
1048 false
1049 }
1050
1051 fn enter(&mut self) -> bool {
1058 if self.nesting.enter() {
1059 return true;
1060 }
1061 if self.nesting.should_report() {
1062 let span = self.span();
1063 let note = self.nesting.note();
1064 self.diags.push(
1065 Diagnostic::error("B0121", "nesting is too deep to read", span)
1066 .with_primary_label("the parser gave up here")
1067 .with_note(note),
1068 );
1069 }
1070 self.poisoned = true;
1071 false
1072 }
1073
1074 fn block(&mut self) -> Option<Node> {
1077 self.block_of(false)
1078 }
1079
1080 fn block_of(&mut self, items: bool) -> Option<Node> {
1081 if !self.enter() {
1082 return None;
1083 }
1084 let was = std::mem::replace(&mut self.items_here, items);
1085 let out = self.block_inner();
1086 self.items_here = was;
1087 self.nesting.leave();
1088 out
1089 }
1090
1091 fn block_inner(&mut self) -> Option<Node> {
1092 let start = self.span();
1093 if !matches!(self.cur().tok, Tok::Newline) {
1095 let e = self.statement()?;
1096 let s = e.span();
1097 return Some(Node::form(sym::DO, vec![e], start.to(s)));
1098 }
1099 self.skip_newlines();
1100 if !matches!(self.cur().tok, Tok::Indent) {
1101 self.error("expected an indented block");
1102 return None;
1103 }
1104 self.bump(); let mut stmts = Vec::new();
1106 loop {
1107 self.skip_newlines();
1108 match self.cur().tok {
1109 Tok::Dedent => {
1110 self.bump();
1111 break;
1112 }
1113 Tok::Eof => break,
1114 _ => match self.line_of_this_block() {
1117 Some(s) => stmts.push(s),
1118 None => {
1119 self.recover_in_block();
1120 if matches!(self.cur().tok, Tok::Dedent) {
1121 self.bump();
1122 break;
1123 }
1124 if self.at_eof() {
1125 break;
1126 }
1127 }
1128 },
1129 }
1130 }
1131 let end = self.span();
1132 Some(Node::form(sym::DO, stmts, start.to(end)))
1133 }
1134
1135 fn line_of_this_block(&mut self) -> Option<Node> {
1137 match self.items_here && self.at_declaration() {
1138 true => self.item(),
1139 false => self.statement(),
1140 }
1141 }
1142
1143 fn at_declaration(&self) -> bool {
1149 if self.at(&Raw::At) {
1150 return true;
1151 }
1152 [
1153 "def", "macro", "model", "union", "trait", "impl", "type", "newtype",
1154 ]
1155 .iter()
1156 .any(|k| self.at_kw(k))
1157 }
1158
1159 fn recover_in_block(&mut self) {
1160 self.poisoned = false;
1161 let mut depth = 0i32;
1162 loop {
1163 match &self.cur().tok {
1164 Tok::Eof => return,
1165 Tok::Indent => {
1166 depth += 1;
1167 self.bump();
1168 }
1169 Tok::Dedent if depth > 0 => {
1170 depth -= 1;
1171 self.bump();
1172 }
1173 Tok::Dedent => return,
1174 Tok::Newline if depth == 0 => {
1175 self.bump();
1176 return;
1177 }
1178 _ => {
1179 self.bump();
1180 }
1181 }
1182 }
1183 }
1184
1185 fn indented_lines(&mut self) -> Option<Vec<Vec<Token>>> {
1188 self.skip_newlines();
1189 if !matches!(self.cur().tok, Tok::Indent) {
1190 self.error("expected an indented block");
1191 return None;
1192 }
1193 self.bump();
1194 let mut lines = Vec::new();
1195 let mut cur: Vec<Token> = Vec::new();
1196 let mut depth = 0i32;
1197 loop {
1198 match &self.cur().tok {
1199 Tok::Eof => break,
1200 Tok::Dedent if depth == 0 => {
1201 self.bump();
1202 break;
1203 }
1204 Tok::Dedent => {
1205 depth -= 1;
1206 cur.push(self.bump());
1207 }
1208 Tok::Indent => {
1209 depth += 1;
1210 cur.push(self.bump());
1211 }
1212 Tok::Newline if depth == 0 => {
1213 self.bump();
1214 if !cur.is_empty() {
1215 lines.push(std::mem::take(&mut cur));
1216 }
1217 }
1218 _ => cur.push(self.bump()),
1219 }
1220 }
1221 if !cur.is_empty() {
1222 lines.push(cur);
1223 }
1224 Some(lines)
1225 }
1226
1227 fn sub(&mut self, mut toks: Vec<Token>) -> Parser<'_> {
1229 let end = toks.last().map(|t| t.span).unwrap_or(Span::NONE);
1230 toks.push(Token {
1231 tok: Tok::Eof,
1232 span: end,
1233 });
1234 Parser {
1235 toks,
1236 pos: 0,
1237 diags: self.diags,
1238 file: self.file,
1239 poisoned: false,
1240 attached_block: false,
1241 nesting: self.nesting.resumed(),
1242 in_test: self.in_test,
1243 items_here: self.items_here,
1244 }
1245 }
1246
1247 fn line_has_assignment(&self) -> bool {
1252 let mut depth = 0i32;
1253 for t in &self.toks[self.pos..] {
1254 match &t.tok {
1255 Tok::Newline | Tok::Indent | Tok::Dedent | Tok::Eof if depth == 0 => return false,
1256 Tok::Raw(Raw::LParen | Raw::LBracket | Raw::LBrace) => depth += 1,
1257 Tok::Raw(Raw::RParen | Raw::RBracket | Raw::RBrace) => depth -= 1,
1258 Tok::Raw(Raw::Eq) if depth == 0 => return true,
1259 _ => {}
1260 }
1261 }
1262 false
1263 }
1264
1265 fn end_of_line(&mut self) {
1266 if matches!(self.cur().tok, Tok::Newline) {
1267 self.bump();
1268 }
1269 }
1270
1271 fn statement(&mut self) -> Option<Node> {
1272 let start = self.span();
1273
1274 if self.in_test > 0 {
1276 if self.at_kw("given") {
1277 return self.given_clause();
1278 }
1279 if self.at_kw("when") {
1280 return self.when_clause();
1281 }
1282 if self.at_kw("expect") {
1283 return self.expect_clause();
1284 }
1285 if self.at_kw("stub") {
1286 return self.stub_clause();
1287 }
1288 }
1289
1290 if self.at(&Raw::At) {
1291 return self.decorated();
1292 }
1293 if self.at_kw("def") {
1294 return self.def_item();
1295 }
1296 if self.at_kw("return") {
1297 self.bump();
1298 if matches!(self.cur().tok, Tok::Newline | Tok::Dedent | Tok::Eof) {
1299 self.end_of_line();
1300 return Some(Node::form(sym::RETURN, vec![], start));
1301 }
1302 let e = self.expr_stmt()?;
1303 let span = start.to(e.span());
1304 self.end_of_line();
1305 return Some(Node::form(sym::RETURN, vec![e], span));
1306 }
1307 if self.at_kw("if") {
1308 return self.if_stmt();
1309 }
1310 if self.at_kw("for") {
1311 self.bump();
1312 let (name, name_span) = self.ident("a loop variable")?;
1313 if !self.eat_kw("in") {
1314 self.error("expected `in`");
1315 return None;
1316 }
1317 let seq = self.expr()?;
1318 self.expect(&Raw::Colon, "`:`");
1319 let body = self.block()?;
1320 let span = start.to(body.span());
1321 return Some(Node::form(
1322 sym::FOR,
1323 vec![Node::sym(name, name_span), seq, body],
1324 span,
1325 ));
1326 }
1327 if self.at_kw("while") {
1328 self.bump();
1329 let c = self.expr()?;
1330 self.expect(&Raw::Colon, "`:`");
1331 let body = self.block()?;
1332 let span = start.to(body.span());
1333 return Some(Node::form(sym::WHILE, vec![c, body], span));
1334 }
1335 if self.at_kw("match") {
1336 return self.match_stmt();
1337 }
1338 if self.at_kw("var") {
1339 self.bump();
1340 let (name, name_span) = self.ident("a variable name")?;
1341 let ty = if self.eat(&Raw::Colon) {
1342 Some(self.type_expr()?)
1343 } else {
1344 None
1345 };
1346 self.expect(&Raw::Eq, "`=`");
1347 let e = self.expr_stmt()?;
1348 let span = start.to(e.span());
1349 self.end_of_line();
1350 let target = match ty {
1351 Some(t) => Node::form(sym::ANNOT, vec![Node::sym(name, name_span), t], name_span),
1352 None => Node::sym(name, name_span),
1353 };
1354 return Some(Node::form(sym::VAR, vec![target, e], span));
1355 }
1356 if self.at_kw("quote") {
1357 }
1359
1360 let save = self.pos;
1366 if self.line_has_assignment() {
1367 if let Some(Raw::Ident(name)) = self.cur().raw().cloned() {
1368 let name_span = self.span();
1369 self.bump();
1370 let ty = if self.at(&Raw::Colon) {
1371 self.bump();
1372 match self.type_expr() {
1373 Some(t) => Some(t),
1374 None => {
1375 self.pos = save;
1376 self.poisoned = false;
1377 None
1378 }
1379 }
1380 } else {
1381 None
1382 };
1383 if self.at(&Raw::Eq) {
1384 self.bump();
1385 let e = self.expr_stmt()?;
1386 let span = start.to(e.span());
1387 self.end_of_line();
1388 let target = match ty {
1389 Some(t) => {
1390 Node::form(sym::ANNOT, vec![Node::sym(&name, name_span), t], name_span)
1391 }
1392 None => Node::sym(&name, name_span),
1393 };
1394 return Some(Node::form(sym::LET, vec![target, e], span));
1395 }
1396 self.pos = save;
1397 self.poisoned = false;
1398 }
1399 }
1400
1401 let e = self.expr_stmt()?;
1402 self.end_of_line();
1403 Some(e)
1404 }
1405
1406 fn if_stmt(&mut self) -> Option<Node> {
1407 let start = self.span();
1408 self.bump(); let cond = self.expr()?;
1410 self.expect(&Raw::Colon, "`:`");
1411 let then = self.block()?;
1412 self.skip_newlines();
1413 let mut args = vec![cond, then];
1414 if self.at_kw("elif") {
1415 let e = self.if_stmt()?;
1416 let s = e.span();
1417 args.push(Node::form(sym::DO, vec![e], s));
1418 } else if self.at_kw("else") {
1419 self.bump();
1420 self.expect(&Raw::Colon, "`:`");
1421 args.push(self.block()?);
1422 }
1423 let span = start.to(args.last().map(|n| n.span()).unwrap_or(start));
1424 Some(Node::form(sym::IF, args, span))
1425 }
1426
1427 fn match_stmt(&mut self) -> Option<Node> {
1428 let start = self.span();
1429 self.bump(); let scrutinee = self.expr()?;
1431 self.expect(&Raw::Colon, "`:`");
1432 self.skip_newlines();
1433 if !matches!(self.cur().tok, Tok::Indent) {
1434 self.error("expected an indented block of `case` arms");
1435 return None;
1436 }
1437 self.bump();
1438 let mut arms = vec![scrutinee];
1439 arms.extend(self.case_arms()?);
1440 let span = start.to(self.span());
1441 Some(Node::form(sym::MATCH, arms, span))
1442 }
1443
1444 fn case_arms(&mut self) -> Option<Vec<Node>> {
1449 let mut arms = Vec::new();
1450 loop {
1451 self.skip_newlines();
1452 match self.cur().tok {
1453 Tok::Dedent => {
1454 self.bump();
1455 break;
1456 }
1457 Tok::Eof => break,
1458 _ => {}
1459 }
1460 let arm_start = self.span();
1461 if !self.eat_kw("case") {
1462 self.error("expected `case`");
1463 self.recover_in_block();
1464 continue;
1465 }
1466 let pat = self.expr_bp(1)?;
1474 let guard = if self.eat_kw("if") {
1475 Some(self.expr()?)
1476 } else {
1477 None
1478 };
1479 self.expect(&Raw::Colon, "`:`");
1480 let body = self.block()?;
1481 let span = arm_start.to(body.span());
1482 let mut args = vec![pat, body];
1483 args.extend(guard);
1484 arms.push(Node::form(sym::CASE, args, span));
1485 }
1486 Some(arms)
1487 }
1488
1489 pub fn expr(&mut self) -> Option<Node> {
1492 self.expr_bp(0)
1493 }
1494
1495 fn expr_stmt(&mut self) -> Option<Node> {
1503 if self.at_kw("not")
1504 || self.at(&Raw::Minus)
1505 || self.at(&Raw::Dollar)
1506 || self.at(&Raw::DollarStar)
1507 {
1508 return self.expr();
1509 }
1510 let first = self.postfix(true)?;
1511 if self.attached_block {
1512 self.attached_block = false;
1513 return Some(first);
1514 }
1515 self.expr_bp_from(first, 0)
1516 }
1517
1518 fn expr_bp(&mut self, min_bp: u8) -> Option<Node> {
1519 let lhs = self.unary()?;
1520 self.expr_bp_from(lhs, min_bp)
1521 }
1522
1523 fn expr_bp_from(&mut self, lhs: Node, min_bp: u8) -> Option<Node> {
1536 let mut lhs = lhs;
1537 let mut chain: u32 = 0;
1538
1539 loop {
1540 chain += 1;
1541 if chain > beck_diag::depth::MAX_BLOCK {
1542 if self.nesting.should_report() {
1543 let span = lhs.span();
1544 let note = self.nesting.note_about("operators in one chain").replace(
1545 &format!("{} operators", self.nesting.limit()),
1546 &format!("{} operators", beck_diag::depth::MAX_BLOCK),
1547 );
1548 self.diags.push(
1549 beck_diag::Diagnostic::error(
1550 "B0122",
1551 "this expression chains too many operators to read",
1552 span,
1553 )
1554 .with_primary_label("the reader gave up here")
1555 .with_note(note),
1556 );
1557 }
1558 return None;
1559 }
1560 if self.at_kw("if") && min_bp == 0 {
1563 self.bump();
1564 let cond = self.expr_bp(1)?;
1565 if !self.eat_kw("else") {
1566 self.error("expected `else` in a conditional expression");
1567 return None;
1568 }
1569 let alt = self.expr_bp(0)?;
1570 let span = lhs.span().to(alt.span());
1571 lhs = Node::form(sym::IF, vec![cond, lhs, alt], span);
1572 continue;
1573 }
1574
1575 let (op, lbp, rbp) = match self.infix_op() {
1576 Some(x) => x,
1577 None => break,
1578 };
1579 if lbp < min_bp {
1580 break;
1581 }
1582 self.bump();
1583 let rhs = self.expr_bp(rbp)?;
1584 let span = lhs.span().to(rhs.span());
1585 lhs = Node::form(op, vec![lhs, rhs], span);
1586 }
1587 Some(lhs)
1588 }
1589
1590 fn infix_op(&self) -> Option<(&'static str, u8, u8)> {
1593 if self.at_kw("or") {
1594 return Some(("or", 1, 2));
1595 }
1596 if self.at_kw("and") {
1597 return Some(("and", 3, 4));
1598 }
1599 if self.at_kw("in") {
1600 return Some(("contains", 5, 6));
1601 }
1602 let r = self.cur().raw()?;
1603 Some(match r {
1604 Raw::Pipe => ("|", 1, 2),
1610 Raw::At => ("@", 3, 4),
1614 Raw::EqEq => ("==", 5, 6),
1615 Raw::NotEq => ("!=", 5, 6),
1616 Raw::Lt => ("<", 5, 6),
1617 Raw::LtEq => ("<=", 5, 6),
1618 Raw::Gt => (">", 5, 6),
1619 Raw::GtEq => (">=", 5, 6),
1620 Raw::Plus => ("+", 7, 8),
1621 Raw::Minus => ("-", 7, 8),
1622 Raw::Star => ("*", 9, 10),
1623 Raw::Slash => ("/", 9, 10),
1624 Raw::Percent => ("%", 9, 10),
1625 _ => return None,
1626 })
1627 }
1628
1629 fn unary(&mut self) -> Option<Node> {
1630 let start = self.span();
1631 if self.at_kw("not") {
1632 self.bump();
1633 let e = self.unary()?;
1634 let span = start.to(e.span());
1635 return Some(Node::form("not", vec![e], span));
1636 }
1637 if self.at(&Raw::Minus) {
1638 self.bump();
1639 let e = self.unary()?;
1640 let span = start.to(e.span());
1641 return Some(Node::form("negate", vec![e], span));
1642 }
1643 if self.at(&Raw::Dollar) {
1644 self.bump();
1645 let e = self.unary()?;
1646 let span = start.to(e.span());
1647 return Some(Node::form(sym::UNQUOTE, vec![e], span));
1648 }
1649 if self.at(&Raw::DollarStar) {
1650 self.bump();
1651 let e = self.unary()?;
1652 let span = start.to(e.span());
1653 return Some(Node::form(sym::SPLICE, vec![e], span));
1654 }
1655 self.postfix(false)
1656 }
1657
1658 fn postfix(&mut self, allow_block: bool) -> Option<Node> {
1674 if !self.enter() {
1675 return None;
1676 }
1677 let out = self.postfix_inner(allow_block);
1678 self.nesting.leave();
1679 out
1680 }
1681
1682 fn postfix_inner(&mut self, allow_block: bool) -> Option<Node> {
1683 let mut e = self.primary()?;
1684 loop {
1685 if self.at(&Raw::Dot) {
1686 self.bump();
1687 if self.at(&Raw::Dollar) {
1692 let dollar = self.span();
1693 self.bump();
1694 let inner = self.primary()?;
1695 let name = Node::form(sym::UNQUOTE, vec![inner], dollar.to(self.span()));
1696 let span = e.span().to(name.span());
1697 e = match self.at(&Raw::LParen) {
1698 true => {
1699 let (args, aspan) = self.call_args()?;
1700 let mut items = vec![e, name];
1701 items.extend(args);
1702 Node::form(sym::DOT, items, span.to(aspan))
1703 }
1704 false => Node::form(sym::DOT, vec![e, name], span),
1705 };
1706 continue;
1707 }
1708 let (name, name_span) = self.ident("a field or method name")?;
1709 let span = e.span().to(name_span);
1710 if self.at(&Raw::LParen) {
1713 let (args, aspan) = self.call_args()?;
1714 let mut items = vec![e, Node::sym(name, name_span)];
1715 items.extend(args);
1716 e = Node::form(sym::DOT, items, span.to(aspan));
1717 } else {
1718 e = Node::form(sym::DOT, vec![e, Node::sym(name, name_span)], span);
1719 }
1720 continue;
1721 }
1722 if self.at(&Raw::LParen) {
1723 let (args, aspan) = self.call_args()?;
1724 let span = e.span().to(aspan);
1725 e = match e.head {
1726 Head::Sym(s) if e.args.is_empty() => Node::form_sym(s, args, span),
1728 _ => {
1729 let mut items = vec![e];
1730 items.extend(args);
1731 Node::form(sym::CALL, items, span)
1732 }
1733 };
1734 if allow_block && self.at(&Raw::Colon) {
1737 e = self.attach_block(e)?;
1738 break;
1739 }
1740 continue;
1741 }
1742 if self.at(&Raw::LBracket) {
1743 self.bump();
1744 let idx = self.expr()?;
1745 let end = self.span();
1746 self.expect(&Raw::RBracket, "`]`");
1747 let span = e.span().to(end);
1748 e = Node::form("index", vec![e, idx], span);
1749 continue;
1750 }
1751 if allow_block && self.at(&Raw::Colon) && e.as_var().is_some() {
1753 e = self.attach_block(e)?;
1754 break;
1755 }
1756 break;
1757 }
1758 Some(e)
1759 }
1760
1761 fn attach_block(&mut self, callee: Node) -> Option<Node> {
1763 let colon = self.span();
1764 self.bump(); let body = self.block_of(self.items_here)?;
1768 let bspan = body.span();
1769 let quoted = Node::form(sym::QUOTE, vec![body], bspan);
1770 let kw = Node::form(
1771 sym::KW_ARG,
1772 vec![Node::sym("do", colon), quoted],
1773 colon.to(bspan),
1774 );
1775 let span = callee.span().to(bspan);
1776 let mut n = callee;
1777 n.args.push(kw);
1778 n.applied = true;
1779 n.meta.span = span;
1780 self.attached_block = true;
1781 Some(n)
1782 }
1783
1784 fn call_args(&mut self) -> Option<(Vec<Node>, Span)> {
1785 let start = self.span();
1786 self.expect(&Raw::LParen, "`(`");
1787 let mut args = Vec::new();
1788 while !self.at(&Raw::RParen) && !self.at_eof() {
1789 let save = self.pos;
1791 if let Some(Raw::Ident(name)) = self.cur().raw().cloned() {
1792 let nspan = self.span();
1793 self.bump();
1794 if self.at(&Raw::Eq) {
1795 self.bump();
1796 let v = self.expr()?;
1797 let span = nspan.to(v.span());
1798 args.push(Node::form(
1799 sym::KW_ARG,
1800 vec![Node::sym(&name, nspan), v],
1801 span,
1802 ));
1803 if !self.eat(&Raw::Comma) {
1804 break;
1805 }
1806 continue;
1807 }
1808 self.pos = save;
1809 }
1810 args.push(self.expr()?);
1811 if !self.eat(&Raw::Comma) {
1812 break;
1813 }
1814 }
1815 let end = self.span();
1816 self.expect(&Raw::RParen, "`)`");
1817 Some((args, start.to(end)))
1818 }
1819
1820 fn primary(&mut self) -> Option<Node> {
1821 if !self.enter() {
1822 return None;
1823 }
1824 let out = self.primary_inner();
1825 self.nesting.leave();
1826 out
1827 }
1828
1829 fn primary_inner(&mut self) -> Option<Node> {
1830 let span = self.span();
1831 if self.at_kw("lambda") {
1832 self.bump();
1833 let mut params = Vec::new();
1834 while !self.at(&Raw::Colon) && !self.at_eof() {
1835 let (name, nspan) = self.ident("a parameter name")?;
1836 params.push(Node::sym(name, nspan));
1837 if !self.eat(&Raw::Comma) {
1838 break;
1839 }
1840 }
1841 self.expect(&Raw::Colon, "`:`");
1842 let body = self.expr()?;
1843 let bspan = body.span();
1844 return Some(Node::form(
1845 sym::FN,
1846 vec![
1847 Node::form(sym::PARAMS, params, span),
1848 Node::form(sym::DO, vec![body], bspan),
1849 ],
1850 span.to(bspan),
1851 ));
1852 }
1853 if self.at_kw("raise") {
1857 self.bump();
1858 let e = self.expr()?;
1859 let espan = e.span();
1860 return Some(Node::form(sym::RAISE, vec![e], span.to(espan)));
1861 }
1862 if self.at_kw("try") {
1863 self.bump();
1864 self.expect(&Raw::Colon, "`:` after `try`");
1865 let body = self.block()?;
1866 let bspan = body.span();
1867 return Some(Node::form(sym::TRY, vec![body], span.to(bspan)));
1868 }
1869 if self.at_kw("parallel") {
1870 self.bump();
1871 self.expect(&Raw::Colon, "`:` after `parallel`");
1872 let body = self.block()?;
1873 let bspan = body.span();
1874 return Some(Node::form(sym::PARALLEL, vec![body], span.to(bspan)));
1875 }
1876 if self.at_kw("quote") {
1877 self.bump();
1878 self.expect(&Raw::Colon, "`:` after `quote`");
1879 let body = self.block_of(true)?;
1884 let bspan = body.span();
1885 return Some(Node::form(sym::QUOTE, vec![body], span.to(bspan)));
1886 }
1887
1888 match self.cur().raw().cloned() {
1889 Some(Raw::Int(n)) => {
1890 self.bump();
1891 Some(Node::lit(Lit::Int(n), span))
1892 }
1893 Some(Raw::Float(n)) => {
1894 self.bump();
1895 Some(Node::lit(Lit::Float(n), span))
1896 }
1897 Some(Raw::Str(s)) => {
1898 self.bump();
1899 Some(Node::lit(Lit::Str(s.into()), span))
1900 }
1901 Some(Raw::Sigil(t)) => {
1907 self.bump();
1908 let open = span.start + t.name.len() as u32 + 1;
1909 let body = Span {
1910 file: span.file,
1911 start: open,
1912 end: open + t.raw.len() as u32,
1913 };
1914 let kw = Node::form(
1915 sym::KW_ARG,
1916 vec![
1917 Node::sym("raw", body),
1918 Node::lit(Lit::Str(t.raw.as_str().into()), body),
1919 ],
1920 body,
1921 );
1922 let mut n = Node::symbol(Symbol::new(format!("{}_sigil", t.name)), span);
1923 n.args.push(kw);
1924 n.applied = true;
1925 Some(n)
1926 }
1927 Some(Raw::Keyword(k)) => {
1928 self.bump();
1929 Some(Node::lit(Lit::Keyword(k.into()), span))
1930 }
1931 Some(Raw::Ident(name)) => {
1932 self.bump();
1933 match name.as_str() {
1934 "True" | "true" => Some(Node::lit(Lit::Bool(true), span)),
1935 "False" | "false" => Some(Node::lit(Lit::Bool(false), span)),
1936 _ => Some(Node::symbol(Symbol::new(&name), span)),
1937 }
1938 }
1939 Some(Raw::LParen) => {
1940 self.bump();
1941 if self.at(&Raw::RParen) {
1942 let end = self.span();
1943 self.bump();
1944 return Some(Node::sym("unit", span.to(end)));
1945 }
1946 let e = self.expr()?;
1947 self.expect(&Raw::RParen, "`)`");
1948 Some(e)
1949 }
1950 Some(Raw::LBracket) => {
1951 self.bump();
1952 let mut items = Vec::new();
1953 while !self.at(&Raw::RBracket) && !self.at_eof() {
1954 if self.at(&Raw::Star) {
1960 let star = self.span();
1961 self.bump();
1962 let e = self.postfix(false)?;
1963 let sp = star.to(e.span());
1964 items.push(Node::form(sym::REST, vec![e], sp));
1965 } else {
1966 items.push(self.expr()?);
1967 }
1968 if !self.eat(&Raw::Comma) {
1969 break;
1970 }
1971 }
1972 let end = self.span();
1973 self.expect(&Raw::RBracket, "`]`");
1974 Some(Node::form(sym::LIST, items, span.to(end)))
1975 }
1976 Some(Raw::LBrace) => {
1977 self.bump();
1978 let mut items = Vec::new();
1982 let mut is_record = true;
1983 while !self.at(&Raw::RBrace) && !self.at_eof() {
1984 let key_span = self.span();
1985 let key = match self.cur().raw().cloned() {
1986 Some(Raw::Ident(name))
1987 if self.toks.get(self.pos + 1).map(|t| t.raw())
1988 == Some(Some(&Raw::Colon)) =>
1989 {
1990 self.bump();
1991 Node::lit(Lit::Keyword(name.into()), key_span)
1992 }
1993 _ => {
1994 is_record = false;
1995 self.expr()?
1996 }
1997 };
1998 self.expect(&Raw::Colon, "`:`");
1999 let value = self.expr()?;
2000 items.push(key);
2001 items.push(value);
2002 if !self.eat(&Raw::Comma) {
2003 break;
2004 }
2005 }
2006 let end = self.span();
2007 self.expect(&Raw::RBrace, "`}`");
2008 let head = if is_record { sym::RECORD } else { sym::MAP };
2009 Some(Node::form(head, items, span.to(end)))
2010 }
2011 _ => {
2012 self.error(format!(
2013 "expected an expression, found {}",
2014 self.cur().describe()
2015 ));
2016 None
2017 }
2018 }
2019 }
2020
2021 fn type_expr(&mut self) -> Option<Node> {
2034 if !self.enter() {
2035 return None;
2036 }
2037 let out = self.type_expr_inner();
2038 self.nesting.leave();
2039 out
2040 }
2041
2042 fn type_expr_inner(&mut self) -> Option<Node> {
2043 let start = self.span();
2044 if self.at(&Raw::Dollar) {
2049 self.bump();
2050 let inner = self.type_expr()?;
2051 let span = start.to(inner.span());
2052 return Some(Node::form(sym::UNQUOTE, vec![inner], span));
2053 }
2054 if self.at(&Raw::LParen) {
2055 self.bump();
2056 let mut params = Vec::new();
2057 while !self.at(&Raw::RParen) && !self.at_eof() {
2058 params.push(self.type_expr()?);
2059 if !self.eat(&Raw::Comma) {
2060 break;
2061 }
2062 }
2063 self.expect(&Raw::RParen, "`)`");
2064 if self.eat(&Raw::Arrow) {
2065 let ret = self.type_expr()?;
2066 let span = start.to(ret.span());
2067 let mut items = params;
2068 items.push(ret);
2069 return Some(Node::form("fn-type", items, span));
2070 }
2071 if params.len() == 1 {
2073 return params.pop();
2074 }
2075 let span = start.to(self.span());
2076 return Some(Node::form("tuple-type", params, span));
2077 }
2078
2079 let (name, name_span) = self.ident("a type")?;
2080 let mut node = Node::sym(&name, name_span);
2081 if self.at(&Raw::LBracket) {
2082 self.bump();
2083 let mut args = Vec::new();
2084 while !self.at(&Raw::RBracket) && !self.at_eof() {
2085 args.push(self.type_expr()?);
2086 if !self.eat(&Raw::Comma) {
2087 break;
2088 }
2089 }
2090 let end = self.span();
2091 self.expect(&Raw::RBracket, "`]`");
2092 node = Node::form(&name, args, name_span.to(end));
2093 }
2094 if self.eat(&Raw::Arrow) {
2096 let ret = self.type_expr()?;
2097 let span = node.span().to(ret.span());
2098 return Some(Node::form("fn-type", vec![node, ret], span));
2099 }
2100 Some(node)
2101 }
2102}
2103
2104fn token_text(t: &Token) -> String {
2107 match &t.tok {
2108 Tok::Raw(Raw::Ident(s)) => s.clone(),
2109 Tok::Raw(Raw::Str(s)) => s.clone(),
2110 Tok::Raw(Raw::Keyword(s)) => format!(":{s}"),
2111 Tok::Raw(Raw::Int(n)) => n.to_string(),
2112 Tok::Raw(Raw::Float(n)) => n.to_string(),
2113 Tok::Raw(Raw::Dot) => ".".into(),
2114 Tok::Raw(Raw::Slash) => "/".into(),
2115 Tok::Raw(Raw::Minus) => "-".into(),
2116 Tok::Raw(Raw::Star) => "*".into(),
2117 Tok::Raw(Raw::Comma) => ",".into(),
2118 Tok::Raw(Raw::Colon) => ":".into(),
2119 _ => String::new(),
2120 }
2121}
2122
2123#[cfg(test)]
2124mod tests {
2125 use super::*;
2126 use crate::print;
2127
2128 fn parse(src: &str) -> (Node, beck_diag::SourceMap) {
2129 let mut map = beck_diag::SourceMap::new();
2130 let f = map.add("t.beck", src);
2131 let mut d = Diagnostics::new();
2132 let n = parse_module(f, "t", src, &mut d);
2133 assert!(!d.has_errors(), "{}", d.render(&map));
2134 (n, map)
2135 }
2136
2137 fn sx(src: &str) -> String {
2138 let (n, _) = parse(src);
2139 print::to_sexpr(&n.args[1])
2141 }
2142
2143 #[test]
2144 fn a_def_carries_params_returns_and_effects() {
2145 assert_eq!(
2146 sx("def toggle(t: Todo) -> Todo uses durable:\n return t\n"),
2147 "(def toggle (typarams) (params (: t Todo)) (returns Todo) (uses durable) (do (return t)))"
2148 );
2149 }
2150
2151 #[test]
2152 fn the_doc_example_produces_the_documented_tree() {
2153 assert_eq!(
2155 sx("def toggle(todos: Map[Id, Todo], e: Toggled) -> Map[Id, Todo]:\n\
2156 \x20 return todos.update(e.id, lambda t: t.with(done=not t.done))\n"),
2157 "(def toggle (typarams) (params (: todos (Map Id Todo)) (: e Toggled)) (returns (Map Id Todo)) \
2158 (uses) (do (return (. todos update (. e id) (fn (params t) (do (. t with (kw done (not (. t done)))))))))) "
2159 .trim_end()
2160 );
2161 }
2162
2163 #[test]
2164 fn precedence_is_conventional() {
2165 let (n, _) = parse("x = 1 + 2 * 3 < 4 and not b\n");
2166 assert_eq!(
2167 print::to_sexpr(&n.args[1]),
2168 "(let x (and (< (+ 1 (* 2 3)) 4) (not b)))"
2169 );
2170 }
2171
2172 #[test]
2173 fn the_block_rule_passes_the_body_as_a_quoted_argument() {
2174 assert_eq!(
2175 sx("retry(times=3):\n charge(card)\n"),
2176 "(retry (kw times 3) (kw do (quote (do (charge card)))))"
2177 );
2178 assert_eq!(
2180 sx("main:\n h1: \"todos\"\n"),
2181 "(main (kw do (quote (do (h1 (kw do (quote (do \"todos\"))))))))"
2182 );
2183 }
2184
2185 #[test]
2186 fn decorators_receive_the_definitions_ast() {
2187 assert_eq!(
2188 sx("@on(server)\ndef f() -> Int:\n return 1\n"),
2189 "(decorate (on server) (def f (typarams) (params) (returns Int) (uses) (do (return 1))))"
2190 );
2191 }
2192
2193 #[test]
2194 fn models_unions_and_newtypes() {
2195 assert_eq!(
2196 sx("model Todo:\n id: Id\n done: Bool\n"),
2197 "(model Todo (typarams) (field id Id) (field done Bool))"
2198 );
2199 assert_eq!(
2200 sx("union Event:\n Added(id: Id, text: Str)\n Toggled(id: Id)\n"),
2201 "(union Event (typarams) (variant Added (field id Id) (field text Str)) \
2202 (variant Toggled (field id Id)))"
2203 );
2204 assert_eq!(
2205 sx("type Id = newtype[Uuid]\n"),
2206 "(newtype Id (typarams) Uuid)"
2207 );
2208 assert_eq!(
2209 sx("type Ids = list[Id]\n"),
2210 "(type Ids (typarams) (list Id))"
2211 );
2212 }
2213
2214 #[test]
2215 fn match_arms_are_ordinary_nodes() {
2216 assert_eq!(
2217 sx("match e:\n case Added(id, text):\n return 1\n case _:\n return 2\n"),
2218 "(match e (case (Added id text) (do (return 1))) (case _ (do (return 2))))"
2219 );
2220 }
2221
2222 #[test]
2223 fn conditional_expressions_and_collections() {
2224 assert_eq!(sx("x = 1 if c else 2\n"), "(let x (if c 1 2))");
2225 assert_eq!(sx("x = [1, 2]\n"), "(let x (list 1 2))");
2226 assert_eq!(sx("x = {id: 1}\n"), "(let x (record :id 1))");
2227 assert_eq!(sx("x = {k: 1}[k]\n"), "(let x (index (record :k 1) k))");
2228 }
2229
2230 #[test]
2231 fn quote_and_unquote() {
2232 assert_eq!(
2233 sx("macro unless(cond, do):\n return quote:\n if not $cond:\n $do\n"),
2234 "(macro unless (params cond do) (do (return (quote (do (if (not (unquote cond)) (do (unquote do))))))))"
2235 );
2236 }
2237
2238 #[test]
2239 fn errors_recover_so_later_items_still_parse() {
2240 let src = "def a(x: Int y: Int) -> Int:\n return 1\n\ndef b() -> Int:\n return 2\n";
2245 let mut map = beck_diag::SourceMap::new();
2246 let f = map.add("t.beck", src);
2247 let mut d = Diagnostics::new();
2248 let n = parse_module(f, "t", src, &mut d);
2249 assert!(d.has_errors());
2250 let names: Vec<String> = n
2251 .args
2252 .iter()
2253 .skip(1)
2254 .filter(|i| i.is_form(sym::DEF))
2255 .map(|i| i.args[0].as_var().unwrap().as_str().to_string())
2256 .collect();
2257 assert!(
2258 names.contains(&"b".to_string()),
2259 "the definition after the error must still be parsed, got {names:?}"
2260 );
2261 }
2262}
2263
2264#[cfg(test)]
2265mod test_clause_tests {
2266 use super::*;
2267
2268 fn sx(src: &str) -> String {
2269 let mut map = beck_diag::SourceMap::new();
2270 let f = map.add("t.beck", src);
2271 let mut d = Diagnostics::new();
2272 let n = parse_module(f, "t", src, &mut d);
2273 assert!(!d.has_errors(), "{}", d.render(&map));
2274 crate::print::to_sexpr(&n.args[1])
2275 }
2276
2277 #[test]
2278 fn the_four_clauses_read_as_forms() {
2279 assert_eq!(
2280 sx("test \"x\":\n given []\n"),
2281 "(test \"x\" (do (given (list))))"
2282 );
2283 assert_eq!(
2284 sx("test \"x\":\n given [a] by \"ana\"\n"),
2285 "(test \"x\" (do (given (list a) \"ana\")))"
2286 );
2287 assert_eq!(
2288 sx("test \"x\":\n when A(id=1), B(id=2)\n"),
2289 "(test \"x\" (do (when _ (A (kw id 1)) (B (kw id 2)))))"
2290 );
2291 assert_eq!(
2292 sx("test \"x\":\n when session(\"ana\") sends A(id=1)\n"),
2293 "(test \"x\" (do (when \"ana\" (A (kw id 1)))))"
2294 );
2295 assert_eq!(
2296 sx("test \"x\":\n stub net.out(payments.example.com): Declined\n"),
2297 "(test \"x\" (do (stub \"net.out(payments.example.com)\" Declined)))"
2298 );
2299 }
2300
2301 #[test]
2302 fn expect_has_six_shapes_and_they_are_decided_without_backtracking() {
2303 assert_eq!(
2304 sx("test \"x\":\n expect page contains \"milk\"\n"),
2305 "(test \"x\" (do (expect-contains \"milk\")))"
2306 );
2307 assert_eq!(
2308 sx("test \"x\":\n expect place(charge) == server\n"),
2309 "(test \"x\" (do (expect-place charge server)))"
2310 );
2311 assert_eq!(
2312 sx("test \"x\":\n expect flow(ApiKey) reaches nothing on client\n"),
2313 "(test \"x\" (do (expect-flow ApiKey client)))"
2314 );
2315 assert_eq!(
2316 sx("test \"x\":\n expect wire_compatible_with \"o.becki\"\n"),
2317 "(test \"x\" (do (expect-wire \"o.becki\")))"
2318 );
2319 assert_eq!(
2320 sx("test \"x\":\n expect no net.out\n"),
2321 "(test \"x\" (do (expect-effect \"net.out\" none)))"
2322 );
2323 assert_eq!(
2324 sx("test \"x\":\n expect net.out(h.example.com) once\n"),
2325 "(test \"x\" (do (expect-effect \"net.out(h.example.com)\" (times 1))))"
2326 );
2327 assert_eq!(
2329 sx("test \"x\":\n expect list_len(events) == 1\n"),
2330 "(test \"x\" (do (expect (== (list_len events) 1))))"
2331 );
2332 assert_eq!(
2334 sx("test \"x\":\n expect Err(error=BlankText)\n"),
2335 "(test \"x\" (do (expect (== result (Err (kw error BlankText))))))"
2336 );
2337 }
2338
2339 #[test]
2340 fn the_clause_keywords_are_not_reserved_outside_a_test() {
2341 assert_eq!(
2344 sx("def f() -> Int:\n return expect(1)\n"),
2345 "(def f (typarams) (params) (returns Int) (uses) (do (return (expect 1))))"
2346 );
2347 }
2348
2349 #[test]
2350 fn a_property_carries_its_generated_parameters() {
2351 assert_eq!(
2352 sx("property \"p\"(events: list[Event]):\n given events\n"),
2353 "(property \"p\" (params (: events (list Event))) (do (given events)))"
2354 );
2355 }
2356}
2357
2358#[cfg(test)]
2364mod nesting_tests {
2365 use super::*;
2366 use beck_diag::depth::{MAX_NESTING, STACK_BYTES};
2367
2368 fn nested_parens(n: usize) -> String {
2370 format!(
2371 "def f() -> Int:\n return {}1{}\n",
2372 "(".repeat(n),
2373 ")".repeat(n)
2374 )
2375 }
2376
2377 fn diagnose(src: &str) -> Vec<String> {
2380 beck_diag::depth::on_the_front_end_stack(|| {
2381 let mut map = beck_diag::SourceMap::new();
2382 let f = map.add("deep.beck", src);
2383 let mut d = Diagnostics::new();
2384 let _ = parse_module(f, "deep", src, &mut d);
2385 d.iter().map(|x| x.code.to_string()).collect()
2386 })
2387 }
2388
2389 #[test]
2390 fn one_level_past_the_ceiling_is_a_diagnostic_rather_than_an_abort() {
2391 let codes = diagnose(&nested_parens(MAX_NESTING as usize + 8));
2395 assert!(
2396 codes.contains(&"B0121".to_string()),
2397 "a program past the ceiling should be refused with B0121, got {codes:?}"
2398 );
2399 }
2400
2401 #[test]
2402 fn the_refusal_is_one_diagnostic_and_not_one_per_level() {
2403 let codes = diagnose(&nested_parens(MAX_NESTING as usize + 8));
2404 assert_eq!(
2405 codes.iter().filter(|c| *c == "B0121").count(),
2406 1,
2407 "got {codes:?}"
2408 );
2409 }
2410
2411 #[test]
2412 fn nesting_a_person_would_write_is_still_read() {
2413 let mut map = beck_diag::SourceMap::new();
2414 let src = nested_parens(64);
2415 let f = map.add("ok.beck", &src);
2416 let mut d = Diagnostics::new();
2417 let _ = parse_module(f, "ok", &src, &mut d);
2418 assert!(!d.has_errors(), "{}", d.render(&map));
2419 }
2420
2421 #[test]
2424 fn the_ceiling_fits_the_declared_stack() {
2425 const PROBE_DEPTH: usize = 200;
2426 let spent = std::thread::Builder::new()
2429 .stack_size(256 * 1024 * 1024)
2430 .spawn(|| {
2431 let src = nested_parens(PROBE_DEPTH);
2432 beck_diag::depth::probe::stack_spent(|| {
2433 let mut map = beck_diag::SourceMap::new();
2434 let f = map.add("probe.beck", &src);
2435 let mut d = Diagnostics::new();
2436 parse_module(f, "probe", &src, &mut d)
2437 })
2438 })
2439 .expect("a thread")
2440 .join()
2441 .expect("the probe parses");
2442
2443 let per_level = spent / PROBE_DEPTH;
2444 println!("parser: {spent} bytes for {PROBE_DEPTH} levels ({per_level} per level)");
2445 let needed = MAX_NESTING as usize * per_level * 2;
2448 assert!(
2449 needed < STACK_BYTES,
2450 "a ceiling of {MAX_NESTING} levels at {per_level} bytes each needs {needed} bytes \
2451 with the margin, against a declared STACK_BYTES of {STACK_BYTES} — raise the \
2452 declaration or lower the ceiling"
2453 );
2454 }
2455}