1#![warn(missing_docs)]
7
8use bhc_ast::{Expr, Module};
9use bhc_diagnostics::{Diagnostic, DiagnosticHandler, FullSpan};
10use bhc_lexer::{Lexer, Token, TokenKind};
11use bhc_span::{FileId, Span, Spanned};
12use thiserror::Error;
13
14mod decl;
15mod expr;
16mod pattern;
17mod types;
18
19#[derive(Debug, Error)]
21pub enum ParseError {
22 #[error("unexpected {found}, expected {expected}")]
24 Unexpected {
25 found: String,
27 expected: String,
29 span: Span,
31 },
32
33 #[error("unexpected end of file")]
35 UnexpectedEof {
36 expected: String,
38 },
39
40 #[error("invalid literal: {message}")]
42 InvalidLiteral {
43 message: String,
45 span: Span,
47 },
48
49 #[error("expression nesting exceeds the maximum depth of {limit}")]
51 RecursionLimit {
52 limit: usize,
54 span: Span,
56 },
57}
58
59impl ParseError {
60 #[must_use]
62 pub fn to_diagnostic(&self, file: FileId) -> Diagnostic {
63 match self {
64 Self::Unexpected {
65 found,
66 expected,
67 span,
68 } => Diagnostic::error(format!("unexpected {found}, expected {expected}"))
69 .with_label(FullSpan::new(file, *span), "unexpected token here"),
70 Self::UnexpectedEof { expected } => {
71 Diagnostic::error(format!("unexpected end of file, expected {expected}"))
72 }
73 Self::InvalidLiteral { message, span } => {
74 Diagnostic::error(format!("invalid literal: {message}"))
75 .with_label(FullSpan::new(file, *span), "invalid literal")
76 }
77 Self::RecursionLimit { limit, span } => Diagnostic::error(format!(
78 "expression nesting exceeds the maximum depth of {limit}"
79 ))
80 .with_label(FullSpan::new(file, *span), "nesting too deep here"),
81 }
82 }
83}
84
85pub type ParseResult<T> = Result<T, ParseError>;
87
88pub struct Parser<'src> {
90 tokens: Vec<Spanned<Token>>,
92 pos: usize,
94 diagnostics: DiagnosticHandler,
96 file_id: FileId,
98 #[allow(dead_code)]
100 src: &'src str,
101 depth: usize,
103}
104
105const MAX_PARSE_DEPTH: usize = 64;
111
112impl<'src> Parser<'src> {
113 #[must_use]
115 pub fn new(src: &'src str, file_id: FileId) -> Self {
116 let tokens: Vec<_> = Lexer::new(src).collect();
117 Self {
118 tokens,
119 pos: 0,
120 diagnostics: DiagnosticHandler::new(),
121 file_id,
122 src,
123 depth: 0,
124 }
125 }
126
127 pub(crate) fn enter_recursion(&mut self) -> ParseResult<()> {
129 self.depth += 1;
130 if self.depth > MAX_PARSE_DEPTH {
131 return Err(ParseError::RecursionLimit {
132 limit: MAX_PARSE_DEPTH,
133 span: self.current_span(),
134 });
135 }
136 Ok(())
137 }
138
139 pub(crate) fn exit_recursion(&mut self) {
141 self.depth = self.depth.saturating_sub(1);
142 }
143
144 fn current(&self) -> Option<&Spanned<Token>> {
146 self.tokens.get(self.pos)
147 }
148
149 fn peek_nth(&self, n: usize) -> Option<&Spanned<Token>> {
151 self.tokens.get(self.pos + n)
152 }
153
154 fn current_kind(&self) -> Option<&TokenKind> {
156 self.current().map(|t| &t.node.kind)
157 }
158
159 fn current_span(&self) -> Span {
161 self.current().map(|t| t.span).unwrap_or(Span::DUMMY)
162 }
163
164 fn at_eof(&self) -> bool {
166 self.pos >= self.tokens.len() || self.current_kind() == Some(&TokenKind::Eof)
167 }
168
169 fn advance(&mut self) -> Option<Spanned<Token>> {
171 if self.at_eof() {
172 None
173 } else {
174 let tok = self.tokens[self.pos].clone();
175 self.pos += 1;
176 Some(tok)
177 }
178 }
179
180 fn check(&self, kind: &TokenKind) -> bool {
182 self.current_kind() == Some(kind)
183 }
184
185 #[allow(dead_code)]
187 fn check_con_id(&self) -> bool {
188 matches!(self.current_kind(), Some(TokenKind::ConId(_)))
189 }
190
191 #[allow(dead_code)]
193 fn check_ident(&self) -> bool {
194 matches!(self.current_kind(), Some(TokenKind::Ident(_)))
195 }
196
197 fn eat(&mut self, kind: &TokenKind) -> bool {
199 if self.check(kind) {
200 self.advance();
201 true
202 } else {
203 false
204 }
205 }
206
207 fn eat_ident_str(&mut self, s: &str) -> bool {
210 if let Some(TokenKind::Ident(sym)) = self.current_kind() {
211 if sym.as_str() == s {
212 self.advance();
213 return true;
214 }
215 }
216 false
217 }
218
219 fn check_ident_str(&self, s: &str) -> bool {
222 if let Some(TokenKind::Ident(sym)) = self.current_kind() {
223 sym.as_str() == s
224 } else {
225 false
226 }
227 }
228
229 fn expect_ident_str(&mut self, s: &str) -> ParseResult<Spanned<Token>> {
232 if self.check_ident_str(s) {
233 Ok(self.advance().unwrap())
234 } else if self.at_eof() {
235 Err(ParseError::UnexpectedEof {
236 expected: format!("`{}`", s),
237 })
238 } else {
239 let current = self.current().unwrap();
240 Err(ParseError::Unexpected {
241 found: current.node.kind.description().to_string(),
242 expected: format!("`{}`", s),
243 span: current.span,
244 })
245 }
246 }
247
248 fn skip_virtual_tokens(&mut self) {
251 while let Some(kind) = self.current_kind() {
252 if kind.is_virtual() {
253 self.advance();
254 } else {
255 break;
256 }
257 }
258 }
259
260 fn skip_doc_comments(&mut self) {
263 while let Some(kind) = self.current_kind() {
264 match kind {
265 TokenKind::DocCommentLine(_) | TokenKind::DocCommentBlock(_) => {
266 self.advance();
267 }
268 _ => break,
269 }
270 }
271 }
272
273 fn collect_doc_comments(&mut self) -> Option<bhc_ast::DocComment> {
279 let mut texts = Vec::new();
280 let mut first_span: Option<Span> = None;
281 let mut last_span: Option<Span> = None;
282 let mut kind = bhc_ast::DocKind::Preceding;
283
284 while let Some(tok) = self.current() {
285 match &tok.node.kind {
286 TokenKind::DocCommentLine(text) => {
287 let span = tok.span;
288 let text = text.clone();
289 self.advance();
290
291 let trimmed = text.trim_start();
293 let (actual_text, doc_kind) = if trimmed.starts_with('^') {
294 (
295 trimmed
296 .strip_prefix('^')
297 .unwrap_or(trimmed)
298 .trim()
299 .to_string(),
300 bhc_ast::DocKind::Trailing,
301 )
302 } else if trimmed.starts_with('|') {
303 (
304 trimmed
305 .strip_prefix('|')
306 .unwrap_or(trimmed)
307 .trim()
308 .to_string(),
309 bhc_ast::DocKind::Preceding,
310 )
311 } else {
312 (trimmed.to_string(), bhc_ast::DocKind::Preceding)
313 };
314
315 if first_span.is_none() {
316 first_span = Some(span);
317 kind = doc_kind;
318 }
319 last_span = Some(span);
320 texts.push(actual_text);
321 }
322 TokenKind::DocCommentBlock(text) => {
323 let span = tok.span;
324 let text = text.clone();
325 self.advance();
326
327 let trimmed = text.trim();
329 let (actual_text, doc_kind) = if trimmed.starts_with('^') {
330 (
331 trimmed
332 .strip_prefix('^')
333 .unwrap_or(trimmed)
334 .trim()
335 .to_string(),
336 bhc_ast::DocKind::Trailing,
337 )
338 } else if trimmed.starts_with('|') {
339 (
340 trimmed
341 .strip_prefix('|')
342 .unwrap_or(trimmed)
343 .trim()
344 .to_string(),
345 bhc_ast::DocKind::Preceding,
346 )
347 } else {
348 (trimmed.to_string(), bhc_ast::DocKind::Preceding)
349 };
350
351 if first_span.is_none() {
352 first_span = Some(span);
353 kind = doc_kind;
354 }
355 last_span = Some(span);
356 texts.push(actual_text);
357 }
358 TokenKind::VirtualSemi if !texts.is_empty() => {
363 let save = self.pos;
364 self.advance();
365 if !matches!(
366 self.current().map(|t| &t.node.kind),
367 Some(TokenKind::DocCommentLine(_) | TokenKind::DocCommentBlock(_))
368 ) {
369 self.pos = save;
370 break;
371 }
372 }
373 _ => break,
374 }
375 }
376
377 if texts.is_empty() {
378 return None;
379 }
380
381 let combined_text = texts.join("\n");
382 let span = first_span.unwrap().to(last_span.unwrap());
383
384 Some(bhc_ast::DocComment {
385 text: combined_text,
386 kind,
387 span,
388 })
389 }
390
391 fn expect(&mut self, kind: &TokenKind) -> ParseResult<Spanned<Token>> {
393 if self.check(kind) {
394 Ok(self.advance().unwrap())
395 } else if self.at_eof() {
396 Err(ParseError::UnexpectedEof {
397 expected: kind.description().to_string(),
398 })
399 } else {
400 let current = self.current().unwrap();
401 Err(ParseError::Unexpected {
402 found: current.node.kind.description().to_string(),
403 expected: kind.description().to_string(),
404 span: current.span,
405 })
406 }
407 }
408
409 fn emit(&mut self, diagnostic: Diagnostic) {
411 self.diagnostics.emit(diagnostic);
412 }
413
414 #[must_use]
416 pub fn has_errors(&self) -> bool {
417 self.diagnostics.has_errors()
418 }
419
420 pub fn take_diagnostics(&mut self) -> Vec<Diagnostic> {
422 self.diagnostics.take_diagnostics()
423 }
424}
425
426pub fn parse_module(src: &str, file_id: FileId) -> (Option<Module>, Vec<Diagnostic>) {
428 let mut parser = Parser::new(src, file_id);
429 let module = parser.parse_module();
430 let diagnostics = parser.take_diagnostics();
431
432 match module {
433 Ok(m) => (Some(m), diagnostics),
434 Err(e) => {
435 let mut diags = diagnostics;
436 diags.push(e.to_diagnostic(file_id));
437 (None, diags)
438 }
439 }
440}
441
442pub fn parse_expr(src: &str, file_id: FileId) -> (Option<Expr>, Vec<Diagnostic>) {
444 let mut parser = Parser::new(src, file_id);
445 let expr = parser.parse_expr();
446 let diagnostics = parser.take_diagnostics();
447
448 match expr {
449 Ok(e) => (Some(e), diagnostics),
450 Err(e) => {
451 let mut diags = diagnostics;
452 diags.push(e.to_diagnostic(file_id));
453 (None, diags)
454 }
455 }
456}
457
458pub fn parse_import_decl(
462 src: &str,
463 file_id: FileId,
464) -> (Option<bhc_ast::ImportDecl>, Vec<Diagnostic>) {
465 let mut parser = Parser::new(src, file_id);
466 let import = parser.parse_import();
467 let diagnostics = parser.take_diagnostics();
468
469 match import {
470 Ok(decl) => (Some(decl), diagnostics),
471 Err(e) => {
472 let mut diags = diagnostics;
473 let diag: Diagnostic = e.to_diagnostic(file_id);
474 diags.push(diag);
475 (None, diags)
476 }
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483 use bhc_ast::{Decl, ImportSpec, TypeFamilyKind};
484
485 fn parse_expr_ok(src: &str) -> Expr {
486 let (expr, diags) = parse_expr(src, FileId::new(0));
487 assert!(diags.is_empty(), "Parse errors: {:?}", diags);
488 expr.expect("Expected expression")
489 }
490
491 fn parse_module_ok(src: &str) -> Module {
492 let (module, diags) = parse_module(src, FileId::new(0));
493 assert!(diags.is_empty(), "Parse errors: {:?}", diags);
494 module.expect("Expected module")
495 }
496
497 #[test]
498 fn test_parser_creation() {
499 let parser = Parser::new("let x = 1 in x", FileId::new(0));
500 assert!(!parser.at_eof());
501 }
502
503 #[test]
504 fn test_simple_literals() {
505 let expr = parse_expr_ok("42");
506 assert!(matches!(expr, Expr::Lit(bhc_ast::Lit::Int(42), _)));
507
508 let expr = parse_expr_ok("3.14");
509 assert!(matches!(expr, Expr::Lit(bhc_ast::Lit::Float(_), _)));
510
511 let expr = parse_expr_ok("'a'");
512 assert!(matches!(expr, Expr::Lit(bhc_ast::Lit::Char('a'), _)));
513
514 let expr = parse_expr_ok("\"hello\"");
515 assert!(matches!(expr, Expr::Lit(bhc_ast::Lit::String(_), _)));
516 }
517
518 #[test]
519 fn test_variable_and_constructor() {
520 let expr = parse_expr_ok("foo");
521 assert!(matches!(expr, Expr::Var(_, _)));
522
523 let expr = parse_expr_ok("Foo");
524 assert!(matches!(expr, Expr::Con(_, _)));
525 }
526
527 #[test]
528 fn test_application() {
529 let expr = parse_expr_ok("f x");
530 assert!(matches!(expr, Expr::App(_, _, _)));
531
532 let expr = parse_expr_ok("f x y z");
533 assert!(matches!(expr, Expr::App(_, _, _)));
534 }
535
536 #[test]
537 fn test_infix_operators() {
538 let expr = parse_expr_ok("1 + 2");
539 assert!(matches!(expr, Expr::Infix(_, _, _, _)));
540
541 let expr = parse_expr_ok("a && b || c");
542 assert!(matches!(expr, Expr::Infix(_, _, _, _)));
543 }
544
545 #[test]
546 fn test_lambda() {
547 let expr = parse_expr_ok("\\x -> x");
548 assert!(matches!(expr, Expr::Lam(_, _, _)));
549
550 let expr = parse_expr_ok("\\x y -> x + y");
551 if let Expr::Lam(pats, _, _) = expr {
552 assert_eq!(pats.len(), 2);
553 } else {
554 panic!("Expected lambda");
555 }
556 }
557
558 #[test]
559 fn test_let_expression() {
560 let expr = parse_expr_ok("let { x = 1 } in x");
561 assert!(matches!(expr, Expr::Let(_, _, _)));
562 }
563
564 #[test]
565 fn test_if_expression() {
566 let expr = parse_expr_ok("if True then 1 else 2");
567 assert!(matches!(expr, Expr::If(_, _, _, _)));
568 }
569
570 #[test]
571 fn test_case_expression() {
572 let expr = parse_expr_ok("case x of { Just y -> y }");
573 assert!(matches!(expr, Expr::Case(_, _, _)));
574 }
575
576 #[test]
577 fn test_do_expression() {
578 let expr = parse_expr_ok("do { x <- getLine; putStrLn x }");
579 assert!(matches!(expr, Expr::Do(_, _)));
580 }
581
582 #[test]
583 fn test_tuple() {
584 let expr = parse_expr_ok("(1, 2, 3)");
585 if let Expr::Tuple(exprs, _) = expr {
586 assert_eq!(exprs.len(), 3);
587 } else {
588 panic!("Expected tuple");
589 }
590 }
591
592 #[test]
593 fn test_list() {
594 let expr = parse_expr_ok("[1, 2, 3]");
595 if let Expr::List(exprs, _) = expr {
596 assert_eq!(exprs.len(), 3);
597 } else {
598 panic!("Expected list");
599 }
600 }
601
602 #[test]
603 fn test_list_comprehension() {
604 let expr = parse_expr_ok("[x | x <- xs]");
605 assert!(matches!(expr, Expr::ListComp(_, _, _)));
606 }
607
608 #[test]
609 fn test_arithmetic_sequence() {
610 let expr = parse_expr_ok("[1..10]");
611 assert!(matches!(expr, Expr::ArithSeq(_, _)));
612
613 let expr = parse_expr_ok("[1..]");
614 assert!(matches!(expr, Expr::ArithSeq(_, _)));
615
616 let expr = parse_expr_ok("[1,3..10]");
617 assert!(matches!(expr, Expr::ArithSeq(_, _)));
618 }
619
620 #[test]
621 fn test_record_construction() {
622 let expr = parse_expr_ok("Foo { bar = 1, baz = 2 }");
623 assert!(matches!(expr, Expr::RecordCon(_, _, _, _)));
624 }
625
626 #[test]
627 fn test_qualified_record_construction() {
628 let expr = parse_expr_ok("M.Foo { bar = 1, baz = 2 }");
629 assert!(matches!(expr, Expr::QualRecordCon(_, _, _, _, _)));
630 }
631
632 #[test]
633 fn test_record_update() {
634 let expr = parse_expr_ok("foo { bar = 1 }");
635 assert!(matches!(expr, Expr::RecordUpd(_, _, _)));
636 }
637
638 #[test]
639 fn test_operator_section_right() {
640 let expr = parse_expr_ok("(+ 1)");
642 assert!(matches!(expr, Expr::Lam(_, _, _)));
643 }
644
645 #[test]
646 fn test_operator_section_left() {
647 let expr = parse_expr_ok("(1 +)");
649 assert!(matches!(expr, Expr::Lam(_, _, _)));
650 }
651
652 #[test]
653 fn test_operator_as_function() {
654 let expr = parse_expr_ok("(+)");
656 assert!(matches!(expr, Expr::Var(_, _)));
657 }
658
659 #[test]
660 fn test_negation() {
661 let expr = parse_expr_ok("1 + -x");
664 assert!(matches!(expr, Expr::Infix(_, _, _, _)));
666 }
667
668 #[test]
669 fn test_lazy_expression() {
670 let expr = parse_expr_ok("lazy { expensive }");
671 assert!(matches!(expr, Expr::Lazy(_, _)));
672 }
673
674 #[test]
677 fn test_pattern_wildcard() {
678 let module = parse_module_ok("f _ = 1");
679 assert!(!module.decls.is_empty());
680 }
681
682 #[test]
683 fn test_pattern_constructor() {
684 let module = parse_module_ok("f (Just x) = x");
685 assert!(!module.decls.is_empty());
686 }
687
688 #[test]
689 fn test_pattern_infix() {
690 let module = parse_module_ok("f (x : xs) = xs");
691 assert!(!module.decls.is_empty());
692 }
693
694 #[test]
695 fn test_pattern_as() {
696 let module = parse_module_ok("f xs@(x : _) = xs");
697 assert!(!module.decls.is_empty());
698 }
699
700 #[test]
701 fn test_pattern_lazy() {
702 let module = parse_module_ok("f ~x = x");
703 assert!(!module.decls.is_empty());
704 }
705
706 #[test]
707 fn test_pattern_bang() {
708 let module = parse_module_ok("f !x = x");
709 assert!(!module.decls.is_empty());
710 }
711
712 #[test]
713 fn test_record_pattern() {
714 let module = parse_module_ok("f Foo { bar = x } = x");
715 assert!(!module.decls.is_empty());
716 }
717
718 #[test]
721 fn test_simple_type() {
722 let module = parse_module_ok("f :: Int");
723 assert!(!module.decls.is_empty());
724 }
725
726 #[test]
727 fn test_function_type() {
728 let module = parse_module_ok("f :: Int -> Bool");
729 assert!(!module.decls.is_empty());
730 }
731
732 #[test]
733 fn test_type_application() {
734 let module = parse_module_ok("f :: Maybe Int");
735 assert!(!module.decls.is_empty());
736 }
737
738 #[test]
739 fn test_tuple_type() {
740 let module = parse_module_ok("f :: (Int, Bool)");
741 assert!(!module.decls.is_empty());
742 }
743
744 #[test]
745 fn test_list_type() {
746 let module = parse_module_ok("f :: [Int]");
747 assert!(!module.decls.is_empty());
748 }
749
750 #[test]
751 fn test_constrained_type() {
752 let module = parse_module_ok("f :: Eq a => a -> Bool");
753 assert!(!module.decls.is_empty());
754 }
755
756 #[test]
757 fn test_multi_constrained_type() {
758 let module = parse_module_ok("f :: (Eq a, Ord a) => a -> a -> Bool");
759 assert!(!module.decls.is_empty());
760 }
761
762 #[test]
763 fn test_forall_type() {
764 let module = parse_module_ok("f :: forall a. a -> a");
765 assert!(!module.decls.is_empty());
766 }
767
768 #[test]
771 fn test_module_header() {
772 let module = parse_module_ok("module Foo where\nx = 1");
773 assert!(module.name.is_some());
774 }
775
776 #[test]
777 fn test_module_exports() {
778 let module = parse_module_ok("module Foo (bar, baz) where\nbar = 1\nbaz = 2");
779 assert!(module.exports.is_some());
780 }
781
782 #[test]
783 fn test_imports() {
784 let module = parse_module_ok("import Data.List\nx = 1");
785 assert!(!module.imports.is_empty());
786 }
787
788 #[test]
789 fn test_qualified_import() {
790 let module = parse_module_ok("import qualified Data.Map as M\nx = 1");
791 assert!(!module.imports.is_empty());
792 assert!(module.imports[0].qualified);
793 }
794
795 #[test]
798 fn test_data_declaration() {
799 let module = parse_module_ok("data Foo = Bar | Baz Int");
800 assert!(!module.decls.is_empty());
801 }
802
803 #[test]
804 fn test_newtype_declaration() {
805 let module = parse_module_ok("newtype Foo = Foo Int");
806 assert!(!module.decls.is_empty());
807 }
808
809 #[test]
810 fn test_type_alias() {
811 let module = parse_module_ok("type Foo = Int");
812 assert!(!module.decls.is_empty());
813 }
814
815 #[test]
816 fn test_class_declaration() {
817 let module = parse_module_ok("class Eq a where\n eq :: a -> a -> Bool");
818 assert!(!module.decls.is_empty());
819 }
820
821 #[test]
822 fn test_instance_declaration() {
823 let module = parse_module_ok("instance Eq Int where\n eq = primEqInt");
824 assert!(!module.decls.is_empty());
825 }
826
827 #[test]
828 fn test_fixity_declaration() {
829 let module = parse_module_ok("infixl 6 +");
830 assert!(!module.decls.is_empty());
831 }
832
833 #[test]
836 fn test_language_pragma() {
837 let module = parse_module_ok("{-# LANGUAGE GADTs #-}\nx = 1");
838 assert_eq!(module.pragmas.len(), 1);
839 match &module.pragmas[0].kind {
840 bhc_ast::PragmaKind::Language(exts) => {
841 assert_eq!(exts.len(), 1);
842 assert_eq!(exts[0].as_str(), "GADTs");
843 }
844 _ => panic!("Expected Language pragma"),
845 }
846 }
847
848 #[test]
849 fn test_multiple_pragmas() {
850 let module = parse_module_ok(
851 "{-# LANGUAGE GADTs #-}\n{-# LANGUAGE TypeFamilies, DataKinds #-}\nx = 1",
852 );
853 assert_eq!(module.pragmas.len(), 2);
854 }
855
856 #[test]
857 fn test_options_ghc_pragma() {
858 let module = parse_module_ok("{-# OPTIONS_GHC -Wall -Werror #-}\nx = 1");
859 assert_eq!(module.pragmas.len(), 1);
860 match &module.pragmas[0].kind {
861 bhc_ast::PragmaKind::OptionsGhc(opts) => {
862 assert!(opts.contains("-Wall"));
863 assert!(opts.contains("-Werror"));
864 }
865 _ => panic!("Expected OptionsGhc pragma"),
866 }
867 }
868
869 #[test]
870 fn test_inline_pragma() {
871 let module = parse_module_ok("{-# INLINE foo #-}\nfoo = 1");
872 assert_eq!(module.pragmas.len(), 1);
873 match &module.pragmas[0].kind {
874 bhc_ast::PragmaKind::Inline(name) => {
875 assert_eq!(name.name.as_str(), "foo");
876 }
877 _ => panic!("Expected Inline pragma"),
878 }
879 }
880
881 #[test]
886 fn test_guarded_function() {
887 let module = parse_module_ok("abs x | x >= 0 = x | otherwise = -x");
888 assert!(!module.decls.is_empty());
889 if let bhc_ast::Decl::FunBind(fun) = &module.decls[0] {
890 assert_eq!(fun.name.name.as_str(), "abs");
891 assert_eq!(fun.clauses.len(), 1);
892 if let bhc_ast::Rhs::Guarded(guards, _) = &fun.clauses[0].rhs {
893 assert_eq!(guards.len(), 2);
894 } else {
895 panic!("Expected guarded RHS");
896 }
897 } else {
898 panic!("Expected FunBind");
899 }
900 }
901
902 #[test]
903 fn test_multi_clause_function() {
904 let module = parse_module_ok("fac 0 = 1; fac n = (n * fac (n - 1))");
906 assert_eq!(module.decls.len(), 1); if let bhc_ast::Decl::FunBind(fun) = &module.decls[0] {
908 assert_eq!(fun.name.name.as_str(), "fac");
909 assert_eq!(fun.clauses.len(), 2);
910 } else {
911 panic!("Expected FunBind");
912 }
913 }
914
915 #[test]
916 fn test_where_clause() {
917 let module = parse_module_ok("f x = y where { y = x }");
919 if let bhc_ast::Decl::FunBind(fun) = &module.decls[0] {
920 assert_eq!(fun.clauses[0].wheres.len(), 1);
921 } else {
922 panic!("Expected FunBind");
923 }
924 }
925
926 #[test]
927 fn test_where_clause_multiple() {
928 let module = parse_module_ok("f x = y where { y = (x + 1); z = (x + 2) }");
930 if let bhc_ast::Decl::FunBind(fun) = &module.decls[0] {
931 assert_eq!(fun.clauses[0].wheres.len(), 2);
932 } else {
933 panic!("Expected FunBind");
934 }
935 }
936
937 #[test]
938 fn test_strict_field() {
939 let module = parse_module_ok("data Pair = Pair !Int !Int");
940 if let bhc_ast::Decl::DataDecl(data) = &module.decls[0] {
941 assert_eq!(data.constrs.len(), 1);
942 if let bhc_ast::ConFields::Positional(fields) = &data.constrs[0].fields {
943 assert_eq!(fields.len(), 2);
944 assert!(matches!(fields[0], bhc_ast::Type::Bang(_, _)));
945 assert!(matches!(fields[1], bhc_ast::Type::Bang(_, _)));
946 } else {
947 panic!("Expected Positional fields");
948 }
949 } else {
950 panic!("Expected DataDecl");
951 }
952 }
953
954 #[test]
955 fn test_lazy_field() {
956 let module = parse_module_ok("data Lazy a = Lazy ~a");
957 if let bhc_ast::Decl::DataDecl(data) = &module.decls[0] {
958 if let bhc_ast::ConFields::Positional(fields) = &data.constrs[0].fields {
959 assert_eq!(fields.len(), 1);
960 assert!(matches!(fields[0], bhc_ast::Type::Lazy(_, _)));
961 } else {
962 panic!("Expected Positional fields");
963 }
964 } else {
965 panic!("Expected DataDecl");
966 }
967 }
968
969 #[test]
970 fn test_mixed_strict_lazy_fields() {
971 let module = parse_module_ok("data Triple a b c = Triple !a b ~c");
972 if let bhc_ast::Decl::DataDecl(data) = &module.decls[0] {
973 if let bhc_ast::ConFields::Positional(fields) = &data.constrs[0].fields {
974 assert_eq!(fields.len(), 3);
975 assert!(matches!(fields[0], bhc_ast::Type::Bang(_, _)));
976 assert!(matches!(fields[1], bhc_ast::Type::Var(_, _)));
977 assert!(matches!(fields[2], bhc_ast::Type::Lazy(_, _)));
978 } else {
979 panic!("Expected Positional fields");
980 }
981 } else {
982 panic!("Expected DataDecl");
983 }
984 }
985
986 #[test]
987 fn test_guards_with_where() {
988 let module = parse_module_ok(
990 "signum x | x > 0 = positive | otherwise = zero where { positive = 1; zero = 0 }",
991 );
992 if let bhc_ast::Decl::FunBind(fun) = &module.decls[0] {
993 if let bhc_ast::Rhs::Guarded(guards, _) = &fun.clauses[0].rhs {
994 assert_eq!(guards.len(), 2);
995 } else {
996 panic!("Expected guarded RHS");
997 }
998 assert_eq!(fun.clauses[0].wheres.len(), 2);
999 } else {
1000 panic!("Expected FunBind");
1001 }
1002 }
1003
1004 #[test]
1005 fn test_backtick_operator_with_lambda() {
1006 let _ = parse_module_ok("test = f `catch` \\e -> handle e");
1008 let _ = parse_module_ok("test = x `fmap` (\\a -> a + 1)");
1009 let _ = parse_module_ok("test = action `E.catch` \\e -> case e of { Ex -> handler }");
1011 }
1012
1013 #[test]
1014 fn test_as_patterns() {
1015 let _ = parse_module_ok("f x@(Just y) = y");
1017 let _ = parse_module_ok("g xs@(x:_) = x");
1019 let _ = parse_module_ok("h conf@(Config { field = v }) = v");
1021 }
1022
1023 #[test]
1024 fn test_list_type_annotation() {
1025 let _ = parse_module_ok("test = [1 .. 9 :: Int]");
1027 let _ = parse_module_ok("test = map show [4..9]");
1029 }
1030
1031 #[test]
1032 fn test_multi_clause_explicit_layout() {
1033 let module = parse_module_ok("f 0 = 1; f n = n");
1035 if let bhc_ast::Decl::FunBind(fun) = &module.decls[0] {
1037 assert_eq!(fun.clauses.len(), 2, "Expected 2 clauses");
1038 } else {
1039 panic!("Expected FunBind");
1040 }
1041 }
1042
1043 #[test]
1044 fn test_multi_clause_with_type_sig_explicit() {
1045 let module = parse_module_ok("f :: Int -> Int; f 0 = 1; f n = n");
1047 assert!(matches!(module.decls[0], bhc_ast::Decl::TypeSig { .. }));
1049 if let bhc_ast::Decl::FunBind(fun) = &module.decls[1] {
1050 assert_eq!(fun.clauses.len(), 2, "Expected 2 clauses");
1051 } else {
1052 panic!("Expected FunBind");
1053 }
1054 }
1055
1056 #[test]
1057 fn test_multi_clause_with_layout() {
1058 let src = r#"module Test where
1061
1062f :: Int -> Int
1063f 0 = 1
1064f n = n
1065"#;
1066 let (module, diags) = parse_module(src, FileId::new(0));
1067 if !diags.is_empty() {
1068 for d in &diags {
1070 eprintln!("Error: {:?}", d);
1071 }
1072 }
1073 let module = module.expect("Should parse");
1074 assert_eq!(
1076 module.decls.len(),
1077 2,
1078 "Expected 2 decls (TypeSig + FunBind)"
1079 );
1080 if let bhc_ast::Decl::FunBind(fun) = &module.decls[1] {
1081 assert_eq!(
1082 fun.clauses.len(),
1083 2,
1084 "Expected 2 clauses, got: {}",
1085 fun.clauses.len()
1086 );
1087 } else {
1088 panic!("Expected FunBind, got: {:?}", module.decls[1]);
1089 }
1090 }
1091
1092 #[test]
1093 fn test_record_with_layout_style() {
1094 let src = r#"module Test where
1096
1097data Foo = Foo { field1 :: Int
1098 , field2 :: String
1099 } deriving (Show)
1100"#;
1101 let (module, diags) = parse_module(src, FileId::new(0));
1102 for d in &diags {
1103 eprintln!("Error: {:?}", d);
1104 }
1105 assert!(diags.is_empty(), "Should parse without errors");
1106 let module = module.expect("Should parse");
1107 assert_eq!(module.decls.len(), 1);
1108 }
1109
1110 #[test]
1111 fn test_xmonad_stackset_style() {
1112 let src = r#"module Test where
1114
1115data StackSet i l a sid sd =
1116 StackSet { current :: !(Screen i l a sid sd)
1117 , visible :: [Screen i l a sid sd]
1118 } deriving (Show, Read, Eq)
1119
1120data Screen i l a sid sd = Screen { workspace :: !(Workspace i l a) }
1121 deriving (Show, Read, Eq)
1122
1123data Workspace i l a = Workspace { tag :: !i }
1124 deriving (Show, Read, Eq)
1125"#;
1126 let (module, diags) = parse_module(src, FileId::new(0));
1127 for d in &diags {
1128 eprintln!("Error: {:?}", d);
1129 }
1130 assert!(diags.is_empty(), "Should parse without errors");
1131 let module = module.expect("Should parse");
1132 assert_eq!(module.decls.len(), 3, "Expected 3 data declarations");
1133 }
1134
1135 #[test]
1136 fn test_instance_with_operator_method() {
1137 let src = r#"module Test where
1139
1140instance Foldable Stack where
1141 toList = integrate
1142 foldr f z = foldr f z . toList
1143"#;
1144 let (module, diags) = parse_module(src, FileId::new(0));
1145 for d in &diags {
1146 eprintln!("Error: {:?}", d);
1147 }
1148 assert!(diags.is_empty(), "Should parse without errors");
1149 let module = module.expect("Should parse");
1150 assert_eq!(module.decls.len(), 1);
1151 }
1152
1153 #[test]
1154 fn test_do_let_without_in() {
1155 let src = r#"module Test where
1157
1158test = do
1159 let x = 1
1160 y <- getY
1161 pure (x + y)
1162"#;
1163 let (_module, diags) = parse_module(src, FileId::new(0));
1164 for d in &diags {
1165 eprintln!("Error: {:?}", d);
1166 }
1167 assert!(diags.is_empty(), "Do-notation let should work without 'in'");
1168 }
1169
1170 #[test]
1171 fn test_do_let_simple_binding() {
1172 let src = r#"module Test where
1174
1175test = do
1176 sh <- io x
1177 let isFixedSize = isJust sh
1178 isTransient <- isJust sh
1179 pure isTransient
1180"#;
1181 let (_module, diags) = parse_module(src, FileId::new(0));
1182 for d in &diags {
1183 eprintln!("Error: {:?}", d);
1184 }
1185 assert!(
1186 diags.is_empty(),
1187 "Do-notation let followed by statement should parse"
1188 );
1189 }
1190
1191 #[test]
1192 fn test_do_let_complex_binding() {
1193 let src = r#"module Test where
1196
1197isFixedSizeOrTransient d w = do
1198 sh <- io (getWMNormalHints d w)
1199 let isFixedSize = isJust (sh_min_size sh) && sh_min_size sh == sh_max_size sh
1200 isTransient <- isJust <$> io (getTransientForHint d w)
1201 pure (isFixedSize || isTransient)
1202"#;
1203 let (_module, diags) = parse_module(src, FileId::new(0));
1204 for d in &diags {
1205 eprintln!("Error: {:?}", d);
1206 }
1207 assert!(diags.is_empty(), "Complex do-notation should parse");
1208 }
1209
1210 #[test]
1211 fn test_import_then_function() {
1212 let src = r#"module Test where
1214
1215import Data.Maybe
1216
1217-- | Lift action
1218liftX :: X a -> Query a
1219liftX = Query . lift
1220"#;
1221 let (_module, diags) = parse_module(src, FileId::new(0));
1222 for d in &diags {
1223 eprintln!("Error: {:?}", d);
1224 }
1225 assert!(diags.is_empty(), "Import followed by function should parse");
1226 }
1227
1228 #[test]
1229 fn test_infix_function_definition() {
1230 let src = r#"module Test where
1232
1233(-->) :: Bool -> a -> a
1234p --> f = if p then f else undefined
1235
1236(<&&>) :: Bool -> Bool -> Bool
1237x <&&> y = x && y
1238"#;
1239 let (_module, diags) = parse_module(src, FileId::new(0));
1240 for d in &diags {
1241 eprintln!("Error: {:?}", d);
1242 }
1243 assert!(diags.is_empty(), "Infix function definitions should parse");
1244 }
1245
1246 #[test]
1247 fn test_primed_identifier_case_pattern() {
1248 let src = r#"module Test where
1250
1251test xs = case xs of
1252 f':rs' -> Just (f', rs')
1253 [] -> Nothing
1254"#;
1255 let (module, diags) = parse_module(src, FileId::new(0));
1256 for d in &diags {
1257 eprintln!("Error: {:?}", d);
1258 }
1259 assert!(
1260 diags.is_empty(),
1261 "Primed identifier case patterns should parse"
1262 );
1263 let module = module.expect("Should parse");
1264 assert_eq!(module.decls.len(), 1);
1265 }
1266
1267 #[test]
1268 fn test_as_pattern_with_record() {
1269 let src = r#"module Test where
1271
1272test = do
1273 conf@Config { field = x } <- getConfig
1274 return x
1275"#;
1276 let (module, diags) = parse_module(src, FileId::new(0));
1277 for d in &diags {
1278 eprintln!("Error: {:?}", d);
1279 }
1280 assert!(diags.is_empty(), "As-pattern with record should parse");
1281 let module = module.expect("Should parse");
1282 assert_eq!(module.decls.len(), 1);
1283 }
1284
1285 #[test]
1286 fn test_deriving_with_type_applications() {
1287 let src = r#"module Test where
1289
1290newtype X a = X (ReaderT XConf (StateT XState IO) a)
1291 deriving (Functor, Applicative, Monad, MonadState XState, MonadReader XConf)
1292"#;
1293 let (module, diags) = parse_module(src, FileId::new(0));
1294 for d in &diags {
1295 eprintln!("Error: {:?}", d);
1296 }
1297 assert!(
1298 diags.is_empty(),
1299 "Deriving with type applications should parse"
1300 );
1301 let module = module.expect("Should parse");
1302 assert_eq!(module.decls.len(), 1);
1303 }
1304
1305 #[test]
1306 fn test_deriving_via() {
1307 let src = r#"module Test where
1309
1310newtype X a = X (IO a) deriving (Semigroup, Monoid) via Ap X a
1311"#;
1312 let (module, diags) = parse_module(src, FileId::new(0));
1313 for d in &diags {
1314 eprintln!("Error: {:?}", d);
1315 }
1316 assert!(diags.is_empty(), "Deriving via should parse");
1317 let module = module.expect("Should parse");
1318 assert_eq!(module.decls.len(), 1);
1319 }
1320
1321 #[test]
1322 fn test_backtick_in_parentheses() {
1323 let src = r#"module Test where
1325
1326test x xs = guard (x `elem` xs)
1327"#;
1328 let (module, diags) = parse_module(src, FileId::new(0));
1329 for d in &diags {
1330 eprintln!("Error: {:?}", d);
1331 }
1332 assert!(diags.is_empty(), "Backtick in parentheses should parse");
1333 let module = module.expect("Should parse");
1334 assert_eq!(module.decls.len(), 1);
1335 }
1336
1337 #[test]
1338 fn test_backtick_right_section() {
1339 let src = r#"module Test where
1341
1342test = filter (`M.notMember` floatingMap)
1343"#;
1344 let (module, diags) = parse_module(src, FileId::new(0));
1345 for d in &diags {
1346 eprintln!("Error: {:?}", d);
1347 }
1348 assert!(diags.is_empty(), "Backtick right section should parse");
1349 let module = module.expect("Should parse");
1350 assert_eq!(module.decls.len(), 1);
1351 }
1352
1353 #[test]
1354 fn test_backtick_left_section() {
1355 let src = r#"module Test where
1357
1358test xs = filter (\x -> not $ any (x `containedIn`) xs) $ xs
1359"#;
1360 let (module, diags) = parse_module(src, FileId::new(0));
1361 for d in &diags {
1362 eprintln!("Error: {:?}", d);
1363 }
1364 assert!(diags.is_empty(), "Backtick left section should parse");
1365 let module = module.expect("Should parse");
1366 assert_eq!(module.decls.len(), 1);
1367 }
1368
1369 #[test]
1370 fn test_lambda_case_multi_alt() {
1371 let src = r#"module Test where
1373
1374rescreen = getInfo >>= \case
1375 [] -> trace "empty"
1376 x:xs -> process x xs
1377"#;
1378 let (module, diags) = parse_module(src, FileId::new(0));
1379 for d in &diags {
1380 eprintln!("Error: {:?}", d);
1381 }
1382 assert!(
1383 diags.is_empty(),
1384 "Lambda-case with multiple alternatives should parse"
1385 );
1386 let module = module.expect("Should parse");
1387 assert_eq!(module.decls.len(), 1);
1388 }
1389
1390 #[test]
1391 fn test_type_equality_constraint() {
1392 let src = r#"module Test where
1394
1395instance (a ~ Int) => Num a where
1396 fromInteger = undefined
1397"#;
1398 let (module, diags) = parse_module(src, FileId::new(0));
1399 for d in &diags {
1400 eprintln!("Error: {:?}", d);
1401 }
1402 assert!(diags.is_empty(), "Type equality constraint should parse");
1403 let module = module.expect("Should parse");
1404 assert_eq!(module.decls.len(), 1);
1405 }
1406
1407 #[test]
1408 fn test_multiline_type_signature_parsing() {
1409 let src = r#"module Foo where
1411tile
1412 :: Rational
1413 -> Rectangle
1414 -> Int
1415"#;
1416 let (module, diags) = parse_module(src, FileId::new(0));
1417 for d in &diags {
1418 eprintln!("Error: {:?}", d);
1419 }
1420 assert!(diags.is_empty(), "Multi-line type signature should parse");
1421 let module = module.expect("Should parse");
1422 assert_eq!(
1424 module.decls.len(),
1425 1,
1426 "Should have 1 decl, got {:?}",
1427 module.decls
1428 );
1429 }
1430
1431 #[test]
1432 fn test_multiline_type_signature_with_function_parsing() {
1433 let src = r#"module Foo where
1435tile
1436 :: Rational
1437 -> Rectangle
1438tile f r = r
1439"#;
1440 let (module, diags) = parse_module(src, FileId::new(0));
1441 for d in &diags {
1442 eprintln!("Error: {:?}", d);
1443 }
1444 assert!(
1445 diags.is_empty(),
1446 "Multi-line type signature with function should parse"
1447 );
1448 let module = module.expect("Should parse");
1449 assert_eq!(
1451 module.decls.len(),
1452 2,
1453 "Should have 2 decls, got {:?}",
1454 module.decls
1455 );
1456 }
1457
1458 #[test]
1459 fn test_multiline_type_signature_after_instance() {
1460 let src = r#"module Foo where
1462instance Show Foo where
1463 show _ = "Foo"
1464
1465tile
1466 :: Int
1467 -> Bool
1468tile n = n > 0
1469"#;
1470 let (module, diags) = parse_module(src, FileId::new(0));
1471 for d in &diags {
1472 eprintln!("Error: {:?}", d);
1473 }
1474 assert!(
1475 diags.is_empty(),
1476 "Type signature after instance should parse"
1477 );
1478 let module = module.expect("Should parse");
1479 assert_eq!(
1481 module.decls.len(),
1482 3,
1483 "Should have 3 decls, got {:?}",
1484 module.decls
1485 );
1486 }
1487
1488 #[test]
1489 fn test_multiline_type_signature_with_doc_comments() {
1490 let src = r#"module Foo where
1492instance Show Foo where
1493 description _ = "Foo"
1494
1495-- | Doc comment
1496tile
1497 :: Int -- ^ arg1
1498 -> Bool -- ^ result
1499tile n = n > 0
1500"#;
1501 let (module, diags) = parse_module(src, FileId::new(0));
1502 for d in &diags {
1503 eprintln!("Error: {:?}", d);
1504 }
1505 assert!(
1506 diags.is_empty(),
1507 "Type signature with doc comments should parse"
1508 );
1509 let module = module.expect("Should parse");
1510 assert_eq!(
1512 module.decls.len(),
1513 3,
1514 "Should have 3 decls, got {:?}",
1515 module.decls
1516 );
1517 }
1518
1519 #[test]
1520 fn test_class_multiline_method_signature() {
1521 let src = r#"module Foo where
1523class Show a => Foo a b where
1524 -- | Method doc
1525 runMethod :: a
1526 -> b
1527 -> Int
1528 runMethod x y = 42
1529"#;
1530 let (module, diags) = parse_module(src, FileId::new(0));
1531 for d in &diags {
1532 eprintln!("Error: {:?}", d);
1533 }
1534 assert!(
1535 diags.is_empty(),
1536 "Class with multi-line method signature should parse"
1537 );
1538 let module = module.expect("Should parse");
1539 assert_eq!(
1541 module.decls.len(),
1542 1,
1543 "Should have 1 decl, got {:?}",
1544 module.decls
1545 );
1546 }
1547
1548 #[test]
1549 fn test_class_default_method() {
1550 let src = r#"
1552class ExtensionClass a where
1553 initialValue :: a
1554 extensionType :: a -> String
1555 extensionType = show
1556"#;
1557 let (module, diags) = parse_module(src, FileId::new(0));
1558 for d in &diags {
1559 eprintln!("Error: {:?}", d);
1560 }
1561 assert!(diags.is_empty(), "Class with default method should parse");
1562 let module = module.expect("Should parse");
1563 assert_eq!(module.decls.len(), 1);
1564 }
1565
1566 #[test]
1567 fn test_class_default_method_with_docs() {
1568 let src = r#"
1570class ExtensionClass a where
1571 -- | Initial value
1572 initialValue :: a
1573 -- | The extension type.
1574 -- Multi-line doc.
1575 extensionType :: a -> String
1576 extensionType = show
1577"#;
1578 let (module, diags) = parse_module(src, FileId::new(0));
1579 for d in &diags {
1580 eprintln!("Error: {:?}", d);
1581 }
1582 assert!(diags.is_empty(), "Class with doc comments should parse");
1583 let module = module.expect("Should parse");
1584 assert_eq!(module.decls.len(), 1);
1585 }
1586
1587 #[test]
1588 fn test_class_xmonad_style() {
1589 let src = r#"
1591class ExtensionClass a where
1592 initialValue :: a
1593 extensionType :: a -> String
1594 extensionType = show
1595"#;
1596 let (module, diags) = parse_module(src, FileId::new(0));
1597 for d in &diags {
1598 eprintln!("Error (no pragma): {:?}", d);
1599 }
1600 assert!(diags.is_empty(), "Class without pragma should parse");
1601 let module = module.expect("Should parse");
1602 assert_eq!(module.decls.len(), 1);
1603
1604 let src_with_pragma = r#"
1606class ExtensionClass a where
1607 {-# MINIMAL initialValue #-}
1608 initialValue :: a
1609 extensionType :: a -> String
1610 extensionType = show
1611"#;
1612 let (module2, diags2) = parse_module(src_with_pragma, FileId::new(0));
1613 for d in &diags2 {
1614 eprintln!("Error (with pragma): {:?}", d);
1615 }
1616 assert!(diags2.is_empty(), "Class with MINIMAL pragma should parse");
1617 let module2 = module2.expect("Should parse");
1618 assert_eq!(module2.decls.len(), 1);
1619 }
1620
1621 #[test]
1622 fn test_class_with_associated_type() {
1623 let src = r#"
1625class Collection c where
1626 type Elem c
1627 empty :: c
1628 insert :: Elem c -> c -> c
1629"#;
1630 let (module, diags) = parse_module(src, FileId::new(0));
1631 for d in &diags {
1632 eprintln!("Error: {:?}", d);
1633 }
1634 assert!(diags.is_empty(), "Class with associated type should parse");
1635 let module = module.expect("Should parse");
1636 assert_eq!(module.decls.len(), 1);
1637 if let bhc_ast::Decl::ClassDecl(class) = &module.decls[0] {
1638 assert_eq!(class.name.name.as_str(), "Collection");
1639 assert_eq!(class.assoc_types.len(), 1);
1640 assert_eq!(class.assoc_types[0].name.name.as_str(), "Elem");
1641 } else {
1642 panic!("Expected class declaration");
1643 }
1644 }
1645
1646 #[test]
1647 fn test_class_with_associated_type_default() {
1648 let src = r#"
1650class Container c where
1651 type Element c = Int
1652 size :: c -> Int
1653"#;
1654 let (module, diags) = parse_module(src, FileId::new(0));
1655 for d in &diags {
1656 eprintln!("Error: {:?}", d);
1657 }
1658 assert!(
1659 diags.is_empty(),
1660 "Class with associated type default should parse"
1661 );
1662 let module = module.expect("Should parse");
1663 if let bhc_ast::Decl::ClassDecl(class) = &module.decls[0] {
1664 assert_eq!(class.assoc_types.len(), 1);
1665 assert!(class.assoc_types[0].default.is_some());
1666 } else {
1667 panic!("Expected class declaration");
1668 }
1669 }
1670
1671 #[test]
1672 fn test_instance_with_associated_type_def() {
1673 let src = r#"
1675instance Collection [a] where
1676 type Elem [a] = a
1677 empty = []
1678"#;
1679 let (module, diags) = parse_module(src, FileId::new(0));
1680 for d in &diags {
1681 eprintln!("Error: {:?}", d);
1682 }
1683 assert!(
1684 diags.is_empty(),
1685 "Instance with associated type should parse"
1686 );
1687 let module = module.expect("Should parse");
1688 if let bhc_ast::Decl::InstanceDecl(inst) = &module.decls[0] {
1689 assert_eq!(inst.assoc_type_defs.len(), 1);
1690 assert_eq!(inst.assoc_type_defs[0].name.name.as_str(), "Elem");
1691 } else {
1692 panic!("Expected instance declaration");
1693 }
1694 }
1695
1696 #[test]
1697 fn test_inline_let_expression() {
1698 let src = "foo = let x = 1 in x + 1";
1700 let (module, diags) = parse_module(src, FileId::new(0));
1701 for d in &diags {
1702 eprintln!("Error: {:?}", d);
1703 }
1704 assert!(diags.is_empty(), "Inline let expression should parse");
1705 let module = module.expect("Should parse");
1706 assert_eq!(module.decls.len(), 1);
1707 }
1708
1709 #[test]
1710 fn test_xmonad_parsing() {
1711 use std::path::Path;
1713
1714 let xmonad_dir = Path::new("/tmp/xmonad/src/XMonad");
1715 if !xmonad_dir.exists() {
1716 println!("XMonad source not found at {:?}, skipping test", xmonad_dir);
1717 return;
1718 }
1719
1720 let mut total_errors = 0;
1721 for entry in std::fs::read_dir(xmonad_dir).unwrap() {
1722 let entry = entry.unwrap();
1723 let path = entry.path();
1724 if path.extension().is_some_and(|ext| ext == "hs") {
1725 let src = std::fs::read_to_string(&path).unwrap();
1726 let file_id = crate::FileId::new(0);
1727 let (_, diagnostics) = parse_module(&src, file_id);
1728 let error_count = diagnostics.iter().filter(|d| d.is_error()).count();
1729 total_errors += error_count;
1730 if error_count > 0 {
1731 println!(
1732 "{}: {} errors",
1733 path.file_name().unwrap().to_str().unwrap(),
1734 error_count
1735 );
1736 for (i, d) in diagnostics
1738 .iter()
1739 .filter(|d| d.is_error())
1740 .take(25)
1741 .enumerate()
1742 {
1743 println!(" {}: {:?}", i + 1, d);
1744 }
1745 }
1746 }
1747 }
1748 println!("Total XMonad parse errors: {}", total_errors);
1749 }
1752
1753 #[test]
1754 fn test_cpp_if_else() {
1755 let src = r#"module Test where
1756
1757test = do
1758 x <- action
1759#if COND
1760 y <- branch1
1761#else
1762 y <- branch2
1763#endif
1764 return x
1765
1766-- | A doc comment
1767other = 42
1768"#;
1769 let (module, diags) = parse_module(src, FileId::new(0));
1770 for d in &diags {
1771 println!("Diagnostic: {:?}", d);
1772 }
1773 assert!(diags.is_empty(), "Parse errors: {:?}", diags);
1774 assert!(module.is_some(), "Failed to parse CPP if/else");
1775 }
1776
1777 #[test]
1778 fn test_cpp_in_where_clause() {
1779 let src = r#"module Test where
1781
1782xfork x = io x
1783 where
1784 nullStdin = do
1785#if COND
1786 fd <- action1
1787#else
1788 fd <- action2
1789#endif
1790 dupTo fd
1791 closeFd fd
1792
1793-- | Doc comment for next function.
1794xmessage :: String -> IO ()
1795xmessage msg = print msg
1796"#;
1797 let (module, diags) = parse_module(src, FileId::new(0));
1798 for d in &diags {
1799 println!("Diagnostic: {:?}", d);
1800 }
1801 assert!(diags.is_empty(), "Parse errors: {:?}", diags);
1802 assert!(module.is_some(), "Failed to parse CPP in where clause");
1803 }
1804
1805 #[test]
1808 fn test_export_dot_operator() {
1809 let module = parse_module_ok("module Foo ((.), foo) where\nfoo = 1");
1811 assert!(module.exports.is_some());
1812 let exports = module.exports.unwrap();
1813 assert_eq!(exports.len(), 2);
1814 }
1815
1816 #[test]
1817 fn test_export_bang_operator() {
1818 let module = parse_module_ok("module Data.Map ((!), lookup) where\nlookup = undefined");
1820 assert!(module.exports.is_some());
1821 let exports = module.exports.unwrap();
1822 assert_eq!(exports.len(), 2);
1823 }
1824
1825 #[test]
1826 fn test_export_multiple_special_operators() {
1827 let module = parse_module_ok("module Ops ((.), (!), (@), (~)) where\nx = 1");
1829 assert!(module.exports.is_some());
1830 let exports = module.exports.unwrap();
1831 assert_eq!(exports.len(), 4);
1832 }
1833
1834 #[test]
1835 fn test_import_dot_operator() {
1836 let module = parse_module_ok("import Data.Function ((.))\nx = 1");
1838 assert!(!module.imports.is_empty());
1839 let import = &module.imports[0];
1840 assert!(import.spec.is_some());
1841 }
1842
1843 #[test]
1844 fn test_import_bang_operator() {
1845 let module = parse_module_ok("import Data.Map ((!), lookup)\nx = 1");
1847 assert!(!module.imports.is_empty());
1848 }
1849
1850 #[test]
1851 fn test_export_with_doc_comments() {
1852 let src = r#"module Foo (
1854 -- * Section header
1855 foo,
1856 -- | Documentation for bar
1857 bar
1858) where
1859foo = 1
1860bar = 2"#;
1861 let module = parse_module_ok(src);
1862 assert!(module.exports.is_some());
1863 let exports = module.exports.unwrap();
1864 assert_eq!(exports.len(), 2);
1865 }
1866
1867 #[test]
1868 fn test_export_regular_operator() {
1869 let module = parse_module_ok("module Data.List ((++), map) where\nmap = undefined");
1871 assert!(module.exports.is_some());
1872 }
1873
1874 #[test]
1875 fn test_import_hiding_operator() {
1876 let module = parse_module_ok("import Prelude hiding ((.))\nx = 1");
1878 assert!(!module.imports.is_empty());
1879 let import = &module.imports[0];
1880 match &import.spec {
1882 Some(ImportSpec::Hiding(_)) => {}
1883 _ => panic!("Expected hiding import"),
1884 }
1885 }
1886
1887 #[test]
1890 fn test_open_type_family() {
1891 let module = parse_module_ok("type family F a");
1892 assert_eq!(module.decls.len(), 1);
1893 match &module.decls[0] {
1894 Decl::TypeFamilyDecl(tf) => {
1895 assert_eq!(tf.name.name.as_str(), "F");
1896 assert_eq!(tf.params.len(), 1);
1897 assert_eq!(tf.family_kind, TypeFamilyKind::Open);
1898 assert!(tf.equations.is_empty());
1899 }
1900 _ => panic!("Expected TypeFamilyDecl"),
1901 }
1902 }
1903
1904 #[test]
1905 fn test_closed_type_family() {
1906 let src = "type family F a where\n F Int = Bool\n F a = ()";
1907 let module = parse_module_ok(src);
1908 assert_eq!(module.decls.len(), 1);
1909 match &module.decls[0] {
1910 Decl::TypeFamilyDecl(tf) => {
1911 assert_eq!(tf.name.name.as_str(), "F");
1912 assert_eq!(tf.family_kind, TypeFamilyKind::Closed);
1913 assert_eq!(tf.equations.len(), 2);
1914 }
1915 _ => panic!("Expected TypeFamilyDecl"),
1916 }
1917 }
1918
1919 #[test]
1920 fn test_type_instance() {
1921 let module = parse_module_ok("type instance F Int = Bool");
1922 assert_eq!(module.decls.len(), 1);
1923 match &module.decls[0] {
1924 Decl::TypeInstanceDecl(ti) => {
1925 assert_eq!(ti.name.name.as_str(), "F");
1926 assert_eq!(ti.args.len(), 1);
1927 }
1928 _ => panic!("Expected TypeInstanceDecl"),
1929 }
1930 }
1931
1932 #[test]
1933 fn test_type_family_with_kind_sig() {
1934 let module = parse_module_ok("type family F a :: * -> *");
1935 assert_eq!(module.decls.len(), 1);
1936 match &module.decls[0] {
1937 Decl::TypeFamilyDecl(tf) => {
1938 assert_eq!(tf.name.name.as_str(), "F");
1939 assert!(tf.kind.is_some());
1940 assert_eq!(tf.family_kind, TypeFamilyKind::Open);
1941 }
1942 _ => panic!("Expected TypeFamilyDecl"),
1943 }
1944 }
1945
1946 #[test]
1947 fn test_type_alias_still_works() {
1948 let module = parse_module_ok("type Foo = Int");
1950 assert!(!module.decls.is_empty());
1951 match &module.decls[0] {
1952 Decl::TypeAlias(ta) => {
1953 assert_eq!(ta.name.name.as_str(), "Foo");
1954 }
1955 _ => panic!("Expected TypeAlias"),
1956 }
1957 }
1958}