1use crate::ast::{
7 AnonFnExpr, AnonStructField, ArgMode, ArrayLitExpr, AssignStatement, AssignTarget,
8 AssocFnCallExpr, Ast, BinaryExpr, BinaryOp, BlockExpr, BoolLit, BreakExpr, CallArg, CallExpr,
9 CharLit, CheckedBlockExpr, ComptimeBlockExpr, ComptimeUnrollForExpr, ConstDecl, ContinueExpr,
10 DeriveDecl, Directive, DirectiveArg, Directives, Doc, EnumDecl, EnumStructLitExpr, EnumVariant,
11 Expr, FieldDecl, FieldExpr, FieldInit, FieldPattern, FloatLit, ForExpr, Function, Ident,
12 IfExpr, IndexExpr, IntLit, InterfaceDecl, IntrinsicArg, IntrinsicCallExpr, Item, LetStatement,
13 LoopExpr, MatchArm, MatchExpr, Method, MethodCallExpr, MethodSig, NegIntLit, Param, ParamMode,
14 ParenExpr, PathExpr, PathPattern, Pattern, RangeExpr, ReturnExpr, SelfExpr, SelfParam,
15 SelfReceiverKind, Statement, StringLit, StructDecl, StructLitExpr, TupleElemPattern, TupleExpr,
16 TupleIndexExpr, TypeExpr, TypeLitExpr, UnaryExpr, UnaryOp, UnitLit, Visibility, WhileExpr,
17};
18use chumsky::input::{Input as ChumskyInput, MapExtra, Stream, ValueInput};
19use chumsky::prelude::*;
20use chumsky::recovery::via_parser;
21use chumsky::recursive::Direct;
22use gruel_builtins::Posture;
23use gruel_lexer::TokenKind;
24use gruel_util::span::LineIndex;
25use gruel_util::{CompileError, CompileErrors, ErrorKind, MultiErrorResult, PreviewFeatures};
26use gruel_util::{FileId, Span};
27use lasso::{Spur, ThreadedRodeo};
28use std::borrow::Cow;
29use std::collections::HashMap;
30
31use chumsky::extra::SimpleState;
32
33#[derive(Clone, Copy)]
36pub struct PrimitiveTypeSpurs {
37 pub i8: Spur,
38 pub i16: Spur,
39 pub i32: Spur,
40 pub i64: Spur,
41 pub isize: Spur,
42 pub u8: Spur,
43 pub u16: Spur,
44 pub u32: Spur,
45 pub u64: Spur,
46 pub usize: Spur,
47 pub f16: Spur,
48 pub f32: Spur,
49 pub f64: Spur,
50 pub bool: Spur,
51 pub char: Spur,
53 pub self_type: Spur,
55 pub ref_name: Spur,
58 pub mut_ref_name: Spur,
60 pub derive_name: Spur,
64 pub mark_name: Spur,
67 pub unchecked_name: Spur,
72}
73
74impl PrimitiveTypeSpurs {
75 pub fn new(interner: &mut ThreadedRodeo) -> Self {
77 Self {
78 i8: interner.get_or_intern("i8"),
79 i16: interner.get_or_intern("i16"),
80 i32: interner.get_or_intern("i32"),
81 i64: interner.get_or_intern("i64"),
82 isize: interner.get_or_intern("isize"),
83 u8: interner.get_or_intern("u8"),
84 u16: interner.get_or_intern("u16"),
85 u32: interner.get_or_intern("u32"),
86 u64: interner.get_or_intern("u64"),
87 usize: interner.get_or_intern("usize"),
88 f16: interner.get_or_intern("f16"),
89 f32: interner.get_or_intern("f32"),
90 f64: interner.get_or_intern("f64"),
91 bool: interner.get_or_intern("bool"),
92 char: interner.get_or_intern("char"),
93 self_type: interner.get_or_intern("Self"),
94 ref_name: interner.get_or_intern("Ref"),
95 mut_ref_name: interner.get_or_intern("MutRef"),
96 derive_name: interner.get_or_intern("derive"),
97 mark_name: interner.get_or_intern("mark"),
98 unchecked_name: interner.get_or_intern("unchecked"),
99 }
100 }
101}
102
103pub(crate) fn directives_have_mark_unchecked(
107 directives: &Directives,
108 mark_name: Spur,
109 unchecked_name: Spur,
110) -> bool {
111 directives.iter().any(|d| {
112 d.name.name == mark_name
113 && d.args.iter().any(|a| match a {
114 DirectiveArg::Ident(ident) => ident.name == unchecked_name,
115 DirectiveArg::String(_) => false,
116 })
117 })
118}
119
120#[derive(Clone, Copy)]
126pub struct ParserState {
127 pub syms: PrimitiveTypeSpurs,
129 pub file_id: FileId,
131}
132
133impl ParserState {
134 pub fn new(syms: PrimitiveTypeSpurs, file_id: FileId) -> Self {
136 Self { syms, file_id }
137 }
138}
139
140type ParserExtras<'src> = extra::Full<Rich<'src, TokenKind>, SimpleState<ParserState>, ()>;
143
144type GruelParser<'src, I, O> = Boxed<'src, 'src, I, O, ParserExtras<'src>>;
147
148#[inline]
155fn offset_to_u32(offset: usize) -> u32 {
156 debug_assert!(
157 offset <= u32::MAX as usize,
158 "offset {} exceeds u32::MAX (source file too large)",
159 offset
160 );
161 offset as u32
162}
163
164fn to_gruel_util_with_file(span: SimpleSpan, file_id: FileId) -> Span {
171 Span::with_file(file_id, offset_to_u32(span.start), offset_to_u32(span.end))
172}
173
174fn to_gruel_util(span: SimpleSpan) -> Span {
177 Span::new(offset_to_u32(span.start), offset_to_u32(span.end))
178}
179
180#[inline]
183fn span_from_extra<'src, I>(e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>) -> Span
184where
185 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
186{
187 let file_id = e.state().0.file_id;
188 to_gruel_util_with_file(e.span(), file_id)
189}
190
191fn ident_parser<'src, I>() -> GruelParser<'src, I, Ident>
193where
194 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
195{
196 select! {
197 TokenKind::Ident(name) = e => Ident {
198 name,
199 span: span_from_extra(e),
200 },
201 }
202 .boxed()
203}
204
205fn method_name_parser<'src, I>() -> GruelParser<'src, I, Ident>
213where
214 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
215{
216 ident_parser().boxed()
217}
218
219fn primitive_type_parser<'src, I>() -> GruelParser<'src, I, TypeExpr>
222where
223 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
224{
225 let i8_parser =
229 just(TokenKind::I8).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
230 let syms = e.state().0.syms;
231 TypeExpr::Named(Ident {
232 name: syms.i8,
233 span: span_from_extra(e),
234 })
235 });
236 let i16_parser =
237 just(TokenKind::I16).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
238 let syms = e.state().0.syms;
239 TypeExpr::Named(Ident {
240 name: syms.i16,
241 span: span_from_extra(e),
242 })
243 });
244 let i32_parser =
245 just(TokenKind::I32).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
246 let syms = e.state().0.syms;
247 TypeExpr::Named(Ident {
248 name: syms.i32,
249 span: span_from_extra(e),
250 })
251 });
252 let i64_parser =
253 just(TokenKind::I64).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
254 let syms = e.state().0.syms;
255 TypeExpr::Named(Ident {
256 name: syms.i64,
257 span: span_from_extra(e),
258 })
259 });
260 let u8_parser =
261 just(TokenKind::U8).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
262 let syms = e.state().0.syms;
263 TypeExpr::Named(Ident {
264 name: syms.u8,
265 span: span_from_extra(e),
266 })
267 });
268 let u16_parser =
269 just(TokenKind::U16).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
270 let syms = e.state().0.syms;
271 TypeExpr::Named(Ident {
272 name: syms.u16,
273 span: span_from_extra(e),
274 })
275 });
276 let u32_parser =
277 just(TokenKind::U32).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
278 let syms = e.state().0.syms;
279 TypeExpr::Named(Ident {
280 name: syms.u32,
281 span: span_from_extra(e),
282 })
283 });
284 let u64_parser =
285 just(TokenKind::U64).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
286 let syms = e.state().0.syms;
287 TypeExpr::Named(Ident {
288 name: syms.u64,
289 span: span_from_extra(e),
290 })
291 });
292 let isize_parser =
293 just(TokenKind::Isize).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
294 let syms = e.state().0.syms;
295 TypeExpr::Named(Ident {
296 name: syms.isize,
297 span: span_from_extra(e),
298 })
299 });
300 let usize_parser =
301 just(TokenKind::Usize).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
302 let syms = e.state().0.syms;
303 TypeExpr::Named(Ident {
304 name: syms.usize,
305 span: span_from_extra(e),
306 })
307 });
308 let f16_parser =
309 just(TokenKind::F16).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
310 let syms = e.state().0.syms;
311 TypeExpr::Named(Ident {
312 name: syms.f16,
313 span: span_from_extra(e),
314 })
315 });
316 let f32_parser =
317 just(TokenKind::F32).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
318 let syms = e.state().0.syms;
319 TypeExpr::Named(Ident {
320 name: syms.f32,
321 span: span_from_extra(e),
322 })
323 });
324 let f64_parser =
325 just(TokenKind::F64).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
326 let syms = e.state().0.syms;
327 TypeExpr::Named(Ident {
328 name: syms.f64,
329 span: span_from_extra(e),
330 })
331 });
332 let bool_parser =
333 just(TokenKind::Bool).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
334 let syms = e.state().0.syms;
335 TypeExpr::Named(Ident {
336 name: syms.bool,
337 span: span_from_extra(e),
338 })
339 });
340 let char_parser =
341 just(TokenKind::Char).map_with(|_, e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
342 let syms = e.state().0.syms;
343 TypeExpr::Named(Ident {
344 name: syms.char,
345 span: span_from_extra(e),
346 })
347 });
348
349 choice((
350 i8_parser.boxed(),
351 i16_parser.boxed(),
352 i32_parser.boxed(),
353 i64_parser.boxed(),
354 isize_parser.boxed(),
355 u8_parser.boxed(),
356 u16_parser.boxed(),
357 u32_parser.boxed(),
358 u64_parser.boxed(),
359 usize_parser.boxed(),
360 f16_parser.boxed(),
361 f32_parser.boxed(),
362 f64_parser.boxed(),
363 bool_parser.boxed(),
364 char_parser.boxed(),
365 ))
366 .boxed()
367}
368
369fn type_parser<'src, I>() -> GruelParser<'src, I, TypeExpr>
371where
372 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
373{
374 recursive(
375 move |ty: Recursive<Direct<'src, 'src, I, TypeExpr, ParserExtras<'src>>>| {
376 let unit_type = just(TokenKind::LParen)
378 .then(just(TokenKind::RParen))
379 .map_with(|_, e| TypeExpr::Unit(span_from_extra(e)));
380
381 let never_type =
383 just(TokenKind::Bang).map_with(|_, e| TypeExpr::Never(span_from_extra(e)));
384
385 let array_type = just(TokenKind::LBracket)
387 .ignore_then(ty.clone())
388 .then_ignore(just(TokenKind::Semi))
389 .then(select! {
390 TokenKind::Int(n) => n,
391 })
392 .then_ignore(just(TokenKind::RBracket))
393 .map_with(|(element, length), e| TypeExpr::Array {
394 element: Box::new(element),
395 length,
396 span: span_from_extra(e),
397 });
398
399 let anon_struct_field: GruelParser<'src, I, AnonStructField> = ident_parser()
402 .then_ignore(just(TokenKind::Colon))
403 .then(ty.clone())
404 .map_with(|(name, field_ty), e| AnonStructField {
405 doc: None,
406 name,
407 ty: field_ty,
408 span: span_from_extra(e),
409 })
410 .boxed();
411
412 let anon_struct_fields: GruelParser<'src, I, Vec<AnonStructField>> = anon_struct_field
413 .separated_by(just(TokenKind::Comma))
414 .allow_trailing()
415 .collect::<Vec<_>>()
416 .boxed();
417
418 let anon_struct_type = just(TokenKind::Struct)
419 .ignore_then(just(TokenKind::LBrace))
420 .ignore_then(anon_struct_fields)
421 .then_ignore(just(TokenKind::RBrace))
422 .map_with(|fields, e| TypeExpr::AnonymousStruct {
423 directives: Directives::new(),
424 posture: Posture::Affine,
425 fields,
426 methods: vec![],
427 span: span_from_extra(e),
428 });
429
430 let type_call = ident_parser()
434 .then(
435 ty.clone()
436 .separated_by(just(TokenKind::Comma))
437 .allow_trailing()
438 .at_least(1)
439 .collect::<Vec<_>>()
440 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)),
441 )
442 .map_with(|(callee, args), e| TypeExpr::TypeCall {
443 callee,
444 args,
445 span: span_from_extra(e),
446 });
447
448 let named_type = ident_parser().map(TypeExpr::Named);
450
451 let self_type = just(TokenKind::SelfType).map_with(|_, e| {
453 let span = span_from_extra(e);
454 TypeExpr::Named(Ident {
455 name: e.state().syms.self_type,
456 span,
457 })
458 });
459
460 let tuple_type = just(TokenKind::LParen)
465 .ignore_then(ty.clone())
466 .then_ignore(just(TokenKind::Comma))
467 .then(
468 ty.clone()
469 .separated_by(just(TokenKind::Comma))
470 .allow_trailing()
471 .collect::<Vec<_>>(),
472 )
473 .then_ignore(just(TokenKind::RParen))
474 .map_with(|(first, rest), e| {
475 let mut elems = Vec::with_capacity(1 + rest.len());
476 elems.push(first);
477 elems.extend(rest);
478 TypeExpr::Tuple {
479 elems,
480 span: span_from_extra(e),
481 }
482 });
483
484 choice((
485 unit_type.boxed(),
486 never_type.boxed(),
487 array_type.boxed(),
488 anon_struct_type.boxed(),
489 primitive_type_parser().boxed(),
490 self_type.boxed(),
491 tuple_type.boxed(),
492 type_call.boxed(),
496 named_type.boxed(),
497 ))
498 .boxed()
499 },
500 )
501 .boxed()
502}
503
504fn param_mode_parser<'src, I>() -> GruelParser<'src, I, ParamMode>
508where
509 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
510{
511 just(TokenKind::Comptime).to(ParamMode::Comptime).boxed()
512}
513
514fn param_parser<'src, I>() -> GruelParser<'src, I, Param>
516where
517 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
518{
519 just(TokenKind::Comptime)
520 .or_not()
521 .then(param_mode_parser().or_not())
522 .then(ident_parser())
523 .then_ignore(just(TokenKind::Colon))
524 .then(type_parser())
525 .map_with(|(((is_comptime, mode), name), ty), e| Param {
526 is_comptime: is_comptime.is_some(),
527 mode: mode.unwrap_or(ParamMode::Normal),
528 name,
529 ty,
530 span: span_from_extra(e),
531 })
532 .boxed()
533}
534
535fn field_decl_parser<'src, I>() -> GruelParser<'src, I, FieldDecl>
537where
538 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
539{
540 let visibility = just(TokenKind::Pub).or_not().map(|opt| {
542 if opt.is_some() {
543 Visibility::Public
544 } else {
545 Visibility::Private
546 }
547 });
548
549 visibility
550 .then(ident_parser())
551 .then_ignore(just(TokenKind::Colon))
552 .then(type_parser())
553 .map_with(|((visibility, name), ty), e| FieldDecl {
554 doc: None,
555 visibility,
556 name,
557 ty,
558 span: span_from_extra(e),
559 })
560 .boxed()
561}
562
563fn field_decls_parser<'src, I>() -> GruelParser<'src, I, Vec<FieldDecl>>
565where
566 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
567{
568 field_decl_parser()
569 .separated_by(just(TokenKind::Comma))
570 .allow_trailing()
571 .collect::<Vec<_>>()
572 .boxed()
573}
574
575fn params_parser<'src, I>() -> GruelParser<'src, I, Vec<Param>>
577where
578 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
579{
580 param_parser()
581 .separated_by(just(TokenKind::Comma))
582 .collect::<Vec<_>>()
583 .boxed()
584}
585
586fn directive_parser<'src, I>() -> GruelParser<'src, I, Directive>
592where
593 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
594{
595 let directive_name = choice((
596 ident_parser().boxed(),
597 select! {
598 TokenKind::Derive = e => {
599 let state: &mut SimpleState<ParserState> = e.state();
600 Ident {
601 name: state.0.syms.derive_name,
602 span: span_from_extra(e),
603 }
604 },
605 }
606 .boxed(),
607 ))
608 .boxed();
609
610 let directive_arg = choice((
615 select! {
616 TokenKind::String(s) = e => DirectiveArg::String(StringLit {
617 value: s,
618 span: span_from_extra(e),
619 }),
620 }
621 .boxed(),
622 ident_parser().map(DirectiveArg::Ident).boxed(),
623 ))
624 .boxed();
625
626 just(TokenKind::At)
627 .ignore_then(directive_name)
628 .then(
629 directive_arg
630 .separated_by(just(TokenKind::Comma))
631 .allow_trailing()
632 .collect::<Vec<_>>()
633 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen))
634 .or_not(),
635 )
636 .map_with(|(name, args), e| Directive {
637 name,
638 args: args.unwrap_or_default(),
639 span: span_from_extra(e),
640 })
641 .boxed()
642}
643
644fn directives_parser<'src, I>() -> GruelParser<'src, I, Directives>
646where
647 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
648{
649 directive_parser()
653 .repeated()
654 .collect::<Vec<_>>()
655 .map(|v| v.into_iter().collect())
656 .boxed()
657}
658
659fn call_arg_parser<'src, I>(expr: GruelParser<'src, I, Expr>) -> GruelParser<'src, I, CallArg>
663where
664 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
665{
666 chumsky::primitive::empty()
667 .map(|_| None::<ArgMode>)
668 .then(expr)
669 .map_with(|(mode, expr), e| CallArg {
670 mode: mode.unwrap_or(ArgMode::Normal),
671 expr,
672 span: span_from_extra(e),
673 })
674 .boxed()
675}
676
677fn call_args_parser<'src, I>(expr: GruelParser<'src, I, Expr>) -> GruelParser<'src, I, Vec<CallArg>>
679where
680 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
681{
682 call_arg_parser(expr)
683 .separated_by(just(TokenKind::Comma))
684 .collect::<Vec<_>>()
685 .boxed()
686}
687
688fn args_parser<'src, I>(expr: GruelParser<'src, I, Expr>) -> GruelParser<'src, I, Vec<Expr>>
690where
691 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
692{
693 expr.separated_by(just(TokenKind::Comma))
694 .collect::<Vec<_>>()
695 .boxed()
696}
697
698fn field_init_parser<'src, I>(expr: GruelParser<'src, I, Expr>) -> GruelParser<'src, I, FieldInit>
700where
701 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
702{
703 let explicit = ident_parser()
705 .then_ignore(just(TokenKind::Colon))
706 .then(expr)
707 .map_with(|(name, value), e| FieldInit {
708 name,
709 value: Box::new(value),
710 span: span_from_extra(e),
711 });
712
713 let shorthand = ident_parser().map_with(|name, e| FieldInit {
715 value: Box::new(Expr::Ident(name)),
716 name,
717 span: span_from_extra(e),
718 });
719
720 choice((explicit, shorthand)).boxed()
721}
722
723fn field_inits_parser<'src, I>(
725 expr: GruelParser<'src, I, Expr>,
726) -> GruelParser<'src, I, Vec<FieldInit>>
727where
728 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
729{
730 field_init_parser(expr)
731 .separated_by(just(TokenKind::Comma))
732 .allow_trailing()
733 .collect::<Vec<_>>()
734 .boxed()
735}
736
737fn make_binary(left: Expr, op: BinaryOp, right: Expr) -> Expr {
739 let span = Span::new(left.span().start, right.span().end);
740 Expr::Binary(BinaryExpr {
741 left: Box::new(left),
742 op,
743 right: Box::new(right),
744 span,
745 })
746}
747
748fn make_unary(op: UnaryOp, operand: Expr, op_span: SimpleSpan) -> Expr {
750 let span = Span::new(offset_to_u32(op_span.start), operand.span().end);
751 Expr::Unary(UnaryExpr {
752 op,
753 operand: Box::new(operand),
754 span,
755 })
756}
757
758fn expr_parser<'src, I>() -> GruelParser<'src, I, Expr>
776where
777 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
778{
779 recursive(
780 |expr: Recursive<Direct<'src, 'src, I, Expr, ParserExtras<'src>>>| {
781 let atom: GruelParser<I, Expr> = atom_parser(expr.clone().boxed());
783
784 let unary: GruelParser<I, Expr> = {
786 let prefix_op: GruelParser<I, (UnaryOp, SimpleSpan)> = choice((
787 just(TokenKind::Minus)
788 .map_with(|_, e| (UnaryOp::Neg, e.span()))
789 .boxed(),
790 just(TokenKind::Bang)
791 .map_with(|_, e| (UnaryOp::Not, e.span()))
792 .boxed(),
793 just(TokenKind::Tilde)
794 .map_with(|_, e| (UnaryOp::BitNot, e.span()))
795 .boxed(),
796 just(TokenKind::Amp)
799 .then(just(TokenKind::Mut))
800 .map_with(|_, e| (UnaryOp::MutRef, e.span()))
801 .boxed(),
802 just(TokenKind::Amp)
804 .map_with(|_, e| (UnaryOp::Ref, e.span()))
805 .boxed(),
806 ))
807 .boxed();
808 prefix_op
809 .repeated()
810 .collect::<Vec<_>>()
811 .then(atom.clone())
812 .map(|(mut ops, mut rhs)| {
813 ops.reverse();
815 for (op, span) in ops {
816 rhs = make_unary(op, rhs, span);
817 }
818 rhs
819 })
820 .boxed()
821 };
822
823 macro_rules! left_binary {
826 ($prev:expr, $op_parser:expr) => {{
827 let prev: GruelParser<I, Expr> = $prev;
828 let op: GruelParser<I, BinaryOp> = $op_parser;
829 prev.clone()
830 .foldl(op.then(prev).repeated(), |l, (op, r)| make_binary(l, op, r))
831 .boxed()
832 }};
833 }
834
835 let multiplicative: GruelParser<I, Expr> = left_binary!(
837 unary,
838 choice((
839 just(TokenKind::Star).to(BinaryOp::Mul).boxed(),
840 just(TokenKind::Slash).to(BinaryOp::Div).boxed(),
841 just(TokenKind::Percent).to(BinaryOp::Mod).boxed(),
842 ))
843 .boxed()
844 );
845
846 let additive: GruelParser<I, Expr> = left_binary!(
848 multiplicative,
849 choice((
850 just(TokenKind::Plus).to(BinaryOp::Add).boxed(),
851 just(TokenKind::Minus).to(BinaryOp::Sub).boxed(),
852 ))
853 .boxed()
854 );
855
856 let shift: GruelParser<I, Expr> = left_binary!(
858 additive,
859 choice((
860 just(TokenKind::LtLt).to(BinaryOp::Shl).boxed(),
861 just(TokenKind::GtGt).to(BinaryOp::Shr).boxed(),
862 ))
863 .boxed()
864 );
865
866 let comparison: GruelParser<I, Expr> = left_binary!(
868 shift,
869 choice((
870 just(TokenKind::EqEq).to(BinaryOp::Eq).boxed(),
871 just(TokenKind::BangEq).to(BinaryOp::Ne).boxed(),
872 just(TokenKind::Lt).to(BinaryOp::Lt).boxed(),
873 just(TokenKind::Gt).to(BinaryOp::Gt).boxed(),
874 just(TokenKind::LtEq).to(BinaryOp::Le).boxed(),
875 just(TokenKind::GtEq).to(BinaryOp::Ge).boxed(),
876 ))
877 .boxed()
878 );
879
880 let bitwise_and: GruelParser<I, Expr> = left_binary!(
882 comparison,
883 just(TokenKind::Amp).to(BinaryOp::BitAnd).boxed()
884 );
885
886 let bitwise_xor: GruelParser<I, Expr> = left_binary!(
888 bitwise_and,
889 just(TokenKind::Caret).to(BinaryOp::BitXor).boxed()
890 );
891
892 let bitwise_or: GruelParser<I, Expr> = left_binary!(
894 bitwise_xor,
895 just(TokenKind::Pipe).to(BinaryOp::BitOr).boxed()
896 );
897
898 let logical_and: GruelParser<I, Expr> = left_binary!(
900 bitwise_or,
901 just(TokenKind::AmpAmp).to(BinaryOp::And).boxed()
902 );
903
904 let logical_or: GruelParser<I, Expr> = left_binary!(
906 logical_and,
907 just(TokenKind::PipePipe).to(BinaryOp::Or).boxed()
908 );
909
910 logical_or
911 },
912 )
913 .boxed()
914}
915
916fn pattern_parser<'src, I>() -> GruelParser<'src, I, Pattern>
918where
919 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
920{
921 recursive(
922 |pat: Recursive<Direct<'src, 'src, _, Pattern, ParserExtras<'src>>>| {
923 let wildcard =
925 just(TokenKind::Underscore).map_with(|_, e| Pattern::Wildcard(span_from_extra(e)));
926
927 let int_pat = select! {
929 TokenKind::Int(n) = e => Pattern::Int(IntLit {
930 value: n,
931 span: span_from_extra(e),
932 }),
933 };
934
935 let neg_int_pat = just(TokenKind::Minus)
937 .then(select! { TokenKind::Int(n) => n })
938 .map_with(|(_, n), e| {
939 Pattern::NegInt(NegIntLit {
940 value: n,
941 span: span_from_extra(e),
942 })
943 });
944
945 let bool_true = select! {
947 TokenKind::True = e => Pattern::Bool(BoolLit {
948 value: true,
949 span: span_from_extra(e),
950 }),
951 };
952
953 let bool_false = select! {
954 TokenKind::False = e => Pattern::Bool(BoolLit {
955 value: false,
956 span: span_from_extra(e),
957 }),
958 };
959
960 let rest_token = just(TokenKind::Dot)
963 .then(just(TokenKind::Dot))
964 .map_with(|_, e| span_from_extra(e));
965
966 let leaf_binding = choice((
970 just(TokenKind::Underscore).map_with(|_, e| Pattern::Wildcard(span_from_extra(e))),
971 just(TokenKind::Mut)
972 .ignore_then(ident_parser())
973 .map_with(|name, e| Pattern::Ident {
974 is_mut: true,
975 name,
976 span: span_from_extra(e),
977 }),
978 ident_parser().map_with(|name, e| Pattern::Ident {
979 is_mut: false,
980 name,
981 span: span_from_extra(e),
982 }),
983 ));
984
985 let sub_pattern = choice((pat.clone(), leaf_binding.clone())).boxed();
994
995 let tuple_elem = choice((
997 rest_token.map(TupleElemPattern::Rest),
998 sub_pattern.clone().map(TupleElemPattern::Pattern),
999 ))
1000 .boxed();
1001
1002 let tuple_suffix = tuple_elem
1004 .clone()
1005 .separated_by(just(TokenKind::Comma))
1006 .allow_trailing()
1007 .collect::<Vec<_>>()
1008 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen));
1009
1010 let field_rest = rest_token.map_with(|span, _e| FieldPattern {
1013 field_name: None,
1014 sub: None,
1015 is_mut: false,
1016 span,
1017 });
1018 let field_explicit = just(TokenKind::Mut)
1019 .or_not()
1020 .then(ident_parser())
1021 .then_ignore(just(TokenKind::Colon))
1022 .then(sub_pattern.clone())
1023 .map_with(|((is_mut, field_name), sub), e| FieldPattern {
1024 field_name: Some(field_name),
1025 sub: Some(sub),
1026 is_mut: is_mut.is_some(),
1027 span: span_from_extra(e),
1028 });
1029 let field_shorthand =
1030 just(TokenKind::Mut)
1031 .or_not()
1032 .then(ident_parser())
1033 .map_with(|(is_mut, name), e| FieldPattern {
1034 field_name: Some(name),
1035 sub: None,
1036 is_mut: is_mut.is_some(),
1037 span: span_from_extra(e),
1038 });
1039 let field_pat = choice((field_rest, field_explicit, field_shorthand)).boxed();
1040
1041 let struct_suffix = field_pat
1042 .clone()
1043 .separated_by(just(TokenKind::Comma))
1044 .allow_trailing()
1045 .collect::<Vec<_>>()
1046 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace));
1047
1048 #[derive(Debug, Clone)]
1050 enum PatternSuffix {
1051 Tuple(Vec<TupleElemPattern>),
1052 Struct(Vec<FieldPattern>),
1053 }
1054
1055 let pattern_suffix = choice((
1056 tuple_suffix.clone().map(PatternSuffix::Tuple),
1057 struct_suffix.clone().map(PatternSuffix::Struct),
1058 ));
1059
1060 let self_path_pat = just(TokenKind::SelfType)
1062 .ignore_then(just(TokenKind::ColonColon))
1063 .ignore_then(ident_parser())
1064 .then(pattern_suffix.clone().or_not())
1065 .map_with(|(variant, suffix_opt), e| {
1066 let span = span_from_extra(e);
1067 let type_name = Ident {
1068 name: e.state().syms.self_type,
1069 span,
1070 };
1071 match suffix_opt {
1072 Some(PatternSuffix::Tuple(fields)) => Pattern::DataVariant {
1073 base: None,
1074 type_name,
1075 variant,
1076 fields,
1077 span,
1078 },
1079 Some(PatternSuffix::Struct(fields)) => Pattern::StructVariant {
1080 base: None,
1081 type_name,
1082 variant,
1083 fields,
1084 span,
1085 },
1086 None => Pattern::Path(PathPattern {
1087 base: None,
1088 type_name,
1089 variant,
1090 span,
1091 }),
1092 }
1093 });
1094
1095 let struct_destructure =
1101 ident_parser()
1102 .then(struct_suffix.clone())
1103 .map_with(|(type_name, fields), e| Pattern::Struct {
1104 type_name,
1105 fields,
1106 span: span_from_extra(e),
1107 });
1108
1109 let simple_path_pat = ident_parser()
1110 .then_ignore(just(TokenKind::ColonColon))
1111 .then(ident_parser())
1112 .then(pattern_suffix.clone().or_not())
1113 .map_with(|((type_name, variant), suffix_opt), e| match suffix_opt {
1114 Some(PatternSuffix::Tuple(fields)) => Pattern::DataVariant {
1115 base: None,
1116 type_name,
1117 variant,
1118 fields,
1119 span: span_from_extra(e),
1120 },
1121 Some(PatternSuffix::Struct(fields)) => Pattern::StructVariant {
1122 base: None,
1123 type_name,
1124 variant,
1125 fields,
1126 span: span_from_extra(e),
1127 },
1128 None => Pattern::Path(PathPattern {
1129 base: None,
1130 type_name,
1131 variant,
1132 span: span_from_extra(e),
1133 }),
1134 });
1135
1136 let qualified_path_pat = ident_parser()
1138 .then(
1139 just(TokenKind::Dot)
1140 .ignore_then(ident_parser())
1141 .repeated()
1142 .at_least(1)
1143 .collect::<Vec<_>>(),
1144 )
1145 .then_ignore(just(TokenKind::ColonColon))
1146 .then(ident_parser())
1147 .then(pattern_suffix.or_not())
1148 .map_with(|(((first, mut rest), variant), suffix_opt), e| {
1149 let type_name = rest.pop().expect("at_least(1) guarantees non-empty");
1150
1151 let base_expr = if rest.is_empty() {
1152 Expr::Ident(first)
1153 } else {
1154 let mut base = Expr::Ident(first);
1155 for field in rest {
1156 let span = base.span().extend_to(field.span.end);
1157 base = Expr::Field(FieldExpr {
1158 base: Box::new(base),
1159 field,
1160 span,
1161 });
1162 }
1163 base
1164 };
1165
1166 match suffix_opt {
1167 Some(PatternSuffix::Tuple(fields)) => Pattern::DataVariant {
1168 base: Some(Box::new(base_expr)),
1169 type_name,
1170 variant,
1171 fields,
1172 span: span_from_extra(e),
1173 },
1174 Some(PatternSuffix::Struct(fields)) => Pattern::StructVariant {
1175 base: Some(Box::new(base_expr)),
1176 type_name,
1177 variant,
1178 fields,
1179 span: span_from_extra(e),
1180 },
1181 None => Pattern::Path(PathPattern {
1182 base: Some(Box::new(base_expr)),
1183 type_name,
1184 variant,
1185 span: span_from_extra(e),
1186 }),
1187 }
1188 });
1189
1190 let tuple_pat = just(TokenKind::LParen)
1194 .ignore_then(tuple_elem.clone())
1195 .then_ignore(just(TokenKind::Comma))
1196 .then(
1197 tuple_elem
1198 .clone()
1199 .separated_by(just(TokenKind::Comma))
1200 .allow_trailing()
1201 .collect::<Vec<_>>(),
1202 )
1203 .then_ignore(just(TokenKind::RParen))
1204 .map_with(|(first, rest), e| {
1205 let mut elems = Vec::with_capacity(1 + rest.len());
1206 elems.push(first);
1207 elems.extend(rest);
1208 Pattern::Tuple {
1209 elems,
1210 span: span_from_extra(e),
1211 }
1212 });
1213
1214 let ident_leaf =
1216 just(TokenKind::Mut)
1217 .or_not()
1218 .then(ident_parser())
1219 .map_with(|(is_mut, name), e| Pattern::Ident {
1220 is_mut: is_mut.is_some(),
1221 name,
1222 span: span_from_extra(e),
1223 });
1224
1225 choice((
1226 wildcard.boxed(),
1227 neg_int_pat.boxed(),
1228 int_pat.boxed(),
1229 bool_true.boxed(),
1230 bool_false.boxed(),
1231 tuple_pat.boxed(),
1232 qualified_path_pat.boxed(),
1238 self_path_pat.boxed(),
1239 simple_path_pat.boxed(),
1240 struct_destructure.boxed(),
1241 ident_leaf.boxed(),
1242 ))
1243 .boxed()
1244 },
1245 )
1246 .boxed()
1247}
1248
1249fn match_arm_parser<'src, I>(expr: GruelParser<'src, I, Expr>) -> GruelParser<'src, I, MatchArm>
1254where
1255 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
1256{
1257 let regular_arm = pattern_parser()
1258 .then_ignore(just(TokenKind::FatArrow))
1259 .then(expr.clone())
1260 .map_with(|(pattern, body), e| MatchArm {
1261 pattern,
1262 body: Box::new(body),
1263 span: span_from_extra(e),
1264 });
1265
1266 let unroll_arm = just(TokenKind::ComptimeUnroll)
1267 .ignore_then(just(TokenKind::For))
1268 .ignore_then(ident_parser())
1269 .then_ignore(just(TokenKind::In))
1270 .then(expr.clone())
1271 .then(maybe_unit_block_parser(expr))
1272 .map_with(|((binding, iterable), body), e| {
1273 let span = span_from_extra(e);
1274 MatchArm {
1275 pattern: Pattern::ComptimeUnrollArm {
1276 binding,
1277 iterable: Box::new(iterable),
1278 span,
1279 },
1280 body: Box::new(Expr::Block(body)),
1281 span,
1282 }
1283 });
1284
1285 choice((unroll_arm, regular_arm)).boxed()
1286}
1287
1288fn literal_parser<'src, I>() -> GruelParser<'src, I, Expr>
1290where
1291 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
1292{
1293 let int_lit = select! {
1295 TokenKind::Int(n) = e => Expr::Int(IntLit {
1296 value: n,
1297 span: span_from_extra(e),
1298 }),
1299 };
1300
1301 let float_lit = select! {
1303 TokenKind::Float(bits) = e => Expr::Float(FloatLit {
1304 bits,
1305 span: span_from_extra(e),
1306 }),
1307 };
1308
1309 let string_lit = select! {
1311 TokenKind::String(s) = e => Expr::String(StringLit {
1312 value: s,
1313 span: span_from_extra(e),
1314 }),
1315 };
1316
1317 let char_lit = select! {
1319 TokenKind::CharLit(c) = e => Expr::Char(CharLit {
1320 value: c,
1321 span: span_from_extra(e),
1322 }),
1323 };
1324
1325 let bool_true = select! {
1327 TokenKind::True = e => Expr::Bool(BoolLit {
1328 value: true,
1329 span: span_from_extra(e),
1330 }),
1331 };
1332
1333 let bool_false = select! {
1334 TokenKind::False = e => Expr::Bool(BoolLit {
1335 value: false,
1336 span: span_from_extra(e),
1337 }),
1338 };
1339
1340 let unit_lit = just(TokenKind::LParen)
1342 .then(just(TokenKind::RParen))
1343 .map_with(|_, e| {
1344 Expr::Unit(UnitLit {
1345 span: span_from_extra(e),
1346 })
1347 });
1348
1349 choice((
1350 int_lit.boxed(),
1351 float_lit.boxed(),
1352 string_lit.boxed(),
1353 char_lit.boxed(),
1354 bool_true.boxed(),
1355 bool_false.boxed(),
1356 unit_lit.boxed(),
1357 ))
1358 .boxed()
1359}
1360
1361fn control_flow_parser<'src, I>(expr: GruelParser<'src, I, Expr>) -> GruelParser<'src, I, Expr>
1363where
1364 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
1365{
1366 let break_expr = select! {
1368 TokenKind::Break = e => Expr::Break(BreakExpr { span: span_from_extra(e) }),
1369 };
1370
1371 let continue_expr = select! {
1373 TokenKind::Continue = e => Expr::Continue(ContinueExpr { span: span_from_extra(e) }),
1374 };
1375
1376 let return_expr = just(TokenKind::Return)
1378 .ignore_then(expr.clone().or_not())
1379 .map_with(|value, e| {
1380 Expr::Return(ReturnExpr {
1381 value: value.map(Box::new),
1382 span: span_from_extra(e),
1383 })
1384 });
1385
1386 let if_expr: GruelParser<'src, I, Expr> = recursive(
1390 |if_expr_rec: Recursive<Direct<'src, 'src, I, Expr, ParserExtras<'src>>>| {
1391 just(TokenKind::Comptime)
1392 .or_not()
1393 .then_ignore(just(TokenKind::If))
1394 .then(expr.clone())
1395 .then(maybe_unit_block_parser(expr.clone()))
1396 .then(
1397 just(TokenKind::Else)
1398 .ignore_then(choice((
1399 if_expr_rec
1401 .map_with(|nested_if, e| {
1402 let span = span_from_extra(e);
1403 BlockExpr {
1404 statements: Vec::new(),
1405 expr: Box::new(nested_if),
1406 span,
1407 }
1408 })
1409 .boxed(),
1410 maybe_unit_block_parser(expr.clone()),
1412 )))
1413 .or_not(),
1414 )
1415 .map_with(|(((comptime_kw, cond), then_block), else_block), e| {
1416 Expr::If(IfExpr {
1417 cond: Box::new(cond),
1418 then_block,
1419 else_block,
1420 span: span_from_extra(e),
1421 is_comptime: comptime_kw.is_some(),
1422 })
1423 })
1424 .boxed()
1425 },
1426 )
1427 .boxed();
1428
1429 let while_expr: GruelParser<'src, I, Expr> = just(TokenKind::While)
1431 .ignore_then(expr.clone())
1432 .then(maybe_unit_block_parser(expr.clone()))
1433 .map_with(|(cond, body), e| {
1434 Expr::While(WhileExpr {
1435 cond: Box::new(cond),
1436 body,
1437 span: span_from_extra(e),
1438 })
1439 })
1440 .boxed();
1441
1442 let for_expr: GruelParser<'src, I, Expr> = just(TokenKind::For)
1444 .ignore_then(just(TokenKind::Mut).or_not())
1445 .then(ident_parser())
1446 .then_ignore(just(TokenKind::In))
1447 .then(expr.clone())
1448 .then(maybe_unit_block_parser(expr.clone()))
1449 .map_with(|(((is_mut, binding), iterable), body), e| {
1450 Expr::For(ForExpr {
1451 binding,
1452 is_mut: is_mut.is_some(),
1453 iterable: Box::new(iterable),
1454 body,
1455 span: span_from_extra(e),
1456 })
1457 })
1458 .boxed();
1459
1460 let loop_expr: GruelParser<'src, I, Expr> = just(TokenKind::Loop)
1462 .ignore_then(maybe_unit_block_parser(expr.clone()))
1463 .map_with(|body, e| {
1464 Expr::Loop(LoopExpr {
1465 body,
1466 span: span_from_extra(e),
1467 })
1468 })
1469 .boxed();
1470
1471 let match_expr: GruelParser<'src, I, Expr> = just(TokenKind::Match)
1473 .ignore_then(expr.clone())
1474 .then(
1475 match_arm_parser(expr.clone())
1476 .separated_by(just(TokenKind::Comma))
1477 .allow_trailing()
1478 .collect::<Vec<_>>()
1479 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace)),
1480 )
1481 .map_with(|(scrutinee, arms), e| {
1482 Expr::Match(MatchExpr {
1483 scrutinee: Box::new(scrutinee),
1484 arms,
1485 span: span_from_extra(e),
1486 })
1487 })
1488 .boxed();
1489
1490 let comptime_unroll_for_expr: GruelParser<'src, I, Expr> = just(TokenKind::ComptimeUnroll)
1492 .ignore_then(just(TokenKind::For))
1493 .ignore_then(ident_parser())
1494 .then_ignore(just(TokenKind::In))
1495 .then(expr.clone())
1496 .then(maybe_unit_block_parser(expr.clone()))
1497 .map_with(|((binding, iterable), body), e| {
1498 Expr::ComptimeUnrollFor(ComptimeUnrollForExpr {
1499 binding,
1500 iterable: Box::new(iterable),
1501 body,
1502 span: span_from_extra(e),
1503 })
1504 })
1505 .boxed();
1506
1507 choice((
1508 break_expr.boxed(),
1509 continue_expr.boxed(),
1510 return_expr.boxed(),
1511 if_expr,
1512 while_expr,
1513 for_expr,
1514 comptime_unroll_for_expr,
1515 loop_expr,
1516 match_expr,
1517 ))
1518 .boxed()
1519}
1520
1521#[derive(Clone)]
1523enum IdentSuffix {
1524 Call(Vec<CallArg>),
1525 StructLit(Vec<FieldInit>),
1526 Path(Ident), PathCall(Ident, Vec<CallArg>), PathStructLit(Ident, Vec<FieldInit>), TypeCallPathCall(Vec<Expr>, Ident, Vec<CallArg>),
1531 None,
1532}
1533
1534fn call_and_access_parser<'src, I>(expr: GruelParser<'src, I, Expr>) -> GruelParser<'src, I, Expr>
1536where
1537 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
1538{
1539 ident_parser()
1540 .then(
1541 choice((
1542 {
1547 let type_args = expr
1548 .clone()
1549 .separated_by(just(TokenKind::Comma))
1550 .allow_trailing()
1551 .at_least(1)
1552 .collect::<Vec<_>>()
1553 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen));
1554 type_args
1555 .then_ignore(just(TokenKind::ColonColon))
1556 .then(ident_parser())
1557 .then(
1558 call_args_parser(expr.clone())
1559 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)),
1560 )
1561 .map(|((type_args, func), args)| {
1562 IdentSuffix::TypeCallPathCall(type_args, func, args)
1563 })
1564 .boxed()
1565 },
1566 call_args_parser(expr.clone())
1568 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen))
1569 .map(IdentSuffix::Call)
1570 .boxed(),
1571 just(TokenKind::LBrace)
1575 .then(
1576 choice((
1577 just(TokenKind::RBrace).ignored(),
1578 select! { TokenKind::Ident(_) => () }
1579 .then_ignore(just(TokenKind::Colon))
1580 .ignored(),
1581 select! { TokenKind::Ident(_) => () }
1582 .then_ignore(just(TokenKind::Comma))
1583 .ignored(),
1584 ))
1585 .rewind(),
1586 )
1587 .rewind()
1588 .ignore_then(
1589 field_inits_parser(expr.clone())
1590 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace)),
1591 )
1592 .map(IdentSuffix::StructLit)
1593 .boxed(),
1594 just(TokenKind::ColonColon)
1596 .ignore_then(ident_parser())
1597 .then(
1598 call_args_parser(expr.clone())
1599 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)),
1600 )
1601 .map(|(func, args)| IdentSuffix::PathCall(func, args))
1602 .boxed(),
1603 just(TokenKind::ColonColon)
1605 .ignore_then(ident_parser())
1606 .then(
1607 field_inits_parser(expr.clone())
1608 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace)),
1609 )
1610 .map(|(variant, fields)| IdentSuffix::PathStructLit(variant, fields))
1611 .boxed(),
1612 just(TokenKind::ColonColon)
1614 .ignore_then(ident_parser())
1615 .map(IdentSuffix::Path)
1616 .boxed(),
1617 ))
1618 .or_not()
1619 .map(|opt| opt.unwrap_or(IdentSuffix::None)),
1620 )
1621 .map_with(|(name, suffix), e| match suffix {
1622 IdentSuffix::Call(args) => Expr::Call(CallExpr {
1623 name,
1624 args,
1625 span: span_from_extra(e),
1626 }),
1627 IdentSuffix::StructLit(fields) => Expr::StructLit(StructLitExpr {
1628 base: None, name,
1630 fields,
1631 span: span_from_extra(e),
1632 }),
1633 IdentSuffix::PathCall(function, args) => Expr::AssocFnCall(AssocFnCallExpr {
1634 base: None, type_name: name,
1636 type_args: Vec::new(),
1637 function,
1638 args,
1639 span: span_from_extra(e),
1640 }),
1641 IdentSuffix::TypeCallPathCall(type_args, function, args) => {
1642 Expr::AssocFnCall(AssocFnCallExpr {
1643 base: None,
1644 type_name: name,
1645 type_args,
1646 function,
1647 args,
1648 span: span_from_extra(e),
1649 })
1650 }
1651 IdentSuffix::PathStructLit(variant, fields) => Expr::EnumStructLit(EnumStructLitExpr {
1652 base: None,
1653 type_name: name,
1654 variant,
1655 fields,
1656 span: span_from_extra(e),
1657 }),
1658 IdentSuffix::Path(variant) => Expr::Path(PathExpr {
1659 base: None, type_name: name,
1661 variant,
1662 span: span_from_extra(e),
1663 }),
1664 IdentSuffix::None => Expr::Ident(name),
1665 })
1666 .boxed()
1667}
1668
1669#[derive(Clone)]
1672enum Suffix {
1673 Field(Ident),
1675 TupleField(u32, Span),
1678 MethodCall(Ident, Vec<CallArg>, u32),
1680 Index(Expr, u32),
1682 QualifiedStructLit(Ident, Vec<FieldInit>, u32),
1685 QualifiedPath(Ident, Ident, u32),
1687 QualifiedAssocFnCall(Ident, Ident, Vec<CallArg>, u32),
1689 QualifiedEnumStructLit(Ident, Ident, Vec<FieldInit>, u32),
1691}
1692
1693fn with_suffix_parser<'src, I>(
1695 primary: impl Parser<'src, I, Expr, ParserExtras<'src>> + Clone + 'src,
1696 expr: GruelParser<'src, I, Expr>,
1697) -> GruelParser<'src, I, Expr>
1698where
1699 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
1700{
1701 let method_call_suffix = just(TokenKind::Dot)
1703 .ignore_then(ident_parser())
1704 .then(
1705 call_args_parser(expr.clone())
1706 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)),
1707 )
1708 .map_with(|(method, args), e| {
1709 Suffix::MethodCall(method, args, offset_to_u32(e.span().end))
1710 });
1711
1712 let struct_lit_lookahead = just(TokenKind::LBrace)
1724 .then(
1725 choice((
1726 just(TokenKind::RBrace).ignored(),
1728 select! { TokenKind::Ident(_) => () }
1730 .then_ignore(just(TokenKind::Colon))
1731 .ignored(),
1732 ))
1733 .rewind(),
1735 )
1736 .rewind();
1737
1738 let struct_lit_lookahead: GruelParser<'src, I, _> = struct_lit_lookahead.boxed();
1741
1742 let struct_lit_name: GruelParser<'src, I, Ident> = just(TokenKind::Dot)
1746 .ignore_then(ident_parser())
1747 .then_ignore(struct_lit_lookahead)
1748 .boxed();
1749 let qualified_struct_lit_suffix = struct_lit_name
1750 .then(
1751 field_inits_parser(expr.clone())
1752 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace)),
1753 )
1754 .map_with(|(name, fields), e| {
1755 Suffix::QualifiedStructLit(name, fields, offset_to_u32(e.span().end))
1756 })
1757 .boxed();
1758
1759 let type_and_member: GruelParser<'src, I, (Ident, Ident)> = just(TokenKind::Dot)
1762 .ignore_then(ident_parser())
1763 .then_ignore(just(TokenKind::ColonColon))
1764 .then(ident_parser())
1765 .boxed();
1766
1767 let qualified_assoc_fn_suffix = type_and_member
1769 .clone()
1770 .then(
1771 call_args_parser(expr.clone())
1772 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)),
1773 )
1774 .map_with(|((type_name, function), args), e| {
1775 Suffix::QualifiedAssocFnCall(type_name, function, args, offset_to_u32(e.span().end))
1776 });
1777
1778 let qualified_enum_struct_lit_suffix = type_and_member
1780 .clone()
1781 .then(
1782 field_inits_parser(expr.clone())
1783 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace)),
1784 )
1785 .map_with(|((type_name, variant), fields), e| {
1786 Suffix::QualifiedEnumStructLit(type_name, variant, fields, offset_to_u32(e.span().end))
1787 });
1788
1789 let qualified_path_suffix = type_and_member
1792 .map(|(type_name, variant): (Ident, Ident)| {
1793 let end = variant.span.end;
1794 (type_name, variant, end)
1795 })
1796 .then_ignore(none_of([TokenKind::LParen, TokenKind::LBrace]).rewind())
1797 .map(|(type_name, variant, end)| Suffix::QualifiedPath(type_name, variant, end));
1798
1799 let field_suffix = just(TokenKind::Dot)
1803 .ignore_then(ident_parser())
1804 .then_ignore(none_of([TokenKind::LParen, TokenKind::ColonColon]).rewind())
1805 .map(Suffix::Field);
1806
1807 let tuple_field_suffix = just(TokenKind::Dot)
1817 .ignore_then(select! {
1818 TokenKind::Int(n) = e => (n, span_from_extra(e)),
1819 })
1820 .map(|(n, span)| {
1821 let idx = if n > u32::MAX as u64 {
1822 u32::MAX
1823 } else {
1824 n as u32
1825 };
1826 Suffix::TupleField(idx, span)
1827 });
1828
1829 let dot_dot = just(TokenKind::Dot).then(just(TokenKind::Dot));
1837
1838 let range_or_expr = choice((
1839 dot_dot
1841 .ignore_then(expr.clone().or_not())
1842 .map_with(|hi, e| {
1843 Expr::Range(RangeExpr {
1844 lo: None,
1845 hi: hi.map(Box::new),
1846 span: span_from_extra(e),
1847 })
1848 }),
1849 expr.clone()
1852 .then(dot_dot.ignore_then(expr.clone().or_not()).or_not())
1853 .map_with(|(lhs, suffix), e| match suffix {
1854 Some(hi) => Expr::Range(RangeExpr {
1855 lo: Some(Box::new(lhs)),
1856 hi: hi.map(Box::new),
1857 span: span_from_extra(e),
1858 }),
1859 None => lhs,
1860 }),
1861 ));
1862
1863 let index_suffix = range_or_expr
1864 .delimited_by(just(TokenKind::LBracket), just(TokenKind::RBracket))
1865 .map_with(|index, e| Suffix::Index(index, offset_to_u32(e.span().end)));
1866
1867 primary
1877 .foldl(
1878 choice((
1879 method_call_suffix.boxed(),
1880 qualified_assoc_fn_suffix.boxed(),
1881 qualified_enum_struct_lit_suffix.boxed(),
1882 qualified_struct_lit_suffix,
1883 qualified_path_suffix.boxed(),
1884 field_suffix.boxed(),
1885 tuple_field_suffix.boxed(),
1886 index_suffix.boxed(),
1887 ))
1888 .boxed()
1889 .repeated(),
1890 |base, suffix| match suffix {
1891 Suffix::Field(field) => {
1892 let span = base.span().extend_to(field.span.end);
1894 Expr::Field(FieldExpr {
1895 base: Box::new(base),
1896 field,
1897 span,
1898 })
1899 }
1900 Suffix::TupleField(index, index_span) => {
1901 let span = base.span().extend_to(index_span.end);
1902 Expr::TupleIndex(TupleIndexExpr {
1903 base: Box::new(base),
1904 index,
1905 span,
1906 index_span,
1907 })
1908 }
1909 Suffix::MethodCall(method, args, end) => {
1910 let span = base.span().extend_to(end);
1912 Expr::MethodCall(MethodCallExpr {
1913 receiver: Box::new(base),
1914 method,
1915 args,
1916 span,
1917 })
1918 }
1919 Suffix::Index(index, end) => {
1920 let span = base.span().extend_to(end);
1922 Expr::Index(IndexExpr {
1923 base: Box::new(base),
1924 index: Box::new(index),
1925 span,
1926 })
1927 }
1928 Suffix::QualifiedStructLit(name, fields, end) => {
1929 let span = base.span().extend_to(end);
1931 Expr::StructLit(StructLitExpr {
1932 base: Some(Box::new(base)),
1933 name,
1934 fields,
1935 span,
1936 })
1937 }
1938 Suffix::QualifiedPath(type_name, variant, end) => {
1939 let span = base.span().extend_to(end);
1941 Expr::Path(PathExpr {
1942 base: Some(Box::new(base)),
1943 type_name,
1944 variant,
1945 span,
1946 })
1947 }
1948 Suffix::QualifiedEnumStructLit(type_name, variant, fields, end) => {
1949 let span = base.span().extend_to(end);
1951 Expr::EnumStructLit(EnumStructLitExpr {
1952 base: Some(Box::new(base)),
1953 type_name,
1954 variant,
1955 fields,
1956 span,
1957 })
1958 }
1959 Suffix::QualifiedAssocFnCall(type_name, function, args, end) => {
1960 let span = base.span().extend_to(end);
1962 Expr::AssocFnCall(AssocFnCallExpr {
1963 base: Some(Box::new(base)),
1964 type_name,
1965 type_args: Vec::new(),
1966 function,
1967 args,
1968 span,
1969 })
1970 }
1971 },
1972 )
1973 .boxed()
1974}
1975
1976fn atom_parser<'src, I>(expr: GruelParser<'src, I, Expr>) -> GruelParser<'src, I, Expr>
1978where
1979 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
1980{
1981 let self_expr = select! {
1983 TokenKind::SelfValue = e => Expr::SelfExpr(SelfExpr { span: span_from_extra(e) }),
1984 };
1985
1986 let paren_or_tuple = just(TokenKind::LParen)
1997 .ignore_then(expr.clone())
1998 .then(
1999 just(TokenKind::Comma)
2000 .ignore_then(
2001 expr.clone()
2002 .separated_by(just(TokenKind::Comma))
2003 .allow_trailing()
2004 .collect::<Vec<_>>(),
2005 )
2006 .or_not(),
2007 )
2008 .then_ignore(just(TokenKind::RParen))
2009 .map_with(|(first, rest), e| match rest {
2010 None => Expr::Paren(ParenExpr {
2011 inner: Box::new(first),
2012 span: span_from_extra(e),
2013 }),
2014 Some(rest) => {
2015 let mut elems = Vec::with_capacity(1 + rest.len());
2016 elems.push(first);
2017 elems.extend(rest);
2018 Expr::Tuple(TupleExpr {
2019 elems,
2020 span: span_from_extra(e),
2021 })
2022 }
2023 });
2024 let paren_expr = paren_or_tuple;
2025
2026 let block_expr = block_parser(expr.clone());
2028
2029 let comptime_expr = just(TokenKind::Comptime)
2031 .ignore_then(block_parser(expr.clone()))
2032 .map_with(|inner_expr, e| {
2033 Expr::Comptime(ComptimeBlockExpr {
2034 expr: Box::new(inner_expr),
2035 span: span_from_extra(e),
2036 })
2037 });
2038
2039 let checked_expr = just(TokenKind::Checked)
2042 .ignore_then(block_parser(expr.clone()))
2043 .map_with(|inner_expr, e| {
2044 Expr::Checked(CheckedBlockExpr {
2045 expr: Box::new(inner_expr),
2046 span: span_from_extra(e),
2047 })
2048 });
2049
2050 let unambiguous_type = {
2054 let unit_type = just(TokenKind::LParen)
2056 .then(just(TokenKind::RParen))
2057 .map_with(|_, e| IntrinsicArg::Type(TypeExpr::Unit(span_from_extra(e))));
2058
2059 let never_type = just(TokenKind::Bang)
2061 .map_with(|_, e| IntrinsicArg::Type(TypeExpr::Never(span_from_extra(e))));
2062
2063 let array_type = just(TokenKind::LBracket)
2065 .ignore_then(type_parser())
2066 .then_ignore(just(TokenKind::Semi))
2067 .then(select! {
2068 TokenKind::Int(n) => n,
2069 })
2070 .then_ignore(just(TokenKind::RBracket))
2071 .map_with(|(element, length), e| {
2072 IntrinsicArg::Type(TypeExpr::Array {
2073 element: Box::new(element),
2074 length,
2075 span: span_from_extra(e),
2076 })
2077 });
2078
2079 let primitive_type = primitive_type_parser().map(IntrinsicArg::Type);
2081
2082 let self_type_arg = just(TokenKind::SelfType).map_with(|_, e| {
2087 let span = span_from_extra(e);
2088 IntrinsicArg::Type(TypeExpr::Named(Ident {
2089 name: e.state().syms.self_type,
2090 span,
2091 }))
2092 });
2093
2094 choice((
2095 unit_type.boxed(),
2096 never_type.boxed(),
2097 array_type.boxed(),
2098 primitive_type.boxed(),
2099 self_type_arg.boxed(),
2100 ))
2101 .boxed()
2102 };
2103
2104 let intrinsic_arg: GruelParser<I, IntrinsicArg> = choice((
2107 unambiguous_type,
2108 expr.clone().map(IntrinsicArg::Expr).boxed(),
2109 ))
2110 .boxed();
2111
2112 let intrinsic_args: GruelParser<I, Vec<IntrinsicArg>> = intrinsic_arg
2114 .separated_by(just(TokenKind::Comma))
2115 .allow_trailing()
2116 .collect::<Vec<_>>()
2117 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen))
2118 .boxed();
2119
2120 let intrinsic_call: GruelParser<I, Expr> = just(TokenKind::At)
2122 .ignore_then(ident_parser())
2123 .then(intrinsic_args.clone())
2124 .map_with(|(name, args), e| {
2125 Expr::IntrinsicCall(IntrinsicCallExpr {
2126 name,
2127 args,
2128 span: span_from_extra(e),
2129 })
2130 })
2131 .boxed();
2132
2133 let import_call: GruelParser<I, Expr> = select! {
2135 TokenKind::AtImport(import_spur) = e => (import_spur, span_from_extra(e)),
2136 }
2137 .then(intrinsic_args)
2138 .map_with(|((import_spur, import_span), args), e| {
2139 Expr::IntrinsicCall(IntrinsicCallExpr {
2140 name: Ident {
2141 name: import_spur,
2142 span: import_span,
2143 },
2144 args,
2145 span: span_from_extra(e),
2146 })
2147 })
2148 .boxed();
2149
2150 let any_intrinsic_call: GruelParser<I, Expr> = choice((import_call, intrinsic_call)).boxed();
2152
2153 let array_lit = args_parser(expr.clone())
2155 .delimited_by(just(TokenKind::LBracket), just(TokenKind::RBracket))
2156 .map_with(|elements, e| {
2157 Expr::ArrayLit(ArrayLitExpr {
2158 elements,
2159 span: span_from_extra(e),
2160 })
2161 });
2162
2163 let char_assoc_fn_call = just(TokenKind::Char)
2168 .ignore_then(just(TokenKind::ColonColon))
2169 .ignore_then(ident_parser())
2170 .then(
2171 call_args_parser(expr.clone())
2172 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)),
2173 )
2174 .map_with(
2175 |(function, args), e: &mut MapExtra<'src, '_, I, ParserExtras<'src>>| {
2176 let syms = e.state().0.syms;
2177 let span = span_from_extra(e);
2178 Expr::AssocFnCall(AssocFnCallExpr {
2179 base: None,
2180 type_name: Ident {
2181 name: syms.char,
2182 span,
2183 },
2184 type_args: Vec::new(),
2185 function,
2186 args,
2187 span,
2188 })
2189 },
2190 );
2191
2192 let type_lit_expr = primitive_type_parser().map_with(|type_expr, e| {
2195 Expr::TypeLit(TypeLitExpr {
2196 type_expr,
2197 span: span_from_extra(e),
2198 })
2199 });
2200
2201 let self_as_value_expr = just(TokenKind::SelfType).map_with(|_, e| {
2209 let span = span_from_extra(e);
2210 Expr::TypeLit(TypeLitExpr {
2211 type_expr: TypeExpr::Named(Ident {
2212 name: e.state().syms.self_type,
2213 span,
2214 }),
2215 span,
2216 })
2217 });
2218
2219 let anon_struct_field: GruelParser<'src, I, AnonStructField> = ident_parser()
2225 .then_ignore(just(TokenKind::Colon))
2226 .then(type_parser())
2227 .map_with(|(name, field_ty), e| AnonStructField {
2228 doc: None,
2229 name,
2230 ty: field_ty,
2231 span: span_from_extra(e),
2232 })
2233 .boxed();
2234
2235 let anon_struct_fields: GruelParser<'src, I, Vec<AnonStructField>> = anon_struct_field
2236 .separated_by(just(TokenKind::Comma))
2237 .allow_trailing()
2238 .collect::<Vec<_>>()
2239 .boxed();
2240
2241 let anon_struct_method = anon_struct_method_parser(expr.clone());
2244
2245 let anon_struct_header: GruelParser<'src, I, (Directives, Vec<AnonStructField>, Vec<Method>)> =
2251 directives_parser()
2252 .then_ignore(just(TokenKind::Struct))
2253 .then_ignore(just(TokenKind::LBrace))
2254 .then(anon_struct_fields)
2255 .then(
2256 anon_struct_method.repeated().collect::<Vec<_>>(),
2258 )
2259 .map(|((directives, fields), methods)| (directives, fields, methods))
2260 .boxed();
2261
2262 let anon_struct_type_expr = anon_struct_header
2263 .then_ignore(just(TokenKind::RBrace))
2264 .map_with(|(directives, fields, methods), e| {
2265 let span = span_from_extra(e);
2266 Expr::TypeLit(TypeLitExpr {
2267 type_expr: TypeExpr::AnonymousStruct {
2268 directives,
2269 posture: Posture::Affine,
2270 fields,
2271 methods,
2272 span,
2273 },
2274 span,
2275 })
2276 });
2277
2278 let anon_fn_expr: GruelParser<'src, I, Expr> = just(TokenKind::Fn)
2284 .ignore_then(params_parser().delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)))
2285 .then(just(TokenKind::Arrow).ignore_then(type_parser()).or_not())
2286 .then(block_parser(expr.clone()))
2287 .map_with(|((params, return_type), body), e| {
2288 let body_block = match body {
2289 Expr::Block(b) => b,
2290 _ => unreachable!("block_parser always returns Expr::Block"),
2291 };
2292 Expr::AnonFn(AnonFnExpr {
2293 params,
2294 return_type,
2295 body: body_block,
2296 span: span_from_extra(e),
2297 })
2298 })
2299 .boxed();
2300
2301 let anon_enum_method = anon_struct_method_parser(expr.clone());
2305
2306 let anon_enum_type_expr = directives_parser()
2309 .then_ignore(just(TokenKind::Enum))
2310 .then_ignore(just(TokenKind::LBrace))
2311 .then(enum_variants_parser())
2312 .then(
2313 anon_enum_method.repeated().collect::<Vec<_>>(),
2315 )
2316 .then_ignore(just(TokenKind::RBrace))
2317 .map_with(|((directives, variants), methods), e| {
2318 let span = span_from_extra(e);
2319 Expr::TypeLit(TypeLitExpr {
2320 type_expr: TypeExpr::AnonymousEnum {
2321 directives,
2322 posture: Posture::Affine,
2323 variants,
2324 methods,
2325 span,
2326 },
2327 span,
2328 })
2329 });
2330
2331 let anon_interface_type_expr = just(TokenKind::Interface)
2336 .ignore_then(just(TokenKind::LBrace))
2337 .ignore_then(interface_method_sig_parser().repeated().collect::<Vec<_>>())
2338 .then_ignore(just(TokenKind::RBrace))
2339 .map_with(|methods, e| {
2340 let span = span_from_extra(e);
2341 Expr::TypeLit(TypeLitExpr {
2342 type_expr: TypeExpr::AnonymousInterface { methods, span },
2343 span,
2344 })
2345 });
2346
2347 let self_type_expr = just(TokenKind::SelfType)
2350 .ignore_then(
2351 field_inits_parser(expr.clone())
2352 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace)),
2353 )
2354 .map_with(|fields, e| {
2355 let span = span_from_extra(e);
2356 Expr::StructLit(StructLitExpr {
2357 base: None,
2358 name: Ident {
2359 name: e.state().syms.self_type,
2360 span,
2361 },
2362 fields,
2363 span,
2364 })
2365 });
2366
2367 let self_assoc_fn_call = just(TokenKind::SelfType)
2369 .ignore_then(just(TokenKind::ColonColon))
2370 .ignore_then(ident_parser())
2371 .then(
2372 call_args_parser(expr.clone())
2373 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)),
2374 )
2375 .map_with(|(function, args), e| {
2376 let span = span_from_extra(e);
2377 Expr::AssocFnCall(AssocFnCallExpr {
2378 base: None,
2379 type_name: Ident {
2380 name: e.state().syms.self_type,
2381 span,
2382 },
2383 type_args: Vec::new(),
2384 function,
2385 args,
2386 span,
2387 })
2388 });
2389
2390 let self_enum_struct_lit = just(TokenKind::SelfType)
2392 .ignore_then(just(TokenKind::ColonColon))
2393 .ignore_then(ident_parser())
2394 .then(
2395 field_inits_parser(expr.clone())
2396 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace)),
2397 )
2398 .map_with(|(variant, fields), e| {
2399 let span = span_from_extra(e);
2400 Expr::EnumStructLit(EnumStructLitExpr {
2401 base: None,
2402 type_name: Ident {
2403 name: e.state().syms.self_type,
2404 span,
2405 },
2406 variant,
2407 fields,
2408 span,
2409 })
2410 });
2411
2412 let self_enum_variant = just(TokenKind::SelfType)
2414 .ignore_then(just(TokenKind::ColonColon))
2415 .ignore_then(ident_parser())
2416 .then_ignore(none_of([TokenKind::LParen, TokenKind::LBrace]).rewind())
2417 .map_with(|variant, e| {
2418 let span = span_from_extra(e);
2419 Expr::Path(PathExpr {
2420 base: None,
2421 type_name: Ident {
2422 name: e.state().syms.self_type,
2423 span,
2424 },
2425 variant,
2426 span,
2427 })
2428 });
2429
2430 let primary_a: GruelParser<'src, I, Expr> = choice((
2448 literal_parser(),
2449 control_flow_parser(expr.clone()),
2450 self_expr.boxed(),
2451 self_assoc_fn_call.boxed(),
2452 self_enum_struct_lit.boxed(),
2453 self_enum_variant.boxed(),
2454 self_type_expr.boxed(),
2455 anon_struct_type_expr.boxed(),
2456 anon_enum_type_expr.boxed(),
2457 any_intrinsic_call.boxed(),
2458 ))
2459 .boxed();
2460 let primary_b: GruelParser<'src, I, Expr> = choice((
2461 array_lit.boxed(),
2462 anon_interface_type_expr.boxed(),
2463 anon_fn_expr,
2464 char_assoc_fn_call.boxed(),
2466 type_lit_expr.boxed(),
2467 self_as_value_expr.boxed(),
2472 call_and_access_parser(expr.clone()),
2473 paren_expr.boxed(),
2474 ))
2475 .boxed();
2476 let primary_c: GruelParser<'src, I, Expr> = choice((
2477 comptime_expr.boxed(),
2478 checked_expr.boxed(),
2479 block_expr.boxed(),
2480 ))
2481 .boxed();
2482 let primary: GruelParser<'src, I, Expr> = choice((primary_a, primary_b, primary_c)).boxed();
2483
2484 with_suffix_parser(primary, expr)
2486}
2487
2488#[derive(Debug, Clone)]
2490enum BlockItem {
2491 Statement(Statement),
2492 Expr(Expr),
2493}
2494
2495#[derive(Debug, Clone, Copy)]
2497enum ExprFollower {
2498 Semi,
2500 RBrace,
2502 Other,
2504 End,
2506}
2507
2508fn let_pattern_parser<'src, I>() -> GruelParser<'src, I, Pattern>
2513where
2514 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
2515{
2516 pattern_parser()
2517}
2518
2519fn let_statement_parser<'src, I>(
2521 expr: GruelParser<'src, I, Expr>,
2522) -> GruelParser<'src, I, Statement>
2523where
2524 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
2525{
2526 let let_head: GruelParser<I, (Directives, bool, Pattern)> = directives_parser()
2528 .then(just(TokenKind::Let).ignore_then(just(TokenKind::Mut).or_not().map(|m| m.is_some())))
2529 .then(let_pattern_parser())
2530 .map(|((d, m), p)| (d, m, p))
2531 .boxed();
2532
2533 let let_tail: GruelParser<I, (Option<TypeExpr>, Expr)> = just(TokenKind::Colon)
2534 .ignore_then(type_parser())
2535 .or_not()
2536 .then(just(TokenKind::Eq).ignore_then(expr))
2537 .then_ignore(just(TokenKind::Semi))
2538 .boxed();
2539
2540 let_head
2541 .then(let_tail)
2542 .map_with(|((directives, is_mut, pattern), (ty, init)), e| {
2543 Statement::Let(LetStatement {
2544 directives,
2545 is_mut,
2546 pattern,
2547 ty,
2548 init: Box::new(init),
2549 span: span_from_extra(e),
2550 })
2551 })
2552 .boxed()
2553}
2554
2555#[derive(Clone)]
2557enum AssignSuffix {
2558 Field(Ident),
2559 Index(Expr),
2560}
2561
2562fn assign_target_parser<'src, I>(
2565 expr: GruelParser<'src, I, Expr>,
2566) -> GruelParser<'src, I, AssignTarget>
2567where
2568 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
2569{
2570 let field_suffix = just(TokenKind::Dot)
2571 .ignore_then(ident_parser())
2572 .map(AssignSuffix::Field);
2573
2574 let index_suffix = expr
2575 .delimited_by(just(TokenKind::LBracket), just(TokenKind::RBracket))
2576 .map(AssignSuffix::Index);
2577
2578 let self_base = just(TokenKind::SelfValue)
2583 .map_with(|_, e| {
2584 Expr::SelfExpr(SelfExpr {
2585 span: span_from_extra(e),
2586 })
2587 })
2588 .boxed();
2589 let ident_base = ident_parser().map(Expr::Ident).boxed();
2590 let assign_base = choice((self_base, ident_base)).boxed();
2591
2592 assign_base
2593 .then(
2594 choice((field_suffix.boxed(), index_suffix.boxed()))
2595 .repeated()
2596 .collect::<Vec<_>>(),
2597 )
2598 .try_map(|(base_expr_init, suffixes), span| {
2599 if suffixes.is_empty() {
2600 return match base_expr_init {
2604 Expr::Ident(ident) => Ok(AssignTarget::Var(ident)),
2605 _ => Err(chumsky::error::Rich::custom(
2606 span,
2607 "cannot assign to `self`",
2608 )),
2609 };
2610 }
2611 let mut base_expr = base_expr_init;
2614 let mut suffixes_iter = suffixes.into_iter().peekable();
2615 while let Some(suffix) = suffixes_iter.next() {
2616 let is_last = suffixes_iter.peek().is_none();
2617 if is_last {
2618 return Ok(match suffix {
2619 AssignSuffix::Field(field) => {
2620 let span = Span::new(base_expr.span().start, field.span.end);
2621 AssignTarget::Field(FieldExpr {
2622 base: Box::new(base_expr),
2623 field,
2624 span,
2625 })
2626 }
2627 AssignSuffix::Index(index) => {
2628 let span = Span::new(base_expr.span().start, index.span().end);
2629 AssignTarget::Index(IndexExpr {
2630 base: Box::new(base_expr),
2631 index: Box::new(index),
2632 span,
2633 })
2634 }
2635 });
2636 }
2637 match suffix {
2639 AssignSuffix::Field(field) => {
2640 let span = Span::new(base_expr.span().start, field.span.end);
2641 base_expr = Expr::Field(FieldExpr {
2642 base: Box::new(base_expr),
2643 field,
2644 span,
2645 });
2646 }
2647 AssignSuffix::Index(index) => {
2648 let span = Span::new(base_expr.span().start, index.span().end);
2649 base_expr = Expr::Index(IndexExpr {
2650 base: Box::new(base_expr),
2651 index: Box::new(index),
2652 span,
2653 });
2654 }
2655 }
2656 }
2657 unreachable!("suffixes was non-empty so the loop must have returned")
2658 })
2659 .boxed()
2660}
2661
2662fn assign_statement_parser<'src, I>(
2665 expr: GruelParser<'src, I, Expr>,
2666) -> GruelParser<'src, I, Statement>
2667where
2668 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
2669{
2670 assign_target_parser(expr.clone())
2671 .then_ignore(just(TokenKind::Eq))
2672 .then(expr)
2673 .then_ignore(just(TokenKind::Semi))
2674 .map_with(|(target, value), e| {
2675 Statement::Assign(AssignStatement {
2676 target,
2677 value: Box::new(value),
2678 span: span_from_extra(e),
2679 })
2680 })
2681 .boxed()
2682}
2683
2684fn is_control_flow_expr(e: &Expr) -> bool {
2694 matches!(
2695 e,
2696 Expr::If(_)
2697 | Expr::Match(_)
2698 | Expr::While(_)
2699 | Expr::For(_)
2700 | Expr::ComptimeUnrollFor(_)
2701 | Expr::Loop(_)
2702 | Expr::Break(_)
2703 | Expr::Continue(_)
2704 | Expr::Return(_)
2705 | Expr::Block(_)
2706 )
2707}
2708
2709fn is_diverging_expr(e: &Expr) -> bool {
2713 matches!(
2714 e,
2715 Expr::Break(_) | Expr::Continue(_) | Expr::Return(_) | Expr::Loop(_)
2716 )
2717}
2718
2719fn block_item_parser<'src, I>(expr: GruelParser<'src, I, Expr>) -> GruelParser<'src, I, BlockItem>
2769where
2770 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
2771{
2772 let let_stmt = let_statement_parser(expr.clone()).map(BlockItem::Statement);
2775
2776 let assign_stmt = assign_statement_parser(expr.clone()).map(BlockItem::Statement);
2780
2781 let expr_item = expr
2789 .then(
2790 choice((
2791 just(TokenKind::Semi).to(ExprFollower::Semi).boxed(),
2792 just(TokenKind::RBrace)
2793 .rewind()
2794 .to(ExprFollower::RBrace)
2795 .boxed(),
2796 any().rewind().to(ExprFollower::Other).boxed(),
2797 ))
2798 .or(end().to(ExprFollower::End)),
2799 )
2800 .try_map(|(e, follower), span| match follower {
2801 ExprFollower::Semi => {
2802 Ok(BlockItem::Statement(Statement::Expr(e)))
2804 }
2805 ExprFollower::RBrace => {
2806 Ok(BlockItem::Expr(e))
2808 }
2809 ExprFollower::Other | ExprFollower::End => {
2810 if is_control_flow_expr(&e) {
2813 Ok(BlockItem::Statement(Statement::Expr(e)))
2814 } else {
2815 Err(Rich::custom(span, "expected semicolon after expression"))
2816 }
2817 }
2818 });
2819
2820 choice((let_stmt.boxed(), assign_stmt.boxed(), expr_item.boxed())).boxed()
2825}
2826
2827fn process_block_items(items: Vec<BlockItem>, block_span: Span) -> (Vec<Statement>, Expr) {
2829 let mut statements = Vec::new();
2830 let mut final_expr = None;
2831
2832 for item in items {
2833 match item {
2834 BlockItem::Statement(stmt) => {
2835 if let Some(e) = final_expr.take() {
2838 statements.push(Statement::Expr(e));
2839 }
2840 statements.push(stmt);
2841 }
2842 BlockItem::Expr(e) => {
2843 if let Some(prev) = final_expr.take() {
2844 statements.push(Statement::Expr(prev));
2847 }
2848 final_expr = Some(e);
2849 }
2850 }
2851 }
2852
2853 let expr = final_expr.unwrap_or_else(|| {
2854 if let Some(Statement::Expr(e)) = statements.last()
2858 && is_diverging_expr(e)
2859 {
2860 let Statement::Expr(e) = statements.pop().unwrap() else {
2862 unreachable!()
2863 };
2864 return e;
2865 }
2866 Expr::Unit(UnitLit {
2868 span: Span::new(block_span.end, block_span.end),
2869 })
2870 });
2871
2872 (statements, expr)
2873}
2874
2875fn maybe_unit_block_parser<'src, I>(
2877 expr: GruelParser<'src, I, Expr>,
2878) -> GruelParser<'src, I, BlockExpr>
2879where
2880 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
2881{
2882 block_item_parser(expr)
2883 .repeated()
2884 .collect::<Vec<_>>()
2885 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace))
2886 .map_with(|items, e| {
2887 let span = span_from_extra(e);
2888 let (statements, final_expr) = process_block_items(items, span);
2889 BlockExpr {
2890 statements,
2891 expr: Box::new(final_expr),
2892 span,
2893 }
2894 })
2895 .boxed()
2896}
2897
2898fn block_parser<'src, I>(expr: GruelParser<'src, I, Expr>) -> GruelParser<'src, I, Expr>
2900where
2901 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
2902{
2903 block_item_parser(expr)
2904 .repeated()
2905 .collect::<Vec<_>>()
2906 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace))
2907 .map_with(|items, e| {
2908 let span = span_from_extra(e);
2909 let (statements, final_expr) = process_block_items(items, span);
2910 Expr::Block(BlockExpr {
2911 statements,
2912 expr: Box::new(final_expr),
2913 span,
2914 })
2915 })
2916 .boxed()
2917}
2918
2919fn function_parser<'src, I>() -> GruelParser<'src, I, Function>
2924where
2925 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
2926{
2927 let expr = expr_parser();
2928
2929 let visibility = just(TokenKind::Pub).or_not().map(|opt| {
2931 if opt.is_some() {
2932 Visibility::Public
2933 } else {
2934 Visibility::Private
2935 }
2936 });
2937
2938 let fn_head: GruelParser<I, (Directives, Visibility)> =
2939 directives_parser().then(visibility).boxed();
2940
2941 let fn_sig: GruelParser<I, (Ident, Vec<Param>)> = just(TokenKind::Fn)
2942 .ignore_then(ident_parser())
2943 .then(params_parser().delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)))
2944 .boxed();
2945
2946 fn_head
2947 .then(fn_sig)
2948 .then(just(TokenKind::Arrow).ignore_then(type_parser()).or_not())
2949 .then(block_parser(expr))
2950 .map_with(
2951 |((((directives, visibility), (name, params)), return_type), body), e| {
2952 let syms = e.state().0.syms;
2953 let is_unchecked = directives_have_mark_unchecked(
2954 &directives,
2955 syms.mark_name,
2956 syms.unchecked_name,
2957 );
2958 Function {
2959 doc: None,
2960 directives,
2961 visibility,
2962 is_unchecked,
2963 name,
2964 params,
2965 return_type,
2966 body,
2967 span: span_from_extra(e),
2968 }
2969 },
2970 )
2971 .boxed()
2972}
2973
2974fn struct_parser<'src, I>() -> GruelParser<'src, I, StructDecl>
2982where
2983 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
2984{
2985 let visibility = just(TokenKind::Pub).or_not().map(|opt| {
2987 if opt.is_some() {
2988 Visibility::Public
2989 } else {
2990 Visibility::Private
2991 }
2992 });
2993
2994 let struct_head: GruelParser<I, (Directives, Visibility, Ident)> = directives_parser()
2997 .then(visibility)
2998 .then(just(TokenKind::Struct).ignore_then(ident_parser()))
2999 .map(|((d, v), name)| (d, v, name))
3000 .boxed();
3001
3002 let struct_body: GruelParser<I, (Vec<FieldDecl>, Vec<Method>)> = field_decls_parser()
3004 .then(method_parser().repeated().collect::<Vec<_>>())
3005 .boxed();
3006
3007 struct_head
3008 .then(struct_body.delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace)))
3009 .map_with(
3010 |((directives, visibility, name), (fields, methods)), e| StructDecl {
3011 doc: None,
3012 directives,
3013 visibility,
3014 posture: Posture::Affine,
3015 name,
3016 fields,
3017 methods,
3018 span: span_from_extra(e),
3019 },
3020 )
3021 .boxed()
3022}
3023
3024fn enum_variant_parser<'src, I>() -> GruelParser<'src, I, EnumVariant>
3026where
3027 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3028{
3029 use crate::ast::{EnumVariantField, EnumVariantKind};
3030
3031 let tuple_fields = type_parser()
3033 .separated_by(just(TokenKind::Comma))
3034 .allow_trailing()
3035 .collect::<Vec<_>>()
3036 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen));
3037
3038 let variant_field_visibility = just(TokenKind::Pub).or_not().map(|opt| {
3040 if opt.is_some() {
3041 Visibility::Public
3042 } else {
3043 Visibility::Private
3044 }
3045 });
3046 let struct_field = variant_field_visibility
3047 .then(ident_parser())
3048 .then_ignore(just(TokenKind::Colon))
3049 .then(type_parser())
3050 .map_with(|((visibility, name), ty), e| EnumVariantField {
3051 doc: None,
3052 visibility,
3053 name,
3054 ty,
3055 span: span_from_extra(e),
3056 });
3057 let struct_fields = struct_field
3058 .separated_by(just(TokenKind::Comma))
3059 .allow_trailing()
3060 .collect::<Vec<_>>()
3061 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace));
3062
3063 let variant_kind = choice((
3065 tuple_fields.map(EnumVariantKind::Tuple),
3066 struct_fields.map(EnumVariantKind::Struct),
3067 ))
3068 .or_not()
3069 .map(|opt| opt.unwrap_or(EnumVariantKind::Unit));
3070
3071 ident_parser()
3072 .then(variant_kind)
3073 .map_with(|(name, kind), e| EnumVariant {
3074 doc: None,
3075 name,
3076 kind,
3077 span: span_from_extra(e),
3078 })
3079 .boxed()
3080}
3081
3082fn enum_variants_parser<'src, I>() -> GruelParser<'src, I, Vec<EnumVariant>>
3084where
3085 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3086{
3087 enum_variant_parser()
3088 .separated_by(just(TokenKind::Comma))
3089 .allow_trailing()
3090 .collect::<Vec<_>>()
3091 .boxed()
3092}
3093
3094fn enum_parser<'src, I>() -> GruelParser<'src, I, EnumDecl>
3102where
3103 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3104{
3105 let visibility = just(TokenKind::Pub).or_not().map(|opt| {
3107 if opt.is_some() {
3108 Visibility::Public
3109 } else {
3110 Visibility::Private
3111 }
3112 });
3113
3114 let enum_body: GruelParser<I, (Vec<EnumVariant>, Vec<Method>)> = enum_variants_parser()
3116 .then(method_parser().repeated().collect::<Vec<_>>())
3117 .boxed();
3118
3119 directives_parser()
3120 .then(visibility)
3121 .then(just(TokenKind::Enum).ignore_then(ident_parser()))
3122 .then(enum_body.delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace)))
3123 .map_with(
3124 |(((directives, visibility), name), (variants, methods)), e| EnumDecl {
3125 doc: None,
3126 directives,
3127 visibility,
3128 posture: Posture::Affine,
3129 name,
3130 variants,
3131 methods,
3132 span: span_from_extra(e),
3133 },
3134 )
3135 .boxed()
3136}
3137
3138fn method_parser<'src, I>() -> GruelParser<'src, I, Method>
3141where
3142 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3143{
3144 let expr = expr_parser();
3145 method_parser_with_expr(expr)
3146}
3147
3148fn anon_struct_method_parser<'src, I>(
3151 expr: GruelParser<'src, I, Expr>,
3152) -> GruelParser<'src, I, Method>
3153where
3154 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3155{
3156 method_parser_with_expr(expr)
3157}
3158
3159fn method_parser_with_expr<'src, I>(
3162 expr: GruelParser<'src, I, Expr>,
3163) -> GruelParser<'src, I, Method>
3164where
3165 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3166{
3167 let self_param = self_param_parser();
3169
3170 let self_then_params = self_param
3172 .then(
3173 just(TokenKind::Comma)
3174 .ignore_then(params_parser())
3175 .or_not()
3176 .map(|opt| opt.unwrap_or_default()),
3177 )
3178 .map(|(self_param, params)| (Some(self_param), params));
3179
3180 let just_params = params_parser().map(|params| (None, params));
3182
3183 let params_with_optional_self: GruelParser<I, (Option<SelfParam>, Vec<Param>)> =
3185 choice((self_then_params.boxed(), just_params.boxed())).boxed();
3186
3187 let method_visibility = just(TokenKind::Pub).or_not().map(|opt| {
3193 if opt.is_some() {
3194 Visibility::Public
3195 } else {
3196 Visibility::Private
3197 }
3198 });
3199 let method_head: GruelParser<I, (Directives, Visibility, Ident)> = directives_parser()
3200 .then(method_visibility)
3201 .then(just(TokenKind::Fn).ignore_then(method_name_parser()))
3202 .map(|((directives, visibility), name)| (directives, visibility, name))
3203 .boxed();
3204
3205 let method_params: GruelParser<I, (Option<SelfParam>, Vec<Param>)> = params_with_optional_self
3206 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen))
3207 .boxed();
3208
3209 let method_return: GruelParser<I, Option<TypeExpr>> = just(TokenKind::Arrow)
3210 .ignore_then(type_parser())
3211 .or_not()
3212 .boxed();
3213
3214 method_head
3215 .then(method_params)
3216 .then(method_return)
3217 .then(block_parser(expr))
3218 .map_with(
3219 |((((directives, visibility, name), (receiver, params)), return_type), body), e| {
3220 let syms = e.state().0.syms;
3221 let is_unchecked = directives_have_mark_unchecked(
3222 &directives,
3223 syms.mark_name,
3224 syms.unchecked_name,
3225 );
3226 Method {
3227 doc: None,
3228 directives,
3229 visibility,
3230 is_unchecked,
3231 name,
3232 receiver,
3233 params,
3234 return_type,
3235 body,
3236 span: span_from_extra(e),
3237 }
3238 },
3239 )
3240 .boxed()
3241}
3242
3243fn const_parser<'src, I>() -> GruelParser<'src, I, ConstDecl>
3251where
3252 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3253{
3254 let expr = expr_parser();
3255
3256 let visibility = just(TokenKind::Pub).or_not().map(|opt| {
3258 if opt.is_some() {
3259 Visibility::Public
3260 } else {
3261 Visibility::Private
3262 }
3263 });
3264
3265 let const_head: GruelParser<I, (Directives, Visibility, Ident)> = directives_parser()
3267 .then(visibility)
3268 .then(just(TokenKind::Const).ignore_then(ident_parser()))
3269 .map(|((d, v), n)| (d, v, n))
3270 .boxed();
3271
3272 let const_tail: GruelParser<I, (Option<TypeExpr>, Expr)> = just(TokenKind::Colon)
3273 .ignore_then(type_parser())
3274 .or_not()
3275 .then(just(TokenKind::Eq).ignore_then(expr))
3276 .then_ignore(just(TokenKind::Semi))
3277 .boxed();
3278
3279 const_head
3280 .then(const_tail)
3281 .map_with(
3282 |((directives, visibility, name), (ty, init)), e| ConstDecl {
3283 doc: None,
3284 directives,
3285 visibility,
3286 name,
3287 ty,
3288 init: Box::new(init),
3289 span: span_from_extra(e),
3290 },
3291 )
3292 .boxed()
3293}
3294
3295fn self_param_parser<'src, I>() -> GruelParser<'src, I, SelfParam>
3304where
3305 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3306{
3307 let typed_byvalue = just(TokenKind::SelfValue)
3308 .then_ignore(just(TokenKind::Colon))
3309 .then_ignore(just(TokenKind::SelfType))
3310 .map_with(|_, e| SelfParam {
3311 kind: SelfReceiverKind::ByValue,
3312 span: span_from_extra(e),
3313 })
3314 .boxed();
3315
3316 let ref_or_mut_ref = any().try_map_with(
3320 |t: TokenKind, e: &mut chumsky::input::MapExtra<I, ParserExtras<'src>>| match t {
3321 TokenKind::Ident(s) => {
3322 let syms = &e.state().syms;
3323 if s == syms.ref_name {
3324 Ok(SelfReceiverKind::Ref)
3325 } else if s == syms.mut_ref_name {
3326 Ok(SelfReceiverKind::MutRef)
3327 } else {
3328 Err(chumsky::error::Rich::custom(
3329 e.span(),
3330 "expected identifier `Ref` or `MutRef`",
3331 ))
3332 }
3333 }
3334 _ => Err(chumsky::error::Rich::custom(
3335 e.span(),
3336 "expected identifier `Ref` or `MutRef`",
3337 )),
3338 },
3339 );
3340
3341 let typed_ref = just(TokenKind::SelfValue)
3342 .then_ignore(just(TokenKind::Colon))
3343 .ignore_then(ref_or_mut_ref)
3344 .then_ignore(just(TokenKind::LParen))
3345 .then_ignore(just(TokenKind::SelfType))
3346 .then_ignore(just(TokenKind::RParen))
3347 .map_with(|kind, e| SelfParam {
3348 kind,
3349 span: span_from_extra(e),
3350 })
3351 .boxed();
3352
3353 let bare_self = just(TokenKind::SelfValue)
3355 .map_with(|_, e| SelfParam {
3356 kind: SelfReceiverKind::ByValue,
3357 span: span_from_extra(e),
3358 })
3359 .boxed();
3360
3361 choice((typed_ref, typed_byvalue, bare_self)).boxed()
3362}
3363
3364fn interface_method_sig_parser<'src, I>() -> GruelParser<'src, I, MethodSig>
3370where
3371 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3372{
3373 let self_param = self_param_parser();
3374
3375 let extra_params = just(TokenKind::Comma)
3376 .ignore_then(params_parser())
3377 .or_not()
3378 .map(|opt| opt.unwrap_or_default());
3379
3380 let receiver_and_params: GruelParser<I, (SelfParam, Vec<Param>)> = self_param
3381 .then(extra_params)
3382 .delimited_by(just(TokenKind::LParen), just(TokenKind::RParen))
3383 .boxed();
3384
3385 directives_parser()
3386 .then_ignore(just(TokenKind::Fn))
3387 .then(method_name_parser())
3388 .then(receiver_and_params)
3389 .then(just(TokenKind::Arrow).ignore_then(type_parser()).or_not())
3390 .then_ignore(just(TokenKind::Semi))
3391 .map_with(
3392 |(((directives, name), (receiver, params)), return_type), e| {
3393 let syms = e.state().0.syms;
3394 let is_unchecked = directives_have_mark_unchecked(
3395 &directives,
3396 syms.mark_name,
3397 syms.unchecked_name,
3398 );
3399 MethodSig {
3400 doc: None,
3401 directives,
3402 is_unchecked,
3403 name,
3404 receiver,
3405 params,
3406 return_type,
3407 span: span_from_extra(e),
3408 }
3409 },
3410 )
3411 .boxed()
3412}
3413
3414fn interface_parser<'src, I>() -> GruelParser<'src, I, InterfaceDecl>
3423where
3424 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3425{
3426 let visibility = just(TokenKind::Pub).or_not().map(|opt| {
3427 if opt.is_some() {
3428 Visibility::Public
3429 } else {
3430 Visibility::Private
3431 }
3432 });
3433
3434 let body = interface_method_sig_parser()
3435 .repeated()
3436 .collect::<Vec<_>>()
3437 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace))
3438 .boxed();
3439
3440 directives_parser()
3441 .then(visibility)
3442 .then(just(TokenKind::Interface).ignore_then(ident_parser()))
3443 .then(body)
3444 .map_with(
3445 |(((directives, visibility), name), methods), e| InterfaceDecl {
3446 doc: None,
3447 directives,
3448 visibility,
3449 name,
3450 methods,
3451 span: span_from_extra(e),
3452 },
3453 )
3454 .boxed()
3455}
3456
3457fn derive_parser<'src, I>() -> GruelParser<'src, I, DeriveDecl>
3466where
3467 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3468{
3469 let body = method_parser()
3470 .repeated()
3471 .collect::<Vec<_>>()
3472 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace))
3473 .boxed();
3474
3475 just(TokenKind::Derive)
3476 .ignore_then(ident_parser())
3477 .then(body)
3478 .map_with(|(name, methods), e| DeriveDecl {
3479 doc: None,
3480 name,
3481 methods,
3482 span: span_from_extra(e),
3483 })
3484 .boxed()
3485}
3486
3487fn extern_fn_parser<'src, I>() -> GruelParser<'src, I, crate::ast::ExternFn>
3496where
3497 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3498{
3499 directives_parser()
3500 .then(just(TokenKind::Fn).ignore_then(ident_parser()))
3501 .then(params_parser().delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)))
3502 .then(just(TokenKind::Arrow).ignore_then(type_parser()).or_not())
3503 .then_ignore(just(TokenKind::Semi))
3504 .map_with(
3505 |(((directives, name), params), return_type), e| crate::ast::ExternFn {
3506 doc: None,
3507 directives,
3508 name,
3509 params,
3510 return_type,
3511 span: span_from_extra(e),
3512 },
3513 )
3514 .boxed()
3515}
3516
3517fn link_extern_parser<'src, I>() -> GruelParser<'src, I, crate::ast::LinkExternBlock>
3520where
3521 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3522{
3523 let library = select! {
3524 TokenKind::String(s) = e => StringLit {
3525 value: s,
3526 span: span_from_extra(e),
3527 },
3528 }
3529 .boxed();
3530
3531 let mode_keyword = choice((
3532 just(TokenKind::LinkExtern).to(crate::ast::LinkMode::Dynamic),
3533 just(TokenKind::StaticLinkExtern).to(crate::ast::LinkMode::Static),
3534 ))
3535 .boxed();
3536
3537 mode_keyword
3538 .then(library.delimited_by(just(TokenKind::LParen), just(TokenKind::RParen)))
3539 .then(
3540 extern_fn_parser()
3541 .repeated()
3542 .collect::<Vec<_>>()
3543 .delimited_by(just(TokenKind::LBrace), just(TokenKind::RBrace)),
3544 )
3545 .map_with(
3546 |((link_mode, library), items), e| crate::ast::LinkExternBlock {
3547 doc: None,
3548 library,
3549 items,
3550 link_mode,
3551 span: span_from_extra(e),
3552 },
3553 )
3554 .boxed()
3555}
3556
3557fn item_parser<'src, I>() -> GruelParser<'src, I, Item>
3558where
3559 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3560{
3561 choice((
3562 function_parser().map(Item::Function).boxed(),
3563 struct_parser().map(Item::Struct).boxed(),
3564 enum_parser().map(Item::Enum).boxed(),
3565 interface_parser().map(Item::Interface).boxed(),
3566 derive_parser().map(Item::Derive).boxed(),
3567 const_parser().map(Item::Const).boxed(),
3568 link_extern_parser().map(Item::LinkExtern).boxed(),
3569 ))
3570 .boxed()
3571}
3572
3573fn item_start<'src, I>() -> GruelParser<'src, I, ()>
3576where
3577 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3578{
3579 let item_start_a: GruelParser<'src, I, ()> = choice((
3582 just(TokenKind::Fn).ignored().boxed(),
3583 just(TokenKind::Struct).ignored().boxed(),
3584 just(TokenKind::Enum).ignored().boxed(),
3585 just(TokenKind::Interface).ignored().boxed(),
3586 just(TokenKind::Derive).ignored().boxed(),
3587 just(TokenKind::Const).ignored().boxed(),
3588 just(TokenKind::LinkExtern).ignored().boxed(),
3589 ))
3590 .boxed();
3591 let item_start_b: GruelParser<'src, I, ()> = choice((
3592 just(TokenKind::Pub).ignored().boxed(),
3593 just(TokenKind::At).ignored().boxed(), ))
3595 .boxed();
3596 choice((item_start_a, item_start_b))
3597 .rewind() .boxed()
3599}
3600
3601fn error_recovery<'src, I>() -> GruelParser<'src, I, Item>
3605where
3606 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3607{
3608 any()
3610 .map_with(|_, extra| extra.span())
3611 .then(
3613 any()
3614 .and_is(item_start().not())
3615 .repeated()
3616 .collect::<Vec<_>>(),
3617 )
3618 .map(|(start_span, _): (SimpleSpan, Vec<TokenKind>)| {
3619 Item::Error(to_gruel_util(start_span))
3621 })
3622 .boxed()
3623}
3624
3625fn item_with_recovery<'src, I>() -> GruelParser<'src, I, Item>
3629where
3630 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3631{
3632 item_parser()
3633 .recover_with(via_parser(error_recovery()))
3634 .boxed()
3635}
3636
3637fn ast_parser<'src, I>() -> GruelParser<'src, I, Ast>
3639where
3640 I: ValueInput<'src, Token = TokenKind, Span = SimpleSpan>,
3641{
3642 item_with_recovery()
3643 .repeated()
3644 .collect::<Vec<_>>()
3645 .then_ignore(end())
3646 .map(|items| Ast {
3647 module_doc: None,
3648 items,
3649 })
3650 .boxed()
3651}
3652
3653fn format_pattern(pattern: &chumsky::error::RichPattern<'_, TokenKind>) -> String {
3655 use chumsky::error::RichPattern;
3656 match pattern {
3657 RichPattern::Token(tok) => tok.name().to_string(),
3658 RichPattern::Label(label) => label.to_string(),
3659 RichPattern::Identifier(ident) => format!("'{}'", ident),
3660 RichPattern::Any => "any token".to_string(),
3661 RichPattern::SomethingElse => "something else".to_string(),
3662 RichPattern::EndOfInput => "end of input".to_string(),
3663 }
3664}
3665
3666fn convert_error(err: Rich<'_, TokenKind>) -> CompileError {
3668 let span = to_gruel_util(*err.span());
3669
3670 let mut error = match err.reason() {
3672 chumsky::error::RichReason::ExpectedFound { expected, found } => {
3673 let expected_str: Cow<'static, str> = if expected.is_empty() {
3674 Cow::Borrowed("something")
3675 } else {
3676 Cow::Owned(
3677 expected
3678 .iter()
3679 .take(3) .map(format_pattern)
3681 .collect::<Vec<_>>()
3682 .join(" or "),
3683 )
3684 };
3685
3686 let found_str: Cow<'static, str> = match found.as_ref() {
3687 Some(t) => Cow::Owned(t.name().to_string()),
3688 None => Cow::Borrowed("end of file"),
3689 };
3690
3691 CompileError::new(
3692 ErrorKind::UnexpectedToken {
3693 expected: expected_str,
3694 found: found_str,
3695 },
3696 span,
3697 )
3698 }
3699 chumsky::error::RichReason::Custom(msg) => {
3700 CompileError::new(ErrorKind::ParseError(msg.clone()), span)
3702 }
3703 };
3704
3705 for (pattern, ctx_span) in err.contexts() {
3707 let label_msg = format!("while parsing {}", format_pattern(pattern));
3708 let label_span = to_gruel_util(*ctx_span);
3709 error = error.with_label(label_msg, label_span);
3710 }
3711
3712 error
3713}
3714
3715pub struct ChumskyParser {
3717 tokens: Vec<(TokenKind, SimpleSpan)>,
3718 raw_tokens: Vec<gruel_lexer::Token>,
3721 source_len: usize,
3722 interner: ThreadedRodeo,
3723 file_id: FileId,
3725 preview_features: PreviewFeatures,
3731 source: Option<String>,
3734}
3735
3736impl ChumskyParser {
3737 pub fn new(tokens: Vec<gruel_lexer::Token>, interner: ThreadedRodeo) -> Self {
3739 let source_len = tokens.last().map(|t| t.span.end as usize).unwrap_or(0);
3740 let file_id = tokens
3742 .first()
3743 .map(|t| t.span.file_id)
3744 .unwrap_or(FileId::DEFAULT);
3745
3746 let raw_tokens = tokens.clone();
3747 let spanned_tokens: Vec<(TokenKind, SimpleSpan)> = tokens
3748 .into_iter()
3749 .filter(|t| t.kind != TokenKind::Eof) .filter(|t| !matches!(t.kind, TokenKind::LineDoc(_)))
3753 .map(|t| {
3754 (
3755 t.kind,
3756 SimpleSpan::new(t.span.start as usize, t.span.end as usize),
3757 )
3758 })
3759 .collect();
3760 Self {
3761 tokens: spanned_tokens,
3762 raw_tokens,
3763 source_len,
3764 interner,
3765 file_id,
3766 preview_features: PreviewFeatures::default(),
3767 source: None,
3768 }
3769 }
3770
3771 pub fn with_preview_features(mut self, features: PreviewFeatures) -> Self {
3774 self.preview_features = features;
3775 self
3776 }
3777
3778 pub fn with_source(mut self, source: impl Into<String>) -> Self {
3782 self.source = Some(source.into());
3783 self
3784 }
3785
3786 pub fn parse(mut self) -> MultiErrorResult<(Ast, ThreadedRodeo)> {
3790 let syms = PrimitiveTypeSpurs::new(&mut self.interner);
3792 let parser_state = ParserState::new(syms, self.file_id);
3793 let mut state = SimpleState(parser_state);
3794
3795 let token_iter = self.tokens.iter().cloned();
3797 let stream = Stream::from_iter(token_iter);
3798
3799 let eoi: SimpleSpan = (self.source_len..self.source_len).into();
3801 let mapped = stream.map(eoi, |(tok, span)| (tok, span));
3802
3803 let mut ast = ast_parser()
3804 .parse_with_state(mapped, &mut state)
3805 .into_result()
3806 .map_err(|errs| {
3807 let errors: Vec<CompileError> = errs.into_iter().map(convert_error).collect();
3808 CompileErrors::from(errors)
3809 })?;
3810
3811 let mut errors = Vec::new();
3815 let validator = AstValidator;
3816 validator.walk_ast(&ast, &mut errors);
3817 if !errors.is_empty() {
3818 return Err(CompileErrors::from(errors));
3819 }
3820
3821 if let Some(ref source) = self.source {
3825 let mut doc_errors = Vec::new();
3826 attach_docs(
3827 &mut ast,
3828 &self.raw_tokens,
3829 source,
3830 self.file_id,
3831 &self.interner,
3832 &mut doc_errors,
3833 );
3834 if !doc_errors.is_empty() {
3835 return Err(CompileErrors::from(doc_errors));
3836 }
3837 }
3838
3839 Ok((ast, self.interner))
3840 }
3841}
3842
3843#[derive(Debug, Clone)]
3845struct DocBlock {
3846 body: String,
3849 span: Span,
3851 start_line: usize,
3853 end_line: usize,
3855}
3856
3857fn collect_doc_blocks(
3863 raw_tokens: &[gruel_lexer::Token],
3864 line_index: &LineIndex,
3865 interner: &ThreadedRodeo,
3866) -> Vec<DocBlock> {
3867 let mut blocks: Vec<DocBlock> = Vec::new();
3868 let mut current_lines: Vec<&str> = Vec::new();
3869 let mut current_span: Option<Span> = None;
3870 let mut current_start_line: usize = 0;
3871 let mut current_end_line: usize = 0;
3872 let mut last_was_doc = false;
3873
3874 for tok in raw_tokens {
3875 match tok.kind {
3876 TokenKind::LineDoc(spur) => {
3877 let line = line_index.span_line_number(tok.span);
3878 let body = interner.resolve(&spur);
3879 if last_was_doc && line == current_end_line + 1 {
3880 current_lines.push(body);
3881 current_end_line = line;
3882 current_span = current_span.map(|s| Span::cover(s, tok.span));
3883 } else {
3884 if let (Some(span), false) = (current_span, current_lines.is_empty()) {
3885 blocks.push(DocBlock {
3886 body: current_lines.join("\n"),
3887 span,
3888 start_line: current_start_line,
3889 end_line: current_end_line,
3890 });
3891 }
3892 current_lines = vec![body];
3893 current_span = Some(tok.span);
3894 current_start_line = line;
3895 current_end_line = line;
3896 }
3897 last_was_doc = true;
3898 }
3899 TokenKind::Eof => {}
3900 _ => {
3901 if let (Some(span), false) = (current_span, current_lines.is_empty()) {
3902 blocks.push(DocBlock {
3903 body: current_lines.join("\n"),
3904 span,
3905 start_line: current_start_line,
3906 end_line: current_end_line,
3907 });
3908 current_lines = Vec::new();
3909 current_span = None;
3910 }
3911 last_was_doc = false;
3912 }
3913 }
3914 }
3915 if let (Some(span), false) = (current_span, current_lines.is_empty()) {
3916 blocks.push(DocBlock {
3917 body: current_lines.join("\n"),
3918 span,
3919 start_line: current_start_line,
3920 end_line: current_end_line,
3921 });
3922 }
3923 blocks
3924}
3925
3926fn attach_docs(
3930 ast: &mut Ast,
3931 raw_tokens: &[gruel_lexer::Token],
3932 source: &str,
3933 file_id: FileId,
3934 interner: &ThreadedRodeo,
3935 errors: &mut Vec<CompileError>,
3936) {
3937 let line_index = LineIndex::new(source);
3938 let blocks = collect_doc_blocks(raw_tokens, &line_index, interner);
3939 if blocks.is_empty() {
3940 return;
3941 }
3942
3943 let first_non_doc_line: Option<usize> = raw_tokens
3947 .iter()
3948 .find(|t| !matches!(t.kind, TokenKind::LineDoc(_) | TokenKind::Eof))
3949 .map(|t| line_index.span_line_number(t.span));
3950
3951 let mut token_line_by_start: HashMap<u32, usize> = HashMap::new();
3954 for tok in raw_tokens {
3955 if matches!(tok.kind, TokenKind::LineDoc(_) | TokenKind::Eof) {
3956 continue;
3957 }
3958 token_line_by_start.insert(tok.span.start, line_index.span_line_number(tok.span));
3959 }
3960
3961 let mut module_doc_assigned = false;
3966 let mut item_docs: HashMap<u32, Doc> = HashMap::new();
3968
3969 for (idx, block) in blocks.iter().enumerate() {
3970 let is_first_block = idx == 0;
3971 let no_item_above = match first_non_doc_line {
3972 None => true,
3973 Some(line) => line >= block.start_line,
3974 };
3975 let qualifies_as_module = is_first_block && no_item_above;
3976
3977 let next_non_doc = raw_tokens.iter().find(|t| {
3980 !matches!(t.kind, TokenKind::LineDoc(_) | TokenKind::Eof)
3981 && t.span.start > block.span.end
3982 });
3983 let glued = next_non_doc
3984 .map(|t| line_index.span_line_number(t.span) == block.end_line + 1)
3985 .unwrap_or(false);
3986
3987 let doc = Doc {
3988 body: block.body.clone(),
3989 span: with_file(block.span, file_id),
3990 };
3991
3992 if qualifies_as_module && !glued {
3993 if !module_doc_assigned {
3995 ast.module_doc = Some(doc);
3996 module_doc_assigned = true;
3997 }
3998 continue;
3999 }
4000
4001 if glued {
4002 let target = next_non_doc.expect("glued implies next token exists");
4005 item_docs.insert(target.span.start, doc);
4006 continue;
4007 }
4008
4009 let span_in_file = with_file(block.span, file_id);
4011 errors.push(CompileError::new(
4012 ErrorKind::ParseError(
4013 "doc comment must be immediately followed by an item".to_string(),
4014 ),
4015 span_in_file,
4016 ));
4017 }
4018
4019 if !item_docs.is_empty() {
4021 distribute_docs_to_items(ast, &mut item_docs);
4022 }
4023}
4024
4025fn with_file(span: Span, file_id: FileId) -> Span {
4028 Span::with_file(file_id, span.start, span.end)
4029}
4030
4031fn distribute_docs_to_items(ast: &mut Ast, item_docs: &mut HashMap<u32, Doc>) {
4035 for item in &mut ast.items {
4036 match item {
4037 Item::Function(f) => {
4038 attach_if_match(&mut f.doc, item_docs, f.span.start);
4039 }
4040 Item::Struct(s) => {
4041 attach_if_match(&mut s.doc, item_docs, s.span.start);
4042 for field in &mut s.fields {
4043 attach_if_match(&mut field.doc, item_docs, field.span.start);
4044 }
4045 for method in &mut s.methods {
4046 attach_if_match(&mut method.doc, item_docs, method.span.start);
4047 }
4048 }
4049 Item::Enum(e) => {
4050 attach_if_match(&mut e.doc, item_docs, e.span.start);
4051 for variant in &mut e.variants {
4052 attach_if_match(&mut variant.doc, item_docs, variant.span.start);
4053 if let crate::ast::EnumVariantKind::Struct(fields) = &mut variant.kind {
4054 for field in fields {
4055 attach_if_match(&mut field.doc, item_docs, field.span.start);
4056 }
4057 }
4058 }
4059 for method in &mut e.methods {
4060 attach_if_match(&mut method.doc, item_docs, method.span.start);
4061 }
4062 }
4063 Item::Interface(i) => {
4064 attach_if_match(&mut i.doc, item_docs, i.span.start);
4065 for sig in &mut i.methods {
4066 attach_if_match(&mut sig.doc, item_docs, sig.span.start);
4067 }
4068 }
4069 Item::Derive(d) => {
4070 attach_if_match(&mut d.doc, item_docs, d.span.start);
4071 for method in &mut d.methods {
4072 attach_if_match(&mut method.doc, item_docs, method.span.start);
4073 }
4074 }
4075 Item::Const(c) => {
4076 attach_if_match(&mut c.doc, item_docs, c.span.start);
4077 }
4078 Item::LinkExtern(b) => {
4079 attach_if_match(&mut b.doc, item_docs, b.span.start);
4080 for fn_decl in &mut b.items {
4081 attach_if_match(&mut fn_decl.doc, item_docs, fn_decl.span.start);
4082 }
4083 }
4084 Item::Error(_) => {}
4085 }
4086 }
4087}
4088
4089fn attach_if_match(slot: &mut Option<Doc>, item_docs: &mut HashMap<u32, Doc>, key: u32) {
4090 if let Some(doc) = item_docs.remove(&key) {
4091 *slot = Some(doc);
4092 }
4093}
4094
4095struct AstValidator;
4100
4101impl AstValidator {
4102 fn walk_ast(&self, ast: &Ast, errors: &mut Vec<CompileError>) {
4103 for item in &ast.items {
4104 validate_item(item, errors, self);
4105 }
4106 }
4107}
4108
4109fn is_refutable(pat: &Pattern) -> bool {
4112 match pat {
4113 Pattern::Wildcard(_) => false,
4114 Pattern::Ident { .. } => false,
4115 Pattern::Int(_) | Pattern::NegInt(_) | Pattern::Bool(_) => true,
4116 Pattern::Path(_) => true,
4117 Pattern::DataVariant { .. } | Pattern::StructVariant { .. } => true,
4120 Pattern::Struct { fields, .. } => fields.iter().any(|f| {
4121 f.sub.as_ref().is_some_and(is_refutable)
4123 }),
4124 Pattern::Tuple { elems, .. } => elems.iter().any(|e| match e {
4125 TupleElemPattern::Pattern(p) => is_refutable(p),
4126 TupleElemPattern::Rest(_) => false,
4127 }),
4128 Pattern::ComptimeUnrollArm { .. } => true,
4131 }
4132}
4133
4134fn validate_item(item: &Item, errors: &mut Vec<CompileError>, v: &AstValidator) {
4135 match item {
4136 Item::Function(f) => validate_expr(&f.body, errors, v),
4137 Item::Struct(s) => {
4138 for m in &s.methods {
4139 validate_expr(&m.body, errors, v);
4140 }
4141 }
4142 Item::Enum(e) => {
4143 for m in &e.methods {
4144 validate_expr(&m.body, errors, v);
4145 }
4146 }
4147 Item::Const(c) => validate_expr(&c.init, errors, v),
4148 Item::Interface(_) => {}
4149 Item::Derive(d) => {
4150 for m in &d.methods {
4151 validate_expr(&m.body, errors, v);
4152 }
4153 }
4154 Item::LinkExtern(_) => {
4155 }
4157 Item::Error(_) => {}
4158 }
4159}
4160
4161fn validate_block(block: &crate::ast::BlockExpr, errors: &mut Vec<CompileError>, v: &AstValidator) {
4162 use crate::ast::AssignTarget;
4163 for stmt in &block.statements {
4164 match stmt {
4165 Statement::Let(l) => {
4166 validate_let_pattern(&l.pattern, errors, v);
4167 validate_expr(&l.init, errors, v);
4168 }
4169 Statement::Assign(a) => {
4170 validate_expr(&a.value, errors, v);
4171 match &a.target {
4172 AssignTarget::Var(_) => {}
4173 AssignTarget::Field(f) => validate_expr(&f.base, errors, v),
4174 AssignTarget::Index(i) => {
4175 validate_expr(&i.base, errors, v);
4176 validate_expr(&i.index, errors, v);
4177 }
4178 }
4179 }
4180 Statement::Expr(e) => validate_expr(e, errors, v),
4181 }
4182 }
4183 validate_expr(&block.expr, errors, v);
4184}
4185
4186fn validate_expr(expr: &Expr, errors: &mut Vec<CompileError>, v: &AstValidator) {
4187 use crate::ast::IntrinsicArg;
4188 match expr {
4189 Expr::Block(b) => validate_block(b, errors, v),
4190 Expr::Match(m) => {
4191 validate_expr(&m.scrutinee, errors, v);
4192 for arm in &m.arms {
4193 validate_match_pattern(&arm.pattern, errors, v);
4194 validate_expr(&arm.body, errors, v);
4195 }
4196 }
4197 Expr::If(i) => {
4198 validate_expr(&i.cond, errors, v);
4199 validate_block(&i.then_block, errors, v);
4200 if let Some(e) = &i.else_block {
4201 validate_block(e, errors, v);
4202 }
4203 }
4204 Expr::While(w) => {
4205 validate_expr(&w.cond, errors, v);
4206 validate_block(&w.body, errors, v);
4207 }
4208 Expr::For(f) => {
4209 validate_expr(&f.iterable, errors, v);
4210 validate_block(&f.body, errors, v);
4211 }
4212 Expr::Loop(l) => validate_block(&l.body, errors, v),
4213 Expr::Binary(b) => {
4214 validate_expr(&b.left, errors, v);
4215 validate_expr(&b.right, errors, v);
4216 }
4217 Expr::Unary(u) => validate_expr(&u.operand, errors, v),
4218 Expr::Call(c) => {
4219 for arg in &c.args {
4220 validate_expr(&arg.expr, errors, v);
4221 }
4222 }
4223 Expr::IntrinsicCall(i) => {
4224 for arg in &i.args {
4225 if let IntrinsicArg::Expr(e) = arg {
4226 validate_expr(e, errors, v);
4227 }
4228 }
4229 }
4230 Expr::MethodCall(m) => {
4231 validate_expr(&m.receiver, errors, v);
4232 for arg in &m.args {
4233 validate_expr(&arg.expr, errors, v);
4234 }
4235 }
4236 Expr::AssocFnCall(a) => {
4237 for arg in &a.args {
4238 validate_expr(&arg.expr, errors, v);
4239 }
4240 }
4241 Expr::Field(f) => validate_expr(&f.base, errors, v),
4242 Expr::TupleIndex(t) => validate_expr(&t.base, errors, v),
4243 Expr::Index(i) => {
4244 validate_expr(&i.base, errors, v);
4245 validate_expr(&i.index, errors, v);
4246 }
4247 Expr::Return(r) => {
4248 if let Some(val) = &r.value {
4249 validate_expr(val, errors, v);
4250 }
4251 }
4252 Expr::Paren(p) => validate_expr(&p.inner, errors, v),
4253 Expr::StructLit(s) => {
4254 for f in &s.fields {
4255 validate_expr(&f.value, errors, v);
4256 }
4257 }
4258 Expr::EnumStructLit(s) => {
4259 for f in &s.fields {
4260 validate_expr(&f.value, errors, v);
4261 }
4262 }
4263 Expr::ArrayLit(a) => {
4264 for e in &a.elements {
4265 validate_expr(e, errors, v);
4266 }
4267 }
4268 Expr::Tuple(t) => {
4269 for e in &t.elems {
4270 validate_expr(e, errors, v);
4271 }
4272 }
4273 Expr::Comptime(c) => validate_expr(&c.expr, errors, v),
4274 Expr::AnonFn(a) => validate_block(&a.body, errors, v),
4275 Expr::Range(r) => {
4276 if let Some(lo) = &r.lo {
4277 validate_expr(lo, errors, v);
4278 }
4279 if let Some(hi) = &r.hi {
4280 validate_expr(hi, errors, v);
4281 }
4282 }
4283 Expr::ComptimeUnrollFor(_) | Expr::Checked(_) => {}
4284 Expr::TypeLit(_)
4285 | Expr::Int(_)
4286 | Expr::Float(_)
4287 | Expr::String(_)
4288 | Expr::Char(_)
4289 | Expr::Bool(_)
4290 | Expr::Unit(_)
4291 | Expr::Ident(_)
4292 | Expr::Path(_)
4293 | Expr::SelfExpr(_)
4294 | Expr::Break(_)
4295 | Expr::Continue(_)
4296 | Expr::Error(_) => {}
4297 }
4298}
4299
4300fn validate_let_pattern(pat: &Pattern, errors: &mut Vec<CompileError>, _v: &AstValidator) {
4308 if is_refutable(pat) {
4309 errors.push(CompileError::new(
4310 ErrorKind::RefutablePatternInLet,
4311 refutable_focus_span(pat),
4312 ));
4313 }
4314}
4315
4316fn validate_match_pattern(_pat: &Pattern, _errors: &mut Vec<CompileError>, _v: &AstValidator) {}
4319
4320fn refutable_focus_span(pat: &Pattern) -> Span {
4323 match pat {
4324 Pattern::Int(l) => l.span,
4325 Pattern::NegInt(l) => l.span,
4326 Pattern::Bool(l) => l.span,
4327 Pattern::Path(p) => p.span,
4328 Pattern::DataVariant { span, .. } | Pattern::StructVariant { span, .. } => *span,
4329 Pattern::Struct { fields, .. } => fields
4330 .iter()
4331 .filter_map(|f| f.sub.as_ref())
4332 .find(|sub| is_refutable(sub))
4333 .map(refutable_focus_span)
4334 .unwrap_or(pat.span()),
4335 Pattern::Tuple { elems, .. } => elems
4336 .iter()
4337 .filter_map(|e| match e {
4338 TupleElemPattern::Pattern(p) if is_refutable(p) => Some(p),
4339 _ => None,
4340 })
4341 .next()
4342 .map(refutable_focus_span)
4343 .unwrap_or(pat.span()),
4344 Pattern::Wildcard(_) | Pattern::Ident { .. } => pat.span(),
4345 Pattern::ComptimeUnrollArm { span, .. } => *span,
4346 }
4347}
4348
4349#[cfg(test)]
4356mod tests {
4357 use super::*;
4358 use gruel_lexer::Lexer;
4359
4360 #[derive(Debug)]
4363 struct ParseResult {
4364 ast: Ast,
4365 interner: ThreadedRodeo,
4366 }
4367
4368 impl ParseResult {
4369 fn get(&self, sym: Spur) -> &str {
4371 self.interner.resolve(&sym)
4372 }
4373 }
4374
4375 #[derive(Debug)]
4377 struct ExprResult {
4378 expr: Expr,
4379 interner: ThreadedRodeo,
4380 }
4381
4382 impl ExprResult {
4383 fn get(&self, sym: Spur) -> &str {
4385 self.interner.resolve(&sym)
4386 }
4387 }
4388
4389 fn parse(source: &str) -> MultiErrorResult<ParseResult> {
4390 let lexer = Lexer::new(source);
4391 let (tokens, interner) = lexer.tokenize().map_err(CompileErrors::from)?;
4392 let parser = ChumskyParser::new(tokens, interner);
4393 let (ast, interner) = parser.parse()?;
4394 Ok(ParseResult { ast, interner })
4395 }
4396
4397 fn parse_expr(source: &str) -> MultiErrorResult<ExprResult> {
4398 let result = parse(&format!("fn main() -> i32 {{ {} }}", source))?;
4399 let interner = result.interner;
4400 let expr = match result.ast.items.into_iter().next().unwrap() {
4401 Item::Function(f) => match f.body {
4402 Expr::Block(block) => *block.expr,
4403 other => other,
4404 },
4405 Item::Struct(_) => panic!("parse_expr helper should only be used with functions"),
4406 Item::Enum(_) => panic!("parse_expr helper should only be used with functions"),
4407 Item::Interface(_) => panic!("parse_expr helper should only be used with functions"),
4408 Item::Derive(_) => panic!("parse_expr helper should only be used with functions"),
4409 Item::Const(_) => panic!("parse_expr helper should only be used with functions"),
4410 Item::LinkExtern(_) => {
4411 panic!("parse_expr helper should only be used with functions")
4412 }
4413 Item::Error(_) => panic!("parse_expr helper should only be used with functions"),
4414 };
4415 Ok(ExprResult { expr, interner })
4416 }
4417
4418 #[test]
4419 fn test_chumsky_parse_main() {
4420 let result = parse("fn main() -> i32 { 42 }").unwrap();
4421
4422 assert_eq!(result.ast.items.len(), 1);
4423 match &result.ast.items[0] {
4424 Item::Function(f) => {
4425 assert_eq!(result.get(f.name.name), "main");
4426 match f.return_type.as_ref().unwrap() {
4427 TypeExpr::Named(ident) => assert_eq!(result.get(ident.name), "i32"),
4428 _ => panic!("expected Named type"),
4429 }
4430 match &f.body {
4431 Expr::Block(block) => match block.expr.as_ref() {
4432 Expr::Int(lit) => assert_eq!(lit.value, 42),
4433 _ => panic!("expected Int"),
4434 },
4435 _ => panic!("expected Block"),
4436 }
4437 }
4438 Item::Struct(_) => panic!("expected Function"),
4439 Item::Enum(_) => panic!("expected Function"),
4440 Item::Interface(_) => panic!("expected Function"),
4441 Item::Derive(_) => panic!("expected Function"),
4442 Item::Const(_) => panic!("expected Function"),
4443 Item::LinkExtern(_) => panic!("expected Function"),
4444 Item::Error(_) => panic!("expected Function"),
4445 }
4446 }
4447
4448 #[test]
4449 fn test_chumsky_parse_addition() {
4450 let result = parse_expr("1 + 2").unwrap();
4451 match result.expr {
4452 Expr::Binary(bin) => {
4453 assert!(matches!(bin.op, BinaryOp::Add));
4454 match (*bin.left, *bin.right) {
4455 (Expr::Int(l), Expr::Int(r)) => {
4456 assert_eq!(l.value, 1);
4457 assert_eq!(r.value, 2);
4458 }
4459 _ => panic!("expected Int operands"),
4460 }
4461 }
4462 _ => panic!("expected Binary"),
4463 }
4464 }
4465
4466 #[test]
4467 fn test_chumsky_parse_precedence() {
4468 let result = parse_expr("1 + 2 * 3").unwrap();
4470 match result.expr {
4471 Expr::Binary(bin) => {
4472 assert!(matches!(bin.op, BinaryOp::Add));
4473 match *bin.left {
4474 Expr::Int(l) => assert_eq!(l.value, 1),
4475 _ => panic!("expected Int"),
4476 }
4477 match *bin.right {
4478 Expr::Binary(inner) => {
4479 assert!(matches!(inner.op, BinaryOp::Mul));
4480 }
4481 _ => panic!("expected Binary"),
4482 }
4483 }
4484 _ => panic!("expected Binary"),
4485 }
4486 }
4487
4488 #[test]
4489 fn test_chumsky_parse_let_binding() {
4490 let result = parse("fn main() -> i32 { let x = 42; x }").unwrap();
4491 match &result.ast.items[0] {
4492 Item::Function(f) => match &f.body {
4493 Expr::Block(block) => {
4494 assert_eq!(block.statements.len(), 1);
4495 match &block.statements[0] {
4496 Statement::Let(let_stmt) => {
4497 assert!(!let_stmt.is_mut);
4498 match &let_stmt.pattern {
4499 Pattern::Ident { name, .. } => {
4500 assert_eq!(result.get(name.name), "x")
4501 }
4502 other => panic!("expected Ident, got {:?}", other),
4503 }
4504 }
4505 _ => panic!("expected Let"),
4506 }
4507 }
4508 _ => panic!("expected Block"),
4509 },
4510 Item::Struct(_) => panic!("expected Function"),
4511 Item::Enum(_) => panic!("expected Function"),
4512 Item::Interface(_) => panic!("expected Function"),
4513 Item::Derive(_) => panic!("expected Function"),
4514 Item::Const(_) => panic!("expected Function"),
4515 Item::LinkExtern(_) => panic!("expected Function"),
4516 Item::Error(_) => panic!("expected Function"),
4517 }
4518 }
4519
4520 #[test]
4521 fn test_while_simple() {
4522 let result = parse("fn main() -> i32 { while true { } 0 }").unwrap();
4524 assert_eq!(result.ast.items.len(), 1);
4525 }
4526
4527 #[test]
4528 fn test_while_with_statement() {
4529 let result = parse("fn main() -> i32 { while true { x = 1; } 0 }").unwrap();
4531 assert_eq!(result.ast.items.len(), 1);
4532 }
4533
4534 #[test]
4535 fn test_function_calls() {
4536 let result =
4537 parse("fn add(a: i32, b: i32) -> i32 { a + b } fn main() -> i32 { add(1, 2) }")
4538 .unwrap();
4539 assert_eq!(result.ast.items.len(), 2);
4540 }
4541
4542 #[test]
4543 fn test_if_else() {
4544 let result = parse("fn main() -> i32 { if true { 1 } else { 0 } }").unwrap();
4545 assert_eq!(result.ast.items.len(), 1);
4546 }
4547
4548 #[test]
4549 fn test_nested_control_flow() {
4550 let result =
4551 parse("fn main() -> i32 { let mut x = 0; while x < 10 { x = x + 1; } x }").unwrap();
4552 assert_eq!(result.ast.items.len(), 1);
4553 }
4554
4555 #[test]
4558 fn test_struct_with_single_method() {
4559 let result = parse("struct Point { x: i32, fn get_x(self) -> i32 { self.x } }").unwrap();
4560 assert_eq!(result.ast.items.len(), 1);
4561 match &result.ast.items[0] {
4562 Item::Struct(struct_decl) => {
4563 assert_eq!(result.get(struct_decl.name.name), "Point");
4564 assert_eq!(struct_decl.methods.len(), 1);
4565 let method = &struct_decl.methods[0];
4566 assert_eq!(result.get(method.name.name), "get_x");
4567 assert!(method.receiver.is_some()); assert!(method.params.is_empty()); }
4570 _ => panic!("expected Struct"),
4571 }
4572 }
4573
4574 #[test]
4575 fn test_struct_method_with_params() {
4576 let result =
4577 parse("struct Point { x: i32, fn add(self, n: i32) -> i32 { self.x + n } }").unwrap();
4578 assert_eq!(result.ast.items.len(), 1);
4579 match &result.ast.items[0] {
4580 Item::Struct(struct_decl) => {
4581 let method = &struct_decl.methods[0];
4582 assert_eq!(result.get(method.name.name), "add");
4583 assert!(method.receiver.is_some());
4584 assert_eq!(method.params.len(), 1);
4585 assert_eq!(result.get(method.params[0].name.name), "n");
4586 }
4587 _ => panic!("expected Struct"),
4588 }
4589 }
4590
4591 #[test]
4592 fn test_struct_associated_function() {
4593 let result = parse(
4595 "struct Point { x: i32, y: i32, fn new(x: i32, y: i32) -> Point { Point { x: x, y: y } } }",
4596 )
4597 .unwrap();
4598 assert_eq!(result.ast.items.len(), 1);
4599 match &result.ast.items[0] {
4600 Item::Struct(struct_decl) => {
4601 let method = &struct_decl.methods[0];
4602 assert_eq!(result.get(method.name.name), "new");
4603 assert!(method.receiver.is_none()); assert_eq!(method.params.len(), 2);
4605 }
4606 _ => panic!("expected Struct"),
4607 }
4608 }
4609
4610 #[test]
4611 fn test_struct_multiple_methods() {
4612 let result = parse(
4613 "struct Counter {
4614 value: i32,
4615 fn new() -> Counter { Counter { value: 0 } }
4616 fn get(self) -> i32 { self.value }
4617 fn increment(self) -> i32 { self.value + 1 }
4618 }",
4619 )
4620 .unwrap();
4621 assert_eq!(result.ast.items.len(), 1);
4622 match &result.ast.items[0] {
4623 Item::Struct(struct_decl) => {
4624 assert_eq!(struct_decl.methods.len(), 3);
4625 assert!(struct_decl.methods[0].receiver.is_none());
4627 assert_eq!(result.get(struct_decl.methods[0].name.name), "new");
4628 assert!(struct_decl.methods[1].receiver.is_some());
4630 assert_eq!(result.get(struct_decl.methods[1].name.name), "get");
4631 assert!(struct_decl.methods[2].receiver.is_some());
4633 assert_eq!(result.get(struct_decl.methods[2].name.name), "increment");
4634 }
4635 _ => panic!("expected Struct"),
4636 }
4637 }
4638
4639 #[test]
4640 fn test_struct_method_with_directive() {
4641 let result = parse("struct Foo { @inline fn bar(self) -> i32 { 42 } }").unwrap();
4642 match &result.ast.items[0] {
4643 Item::Struct(struct_decl) => {
4644 let method = &struct_decl.methods[0];
4645 assert_eq!(method.directives.len(), 1);
4646 assert_eq!(result.get(method.directives[0].name.name), "inline");
4647 }
4648 _ => panic!("expected Struct"),
4649 }
4650 }
4651
4652 #[test]
4655 fn test_struct_field_visibility_default_private() {
4656 let result = parse("struct Point { x: i32, y: i32 }").unwrap();
4657 match &result.ast.items[0] {
4658 Item::Struct(s) => {
4659 assert_eq!(s.fields[0].visibility, Visibility::Private);
4660 assert_eq!(s.fields[1].visibility, Visibility::Private);
4661 }
4662 _ => panic!("expected Struct"),
4663 }
4664 }
4665
4666 #[test]
4667 fn test_struct_field_visibility_pub() {
4668 let result = parse("struct Account { pub id: u64, balance: i64 }").unwrap();
4669 match &result.ast.items[0] {
4670 Item::Struct(s) => {
4671 assert_eq!(s.fields[0].visibility, Visibility::Public);
4672 assert_eq!(result.get(s.fields[0].name.name), "id");
4673 assert_eq!(s.fields[1].visibility, Visibility::Private);
4674 assert_eq!(result.get(s.fields[1].name.name), "balance");
4675 }
4676 _ => panic!("expected Struct"),
4677 }
4678 }
4679
4680 #[test]
4681 fn test_method_visibility_default_private() {
4682 let result = parse("struct Foo { fn bar(self) -> i32 { 42 } }").unwrap();
4683 match &result.ast.items[0] {
4684 Item::Struct(s) => {
4685 assert_eq!(s.methods[0].visibility, Visibility::Private);
4686 }
4687 _ => panic!("expected Struct"),
4688 }
4689 }
4690
4691 #[test]
4692 fn test_method_visibility_pub() {
4693 let result =
4694 parse("struct Foo { pub fn bar(self) -> i32 { 42 } fn helper(self) -> i32 { 1 } }")
4695 .unwrap();
4696 match &result.ast.items[0] {
4697 Item::Struct(s) => {
4698 assert_eq!(s.methods[0].visibility, Visibility::Public);
4699 assert_eq!(result.get(s.methods[0].name.name), "bar");
4700 assert_eq!(s.methods[1].visibility, Visibility::Private);
4701 assert_eq!(result.get(s.methods[1].name.name), "helper");
4702 }
4703 _ => panic!("expected Struct"),
4704 }
4705 }
4706
4707 #[test]
4708 fn test_method_visibility_pub_with_directive() {
4709 let result = parse("struct Foo { @inline pub fn bar(self) -> i32 { 42 } }").unwrap();
4711 match &result.ast.items[0] {
4712 Item::Struct(s) => {
4713 let m = &s.methods[0];
4714 assert_eq!(m.visibility, Visibility::Public);
4715 assert_eq!(m.directives.len(), 1);
4716 assert_eq!(result.get(m.directives[0].name.name), "inline");
4717 }
4718 _ => panic!("expected Struct"),
4719 }
4720 }
4721
4722 #[test]
4723 fn test_enum_struct_variant_field_visibility() {
4724 let result = parse("enum Shape { Circle { pub r: i32, color: i32 } }").unwrap();
4725 match &result.ast.items[0] {
4726 Item::Enum(e) => {
4727 use crate::ast::EnumVariantKind;
4728 match &e.variants[0].kind {
4729 EnumVariantKind::Struct(fields) => {
4730 assert_eq!(fields[0].visibility, Visibility::Public);
4731 assert_eq!(fields[1].visibility, Visibility::Private);
4732 }
4733 _ => panic!("expected struct variant"),
4734 }
4735 }
4736 _ => panic!("expected Enum"),
4737 }
4738 }
4739
4740 #[test]
4743 fn test_enum_without_methods_still_parses() {
4744 let result = parse("enum Color { Red, Green, Blue }").unwrap();
4745 match &result.ast.items[0] {
4746 Item::Enum(enum_decl) => {
4747 assert_eq!(enum_decl.variants.len(), 3);
4748 assert!(enum_decl.methods.is_empty());
4749 }
4750 _ => panic!("expected Enum"),
4751 }
4752 }
4753
4754 #[test]
4755 fn test_enum_with_single_method() {
4756 let result =
4757 parse("enum Opt { Some(i32), None, fn is_some(self) -> bool { true } }").unwrap();
4758 match &result.ast.items[0] {
4759 Item::Enum(enum_decl) => {
4760 assert_eq!(enum_decl.variants.len(), 2);
4761 assert_eq!(enum_decl.methods.len(), 1);
4762 let m = &enum_decl.methods[0];
4763 assert_eq!(result.get(m.name.name), "is_some");
4764 assert!(m.receiver.is_some());
4765 }
4766 _ => panic!("expected Enum"),
4767 }
4768 }
4769
4770 #[test]
4771 fn test_enum_method_without_trailing_comma_on_variants() {
4772 let result = parse("enum E { A, B fn count(self) -> i32 { 2 } }").unwrap();
4774 match &result.ast.items[0] {
4775 Item::Enum(enum_decl) => {
4776 assert_eq!(enum_decl.variants.len(), 2);
4777 assert_eq!(enum_decl.methods.len(), 1);
4778 }
4779 _ => panic!("expected Enum"),
4780 }
4781 }
4782
4783 #[test]
4784 fn test_enum_associated_function() {
4785 let result = parse("enum Opt { Some(i32), None, fn zero() -> i32 { 0 } }").unwrap();
4786 match &result.ast.items[0] {
4787 Item::Enum(enum_decl) => {
4788 let m = &enum_decl.methods[0];
4789 assert_eq!(result.get(m.name.name), "zero");
4790 assert!(m.receiver.is_none()); }
4792 _ => panic!("expected Enum"),
4793 }
4794 }
4795
4796 #[test]
4797 fn test_enum_multiple_methods() {
4798 let result = parse(
4799 "enum E {
4800 A,
4801 B,
4802 fn new() -> E { E::A }
4803 fn is_a(self) -> bool { true }
4804 fn is_b(self) -> bool { false }
4805 }",
4806 )
4807 .unwrap();
4808 match &result.ast.items[0] {
4809 Item::Enum(enum_decl) => {
4810 assert_eq!(enum_decl.methods.len(), 3);
4811 assert!(enum_decl.methods[0].receiver.is_none());
4812 assert!(enum_decl.methods[1].receiver.is_some());
4813 assert!(enum_decl.methods[2].receiver.is_some());
4814 }
4815 _ => panic!("expected Enum"),
4816 }
4817 }
4818
4819 #[test]
4822 fn test_method_call_simple() {
4823 let result = parse_expr("x.foo()").unwrap();
4824 match &result.expr {
4825 Expr::MethodCall(call) => {
4826 assert_eq!(result.get(call.method.name), "foo");
4827 assert!(call.args.is_empty());
4828 match call.receiver.as_ref() {
4829 Expr::Ident(ident) => assert_eq!(result.get(ident.name), "x"),
4830 _ => panic!("expected Ident receiver"),
4831 }
4832 }
4833 _ => panic!("expected MethodCall, got {:?}", result.expr),
4834 }
4835 }
4836
4837 #[test]
4838 fn test_method_call_with_args() {
4839 let result = parse_expr("point.add(5, 10)").unwrap();
4840 match &result.expr {
4841 Expr::MethodCall(call) => {
4842 assert_eq!(result.get(call.method.name), "add");
4843 assert_eq!(call.args.len(), 2);
4844 }
4845 _ => panic!("expected MethodCall"),
4846 }
4847 }
4848
4849 #[test]
4850 fn test_method_call_chained() {
4851 let result = parse_expr("x.foo().bar()").unwrap();
4852 match &result.expr {
4853 Expr::MethodCall(outer) => {
4854 assert_eq!(result.get(outer.method.name), "bar");
4855 match outer.receiver.as_ref() {
4856 Expr::MethodCall(inner) => {
4857 assert_eq!(result.get(inner.method.name), "foo");
4858 }
4859 _ => panic!("expected inner MethodCall"),
4860 }
4861 }
4862 _ => panic!("expected outer MethodCall"),
4863 }
4864 }
4865
4866 #[test]
4867 fn test_method_call_on_field_access() {
4868 let result = parse_expr("obj.field.method()").unwrap();
4869 match &result.expr {
4870 Expr::MethodCall(call) => {
4871 assert_eq!(result.get(call.method.name), "method");
4872 match call.receiver.as_ref() {
4873 Expr::Field(field) => {
4874 assert_eq!(result.get(field.field.name), "field");
4875 }
4876 _ => panic!("expected Field receiver"),
4877 }
4878 }
4879 _ => panic!("expected MethodCall"),
4880 }
4881 }
4882
4883 #[test]
4884 fn test_field_access_not_method_call() {
4885 let result = parse_expr("x.field").unwrap();
4887 match &result.expr {
4888 Expr::Field(field) => {
4889 assert_eq!(result.get(field.field.name), "field");
4890 }
4891 _ => panic!("expected Field, got {:?}", result.expr),
4892 }
4893 }
4894
4895 #[test]
4896 fn test_method_call_on_struct_literal() {
4897 let result =
4898 parse("struct Point { x: i32 } fn main() -> i32 { Point { x: 1 }.get() }").unwrap();
4899 match &result.ast.items[1] {
4900 Item::Function(f) => match &f.body {
4901 Expr::Block(block) => match block.expr.as_ref() {
4902 Expr::MethodCall(call) => {
4903 assert_eq!(result.get(call.method.name), "get");
4904 match call.receiver.as_ref() {
4905 Expr::StructLit(lit) => {
4906 assert_eq!(result.get(lit.name.name), "Point")
4907 }
4908 _ => panic!("expected StructLit receiver"),
4909 }
4910 }
4911 _ => panic!("expected MethodCall"),
4912 },
4913 _ => panic!("expected Block"),
4914 },
4915 _ => panic!("expected Function"),
4916 }
4917 }
4918
4919 #[test]
4920 fn test_method_call_on_paren_expr() {
4921 let result = parse_expr("(x).method()").unwrap();
4922 match &result.expr {
4923 Expr::MethodCall(call) => {
4924 assert_eq!(result.get(call.method.name), "method");
4925 match call.receiver.as_ref() {
4926 Expr::Paren(_) => {}
4927 _ => panic!("expected Paren receiver"),
4928 }
4929 }
4930 _ => panic!("expected MethodCall"),
4931 }
4932 }
4933
4934 #[test]
4935 fn test_method_call_mixed_with_index() {
4936 let result = parse_expr("arr[0].get().value").unwrap();
4938 match &result.expr {
4939 Expr::Field(field) => {
4940 assert_eq!(result.get(field.field.name), "value");
4941 match field.base.as_ref() {
4942 Expr::MethodCall(call) => {
4943 assert_eq!(result.get(call.method.name), "get");
4944 match call.receiver.as_ref() {
4945 Expr::Index(_) => {}
4946 _ => panic!("expected Index receiver"),
4947 }
4948 }
4949 _ => panic!("expected MethodCall"),
4950 }
4951 }
4952 _ => panic!("expected Field"),
4953 }
4954 }
4955
4956 #[test]
4957 fn test_associated_function_call() {
4958 let result = parse_expr("Point::new(1, 2)").unwrap();
4960 match &result.expr {
4961 Expr::AssocFnCall(call) => {
4962 assert_eq!(result.get(call.type_name.name), "Point");
4963 assert_eq!(result.get(call.function.name), "new");
4964 assert_eq!(call.args.len(), 2);
4965 }
4966 _ => panic!("expected AssocFnCall, got {:?}", result.expr),
4967 }
4968 }
4969
4970 #[test]
4973 fn test_block_statement_followed_by_identifier() {
4974 let result = parse(
4977 "fn main() -> i32 {
4978 let a = 1;
4979 {
4980 let b = 2;
4981 }
4982 a
4983 }",
4984 )
4985 .unwrap();
4986 match &result.ast.items[0] {
4987 Item::Function(f) => match &f.body {
4988 Expr::Block(block) => {
4989 assert_eq!(block.statements.len(), 2);
4991 assert!(matches!(&block.statements[0], Statement::Let(_)));
4993 match &block.statements[1] {
4995 Statement::Expr(Expr::Block(_)) => {}
4996 _ => panic!("expected Expr(Block), got {:?}", block.statements[1]),
4997 }
4998 match block.expr.as_ref() {
5000 Expr::Ident(ident) => assert_eq!(result.get(ident.name), "a"),
5001 _ => panic!("expected Ident expression, got {:?}", block.expr),
5002 }
5003 }
5004 _ => panic!("expected Block"),
5005 },
5006 _ => panic!("expected Function"),
5007 }
5008 }
5009
5010 #[test]
5013 fn test_error_preserves_span() {
5014 let result = parse("fn main() -> i32 { let = 42; }");
5016 assert!(result.is_err());
5017 let errors = result.unwrap_err();
5018 let error = errors.first().expect("should have at least one error");
5020 assert!(error.has_span());
5021 assert!(error.span().is_some());
5022 }
5023
5024 #[test]
5025 fn test_error_expected_found() {
5026 let result = parse("fn main() -> i32 { let x = ; }");
5028 assert!(result.is_err());
5029 let errors = result.unwrap_err();
5030 let error = errors.first().expect("should have at least one error");
5031 let msg = error.to_string();
5033 assert!(
5034 msg.contains("expected") || msg.contains("found"),
5035 "error message: {}",
5036 msg
5037 );
5038 }
5039
5040 #[test]
5041 fn test_error_unexpected_eof() {
5042 let result = parse("fn main() -> i32 {");
5044 assert!(result.is_err());
5045 let errors = result.unwrap_err();
5046 let error = errors.first().expect("should have at least one error");
5047 let msg = error.to_string();
5048 assert!(
5050 msg.contains("end of file") || msg.contains("expected"),
5051 "error message: {}",
5052 msg
5053 );
5054 }
5055
5056 #[test]
5057 fn test_format_pattern_token() {
5058 use chumsky::error::RichPattern;
5059 use chumsky::util::MaybeRef;
5060
5061 let pattern = RichPattern::Token(MaybeRef::Val(TokenKind::Plus));
5062 let formatted = format_pattern(&pattern);
5063 assert_eq!(formatted, "'+'");
5065 }
5066
5067 #[test]
5068 fn test_format_pattern_label() {
5069 use chumsky::error::RichPattern;
5070
5071 let pattern: RichPattern<'_, TokenKind> = RichPattern::Label(Cow::Borrowed("expression"));
5072 let formatted = format_pattern(&pattern);
5073 assert_eq!(formatted, "expression");
5074 }
5075
5076 #[test]
5077 fn test_format_pattern_identifier() {
5078 use chumsky::error::RichPattern;
5079
5080 let pattern: RichPattern<'_, TokenKind> = RichPattern::Identifier("while".to_string());
5081 let formatted = format_pattern(&pattern);
5082 assert_eq!(formatted, "'while'");
5083 }
5084
5085 #[test]
5086 fn test_format_pattern_any() {
5087 use chumsky::error::RichPattern;
5088
5089 let pattern: RichPattern<'_, TokenKind> = RichPattern::Any;
5090 let formatted = format_pattern(&pattern);
5091 assert_eq!(formatted, "any token");
5092 }
5093
5094 #[test]
5095 fn test_format_pattern_end_of_input() {
5096 use chumsky::error::RichPattern;
5097
5098 let pattern: RichPattern<'_, TokenKind> = RichPattern::EndOfInput;
5099 let formatted = format_pattern(&pattern);
5100 assert_eq!(formatted, "end of input");
5101 }
5102
5103 #[test]
5104 fn test_parse_error_no_empty_found_clause() {
5105 let result = parse("fn main() -> i32 { let x = ; }");
5108 assert!(result.is_err());
5109 let errors = result.unwrap_err();
5110 let error = errors.first().expect("should have at least one error");
5111 let msg = error.to_string();
5112 assert!(
5114 !msg.ends_with("found "),
5115 "error message should not have trailing empty 'found': {}",
5116 msg
5117 );
5118 }
5119
5120 #[test]
5121 fn test_parse_error_variant_display() {
5122 let error = CompileError::new(
5124 ErrorKind::ParseError("expected semicolon after expression".to_string()),
5125 gruel_util::Span::new(0, 10),
5126 );
5127 assert_eq!(error.to_string(), "expected semicolon after expression");
5128 }
5129
5130 #[test]
5131 fn test_offset_to_u32_normal() {
5132 assert_eq!(offset_to_u32(0), 0);
5134 assert_eq!(offset_to_u32(42), 42);
5135 assert_eq!(offset_to_u32(1000000), 1000000);
5136 assert_eq!(offset_to_u32(u32::MAX as usize), u32::MAX);
5137 }
5138
5139 #[test]
5140 #[should_panic(expected = "offset 4294967296 exceeds u32::MAX")]
5141 #[cfg(debug_assertions)]
5142 fn test_offset_to_u32_overflow_panics_in_debug() {
5143 let _ = offset_to_u32((u32::MAX as usize) + 1);
5145 }
5146
5147 #[test]
5148 fn test_to_gruel_util_normal() {
5149 let simple = SimpleSpan::new(10, 20);
5151 let gruel = to_gruel_util(simple);
5152 assert_eq!(gruel.start, 10);
5153 assert_eq!(gruel.end, 20);
5154 }
5155
5156 #[test]
5157 fn test_parse_returns_multiple_errors() {
5158 let source = "fn main() { let }"; let result = parse(source);
5165 assert!(result.is_err(), "Expected parsing to fail");
5166
5167 let errors = result.unwrap_err();
5169 assert!(
5170 !errors.is_empty(),
5171 "Expected at least one error but got none"
5172 );
5173
5174 let error_count = errors.len();
5176 assert!(
5177 error_count >= 1,
5178 "Expected at least 1 error, got {}",
5179 error_count
5180 );
5181 }
5182
5183 #[test]
5184 fn test_parse_error_collection_preserves_all() {
5185 let errors = vec![
5188 CompileError::without_span(ErrorKind::UnexpectedToken {
5189 expected: std::borrow::Cow::Borrowed("ident"),
5190 found: std::borrow::Cow::Borrowed("let"),
5191 }),
5192 CompileError::without_span(ErrorKind::UnexpectedToken {
5193 expected: std::borrow::Cow::Borrowed("expr"),
5194 found: std::borrow::Cow::Borrowed("rbrace"),
5195 }),
5196 ];
5197
5198 let compile_errors = CompileErrors::from(errors);
5199 assert_eq!(compile_errors.len(), 2, "Expected 2 errors to be preserved");
5200 }
5201
5202 #[test]
5205 fn test_qualified_struct_literal() {
5206 let result = parse_expr("mod.Point { x: 1, y: 2 }").unwrap();
5208 match &result.expr {
5209 Expr::StructLit(lit) => {
5210 assert!(
5212 lit.base.is_some(),
5213 "qualified struct literal should have a base"
5214 );
5215 match lit.base.as_ref().unwrap().as_ref() {
5216 Expr::Ident(ident) => assert_eq!(result.get(ident.name), "mod"),
5217 _ => panic!("base should be Ident, got {:?}", lit.base),
5218 }
5219 assert_eq!(result.get(lit.name.name), "Point");
5221 assert_eq!(lit.fields.len(), 2);
5223 assert_eq!(result.get(lit.fields[0].name.name), "x");
5224 assert_eq!(result.get(lit.fields[1].name.name), "y");
5225 }
5226 _ => panic!("expected StructLit, got {:?}", result.expr),
5227 }
5228 }
5229
5230 #[test]
5231 fn test_qualified_struct_literal_empty() {
5232 let result = parse_expr("mod.Empty {}").unwrap();
5234 match &result.expr {
5235 Expr::StructLit(lit) => {
5236 assert!(
5237 lit.base.is_some(),
5238 "qualified struct literal should have a base"
5239 );
5240 assert_eq!(result.get(lit.name.name), "Empty");
5241 assert_eq!(lit.fields.len(), 0);
5242 }
5243 _ => panic!("expected StructLit, got {:?}", result.expr),
5244 }
5245 }
5246
5247 #[test]
5248 fn test_field_access_then_block() {
5249 let result = parse("fn main() -> i32 { x.field; { 1 } }").unwrap();
5253 match &result.ast.items[0] {
5254 Item::Function(f) => match &f.body {
5255 Expr::Block(block) => {
5256 assert_eq!(block.statements.len(), 1);
5259 match &block.statements[0] {
5260 Statement::Expr(Expr::Field(field)) => {
5261 assert_eq!(result.get(field.field.name), "field");
5262 }
5263 _ => panic!("expected Field statement, got {:?}", block.statements[0]),
5264 }
5265 match block.expr.as_ref() {
5266 Expr::Block(inner) => match inner.expr.as_ref() {
5267 Expr::Int(lit) => assert_eq!(lit.value, 1),
5268 _ => panic!("expected Int, got {:?}", inner.expr),
5269 },
5270 _ => panic!("expected Block, got {:?}", block.expr),
5271 }
5272 }
5273 _ => panic!("expected Block"),
5274 },
5275 _ => panic!("expected Function"),
5276 }
5277 }
5278
5279 #[test]
5280 fn test_field_access_block_without_semicolon_is_error() {
5281 let result = parse("fn main() -> i32 { x.field { 1 } }");
5284 assert!(
5285 result.is_err(),
5286 "field + block without semicolon should be syntax error"
5287 );
5288 }
5289
5290 #[test]
5291 fn test_chained_qualified_struct_literal() {
5292 let result = parse_expr("a.b.Point { x: 1 }").unwrap();
5294 match &result.expr {
5295 Expr::StructLit(lit) => {
5296 assert!(lit.base.is_some());
5298 match lit.base.as_ref().unwrap().as_ref() {
5299 Expr::Field(field) => {
5300 assert_eq!(result.get(field.field.name), "b");
5301 match field.base.as_ref() {
5302 Expr::Ident(ident) => assert_eq!(result.get(ident.name), "a"),
5303 _ => panic!("inner base should be Ident"),
5304 }
5305 }
5306 _ => panic!("base should be Field, got {:?}", lit.base),
5307 }
5308 assert_eq!(result.get(lit.name.name), "Point");
5309 }
5310 _ => panic!("expected StructLit, got {:?}", result.expr),
5311 }
5312 }
5313
5314 #[test]
5317 fn test_anon_struct_with_fields_only() {
5318 let result = parse("fn make_type() -> type { struct { x: i32, y: i32 } }").unwrap();
5320 match &result.ast.items[0] {
5321 Item::Function(f) => {
5322 assert_eq!(result.get(f.name.name), "make_type");
5323 match &f.body {
5324 Expr::Block(block) => match block.expr.as_ref() {
5325 Expr::TypeLit(type_lit) => match &type_lit.type_expr {
5326 TypeExpr::AnonymousStruct {
5327 fields, methods, ..
5328 } => {
5329 assert_eq!(fields.len(), 2);
5330 assert_eq!(result.get(fields[0].name.name), "x");
5331 assert_eq!(result.get(fields[1].name.name), "y");
5332 assert!(methods.is_empty());
5333 }
5334 _ => panic!("expected AnonymousStruct"),
5335 },
5336 _ => panic!("expected TypeLit"),
5337 },
5338 _ => panic!("expected Block"),
5339 }
5340 }
5341 _ => panic!("expected Function"),
5342 }
5343 }
5344
5345 #[test]
5346 fn test_anon_struct_with_method() {
5347 let result =
5349 parse("fn make_type() -> type { struct { x: i32, fn get_x(self) -> i32 { self.x } } }")
5350 .unwrap();
5351 match &result.ast.items[0] {
5352 Item::Function(f) => match &f.body {
5353 Expr::Block(block) => match block.expr.as_ref() {
5354 Expr::TypeLit(type_lit) => match &type_lit.type_expr {
5355 TypeExpr::AnonymousStruct {
5356 fields, methods, ..
5357 } => {
5358 assert_eq!(fields.len(), 1);
5359 assert_eq!(result.get(fields[0].name.name), "x");
5360 assert_eq!(methods.len(), 1);
5361 assert_eq!(result.get(methods[0].name.name), "get_x");
5362 assert!(
5363 methods[0].receiver.is_some(),
5364 "method should have self receiver"
5365 );
5366 }
5367 _ => panic!("expected AnonymousStruct"),
5368 },
5369 _ => panic!("expected TypeLit"),
5370 },
5371 _ => panic!("expected Block"),
5372 },
5373 _ => panic!("expected Function"),
5374 }
5375 }
5376
5377 #[test]
5378 fn test_anon_struct_with_associated_function() {
5379 let result = parse(
5381 "fn make_type() -> type { struct { x: i32, fn new() -> Self { Self { x: 0 } } } }",
5382 )
5383 .unwrap();
5384 match &result.ast.items[0] {
5385 Item::Function(f) => match &f.body {
5386 Expr::Block(block) => match block.expr.as_ref() {
5387 Expr::TypeLit(type_lit) => match &type_lit.type_expr {
5388 TypeExpr::AnonymousStruct {
5389 fields, methods, ..
5390 } => {
5391 assert_eq!(fields.len(), 1);
5392 assert_eq!(methods.len(), 1);
5393 assert_eq!(result.get(methods[0].name.name), "new");
5394 assert!(
5395 methods[0].receiver.is_none(),
5396 "associated function should not have self"
5397 );
5398 match &methods[0].return_type {
5400 Some(TypeExpr::Named(ident)) => {
5401 assert_eq!(result.get(ident.name), "Self");
5402 }
5403 _ => panic!("expected Self return type"),
5404 }
5405 }
5406 _ => panic!("expected AnonymousStruct"),
5407 },
5408 _ => panic!("expected TypeLit"),
5409 },
5410 _ => panic!("expected Block"),
5411 },
5412 _ => panic!("expected Function"),
5413 }
5414 }
5415
5416 #[test]
5417 fn test_anon_struct_with_multiple_methods() {
5418 let result = parse(
5420 r#"
5421 fn make_type() -> type {
5422 struct {
5423 value: i32,
5424 fn get(self) -> i32 { self.value }
5425 fn set(self, v: i32) -> Self { Self { value: v } }
5426 }
5427 }
5428 "#,
5429 )
5430 .unwrap();
5431 match &result.ast.items[0] {
5432 Item::Function(f) => match &f.body {
5433 Expr::Block(block) => match block.expr.as_ref() {
5434 Expr::TypeLit(type_lit) => match &type_lit.type_expr {
5435 TypeExpr::AnonymousStruct {
5436 fields, methods, ..
5437 } => {
5438 assert_eq!(fields.len(), 1);
5439 assert_eq!(result.get(fields[0].name.name), "value");
5440 assert_eq!(methods.len(), 2);
5441 assert_eq!(result.get(methods[0].name.name), "get");
5442 assert_eq!(result.get(methods[1].name.name), "set");
5443 assert_eq!(methods[1].params.len(), 1);
5445 assert_eq!(result.get(methods[1].params[0].name.name), "v");
5446 }
5447 _ => panic!("expected AnonymousStruct"),
5448 },
5449 _ => panic!("expected TypeLit"),
5450 },
5451 _ => panic!("expected Block"),
5452 },
5453 _ => panic!("expected Function"),
5454 }
5455 }
5456
5457 #[test]
5458 fn test_anon_struct_methods_only() {
5459 let result =
5461 parse("fn make_type() -> type { struct { fn new() -> Self { Self { } } } }").unwrap();
5462 match &result.ast.items[0] {
5463 Item::Function(f) => match &f.body {
5464 Expr::Block(block) => match block.expr.as_ref() {
5465 Expr::TypeLit(type_lit) => match &type_lit.type_expr {
5466 TypeExpr::AnonymousStruct {
5467 fields, methods, ..
5468 } => {
5469 assert!(fields.is_empty());
5470 assert_eq!(methods.len(), 1);
5471 assert_eq!(result.get(methods[0].name.name), "new");
5472 }
5473 _ => panic!("expected AnonymousStruct"),
5474 },
5475 _ => panic!("expected TypeLit"),
5476 },
5477 _ => panic!("expected Block"),
5478 },
5479 _ => panic!("expected Function"),
5480 }
5481 }
5482
5483 #[test]
5484 fn test_self_type_in_return() {
5485 let result =
5487 parse("fn make_type() -> type { struct { x: i32, fn clone(self) -> Self { self } } }")
5488 .unwrap();
5489 match &result.ast.items[0] {
5490 Item::Function(f) => match &f.body {
5491 Expr::Block(block) => match block.expr.as_ref() {
5492 Expr::TypeLit(type_lit) => match &type_lit.type_expr {
5493 TypeExpr::AnonymousStruct { methods, .. } => {
5494 match &methods[0].return_type {
5495 Some(TypeExpr::Named(ident)) => {
5496 assert_eq!(result.get(ident.name), "Self");
5497 }
5498 _ => panic!("expected Self return type"),
5499 }
5500 }
5501 _ => panic!("expected AnonymousStruct"),
5502 },
5503 _ => panic!("expected TypeLit"),
5504 },
5505 _ => panic!("expected Block"),
5506 },
5507 _ => panic!("expected Function"),
5508 }
5509 }
5510
5511 #[test]
5512 fn test_self_type_in_param() {
5513 let result = parse(
5515 "fn make_type() -> type { struct { fn combine(self, other: Self) -> Self { self } } }",
5516 )
5517 .unwrap();
5518 match &result.ast.items[0] {
5519 Item::Function(f) => match &f.body {
5520 Expr::Block(block) => match block.expr.as_ref() {
5521 Expr::TypeLit(type_lit) => match &type_lit.type_expr {
5522 TypeExpr::AnonymousStruct { methods, .. } => {
5523 let param = &methods[0].params[0];
5525 match ¶m.ty {
5526 TypeExpr::Named(ident) => {
5527 assert_eq!(result.get(ident.name), "Self");
5528 }
5529 _ => panic!("expected Self param type"),
5530 }
5531 }
5532 _ => panic!("expected AnonymousStruct"),
5533 },
5534 _ => panic!("expected TypeLit"),
5535 },
5536 _ => panic!("expected Block"),
5537 },
5538 _ => panic!("expected Function"),
5539 }
5540 }
5541
5542 #[test]
5543 fn test_self_type_standalone() {
5544 let result = parse("struct Foo { x: i32, fn clone(self) -> Self { self } }").unwrap();
5547 match &result.ast.items[0] {
5548 Item::Struct(struct_decl) => {
5549 let method = &struct_decl.methods[0];
5550 match &method.return_type {
5551 Some(TypeExpr::Named(ident)) => {
5552 assert_eq!(result.get(ident.name), "Self");
5553 }
5554 _ => panic!("expected Self return type"),
5555 }
5556 }
5557 _ => panic!("expected Struct"),
5558 }
5559 }
5560
5561 #[test]
5566 fn test_tuple_expr_pair() {
5567 let result = parse_expr("(1, 2)").unwrap();
5568 match &result.expr {
5569 Expr::Tuple(t) => {
5570 assert_eq!(t.elems.len(), 2);
5571 match &t.elems[0] {
5572 Expr::Int(lit) => assert_eq!(lit.value, 1),
5573 _ => panic!("expected Int"),
5574 }
5575 match &t.elems[1] {
5576 Expr::Int(lit) => assert_eq!(lit.value, 2),
5577 _ => panic!("expected Int"),
5578 }
5579 }
5580 other => panic!("expected Tuple, got {:?}", other),
5581 }
5582 }
5583
5584 #[test]
5585 fn test_tuple_expr_triple_mixed() {
5586 let result = parse_expr("(1, true, 3)").unwrap();
5587 match &result.expr {
5588 Expr::Tuple(t) => {
5589 assert_eq!(t.elems.len(), 3);
5590 assert!(matches!(t.elems[0], Expr::Int(_)));
5591 assert!(matches!(t.elems[1], Expr::Bool(_)));
5592 assert!(matches!(t.elems[2], Expr::Int(_)));
5593 }
5594 _ => panic!("expected Tuple"),
5595 }
5596 }
5597
5598 #[test]
5599 fn test_tuple_expr_singleton_needs_trailing_comma() {
5600 let result = parse_expr("(42,)").unwrap();
5602 match &result.expr {
5603 Expr::Tuple(t) => {
5604 assert_eq!(t.elems.len(), 1);
5605 assert!(matches!(t.elems[0], Expr::Int(_)));
5606 }
5607 _ => panic!("expected Tuple singleton"),
5608 }
5609 }
5610
5611 #[test]
5612 fn test_paren_expr_without_comma_is_not_tuple() {
5613 let result = parse_expr("(42)").unwrap();
5615 assert!(matches!(result.expr, Expr::Paren(_)));
5616 }
5617
5618 #[test]
5619 fn test_unit_literal_is_not_tuple() {
5620 let result = parse_expr("()").unwrap();
5621 assert!(matches!(result.expr, Expr::Unit(_)));
5622 }
5623
5624 #[test]
5625 fn test_tuple_expr_trailing_comma_allowed() {
5626 let result = parse_expr("(1, 2,)").unwrap();
5627 match &result.expr {
5628 Expr::Tuple(t) => assert_eq!(t.elems.len(), 2),
5629 _ => panic!("expected Tuple"),
5630 }
5631 }
5632
5633 #[test]
5634 fn test_tuple_index_zero() {
5635 let result = parse_expr("t.0").unwrap();
5636 match &result.expr {
5637 Expr::TupleIndex(ti) => {
5638 assert_eq!(ti.index, 0);
5639 assert!(matches!(*ti.base, Expr::Ident(_)));
5640 }
5641 _ => panic!("expected TupleIndex"),
5642 }
5643 }
5644
5645 #[test]
5646 fn test_tuple_index_multi_digit() {
5647 let result = parse_expr("t.42").unwrap();
5648 match &result.expr {
5649 Expr::TupleIndex(ti) => assert_eq!(ti.index, 42),
5650 _ => panic!("expected TupleIndex"),
5651 }
5652 }
5653
5654 #[test]
5655 fn test_parenthesised_nested_tuple_access() {
5656 let result = parse_expr("(t.0).1").unwrap();
5658 match &result.expr {
5659 Expr::TupleIndex(outer) => {
5660 assert_eq!(outer.index, 1);
5661 match &*outer.base {
5662 Expr::Paren(p) => match &*p.inner {
5663 Expr::TupleIndex(inner) => assert_eq!(inner.index, 0),
5664 _ => panic!("expected inner TupleIndex"),
5665 },
5666 _ => panic!("expected Paren wrapping inner access"),
5667 }
5668 }
5669 _ => panic!("expected outer TupleIndex"),
5670 }
5671 }
5672
5673 #[test]
5674 fn test_tuple_type_pair() {
5675 let result = parse("fn f() -> (i32, bool) { (1, true) }").unwrap();
5676 match &result.ast.items[0] {
5677 Item::Function(f) => match f.return_type.as_ref().unwrap() {
5678 TypeExpr::Tuple { elems, .. } => {
5679 assert_eq!(elems.len(), 2);
5680 }
5681 other => panic!("expected Tuple type, got {:?}", other),
5682 },
5683 _ => panic!("expected Function"),
5684 }
5685 }
5686
5687 #[test]
5688 fn test_tuple_type_singleton() {
5689 let result = parse("fn f() -> (i32,) { (1,) }").unwrap();
5690 match &result.ast.items[0] {
5691 Item::Function(f) => match f.return_type.as_ref().unwrap() {
5692 TypeExpr::Tuple { elems, .. } => assert_eq!(elems.len(), 1),
5693 _ => panic!("expected Tuple type"),
5694 },
5695 _ => panic!("expected Function"),
5696 }
5697 }
5698
5699 #[test]
5700 fn test_unit_type_still_unit() {
5701 let result = parse("fn f() -> () { () }").unwrap();
5702 match &result.ast.items[0] {
5703 Item::Function(f) => match f.return_type.as_ref().unwrap() {
5704 TypeExpr::Unit(_) => {}
5705 other => panic!("expected Unit type, got {:?}", other),
5706 },
5707 _ => panic!("expected Function"),
5708 }
5709 }
5710
5711 fn assert_tuple_ident(
5712 elem: &TupleElemPattern,
5713 result: &ParseResult,
5714 expected: &str,
5715 expected_mut: bool,
5716 ) {
5717 match elem {
5718 TupleElemPattern::Pattern(Pattern::Ident { name, is_mut, .. }) => {
5719 assert_eq!(result.get(name.name), expected);
5720 assert_eq!(*is_mut, expected_mut);
5721 }
5722 other => panic!("expected Pattern::Ident, got {:?}", other),
5723 }
5724 }
5725
5726 #[test]
5727 fn test_tuple_destructure_basic() {
5728 let result = parse("fn main() -> i32 { let (a, b) = (1, 2); a }").unwrap();
5729 match &result.ast.items[0] {
5730 Item::Function(f) => match &f.body {
5731 Expr::Block(block) => match &block.statements[0] {
5732 Statement::Let(let_stmt) => match &let_stmt.pattern {
5733 Pattern::Tuple { elems, .. } => {
5734 assert_eq!(elems.len(), 2);
5735 assert_tuple_ident(&elems[0], &result, "a", false);
5736 assert_tuple_ident(&elems[1], &result, "b", false);
5737 }
5738 _ => panic!("expected Tuple pattern"),
5739 },
5740 _ => panic!("expected Let"),
5741 },
5742 _ => panic!("expected Block"),
5743 },
5744 _ => panic!("expected Function"),
5745 }
5746 }
5747
5748 #[test]
5749 fn test_tuple_destructure_mut_and_wildcard() {
5750 let result = parse("fn main() -> i32 { let (mut a, _) = (1, 2); a }").unwrap();
5751 match &result.ast.items[0] {
5752 Item::Function(f) => match &f.body {
5753 Expr::Block(block) => match &block.statements[0] {
5754 Statement::Let(let_stmt) => match &let_stmt.pattern {
5755 Pattern::Tuple { elems, .. } => {
5756 assert_eq!(elems.len(), 2);
5757 assert_tuple_ident(&elems[0], &result, "a", true);
5758 assert!(matches!(
5759 &elems[1],
5760 TupleElemPattern::Pattern(Pattern::Wildcard(_))
5761 ));
5762 }
5763 _ => panic!("expected Tuple pattern"),
5764 },
5765 _ => panic!("expected Let"),
5766 },
5767 _ => panic!("expected Block"),
5768 },
5769 _ => panic!("expected Function"),
5770 }
5771 }
5772
5773 #[test]
5774 fn test_tuple_destructure_singleton() {
5775 let result = parse("fn main() -> i32 { let (x,) = (42,); x }").unwrap();
5776 match &result.ast.items[0] {
5777 Item::Function(f) => match &f.body {
5778 Expr::Block(block) => match &block.statements[0] {
5779 Statement::Let(let_stmt) => match &let_stmt.pattern {
5780 Pattern::Tuple { elems, .. } => {
5781 assert_eq!(elems.len(), 1);
5782 }
5783 _ => panic!("expected Tuple pattern"),
5784 },
5785 _ => panic!("expected Let"),
5786 },
5787 _ => panic!("expected Block"),
5788 },
5789 _ => panic!("expected Function"),
5790 }
5791 }
5792
5793 fn parse_with_nested(source: &str) -> MultiErrorResult<ParseResult> {
5800 let lexer = Lexer::new(source);
5801 let (tokens, interner) = lexer.tokenize().unwrap();
5802 let parser = ChumskyParser::new(tokens, interner);
5803 parser
5804 .parse()
5805 .map(|(ast, interner)| ParseResult { ast, interner })
5806 }
5807
5808 fn find_first_let_pattern(result: &ParseResult) -> &Pattern {
5809 match &result.ast.items[0] {
5810 Item::Function(f) => match &f.body {
5811 Expr::Block(block) => match &block.statements[0] {
5812 Statement::Let(l) => &l.pattern,
5813 _ => panic!("expected let"),
5814 },
5815 _ => panic!("expected block"),
5816 },
5817 _ => panic!("expected function"),
5818 }
5819 }
5820
5821 fn find_first_match_arm_pattern(result: &ParseResult) -> &Pattern {
5822 match &result.ast.items[0] {
5823 Item::Function(f) => {
5824 fn find_match(e: &Expr) -> Option<&Pattern> {
5825 match e {
5826 Expr::Block(b) => find_match(&b.expr),
5827 Expr::Match(m) => Some(&m.arms[0].pattern),
5828 _ => None,
5829 }
5830 }
5831 find_match(&f.body).expect("expected a match expression")
5832 }
5833 _ => panic!("expected function"),
5834 }
5835 }
5836
5837 #[test]
5838 fn test_nested_let_struct_in_struct() {
5839 let source = r#"
5840 fn main() -> i32 {
5841 let Outer { inner: Inner { x, y }, tag } = make();
5842 0
5843 }
5844 "#;
5845 let result = parse_with_nested(source).unwrap();
5846 match find_first_let_pattern(&result) {
5847 Pattern::Struct { fields, .. } => {
5848 assert_eq!(fields.len(), 2);
5849 let inner = &fields[0];
5851 assert_eq!(result.get(inner.field_name.unwrap().name), "inner");
5852 match inner.sub.as_ref().unwrap() {
5853 Pattern::Struct {
5854 fields: inner_fields,
5855 ..
5856 } => assert_eq!(inner_fields.len(), 2),
5857 other => panic!("expected nested Struct, got {:?}", other),
5858 }
5859 let tag = &fields[1];
5861 assert_eq!(result.get(tag.field_name.unwrap().name), "tag");
5862 assert!(tag.sub.is_none());
5863 }
5864 other => panic!("expected Pattern::Struct, got {:?}", other),
5865 }
5866 }
5867
5868 #[test]
5869 fn test_nested_let_tuple_of_tuples() {
5870 let source = "fn main() -> i32 { let ((a, b), c) = ((1, 2), 3); 0 }";
5871 let result = parse_with_nested(source).unwrap();
5872 match find_first_let_pattern(&result) {
5873 Pattern::Tuple { elems, .. } => {
5874 assert_eq!(elems.len(), 2);
5875 match &elems[0] {
5876 TupleElemPattern::Pattern(Pattern::Tuple {
5877 elems: inner_elems, ..
5878 }) => assert_eq!(inner_elems.len(), 2),
5879 other => panic!("expected nested tuple, got {:?}", other),
5880 }
5881 }
5882 other => panic!("expected Pattern::Tuple, got {:?}", other),
5883 }
5884 }
5885
5886 #[test]
5887 fn test_tuple_pattern_in_match() {
5888 let source = r#"
5889 fn main() -> i32 {
5890 match pair() {
5891 (0, 0) => 0,
5892 _ => 1,
5893 }
5894 }
5895 "#;
5896 let result = parse_with_nested(source).unwrap();
5897 match find_first_match_arm_pattern(&result) {
5898 Pattern::Tuple { elems, .. } => {
5899 assert_eq!(elems.len(), 2);
5900 for e in elems {
5901 match e {
5902 TupleElemPattern::Pattern(Pattern::Int(lit)) => {
5903 assert_eq!(lit.value, 0)
5904 }
5905 other => panic!("expected Int sub-pattern, got {:?}", other),
5906 }
5907 }
5908 }
5909 other => panic!("expected Pattern::Tuple in match, got {:?}", other),
5910 }
5911 }
5912
5913 #[test]
5914 fn test_rest_in_tuple() {
5915 let source = "fn main() -> i32 { let (a, .., z) = quintuple(); 0 }";
5916 let result = parse_with_nested(source).unwrap();
5917 match find_first_let_pattern(&result) {
5918 Pattern::Tuple { elems, .. } => {
5919 assert_eq!(elems.len(), 3);
5920 assert!(matches!(&elems[1], TupleElemPattern::Rest(_)));
5921 }
5922 other => panic!("expected Pattern::Tuple, got {:?}", other),
5923 }
5924 }
5925
5926 #[test]
5927 fn test_rest_in_struct() {
5928 let source = "fn main() -> i32 { let Point { x, .. } = p(); 0 }";
5929 let result = parse_with_nested(source).unwrap();
5930 match find_first_let_pattern(&result) {
5931 Pattern::Struct { fields, .. } => {
5932 assert_eq!(fields.len(), 2);
5933 assert!(fields[0].field_name.is_some());
5934 assert!(fields[1].field_name.is_none()); }
5936 other => panic!("expected Pattern::Struct, got {:?}", other),
5937 }
5938 }
5939
5940 #[test]
5946 fn test_flat_tuple_destructure_still_parses() {
5947 let source = "fn main() -> i32 { let (a, b) = pair(); 0 }";
5949 let result = parse(source);
5950 assert!(
5951 result.is_ok(),
5952 "flat tuple destructure should parse unconditionally"
5953 );
5954 }
5955
5956 fn assert_refutable_in_let_err(result: &MultiErrorResult<ParseResult>) {
5959 use gruel_util::ErrorKind;
5960 let errors = result.as_ref().expect_err("expected errors");
5961 let found = errors
5962 .iter()
5963 .any(|e| matches!(e.kind, ErrorKind::RefutablePatternInLet));
5964 assert!(
5965 found,
5966 "expected RefutablePatternInLet in: {:?}",
5967 errors
5968 .iter()
5969 .map(|e| e.kind.to_string())
5970 .collect::<Vec<_>>()
5971 );
5972 }
5973
5974 #[test]
5975 fn test_refutable_int_literal_in_let() {
5976 let source = "fn main() -> i32 { let 1 = 1; 0 }";
5978 assert_refutable_in_let_err(&parse(source));
5979 }
5980
5981 #[test]
5982 fn test_refutable_bool_in_let() {
5983 let source = "fn main() -> i32 { let true = true; 0 }";
5984 assert_refutable_in_let_err(&parse(source));
5985 }
5986
5987 #[test]
5988 fn test_refutable_enum_path_in_let() {
5989 let source = "fn main() -> i32 { let Color::Red = c; 0 }";
5990 assert_refutable_in_let_err(&parse(source));
5991 }
5992
5993 #[test]
5994 fn test_refutable_variant_in_let() {
5995 let source = "fn main() -> i32 { let Option::Some(x) = opt(); 0 }";
5998 let result = parse_with_nested(source);
5999 assert_refutable_in_let_err(&result);
6000 }
6001
6002 #[test]
6003 fn test_refutable_nested_literal_in_let() {
6004 let source = "fn main() -> i32 { let (1, y) = t(); 0 }";
6006 let result = parse_with_nested(source);
6007 assert_refutable_in_let_err(&result);
6008 }
6009
6010 #[test]
6011 fn test_irrefutable_tuple_in_let() {
6012 let source = "fn main() -> i32 { let (a, b) = t(); 0 }";
6014 assert!(parse(source).is_ok());
6015 }
6016
6017 #[test]
6018 fn test_irrefutable_nested_struct_in_let() {
6019 let source = "fn main() -> i32 { let Outer { inner: Inner { x, y }, tag } = make(); 0 }";
6020 assert!(parse_with_nested(source).is_ok());
6021 }
6022
6023 #[test]
6028 fn test_anon_fn_single_param_with_return() {
6029 let result = parse_expr("fn(x: i32) -> i32 { x + 1 }").unwrap();
6030 match &result.expr {
6031 Expr::AnonFn(anon) => {
6032 assert_eq!(anon.params.len(), 1);
6033 assert_eq!(result.get(anon.params[0].name.name), "x");
6034 assert!(anon.return_type.is_some());
6035 }
6036 other => panic!("expected AnonFn, got {:?}", other),
6037 }
6038 }
6039
6040 #[test]
6041 fn test_anon_fn_zero_param_no_return() {
6042 let result = parse_expr("fn() { 0 }").unwrap();
6043 match result.expr {
6044 Expr::AnonFn(anon) => {
6045 assert!(anon.params.is_empty());
6046 assert!(anon.return_type.is_none());
6047 }
6048 other => panic!("expected AnonFn, got {:?}", other),
6049 }
6050 }
6051
6052 #[test]
6053 fn test_anon_fn_multi_param() {
6054 let result = parse_expr("fn(x: i32, y: i32) -> i32 { x + y }").unwrap();
6055 match &result.expr {
6056 Expr::AnonFn(anon) => {
6057 assert_eq!(anon.params.len(), 2);
6058 assert_eq!(result.get(anon.params[0].name.name), "x");
6059 assert_eq!(result.get(anon.params[1].name.name), "y");
6060 }
6061 other => panic!("expected AnonFn, got {:?}", other),
6062 }
6063 }
6064
6065 #[test]
6066 fn test_anon_fn_in_call_arg() {
6067 let result = parse_expr("apply(fn(x: i32) -> i32 { x * 2 }, 3)").unwrap();
6070 match result.expr {
6071 Expr::Call(call) => {
6072 assert_eq!(call.args.len(), 2);
6073 assert!(matches!(call.args[0].expr, Expr::AnonFn(_)));
6074 }
6075 other => panic!("expected Call, got {:?}", other),
6076 }
6077 }
6078
6079 #[test]
6080 fn test_anon_fn_nested() {
6081 let result = parse_expr("fn() { fn(x: i32) -> i32 { x } }").unwrap();
6083 match result.expr {
6084 Expr::AnonFn(outer) => {
6085 assert!(matches!(*outer.body.expr, Expr::AnonFn(_)));
6086 }
6087 other => panic!("expected AnonFn, got {:?}", other),
6088 }
6089 }
6090
6091 #[test]
6092 fn test_named_fn_at_top_level_still_works() {
6093 let result = parse("fn main() -> i32 { 0 }").unwrap();
6096 assert_eq!(result.ast.items.len(), 1);
6097 assert!(matches!(result.ast.items[0], Item::Function(_)));
6098 }
6099
6100 fn parse_with_docs(source: &str) -> MultiErrorResult<ParseResult> {
6105 let lexer = Lexer::new(source);
6106 let (tokens, interner) = lexer.tokenize().map_err(CompileErrors::from)?;
6107 let parser = ChumskyParser::new(tokens, interner).with_source(source);
6108 let (ast, interner) = parser.parse()?;
6109 Ok(ParseResult { ast, interner })
6110 }
6111
6112 #[test]
6113 fn test_docs_dropped_when_source_not_provided() {
6114 let source = "/// Module docs.\nfn main() -> i32 { 0 }";
6117 let result = parse(source).unwrap();
6118 assert!(result.ast.module_doc.is_none());
6119 match &result.ast.items[0] {
6120 Item::Function(f) => assert!(f.doc.is_none()),
6121 _ => panic!("expected Function"),
6122 }
6123 }
6124
6125 #[test]
6126 fn test_docs_on_attaches_glued_doc_to_function() {
6127 let source = "/// Docs for main.\nfn main() -> i32 { 0 }";
6128 let result = parse_with_docs(source).unwrap();
6129 assert!(result.ast.module_doc.is_none());
6130 match &result.ast.items[0] {
6131 Item::Function(f) => {
6132 let doc = f.doc.as_ref().expect("expected doc on main");
6133 assert_eq!(doc.body, "Docs for main.");
6134 }
6135 _ => panic!("expected Function"),
6136 }
6137 }
6138
6139 #[test]
6140 fn test_module_doc_separated_from_first_item() {
6141 let source = "/// Module docs.\n\nfn main() -> i32 { 0 }";
6142 let result = parse_with_docs(source).unwrap();
6143 let module_doc = result
6144 .ast
6145 .module_doc
6146 .as_ref()
6147 .expect("expected a module doc");
6148 assert_eq!(module_doc.body, "Module docs.");
6149 match &result.ast.items[0] {
6150 Item::Function(f) => assert!(f.doc.is_none()),
6151 _ => panic!("expected Function"),
6152 }
6153 }
6154
6155 #[test]
6156 fn test_module_doc_then_item_doc() {
6157 let source = "/// Module docs.\n\n/// Docs for main.\nfn main() -> i32 { 0 }";
6158 let result = parse_with_docs(source).unwrap();
6159 assert_eq!(result.ast.module_doc.as_ref().unwrap().body, "Module docs.");
6160 match &result.ast.items[0] {
6161 Item::Function(f) => {
6162 assert_eq!(f.doc.as_ref().unwrap().body, "Docs for main.");
6163 }
6164 _ => panic!("expected Function"),
6165 }
6166 }
6167
6168 #[test]
6169 fn test_doc_block_joins_consecutive_lines() {
6170 let source = "/// Line 1\n/// Line 2\nfn main() -> i32 { 0 }";
6171 let result = parse_with_docs(source).unwrap();
6172 match &result.ast.items[0] {
6173 Item::Function(f) => {
6174 assert_eq!(f.doc.as_ref().unwrap().body, "Line 1\nLine 2");
6175 }
6176 _ => panic!("expected Function"),
6177 }
6178 }
6179
6180 #[test]
6181 fn test_doc_after_other_item_attaches_to_main() {
6182 let source = "fn helper() {}\n\n/// Docs for main.\nfn main() -> i32 { 0 }";
6185 let result = parse_with_docs(source).unwrap();
6186 assert!(result.ast.module_doc.is_none());
6187 match &result.ast.items[1] {
6188 Item::Function(f) => {
6189 assert_eq!(f.doc.as_ref().unwrap().body, "Docs for main.");
6190 }
6191 _ => panic!("expected Function at index 1"),
6192 }
6193 }
6194
6195 #[test]
6196 fn test_unglued_doc_after_first_item_is_error() {
6197 let source = "fn helper() {}\n\n/// Stray.\n\nfn main() -> i32 { 0 }";
6200 let result = parse_with_docs(source);
6201 assert!(result.is_err(), "expected parse error for orphan doc");
6202 }
6203
6204 #[test]
6205 fn test_doc_strips_one_leading_space() {
6206 let source = "/// hello\nfn main() -> i32 { 0 }";
6208 let result = parse_with_docs(source).unwrap();
6209 match &result.ast.items[0] {
6210 Item::Function(f) => assert_eq!(f.doc.as_ref().unwrap().body, "hello"),
6211 _ => panic!("expected Function"),
6212 }
6213 }
6214
6215 #[test]
6216 fn test_docs_on_struct_and_field() {
6217 let source = "\
6218/// Docs for Point.
6219struct Point {
6220 x: i32,
6221 y: i32,
6222}";
6223 let result = parse_with_docs(source).unwrap();
6224 match &result.ast.items[0] {
6225 Item::Struct(s) => {
6226 assert_eq!(s.doc.as_ref().unwrap().body, "Docs for Point.");
6227 }
6228 _ => panic!("expected Struct"),
6229 }
6230 }
6231}