1use bhc_ast::{Expr, FieldPat, Lit, ModuleName, Pat};
4use bhc_intern::{Ident, Symbol};
5use bhc_lexer::TokenKind;
6use bhc_span::Span;
7
8use crate::{ParseError, ParseResult, Parser};
9
10impl<'src> Parser<'src> {
11 pub fn is_pattern_start(&self) -> bool {
13 match self.current_kind() {
14 Some(kind) => matches!(
15 kind,
16 TokenKind::Ident(_)
17 | TokenKind::QualIdent(_, _)
18 | TokenKind::ConId(_)
19 | TokenKind::QualConId(_, _)
20 | TokenKind::IntLit(_)
21 | TokenKind::FloatLit(_)
22 | TokenKind::CharLit(_)
23 | TokenKind::StringLit(_)
24 | TokenKind::LParen
25 | TokenKind::LBracket
26 | TokenKind::Underscore
27 | TokenKind::Tilde
28 | TokenKind::Bang
29 ),
30 None => false,
31 }
32 }
33
34 pub fn parse_pattern(&mut self) -> ParseResult<Pat> {
36 self.enter_recursion()?;
37 let result = self.parse_infix_pattern();
38 self.exit_recursion();
39 result
40 }
41
42 fn parse_infix_pattern(&mut self) -> ParseResult<Pat> {
44 let mut pat = self.parse_app_pattern()?;
45
46 while let Some(tok) = self.current() {
47 match &tok.node.kind {
48 TokenKind::ConOperator(sym) => {
50 let op = Ident::new(*sym);
51 self.advance();
52 let rhs = self.parse_infix_pattern()?;
53 let span = pat.span().to(rhs.span());
54 pat = Pat::Infix(Box::new(pat), op, Box::new(rhs), span);
55 }
56 TokenKind::QualConOperator(qual, sym) => {
58 let qualified_name =
59 Symbol::intern(&format!("{}.{}", qual.as_str(), sym.as_str()));
60 let op = Ident::new(qualified_name);
61 self.advance();
62 let rhs = self.parse_infix_pattern()?;
63 let span = pat.span().to(rhs.span());
64 pat = Pat::Infix(Box::new(pat), op, Box::new(rhs), span);
65 }
66 _ => break,
67 }
68 }
69
70 Ok(pat)
71 }
72
73 fn parse_app_pattern(&mut self) -> ParseResult<Pat> {
75 let first = self.parse_atom_pattern()?;
76
77 match first {
79 Pat::Con(con, args, span) if args.is_empty() => {
80 let mut new_args = Vec::new();
81 while self.is_apat_start() {
82 new_args.push(self.parse_atom_pattern()?);
83 }
84 if new_args.is_empty() {
85 return Ok(Pat::Con(con, args, span));
86 }
87 let new_span = span.to(new_args.last().unwrap().span());
88 return Ok(Pat::Con(con, new_args, new_span));
89 }
90 Pat::Con(con, args, span) => {
91 return Ok(Pat::Con(con, args, span));
92 }
93 Pat::QualCon(module_name, con, args, span) if args.is_empty() => {
94 let mut new_args = Vec::new();
96 while self.is_apat_start() {
97 new_args.push(self.parse_atom_pattern()?);
98 }
99 if new_args.is_empty() {
100 return Ok(Pat::QualCon(module_name, con, args, span));
101 }
102 let new_span = span.to(new_args.last().unwrap().span());
103 return Ok(Pat::QualCon(module_name, con, new_args, new_span));
104 }
105 Pat::QualCon(module_name, con, args, span) => {
106 return Ok(Pat::QualCon(module_name, con, args, span));
107 }
108 _ => {}
109 }
110
111 Ok(first)
112 }
113
114 pub fn is_apat_start(&self) -> bool {
116 match self.current_kind() {
117 Some(kind) => matches!(
118 kind,
119 TokenKind::Ident(_)
120 | TokenKind::ConId(_) | TokenKind::QualConId(_, _) | TokenKind::IntLit(_)
123 | TokenKind::FloatLit(_)
124 | TokenKind::CharLit(_)
125 | TokenKind::StringLit(_)
126 | TokenKind::LParen
127 | TokenKind::LBracket
128 | TokenKind::Underscore
129 | TokenKind::Tilde | TokenKind::Bang ),
132 None => false,
133 }
134 }
135
136 pub fn parse_atom_pattern(&mut self) -> ParseResult<Pat> {
139 let tok = self.current().ok_or(ParseError::UnexpectedEof {
140 expected: "pattern".to_string(),
141 })?;
142
143 match &tok.node.kind.clone() {
144 TokenKind::Underscore => {
145 let span = tok.span;
146 self.advance();
147 Ok(Pat::Wildcard(span))
148 }
149
150 TokenKind::Ident(sym) => {
151 let ident = Ident::new(*sym);
152 let span = tok.span;
153 self.advance();
154
155 if self.eat(&TokenKind::At) {
157 let pat = self.parse_atom_pattern()?;
158 let new_span = span.to(pat.span());
159 Ok(Pat::As(ident, Box::new(pat), new_span))
160 } else {
161 Ok(Pat::Var(ident, span))
162 }
163 }
164
165 TokenKind::QualIdent(qual, name) => {
166 let full_name = format!("{}.{}", qual.as_str(), name.as_str());
168 let ident = Ident::from_str(&full_name);
169 let span = tok.span;
170 self.advance();
171 Ok(Pat::Var(ident, span))
172 }
173
174 TokenKind::ConId(sym) => {
175 let ident = Ident::new(*sym);
176 let span = tok.span;
177 self.advance();
178
179 if self.check(&TokenKind::LBrace) {
181 return self.parse_record_pattern(ident, span);
182 }
183
184 Ok(Pat::Con(ident, vec![], span))
185 }
186
187 TokenKind::QualConId(qual, name) => {
188 let module_name = ModuleName {
190 parts: vec![*qual],
191 span: tok.span,
192 };
193 let ident = Ident::new(*name);
194 let span = tok.span;
195 self.advance();
196
197 if self.check(&TokenKind::LBrace) {
199 return self.parse_qual_record_pattern(module_name, ident, span);
200 }
201
202 Ok(Pat::QualCon(module_name, ident, vec![], span))
203 }
204
205 TokenKind::IntLit(ref lit) => {
206 let span = tok.span;
207 let value = self.parse_int_literal(&lit.text, span)?;
208 self.advance();
209 Ok(Pat::Lit(Lit::Int(value), span))
210 }
211
212 TokenKind::FloatLit(ref lit) => {
213 let span = tok.span;
214 let value = self.parse_float_literal(&lit.text, span)?;
215 self.advance();
216 Ok(Pat::Lit(Lit::Float(value), span))
217 }
218
219 TokenKind::CharLit(c) => {
220 let span = tok.span;
221 let c = *c;
222 self.advance();
223 Ok(Pat::Lit(Lit::Char(c), span))
224 }
225
226 TokenKind::StringLit(s) => {
227 let span = tok.span;
228 let s = s.clone();
229 self.advance();
230 Ok(Pat::Lit(Lit::String(s), span))
231 }
232
233 TokenKind::LParen => self.parse_paren_pattern(),
234
235 TokenKind::LBracket => self.parse_list_pattern(),
236
237 TokenKind::Tilde => {
238 let start = tok.span;
239 self.advance();
240 let pat = self.parse_atom_pattern()?;
241 let span = start.to(pat.span());
242 Ok(Pat::Lazy(Box::new(pat), span))
243 }
244
245 TokenKind::Bang => {
246 let start = tok.span;
247 self.advance();
248 let pat = self.parse_atom_pattern()?;
249 let span = start.to(pat.span());
250 Ok(Pat::Bang(Box::new(pat), span))
251 }
252
253 _ => Err(ParseError::Unexpected {
254 found: tok.node.kind.description().to_string(),
255 expected: "pattern".to_string(),
256 span: tok.span,
257 }),
258 }
259 }
260
261 fn parse_paren_pattern(&mut self) -> ParseResult<Pat> {
263 let start = self.current_span();
264 self.expect(&TokenKind::LParen)?;
265
266 if self.eat(&TokenKind::RParen) {
267 let span = start.to(self.tokens[self.pos - 1].span);
269 return Ok(Pat::Con(Ident::from_str("()"), vec![], span));
270 }
271
272 let first = self.parse_pattern()?;
273
274 if self.eat(&TokenKind::Arrow) {
277 let view_expr = self.pat_to_expr(&first)?;
279 let result_pat = self.parse_pattern()?;
280 let end = self.expect(&TokenKind::RParen)?;
281 let span = start.to(end.span);
282 return Ok(Pat::View(Box::new(view_expr), Box::new(result_pat), span));
283 }
284
285 if matches!(&first, Pat::Var(..)) && self.is_apat_start() {
290 let save_pos = self.pos;
292 let mut args: Vec<Pat> = Vec::new();
293 while self.is_apat_start() && !self.check(&TokenKind::Arrow) {
294 args.push(self.parse_atom_pattern()?);
295 }
296 if self.eat(&TokenKind::Arrow) {
297 let mut view_expr = self.pat_to_expr(&first)?;
299 for arg in &args {
300 let arg_expr = self.pat_to_expr(arg)?;
301 let new_span = view_expr.span().to(arg_expr.span());
302 view_expr = Expr::App(Box::new(view_expr), Box::new(arg_expr), new_span);
303 }
304 let result_pat = self.parse_pattern()?;
305 let end = self.expect(&TokenKind::RParen)?;
306 let span = start.to(end.span);
307 return Ok(Pat::View(Box::new(view_expr), Box::new(result_pat), span));
308 }
309 self.pos = save_pos;
311 }
312
313 if self.eat(&TokenKind::DoubleColon) {
315 let ty = self.parse_type()?;
316 let end = self.expect(&TokenKind::RParen)?;
317 let span = start.to(end.span);
318 return Ok(Pat::Ann(Box::new(first), ty, span));
319 }
320
321 if self.eat(&TokenKind::Comma) {
322 let mut pats = vec![first];
324 loop {
325 pats.push(self.parse_pattern()?);
326 if !self.eat(&TokenKind::Comma) {
327 break;
328 }
329 }
330 let end = self.expect(&TokenKind::RParen)?;
331 let span = start.to(end.span);
332 Ok(Pat::Tuple(pats, span))
333 } else {
334 let end = self.expect(&TokenKind::RParen)?;
336 let span = start.to(end.span);
337 Ok(Pat::Paren(Box::new(first), span))
338 }
339 }
340
341 fn pat_to_expr(&self, pat: &Pat) -> ParseResult<Expr> {
344 use bhc_ast::Expr;
345 match pat {
346 Pat::Var(name, span) => {
347 let name_str = name.name.as_str();
349 if let Some(dot_pos) = name_str.rfind('.') {
350 let qualifier = &name_str[..dot_pos];
351 let local = &name_str[dot_pos + 1..];
352 if !qualifier.is_empty() && !local.is_empty() {
353 let module_name = ModuleName {
354 parts: vec![Symbol::intern(qualifier)],
355 span: *span,
356 };
357 let local_ident = Ident::from_str(local);
358 return Ok(Expr::QualVar(module_name, local_ident, *span));
359 }
360 }
361 Ok(Expr::Var(*name, *span))
362 }
363 Pat::Con(name, args, span) => {
364 if args.is_empty() {
365 Ok(Expr::Con(*name, *span))
366 } else {
367 let mut result = Expr::Con(*name, *span);
369 for arg in args {
370 let arg_expr = self.pat_to_expr(arg)?;
371 let new_span = result.span().to(arg_expr.span());
372 result = Expr::App(Box::new(result), Box::new(arg_expr), new_span);
373 }
374 Ok(result)
375 }
376 }
377 Pat::QualCon(module_name, name, args, span) => {
378 if args.is_empty() {
379 Ok(Expr::QualCon(module_name.clone(), *name, *span))
380 } else {
381 let mut result = Expr::QualCon(module_name.clone(), *name, *span);
383 for arg in args {
384 let arg_expr = self.pat_to_expr(arg)?;
385 let new_span = result.span().to(arg_expr.span());
386 result = Expr::App(Box::new(result), Box::new(arg_expr), new_span);
387 }
388 Ok(result)
389 }
390 }
391 Pat::Lit(lit, span) => Ok(Expr::Lit(lit.clone(), *span)),
392 Pat::Paren(inner, span) => {
393 let inner_expr = self.pat_to_expr(inner)?;
394 Ok(Expr::Paren(Box::new(inner_expr), *span))
395 }
396 Pat::Tuple(elems, span) => {
397 let mut exprs = Vec::new();
398 for elem in elems {
399 exprs.push(self.pat_to_expr(elem)?);
400 }
401 Ok(Expr::Tuple(exprs, *span))
402 }
403 Pat::List(elems, span) => {
404 let mut exprs = Vec::new();
405 for elem in elems {
406 exprs.push(self.pat_to_expr(elem)?);
407 }
408 Ok(Expr::List(exprs, *span))
409 }
410 Pat::Wildcard(span) => {
411 Ok(Expr::Var(Ident::from_str("_"), *span))
413 }
414 _ => Err(ParseError::Unexpected {
415 found: "complex pattern".to_string(),
416 expected: "simple expression for view pattern".to_string(),
417 span: pat.span(),
418 }),
419 }
420 }
421
422 fn parse_list_pattern(&mut self) -> ParseResult<Pat> {
424 let start = self.current_span();
425 self.expect(&TokenKind::LBracket)?;
426
427 if self.eat(&TokenKind::RBracket) {
428 let span = start.to(self.tokens[self.pos - 1].span);
430 return Ok(Pat::List(vec![], span));
431 }
432
433 let mut pats = vec![self.parse_pattern()?];
434 while self.eat(&TokenKind::Comma) {
435 if self.check(&TokenKind::RBracket) {
436 break;
437 }
438 pats.push(self.parse_pattern()?);
439 }
440
441 let end = self.expect(&TokenKind::RBracket)?;
442 let span = start.to(end.span);
443 Ok(Pat::List(pats, span))
444 }
445
446 fn parse_record_pattern(&mut self, con: Ident, start: Span) -> ParseResult<Pat> {
448 self.expect(&TokenKind::LBrace)?;
449
450 let mut fields = Vec::new();
451 let mut has_wildcard = false;
452 if !self.check(&TokenKind::RBrace) {
453 if self.eat(&TokenKind::DotDot) {
454 has_wildcard = true;
455 } else {
456 fields.push(self.parse_field_pat()?);
457 while self.eat(&TokenKind::Comma) {
458 if self.check(&TokenKind::RBrace) {
459 break;
460 }
461 if self.eat(&TokenKind::DotDot) {
462 has_wildcard = true;
463 break;
464 }
465 fields.push(self.parse_field_pat()?);
466 }
467 }
468 }
469
470 let end = self.expect(&TokenKind::RBrace)?;
471 let span = start.to(end.span);
472 Ok(Pat::Record(con, fields, has_wildcard, span))
473 }
474
475 fn parse_qual_record_pattern(
477 &mut self,
478 module_name: ModuleName,
479 con: Ident,
480 start: Span,
481 ) -> ParseResult<Pat> {
482 self.expect(&TokenKind::LBrace)?;
483
484 let mut fields = Vec::new();
485 let mut has_wildcard = false;
486 if !self.check(&TokenKind::RBrace) {
487 if self.eat(&TokenKind::DotDot) {
488 has_wildcard = true;
489 } else {
490 fields.push(self.parse_field_pat()?);
491 while self.eat(&TokenKind::Comma) {
492 if self.check(&TokenKind::RBrace) {
493 break;
494 }
495 if self.eat(&TokenKind::DotDot) {
496 has_wildcard = true;
497 break;
498 }
499 fields.push(self.parse_field_pat()?);
500 }
501 }
502 }
503
504 let end = self.expect(&TokenKind::RBrace)?;
505 let span = start.to(end.span);
506 Ok(Pat::QualRecord(
507 module_name,
508 con,
509 fields,
510 has_wildcard,
511 span,
512 ))
513 }
514
515 fn parse_field_pat(&mut self) -> ParseResult<FieldPat> {
517 let tok = self.current().ok_or(ParseError::UnexpectedEof {
518 expected: "field name".to_string(),
519 })?;
520
521 let (qualifier, name, span) = match &tok.node.kind {
522 TokenKind::Ident(sym) => (None, Ident::new(*sym), tok.span),
523 TokenKind::QualIdent(qual, sym) => {
524 let module_name = ModuleName {
525 parts: vec![*qual],
526 span: tok.span,
527 };
528 (Some(module_name), Ident::new(*sym), tok.span)
529 }
530 _ => {
531 return Err(ParseError::Unexpected {
532 found: tok.node.kind.description().to_string(),
533 expected: "field name".to_string(),
534 span: tok.span,
535 });
536 }
537 };
538 self.advance();
539
540 let pat = if self.eat(&TokenKind::Eq) {
541 Some(self.parse_pattern()?)
542 } else {
543 None };
545
546 let end_span = pat.as_ref().map(|p| p.span()).unwrap_or(span);
547 let full_span = span.to(end_span);
548 Ok(FieldPat {
549 qualifier,
550 name,
551 pat,
552 span: full_span,
553 })
554 }
555}