haskell_match 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +98 -0
  3. data/LICENSE-APACHE +202 -0
  4. data/LICENSE-MIT +21 -0
  5. data/README.md +1484 -0
  6. data/ext/haskell_match/Cargo.lock +33 -0
  7. data/ext/haskell_match/Cargo.toml +22 -0
  8. data/ext/haskell_match/extconf.rb +41 -0
  9. data/ext/haskell_match/src/core/ast.rs +190 -0
  10. data/ext/haskell_match/src/core/error.rs +52 -0
  11. data/ext/haskell_match/src/core/exhaust.rs +699 -0
  12. data/ext/haskell_match/src/core/hs/ast.rs +256 -0
  13. data/ext/haskell_match/src/core/hs/json.rs +225 -0
  14. data/ext/haskell_match/src/core/hs/layout.rs +346 -0
  15. data/ext/haskell_match/src/core/hs/lexer.rs +688 -0
  16. data/ext/haskell_match/src/core/hs/mod.rs +14 -0
  17. data/ext/haskell_match/src/core/hs/parser.rs +1945 -0
  18. data/ext/haskell_match/src/core/lexer.rs +590 -0
  19. data/ext/haskell_match/src/core/mod.rs +19 -0
  20. data/ext/haskell_match/src/core/parser.rs +1116 -0
  21. data/ext/haskell_match/src/core/pretty.rs +373 -0
  22. data/ext/haskell_match/src/core/resolve.rs +336 -0
  23. data/ext/haskell_match/src/core/tree.rs +921 -0
  24. data/ext/haskell_match/src/core/typecheck.rs +226 -0
  25. data/ext/haskell_match/src/core/types.rs +404 -0
  26. data/ext/haskell_match/src/lib.rs +19 -0
  27. data/ext/haskell_match/src/ruby/mod.rs +1195 -0
  28. data/ext/haskell_match/src/ruby/runtime.rs +1045 -0
  29. data/lib/haskell_match/binding_plan.rb +84 -0
  30. data/lib/haskell_match/case_of.rb +71 -0
  31. data/lib/haskell_match/clauses.rb +354 -0
  32. data/lib/haskell_match/data.rb +417 -0
  33. data/lib/haskell_match/deep_call.rb +98 -0
  34. data/lib/haskell_match/deriving.rb +130 -0
  35. data/lib/haskell_match/dsl.rb +71 -0
  36. data/lib/haskell_match/errors.rb +85 -0
  37. data/lib/haskell_match/field_types.rb +140 -0
  38. data/lib/haskell_match/function.rb +240 -0
  39. data/lib/haskell_match/haskell/compiler.rb +961 -0
  40. data/lib/haskell_match/haskell.rb +326 -0
  41. data/lib/haskell_match/inspect.rb +45 -0
  42. data/lib/haskell_match/lazy_list.rb +210 -0
  43. data/lib/haskell_match/native_loader.rb +64 -0
  44. data/lib/haskell_match/pattern.rb +75 -0
  45. data/lib/haskell_match/pattern_ast.rb +394 -0
  46. data/lib/haskell_match/prelude.rb +448 -0
  47. data/lib/haskell_match/scope.rb +44 -0
  48. data/lib/haskell_match/version.rb +5 -0
  49. data/lib/haskell_match.rb +41 -0
  50. metadata +124 -0
@@ -0,0 +1,1945 @@
1
+ //! Parser for the Haskell subset: declarations (data, signatures, function
2
+ //! equations with guards and `where`, pattern bindings) and expressions
3
+ //! (application, infix operators with Prelude fixities, sections, lambdas,
4
+ //! `if`, `case`, `let`, lists, ranges, comprehensions, tuples).
5
+
6
+ use super::ast::*;
7
+ use super::layout::layout;
8
+ use super::lexer::{tokenize, Tok, Token};
9
+ use crate::core::ast::{Lit, RawPat};
10
+ use crate::core::error::{CoreError, ErrorKind, Result};
11
+ use crate::core::parser::{ConDecl, DataDecl};
12
+ use std::collections::HashMap;
13
+
14
+ struct P {
15
+ toks: Vec<Token>,
16
+ i: usize,
17
+ /// Operator fixities declared in the module (`infixl 6 <+>`).
18
+ fixities: HashMap<String, (u8, Assoc)>,
19
+ /// Counter for generated names (`\case` parameters, tuple sections).
20
+ gensym: usize,
21
+ }
22
+
23
+ #[derive(Clone, Copy, PartialEq)]
24
+ enum Assoc {
25
+ Left,
26
+ Right,
27
+ None,
28
+ }
29
+
30
+ fn default_fixity(op: &str) -> (u8, Assoc) {
31
+ match op {
32
+ "." => (9, Assoc::Right),
33
+ "!!" => (9, Assoc::Left),
34
+ "^" | "^^" | "**" => (8, Assoc::Right),
35
+ "*" | "/" | "div" | "mod" | "rem" | "quot" => (7, Assoc::Left),
36
+ "+" | "-" => (6, Assoc::Left),
37
+ ":" | "++" => (5, Assoc::Right),
38
+ "==" | "/=" | "<" | "<=" | ">" | ">=" | "elem" | "notElem" => (4, Assoc::None),
39
+ "&&" => (3, Assoc::Right),
40
+ "||" => (2, Assoc::Right),
41
+ ">>" | ">>=" => (1, Assoc::Left),
42
+ "$" | "$!" | "seq" => (0, Assoc::Right),
43
+ _ => (9, Assoc::Left),
44
+ }
45
+ }
46
+
47
+ impl P {
48
+ fn fixity(&self, op: &str) -> (u8, Assoc) {
49
+ self.fixities
50
+ .get(op)
51
+ .copied()
52
+ .unwrap_or_else(|| default_fixity(op))
53
+ }
54
+ fn fresh(&mut self, prefix: &str) -> String {
55
+ self.gensym += 1;
56
+ format!("{}__{}", prefix, self.gensym)
57
+ }
58
+ fn peek(&self) -> &Tok {
59
+ &self.toks[self.i].tok
60
+ }
61
+ fn peek_at(&self, n: usize) -> &Tok {
62
+ let j = (self.i + n).min(self.toks.len() - 1);
63
+ &self.toks[j].tok
64
+ }
65
+ fn here(&self) -> (usize, usize) {
66
+ let t = &self.toks[self.i];
67
+ (t.line, t.col)
68
+ }
69
+ fn next(&mut self) -> Tok {
70
+ let t = self.toks[self.i].tok.clone();
71
+ if self.i < self.toks.len() - 1 {
72
+ self.i += 1;
73
+ }
74
+ t
75
+ }
76
+ fn err<T>(&self, msg: impl std::fmt::Display) -> Result<T> {
77
+ let (l, c) = self.here();
78
+ Err(CoreError::new(
79
+ ErrorKind::Syntax,
80
+ format!("{}:{}: {}", l, c, msg),
81
+ ))
82
+ }
83
+ fn expect(&mut self, want: Tok, what: &str) -> Result<()> {
84
+ if *self.peek() == want {
85
+ self.next();
86
+ Ok(())
87
+ } else {
88
+ self.err(format!(
89
+ "expected {} but found {}",
90
+ what,
91
+ describe(self.peek())
92
+ ))
93
+ }
94
+ }
95
+ fn at(&self, t: Tok) -> bool {
96
+ *self.peek() == t
97
+ }
98
+ fn is_open(&self) -> bool {
99
+ matches!(self.peek(), Tok::LBrace | Tok::VLBrace)
100
+ }
101
+ fn is_close(&self) -> bool {
102
+ matches!(self.peek(), Tok::RBrace | Tok::VRBrace)
103
+ }
104
+ fn is_semi(&self) -> bool {
105
+ matches!(self.peek(), Tok::Semi | Tok::VSemi)
106
+ }
107
+ }
108
+
109
+ pub fn describe(t: &Tok) -> String {
110
+ match t {
111
+ Tok::VarId(v) => format!("'{}'", v),
112
+ Tok::ConId(c) => format!("'{}'", c),
113
+ Tok::VarSym(s) | Tok::ConSym(s) => format!("operator '{}'", s),
114
+ Tok::Int(s) | Tok::Float(s) => format!("literal {}", s),
115
+ Tok::Char(c) => format!("literal {:?}", c),
116
+ Tok::Str(s) => format!("literal {:?}", s),
117
+ Tok::VLBrace => "start of block".into(),
118
+ Tok::VRBrace => "end of block".into(),
119
+ Tok::VSemi => "end of line".into(),
120
+ Tok::Eof => "end of input".into(),
121
+ other => format!("{:?}", other).to_lowercase(),
122
+ }
123
+ }
124
+
125
+ /// `Data.Map.Map` -> `Map`: a qualified constructor without its module.
126
+ fn unqualify(name: String) -> String {
127
+ match name.rfind('.') {
128
+ Some(i) => name[i + 1..].to_string(),
129
+ None => name,
130
+ }
131
+ }
132
+
133
+ /// Collect `infix[lr] [prec] op, op ...` declarations anywhere in the token
134
+ /// stream: Haskell lets a fixity declaration follow the operator's uses.
135
+ fn collect_fixities(toks: &[Token]) -> Result<HashMap<String, (u8, Assoc)>> {
136
+ let mut out = HashMap::new();
137
+ let mut i = 0;
138
+ while i < toks.len() {
139
+ let assoc = match toks[i].tok {
140
+ Tok::Infix => Assoc::None,
141
+ Tok::Infixl => Assoc::Left,
142
+ Tok::Infixr => Assoc::Right,
143
+ _ => {
144
+ i += 1;
145
+ continue;
146
+ }
147
+ };
148
+ let (line, col) = (toks[i].line, toks[i].col);
149
+ i += 1;
150
+ let mut prec = 9u8;
151
+ if let Tok::Int(n) = &toks[i].tok {
152
+ prec = n.parse::<u8>().ok().filter(|p| *p <= 9).ok_or_else(|| {
153
+ CoreError::new(
154
+ ErrorKind::Syntax,
155
+ format!("{}:{}: fixity precedence must be 0..9", line, col),
156
+ )
157
+ })?;
158
+ i += 1;
159
+ }
160
+ loop {
161
+ match &toks[i].tok {
162
+ Tok::VarSym(s) | Tok::ConSym(s) => {
163
+ out.insert(s.clone(), (prec, assoc));
164
+ i += 1;
165
+ }
166
+ Tok::Backtick => {
167
+ if let (Tok::VarId(v), Tok::Backtick) = (&toks[i + 1].tok, &toks[i + 2].tok) {
168
+ out.insert(v.clone(), (prec, assoc));
169
+ i += 3;
170
+ } else {
171
+ return Err(CoreError::new(
172
+ ErrorKind::Syntax,
173
+ format!("{}:{}: malformed fixity declaration", line, col),
174
+ ));
175
+ }
176
+ }
177
+ t => {
178
+ return Err(CoreError::new(
179
+ ErrorKind::Syntax,
180
+ format!(
181
+ "{}:{}: expected an operator in fixity declaration but found {}",
182
+ line,
183
+ col,
184
+ describe(t)
185
+ ),
186
+ ))
187
+ }
188
+ }
189
+ if toks[i].tok == Tok::Comma {
190
+ i += 1;
191
+ } else {
192
+ break;
193
+ }
194
+ }
195
+ }
196
+ Ok(out)
197
+ }
198
+
199
+ /// Parse a module (a whole source text).
200
+ pub fn parse_module(src: &str) -> Result<Module> {
201
+ let toks = layout(tokenize(src)?);
202
+ let fixities = collect_fixities(&toks)?;
203
+ let mut p = P {
204
+ toks,
205
+ i: 0,
206
+ fixities,
207
+ gensym: 0,
208
+ };
209
+ let mut name = None;
210
+ let mut exports = None;
211
+ if p.at(Tok::Module) {
212
+ p.next();
213
+ match p.next() {
214
+ Tok::ConId(n) => name = Some(n),
215
+ t => return p.err(format!("expected a module name but found {}", describe(&t))),
216
+ }
217
+ if p.at(Tok::LParen) {
218
+ exports = Some(p.item_list(true)?);
219
+ }
220
+ p.expect(Tok::Where, "'where' after module header")?;
221
+ }
222
+ let decls = p.block(|p| p.top_decl())?;
223
+ if !p.at(Tok::Eof) {
224
+ return p.err(format!("unexpected {}", describe(p.peek())));
225
+ }
226
+ Ok(Module {
227
+ name,
228
+ exports,
229
+ decls: group(decls, &p)?,
230
+ })
231
+ }
232
+
233
+ /// Group consecutive equations of one function into a single `Decl::Fun`.
234
+ fn group(items: Vec<Decl>, p: &P) -> Result<Vec<Decl>> {
235
+ let mut out: Vec<Decl> = Vec::new();
236
+ for d in items {
237
+ match d {
238
+ Decl::Fun(mut eqs) => {
239
+ if let Some(Decl::Fun(prev)) = out.last_mut() {
240
+ if prev[0].name == eqs[0].name {
241
+ if prev[0].pats.len() != eqs[0].pats.len() {
242
+ return Err(CoreError::new(
243
+ ErrorKind::ClauseArity,
244
+ format!(
245
+ "{}: equations for '{}' have different numbers of arguments",
246
+ eqs[0].line, eqs[0].name
247
+ ),
248
+ ));
249
+ }
250
+ prev.append(&mut eqs);
251
+ continue;
252
+ }
253
+ }
254
+ // a function defined again after other declarations is an error
255
+ for earlier in &out {
256
+ if let Decl::Fun(e) = earlier {
257
+ if e[0].name == eqs[0].name {
258
+ return Err(CoreError::new(
259
+ ErrorKind::Syntax,
260
+ format!(
261
+ "{}: equations for '{}' are not contiguous (first defined at line {})",
262
+ eqs[0].line, eqs[0].name, e[0].line
263
+ ),
264
+ ));
265
+ }
266
+ }
267
+ }
268
+ out.push(Decl::Fun(eqs));
269
+ }
270
+ other => out.push(other),
271
+ }
272
+ }
273
+ let _ = p;
274
+ Ok(out)
275
+ }
276
+
277
+ impl P {
278
+ /// `{ item ; item ; ... }` with explicit or layout braces.
279
+ fn block<T>(&mut self, mut item: impl FnMut(&mut P) -> Result<Option<T>>) -> Result<Vec<T>> {
280
+ if !self.is_open() {
281
+ return self.err(format!(
282
+ "expected a block but found {}",
283
+ describe(self.peek())
284
+ ));
285
+ }
286
+ self.next();
287
+ let mut items = Vec::new();
288
+ loop {
289
+ while self.is_semi() {
290
+ self.next();
291
+ }
292
+ if self.is_close() {
293
+ self.next();
294
+ break;
295
+ }
296
+ if self.at(Tok::Eof) {
297
+ return self.err("unexpected end of input inside a block");
298
+ }
299
+ if let Some(it) = item(self)? {
300
+ items.push(it);
301
+ }
302
+ if self.is_semi() {
303
+ continue;
304
+ }
305
+ if self.is_close() {
306
+ self.next();
307
+ break;
308
+ }
309
+ return self.err(format!("unexpected {}", describe(self.peek())));
310
+ }
311
+ Ok(items)
312
+ }
313
+
314
+ /// `( item, item, ... )`: an export or import list. Items are
315
+ /// variables, parenthesised operators, and type names optionally followed
316
+ /// by `(..)` or a constructor list; `module M` entries (exports) are
317
+ /// skipped. Returns the flat list of names.
318
+ fn item_list(&mut self, exports: bool) -> Result<Vec<String>> {
319
+ self.expect(Tok::LParen, "'('")?;
320
+ let mut names = Vec::new();
321
+ loop {
322
+ match self.peek().clone() {
323
+ Tok::RParen => {
324
+ self.next();
325
+ break;
326
+ }
327
+ Tok::Comma => {
328
+ self.next();
329
+ }
330
+ Tok::VarId(v) => {
331
+ self.next();
332
+ names.push(v);
333
+ }
334
+ Tok::Module if exports => {
335
+ self.next();
336
+ match self.next() {
337
+ Tok::ConId(_) => {}
338
+ t => {
339
+ return self
340
+ .err(format!("expected a module name but found {}", describe(&t)))
341
+ }
342
+ }
343
+ }
344
+ Tok::ConId(c) => {
345
+ self.next();
346
+ names.push(unqualify(c));
347
+ if self.at(Tok::LParen) {
348
+ // `(..)` or `(C1, C2)` or `(f1, f2)`
349
+ self.next();
350
+ loop {
351
+ match self.next() {
352
+ Tok::RParen => break,
353
+ Tok::DotDot | Tok::Comma | Tok::ConId(_) | Tok::VarId(_) => {}
354
+ Tok::LParen => {
355
+ // `((:+:))`
356
+ self.next();
357
+ self.expect(Tok::RParen, "')'")?;
358
+ }
359
+ t => {
360
+ return self.err(format!(
361
+ "unexpected {} in constructor list",
362
+ describe(&t)
363
+ ))
364
+ }
365
+ }
366
+ }
367
+ }
368
+ }
369
+ Tok::LParen => {
370
+ self.next();
371
+ match self.next() {
372
+ Tok::VarSym(s) | Tok::ConSym(s) => names.push(s),
373
+ t => {
374
+ return self
375
+ .err(format!("expected an operator but found {}", describe(&t)))
376
+ }
377
+ }
378
+ self.expect(Tok::RParen, "')' after operator")?;
379
+ }
380
+ Tok::Type => {
381
+ // `type T` (ExplicitNamespaces): take the name
382
+ self.next();
383
+ }
384
+ t => return self.err(format!("unexpected {} in export/import list", describe(&t))),
385
+ }
386
+ }
387
+ Ok(names)
388
+ }
389
+
390
+ /// `import [qualified] M [as A] [hiding] [(items)]`
391
+ fn import_decl(&mut self) -> Result<Decl> {
392
+ let (line, _) = self.here();
393
+ self.next(); // import
394
+ let mut qualified = false;
395
+ if matches!(self.peek(), Tok::VarId(v) if v == "qualified") {
396
+ qualified = true;
397
+ self.next();
398
+ }
399
+ let module = match self.next() {
400
+ Tok::ConId(m) => m,
401
+ t => return self.err(format!("expected a module name but found {}", describe(&t))),
402
+ };
403
+ // ImportQualifiedPost: `import M qualified`
404
+ if matches!(self.peek(), Tok::VarId(v) if v == "qualified") {
405
+ qualified = true;
406
+ self.next();
407
+ }
408
+ let mut alias = None;
409
+ if matches!(self.peek(), Tok::VarId(v) if v == "as") {
410
+ self.next();
411
+ match self.next() {
412
+ Tok::ConId(a) => alias = Some(a),
413
+ t => {
414
+ return self.err(format!(
415
+ "expected an alias after 'as' but found {}",
416
+ describe(&t)
417
+ ))
418
+ }
419
+ }
420
+ }
421
+ let mut hiding = false;
422
+ if matches!(self.peek(), Tok::VarId(v) if v == "hiding") {
423
+ hiding = true;
424
+ self.next();
425
+ }
426
+ let items = if self.at(Tok::LParen) {
427
+ Some(self.item_list(false)?)
428
+ } else {
429
+ None
430
+ };
431
+ if hiding && items.is_none() {
432
+ return self.err("'hiding' needs a list of names");
433
+ }
434
+ Ok(Decl::Import {
435
+ module,
436
+ qualified,
437
+ alias,
438
+ hiding,
439
+ items,
440
+ line,
441
+ })
442
+ }
443
+
444
+ fn top_decl(&mut self) -> Result<Option<Decl>> {
445
+ match self.peek() {
446
+ Tok::Import => self.import_decl().map(Some),
447
+ Tok::Type | Tok::Class | Tok::Instance | Tok::Infix | Tok::Infixl | Tok::Infixr => {
448
+ let what = describe(self.peek());
449
+ if matches!(self.peek(), Tok::Class | Tok::Instance) {
450
+ return self.err(format!(
451
+ "{} declarations are not supported (type classes are out of scope)",
452
+ what
453
+ ));
454
+ }
455
+ while !self.is_semi() && !self.is_close() && !self.at(Tok::Eof) {
456
+ if self.is_open() {
457
+ self.skip_block()?;
458
+ } else {
459
+ self.next();
460
+ }
461
+ }
462
+ Ok(None)
463
+ }
464
+ Tok::Data | Tok::Newtype => self.data_decl().map(Some),
465
+ _ => self.decl().map(Some),
466
+ }
467
+ }
468
+
469
+ fn skip_block(&mut self) -> Result<()> {
470
+ let mut depth = 0;
471
+ loop {
472
+ match self.peek() {
473
+ Tok::LBrace | Tok::VLBrace => depth += 1,
474
+ Tok::RBrace | Tok::VRBrace => {
475
+ depth -= 1;
476
+ if depth == 0 {
477
+ self.next();
478
+ return Ok(());
479
+ }
480
+ }
481
+ Tok::Eof => return self.err("unexpected end of input"),
482
+ _ => {}
483
+ }
484
+ self.next();
485
+ }
486
+ }
487
+
488
+ fn data_decl(&mut self) -> Result<Decl> {
489
+ let (line, _) = self.here();
490
+ self.next(); // data / newtype
491
+ let name = match self.next() {
492
+ Tok::ConId(n) => unqualify(n),
493
+ t => return self.err(format!("expected a type name but found {}", describe(&t))),
494
+ };
495
+ let mut tyvars = Vec::new();
496
+ while let Tok::VarId(v) = self.peek() {
497
+ tyvars.push(v.clone());
498
+ self.next();
499
+ }
500
+ let mut cons = Vec::new();
501
+ if self.at(Tok::Equals) {
502
+ self.next();
503
+ loop {
504
+ cons.push(self.con_decl()?);
505
+ if self.at(Tok::Pipe) {
506
+ self.next();
507
+ } else {
508
+ break;
509
+ }
510
+ }
511
+ }
512
+ let mut deriving = Vec::new();
513
+ if self.at(Tok::Deriving) {
514
+ self.next();
515
+ if self.at(Tok::LParen) {
516
+ self.next();
517
+ loop {
518
+ match self.next() {
519
+ Tok::ConId(c) => deriving.push(unqualify(c)),
520
+ Tok::RParen => break,
521
+ Tok::Comma => {}
522
+ t => {
523
+ return self
524
+ .err(format!("unexpected {} in deriving clause", describe(&t)))
525
+ }
526
+ }
527
+ }
528
+ } else {
529
+ match self.next() {
530
+ Tok::ConId(c) => deriving.push(unqualify(c)),
531
+ t => {
532
+ return self.err(format!("unexpected {} in deriving clause", describe(&t)))
533
+ }
534
+ }
535
+ }
536
+ }
537
+ if cons.is_empty() {
538
+ return self.err(format!("type '{}' has no constructors", name));
539
+ }
540
+ for (i, c) in cons.iter().enumerate() {
541
+ if cons[..i].iter().any(|d| d.name == c.name) {
542
+ return Err(CoreError::new(
543
+ ErrorKind::DataDeclaration,
544
+ format!("{}: constructor '{}' is declared twice", line, c.name),
545
+ ));
546
+ }
547
+ }
548
+ Ok(Decl::Data {
549
+ decl: DataDecl {
550
+ name,
551
+ tyvars,
552
+ cons,
553
+ deriving: deriving.clone(),
554
+ },
555
+ deriving,
556
+ line,
557
+ })
558
+ }
559
+
560
+ fn con_decl(&mut self) -> Result<ConDecl> {
561
+ // infix constructor `atype :op: atype`
562
+ let infix = match self.peek() {
563
+ Tok::ConId(_) => matches!(self.peek_at(1), Tok::ConSym(_)),
564
+ Tok::LParen if matches!(self.peek_at(1), Tok::ConSym(_)) => false,
565
+ _ => self.starts_atype(),
566
+ };
567
+ if infix {
568
+ self.atype()?;
569
+ let name = match self.next() {
570
+ Tok::ConSym(op) => op,
571
+ t => {
572
+ return self.err(format!(
573
+ "expected an infix constructor but found {}",
574
+ describe(&t)
575
+ ))
576
+ }
577
+ };
578
+ self.atype()?;
579
+ return Ok(ConDecl {
580
+ name,
581
+ arity: 2,
582
+ fields: None,
583
+ types: Vec::new(),
584
+ });
585
+ }
586
+ let name = match self.next() {
587
+ Tok::ConId(n) => unqualify(n),
588
+ Tok::LParen => {
589
+ let op = match self.next() {
590
+ Tok::ConSym(op) => op,
591
+ t => {
592
+ return self.err(format!(
593
+ "expected a constructor operator but found {}",
594
+ describe(&t)
595
+ ))
596
+ }
597
+ };
598
+ self.expect(Tok::RParen, "')' after constructor operator")?;
599
+ op
600
+ }
601
+ t => {
602
+ return self.err(format!(
603
+ "expected a constructor name but found {}",
604
+ describe(&t)
605
+ ))
606
+ }
607
+ };
608
+ if self.at(Tok::LBrace) {
609
+ self.next();
610
+ let mut fields = Vec::new();
611
+ if self.at(Tok::RBrace) {
612
+ self.next();
613
+ return Ok(ConDecl {
614
+ name,
615
+ arity: 0,
616
+ fields: Some(fields),
617
+ types: Vec::new(),
618
+ });
619
+ }
620
+ loop {
621
+ let mut names = Vec::new();
622
+ loop {
623
+ match self.next() {
624
+ Tok::VarId(f) => names.push(f),
625
+ t => {
626
+ return self
627
+ .err(format!("expected a field name but found {}", describe(&t)))
628
+ }
629
+ }
630
+ match self.next() {
631
+ Tok::Comma => {}
632
+ Tok::DoubleColon => break,
633
+ t => return self.err(format!("expected '::' but found {}", describe(&t))),
634
+ }
635
+ }
636
+ self.skip_type_until(&[Tok::Comma, Tok::RBrace])?;
637
+ for f in names {
638
+ if fields.contains(&f) {
639
+ return self.err(format!("field '{}' is declared twice", f));
640
+ }
641
+ fields.push(f);
642
+ }
643
+ match self.next() {
644
+ Tok::Comma => {}
645
+ Tok::RBrace => break,
646
+ t => {
647
+ return self.err(format!("expected ',' or '}}' but found {}", describe(&t)))
648
+ }
649
+ }
650
+ }
651
+ let arity = fields.len();
652
+ return Ok(ConDecl {
653
+ name,
654
+ arity,
655
+ fields: Some(fields),
656
+ types: Vec::new(),
657
+ });
658
+ }
659
+ let mut arity = 0;
660
+ while self.starts_atype() {
661
+ self.atype()?;
662
+ arity += 1;
663
+ }
664
+ Ok(ConDecl {
665
+ name,
666
+ arity,
667
+ fields: None,
668
+ types: Vec::new(),
669
+ })
670
+ }
671
+
672
+ fn starts_atype(&self) -> bool {
673
+ matches!(
674
+ self.peek(),
675
+ Tok::ConId(_) | Tok::VarId(_) | Tok::LParen | Tok::LBracket | Tok::Bang
676
+ )
677
+ }
678
+
679
+ /// Skip one atomic type (we keep no type information).
680
+ fn atype(&mut self) -> Result<()> {
681
+ match self.next() {
682
+ Tok::ConId(_) | Tok::VarId(_) => Ok(()),
683
+ Tok::Bang => self.atype(),
684
+ Tok::LParen => {
685
+ let mut depth = 1;
686
+ while depth > 0 {
687
+ match self.next() {
688
+ Tok::LParen => depth += 1,
689
+ Tok::RParen => depth -= 1,
690
+ Tok::Eof => return self.err("unterminated type"),
691
+ _ => {}
692
+ }
693
+ }
694
+ Ok(())
695
+ }
696
+ Tok::LBracket => {
697
+ let mut depth = 1;
698
+ while depth > 0 {
699
+ match self.next() {
700
+ Tok::LBracket => depth += 1,
701
+ Tok::RBracket => depth -= 1,
702
+ Tok::Eof => return self.err("unterminated type"),
703
+ _ => {}
704
+ }
705
+ }
706
+ Ok(())
707
+ }
708
+ t => self.err(format!("unexpected {} in type", describe(&t))),
709
+ }
710
+ }
711
+
712
+ /// Skip a type until one of `stops` at depth 0; returns the number of
713
+ /// top-level `->` arrows seen (the arity of a signature).
714
+ fn skip_type_until(&mut self, stops: &[Tok]) -> Result<usize> {
715
+ let mut depth = 0;
716
+ let mut arrows = 0;
717
+ loop {
718
+ let t = self.peek().clone();
719
+ if depth == 0
720
+ && (stops.contains(&t) || self.is_semi() || self.is_close() || t == Tok::Eof)
721
+ {
722
+ return Ok(arrows);
723
+ }
724
+ match t {
725
+ Tok::LParen | Tok::LBracket => depth += 1,
726
+ Tok::RParen | Tok::RBracket => depth -= 1,
727
+ Tok::RArrow if depth == 0 => arrows += 1,
728
+ _ => {}
729
+ }
730
+ self.next();
731
+ }
732
+ }
733
+
734
+ /// `(op)` at the current position: the operator's name.
735
+ fn paren_op(&self) -> Option<String> {
736
+ if self.at(Tok::LParen) && self.peek_at(2) == &Tok::RParen {
737
+ if let Tok::VarSym(s) | Tok::ConSym(s) = self.peek_at(1) {
738
+ return Some(s.clone());
739
+ }
740
+ }
741
+ None
742
+ }
743
+
744
+ /// A declaration inside any block: signature, equation or pattern binding.
745
+ fn decl(&mut self) -> Result<Decl> {
746
+ let (line, _) = self.here();
747
+ // operator in prefix form: `(<+>) :: ...` or `(<+>) a b = ...`
748
+ if let Some(op) = self.paren_op() {
749
+ self.next();
750
+ self.next();
751
+ self.next();
752
+ if self.at(Tok::DoubleColon) {
753
+ self.next();
754
+ let arity = self.skip_type_until(&[])?;
755
+ return Ok(Decl::Sig {
756
+ names: vec![op],
757
+ arity,
758
+ line,
759
+ });
760
+ }
761
+ let mut pats = Vec::new();
762
+ while self.starts_apat() {
763
+ pats.push(self.apat()?);
764
+ }
765
+ let (rhs, wheres) = self.rhs(Tok::Equals)?;
766
+ if pats.is_empty() {
767
+ // `(<+>) = someFunction`: a value of function type
768
+ return Ok(Decl::PatBind {
769
+ pat: RawPat::Var(op),
770
+ rhs,
771
+ wheres,
772
+ line,
773
+ });
774
+ }
775
+ return Ok(Decl::Fun(vec![Equation {
776
+ name: op,
777
+ pats,
778
+ rhs,
779
+ wheres,
780
+ line,
781
+ }]));
782
+ }
783
+ // signature: var (, var)* :: type
784
+ if let Tok::VarId(_) = self.peek() {
785
+ let mut j = 1;
786
+ while matches!(self.peek_at(j), Tok::Comma)
787
+ && matches!(self.peek_at(j + 1), Tok::VarId(_))
788
+ {
789
+ j += 2;
790
+ }
791
+ if matches!(self.peek_at(j), Tok::DoubleColon) {
792
+ let mut names = Vec::new();
793
+ loop {
794
+ match self.next() {
795
+ Tok::VarId(v) => names.push(v),
796
+ Tok::Comma => {}
797
+ Tok::DoubleColon => break,
798
+ t => return self.err(format!("unexpected {} in signature", describe(&t))),
799
+ }
800
+ }
801
+ let arity = self.skip_type_until(&[])?;
802
+ return Ok(Decl::Sig { names, arity, line });
803
+ }
804
+ }
805
+ // function equation: var apat* rhs | infix: pat varop pat rhs
806
+ if let Tok::VarId(name) = self.peek().clone() {
807
+ let next = self.peek_at(1).clone();
808
+ if matches!(next, Tok::Equals | Tok::Pipe) {
809
+ // `x = e` : a simple pattern binding (a value)
810
+ self.next();
811
+ let (rhs, wheres) = self.rhs(Tok::Equals)?;
812
+ return Ok(Decl::PatBind {
813
+ pat: RawPat::Var(name),
814
+ rhs,
815
+ wheres,
816
+ line,
817
+ });
818
+ }
819
+ if self.starts_apat_at(1) {
820
+ self.next();
821
+ let mut pats = Vec::new();
822
+ while self.starts_apat() {
823
+ pats.push(self.apat()?);
824
+ }
825
+ if let Tok::VarSym(_) | Tok::Backtick = self.peek() {
826
+ // `f x <+> y = ...` is really an infix definition of `<+>`
827
+ // whose left operand is the pattern `f x`: not valid Haskell
828
+ return self.err(
829
+ "a function application cannot be the left operand of an operator definition",
830
+ );
831
+ }
832
+ let (rhs, wheres) = self.rhs(Tok::Equals)?;
833
+ return Ok(Decl::Fun(vec![Equation {
834
+ name,
835
+ pats,
836
+ rhs,
837
+ wheres,
838
+ line,
839
+ }]));
840
+ }
841
+ }
842
+ // pattern binding `pat = e`, or an infix definition `pat op pat = e`
843
+ let pat = self.pattern()?;
844
+ let infix_name = match self.peek().clone() {
845
+ Tok::VarSym(op) => {
846
+ self.next();
847
+ Some(op)
848
+ }
849
+ Tok::Backtick => {
850
+ self.next();
851
+ let name = match self.next() {
852
+ Tok::VarId(v) => v,
853
+ t => {
854
+ return self.err(format!(
855
+ "expected a function name in backticks but found {}",
856
+ describe(&t)
857
+ ))
858
+ }
859
+ };
860
+ self.expect(Tok::Backtick, "closing backtick")?;
861
+ Some(name)
862
+ }
863
+ _ => None,
864
+ };
865
+ if let Some(name) = infix_name {
866
+ let right = self.pattern()?;
867
+ let (rhs, wheres) = self.rhs(Tok::Equals)?;
868
+ return Ok(Decl::Fun(vec![Equation {
869
+ name,
870
+ pats: vec![pat, right],
871
+ rhs,
872
+ wheres,
873
+ line,
874
+ }]));
875
+ }
876
+ let (rhs, wheres) = self.rhs(Tok::Equals)?;
877
+ Ok(Decl::PatBind {
878
+ pat,
879
+ rhs,
880
+ wheres,
881
+ line,
882
+ })
883
+ }
884
+
885
+ /// `= e [where decls]` or guarded `| g = e ... [where decls]`; `sep` is
886
+ /// `=` for equations and `->` for case alternatives.
887
+ fn rhs(&mut self, sep: Tok) -> Result<(Rhs, Vec<Decl>)> {
888
+ let rhs = if self.at(Tok::Pipe) {
889
+ let mut guards = Vec::new();
890
+ while self.at(Tok::Pipe) {
891
+ self.next();
892
+ let quals = self.quals()?;
893
+ self.expect(sep.clone(), if sep == Tok::Equals { "'='" } else { "'->'" })?;
894
+ let e = self.expr()?;
895
+ guards.push((quals, e));
896
+ }
897
+ Rhs::Guarded(guards)
898
+ } else {
899
+ self.expect(sep.clone(), if sep == Tok::Equals { "'='" } else { "'->'" })?;
900
+ Rhs::Plain(self.expr()?)
901
+ };
902
+ let mut wheres = Vec::new();
903
+ if self.at(Tok::Where) {
904
+ self.next();
905
+ let items = self.block(|p| p.decl().map(Some))?;
906
+ wheres = group(items, self)?;
907
+ }
908
+ Ok((rhs, wheres))
909
+ }
910
+
911
+ // ----------------------------------------------------------------- patterns
912
+
913
+ fn starts_apat(&self) -> bool {
914
+ self.starts_apat_at(0)
915
+ }
916
+
917
+ fn starts_apat_at(&self, n: usize) -> bool {
918
+ matches!(
919
+ self.peek_at(n),
920
+ Tok::VarId(_)
921
+ | Tok::ConId(_)
922
+ | Tok::Int(_)
923
+ | Tok::Float(_)
924
+ | Tok::Char(_)
925
+ | Tok::Str(_)
926
+ | Tok::Underscore
927
+ | Tok::LParen
928
+ | Tok::LBracket
929
+ | Tok::Tilde
930
+ | Tok::Bang
931
+ )
932
+ }
933
+
934
+ /// pattern := lpat (consym pattern)?
935
+ fn pattern(&mut self) -> Result<RawPat> {
936
+ let head = self.lpat()?;
937
+ if let Tok::ConSym(s) = self.peek().clone() {
938
+ self.next();
939
+ let tail = self.pattern()?;
940
+ if s == ":" {
941
+ return Ok(RawPat::Cons(Box::new(head), Box::new(tail)));
942
+ }
943
+ return Ok(RawPat::Con(s, vec![head, tail]));
944
+ }
945
+ Ok(head)
946
+ }
947
+
948
+ fn lpat(&mut self) -> Result<RawPat> {
949
+ match self.peek().clone() {
950
+ Tok::ConId(name) if !matches!(self.peek_at(1), Tok::LBrace) => {
951
+ let name = unqualify(name);
952
+ self.next();
953
+ let mut args = Vec::new();
954
+ while self.starts_apat() {
955
+ args.push(self.apat()?);
956
+ }
957
+ Ok(RawPat::Con(name, args))
958
+ }
959
+ // prefix use of an infix constructor: `(:+:) a b`
960
+ Tok::LParen
961
+ if matches!(self.peek_at(1), Tok::ConSym(_)) && self.peek_at(2) == &Tok::RParen =>
962
+ {
963
+ self.next();
964
+ let name = match self.next() {
965
+ Tok::ConSym(op) => op,
966
+ _ => unreachable!(),
967
+ };
968
+ self.next();
969
+ let mut args = Vec::new();
970
+ while self.starts_apat() {
971
+ args.push(self.apat()?);
972
+ }
973
+ Ok(RawPat::Con(name, args))
974
+ }
975
+ Tok::VarSym(s) if s == "-" => {
976
+ self.next();
977
+ match self.next() {
978
+ Tok::Int(n) => Ok(RawPat::Lit(crate::core::parser::int_lit(&format!(
979
+ "-{}",
980
+ n
981
+ )))),
982
+ Tok::Float(f) => {
983
+ let v: f64 = f
984
+ .parse()
985
+ .map_err(|_| self.err::<()>("bad float").unwrap_err())?;
986
+ Ok(RawPat::Lit(crate::core::parser::float_lit(-v)))
987
+ }
988
+ t => self.err(format!(
989
+ "expected a number after '-' in pattern, found {}",
990
+ describe(&t)
991
+ )),
992
+ }
993
+ }
994
+ _ => self.apat(),
995
+ }
996
+ }
997
+
998
+ fn apat(&mut self) -> Result<RawPat> {
999
+ match self.next() {
1000
+ Tok::Underscore => Ok(RawPat::Wild),
1001
+ Tok::VarId(v) => {
1002
+ if self.at(Tok::At) {
1003
+ self.next();
1004
+ let inner = self.apat()?;
1005
+ Ok(RawPat::As(v, Box::new(inner)))
1006
+ } else {
1007
+ Ok(RawPat::Var(v))
1008
+ }
1009
+ }
1010
+ Tok::Tilde => Ok(RawPat::Lazy(Box::new(self.apat()?))),
1011
+ Tok::Bang => Ok(RawPat::Bang(Box::new(self.apat()?))),
1012
+ Tok::ConId(name) => {
1013
+ let name = unqualify(name);
1014
+ if self.at(Tok::LBrace) {
1015
+ self.next();
1016
+ self.record_pat(name)
1017
+ } else {
1018
+ Ok(RawPat::Con(name, vec![]))
1019
+ }
1020
+ }
1021
+ Tok::Int(s) => Ok(RawPat::Lit(crate::core::parser::int_lit(&s))),
1022
+ Tok::Float(s) => {
1023
+ let v: f64 = s
1024
+ .parse()
1025
+ .map_err(|_| self.err::<()>("bad float").unwrap_err())?;
1026
+ Ok(RawPat::Lit(crate::core::parser::float_lit(v)))
1027
+ }
1028
+ Tok::Char(c) => Ok(RawPat::Lit(Lit::Char(c))),
1029
+ Tok::Str(s) => Ok(RawPat::List(
1030
+ s.chars().map(|c| RawPat::Lit(Lit::Char(c))).collect(),
1031
+ )),
1032
+ Tok::LParen => {
1033
+ if self.at(Tok::RParen) {
1034
+ self.next();
1035
+ return Ok(RawPat::Tuple(vec![]));
1036
+ }
1037
+ let first = self.pattern()?;
1038
+ if self.at(Tok::Comma) {
1039
+ let mut items = vec![first];
1040
+ while self.at(Tok::Comma) {
1041
+ self.next();
1042
+ items.push(self.pattern()?);
1043
+ }
1044
+ self.expect(Tok::RParen, "')'")?;
1045
+ Ok(RawPat::Tuple(items))
1046
+ } else {
1047
+ self.expect(Tok::RParen, "')'")?;
1048
+ Ok(first)
1049
+ }
1050
+ }
1051
+ Tok::LBracket => {
1052
+ let mut items = Vec::new();
1053
+ if self.at(Tok::RBracket) {
1054
+ self.next();
1055
+ return Ok(RawPat::List(items));
1056
+ }
1057
+ loop {
1058
+ items.push(self.pattern()?);
1059
+ match self.next() {
1060
+ Tok::Comma => {}
1061
+ Tok::RBracket => break,
1062
+ t => {
1063
+ return self.err(format!(
1064
+ "expected ',' or ']' in list pattern, found {}",
1065
+ describe(&t)
1066
+ ))
1067
+ }
1068
+ }
1069
+ }
1070
+ Ok(RawPat::List(items))
1071
+ }
1072
+ t => self.err(format!("unexpected {} in pattern", describe(&t))),
1073
+ }
1074
+ }
1075
+
1076
+ fn record_pat(&mut self, con: String) -> Result<RawPat> {
1077
+ let mut fields = Vec::new();
1078
+ let mut rest = false;
1079
+ if self.at(Tok::RBrace) {
1080
+ self.next();
1081
+ return Ok(RawPat::Record(con, fields, false));
1082
+ }
1083
+ loop {
1084
+ match self.next() {
1085
+ Tok::DotDot => {
1086
+ rest = true;
1087
+ self.expect(Tok::RBrace, "'}' after '..'")?;
1088
+ break;
1089
+ }
1090
+ Tok::VarId(f) => {
1091
+ if self.at(Tok::Equals) {
1092
+ self.next();
1093
+ let p = self.pattern()?;
1094
+ fields.push((f, p));
1095
+ } else {
1096
+ let v = f.clone();
1097
+ fields.push((f, RawPat::Var(v)));
1098
+ }
1099
+ match self.next() {
1100
+ Tok::Comma => {}
1101
+ Tok::RBrace => break,
1102
+ t => {
1103
+ return self.err(format!(
1104
+ "expected ',' or '}}' in record pattern, found {}",
1105
+ describe(&t)
1106
+ ))
1107
+ }
1108
+ }
1109
+ }
1110
+ t => return self.err(format!("unexpected {} in record pattern", describe(&t))),
1111
+ }
1112
+ }
1113
+ Ok(RawPat::Record(con, fields, rest))
1114
+ }
1115
+
1116
+ // -------------------------------------------------------------- expressions
1117
+
1118
+ pub fn expr(&mut self) -> Result<Expr> {
1119
+ let e = self.infix_expr(0)?;
1120
+ if self.at(Tok::DoubleColon) {
1121
+ // type annotation: skip
1122
+ self.next();
1123
+ self.skip_type_until(&[
1124
+ Tok::RParen,
1125
+ Tok::Comma,
1126
+ Tok::RBracket,
1127
+ Tok::Then,
1128
+ Tok::Else,
1129
+ Tok::Of,
1130
+ Tok::In,
1131
+ ])?;
1132
+ }
1133
+ Ok(e)
1134
+ }
1135
+
1136
+ fn peek_op(&self) -> Option<(String, usize)> {
1137
+ match self.peek() {
1138
+ Tok::VarSym(s) | Tok::ConSym(s) => Some((s.clone(), 1)),
1139
+ Tok::Backtick => {
1140
+ if let Tok::VarId(v) = self.peek_at(1) {
1141
+ if matches!(self.peek_at(2), Tok::Backtick) {
1142
+ return Some((v.clone(), 3));
1143
+ }
1144
+ }
1145
+ None
1146
+ }
1147
+ _ => None,
1148
+ }
1149
+ }
1150
+
1151
+ /// Precedence climbing over `lexp (op lexp)*`.
1152
+ fn infix_expr(&mut self, min_prec: u8) -> Result<Expr> {
1153
+ let mut lhs = if let Tok::VarSym(s) = self.peek() {
1154
+ if s == "-" {
1155
+ self.next();
1156
+ let operand = self.infix_expr(7)?;
1157
+ Expr::Neg(Box::new(operand))
1158
+ } else {
1159
+ self.lexp()?
1160
+ }
1161
+ } else {
1162
+ self.lexp()?
1163
+ };
1164
+ while let Some((op, width)) = self.peek_op() {
1165
+ // `(e op)`: the operator belongs to a left section, not to us
1166
+ if self.peek_at(width) == &Tok::RParen {
1167
+ break;
1168
+ }
1169
+ let (prec, assoc) = self.fixity(&op);
1170
+ if prec < min_prec {
1171
+ break;
1172
+ }
1173
+ // consume the operator tokens
1174
+ for _ in 0..width {
1175
+ self.next();
1176
+ }
1177
+ let next_min = match assoc {
1178
+ Assoc::Left | Assoc::None => prec + 1,
1179
+ Assoc::Right => prec,
1180
+ };
1181
+ let rhs = self.infix_expr(next_min)?;
1182
+ lhs = Expr::BinOp(op, Box::new(lhs), Box::new(rhs));
1183
+ }
1184
+ Ok(lhs)
1185
+ }
1186
+
1187
+ fn lexp(&mut self) -> Result<Expr> {
1188
+ match self.peek() {
1189
+ Tok::Backslash if self.peek_at(1) == &Tok::Case => {
1190
+ // LambdaCase: `\case alts` == `\x -> case x of alts`
1191
+ self.next();
1192
+ self.next();
1193
+ let alts = self.block(|p| p.alt().map(Some))?;
1194
+ if alts.is_empty() {
1195
+ return self.err("\\case needs at least one alternative");
1196
+ }
1197
+ let v = self.fresh("lc");
1198
+ Ok(Expr::Lambda(
1199
+ vec![RawPat::Var(v.clone())],
1200
+ Box::new(Expr::Case(Box::new(Expr::Var(v)), alts)),
1201
+ ))
1202
+ }
1203
+ Tok::Backslash => {
1204
+ self.next();
1205
+ let mut pats = Vec::new();
1206
+ while self.starts_apat() {
1207
+ pats.push(self.apat()?);
1208
+ }
1209
+ if pats.is_empty() {
1210
+ return self.err("a lambda needs at least one parameter");
1211
+ }
1212
+ self.expect(Tok::RArrow, "'->' in lambda")?;
1213
+ let body = self.expr()?;
1214
+ Ok(Expr::Lambda(pats, Box::new(body)))
1215
+ }
1216
+ Tok::Let => {
1217
+ self.next();
1218
+ let items = self.block(|p| p.decl().map(Some))?;
1219
+ let decls = group(items, self)?;
1220
+ self.expect(Tok::In, "'in' after let bindings")?;
1221
+ let body = self.expr()?;
1222
+ Ok(Expr::Let(decls, Box::new(body)))
1223
+ }
1224
+ Tok::If if self.peek_at(1) == &Tok::Pipe => {
1225
+ // MultiWayIf: `if | quals -> e | quals -> e ...`
1226
+ self.next();
1227
+ let mut arms = Vec::new();
1228
+ while self.at(Tok::Pipe) {
1229
+ self.next();
1230
+ let quals = self.quals()?;
1231
+ self.expect(Tok::RArrow, "'->' in multi-way if")?;
1232
+ let e = self.expr()?;
1233
+ arms.push((quals, e));
1234
+ while self.is_semi() && self.peek_at(1) == &Tok::Pipe {
1235
+ self.next();
1236
+ }
1237
+ }
1238
+ Ok(Expr::MultiIf(arms))
1239
+ }
1240
+ Tok::If => {
1241
+ self.next();
1242
+ let c = self.expr()?;
1243
+ while self.is_semi() {
1244
+ self.next();
1245
+ }
1246
+ self.expect(Tok::Then, "'then'")?;
1247
+ let t = self.expr()?;
1248
+ while self.is_semi() {
1249
+ self.next();
1250
+ }
1251
+ self.expect(Tok::Else, "'else'")?;
1252
+ let e = self.expr()?;
1253
+ Ok(Expr::If(Box::new(c), Box::new(t), Box::new(e)))
1254
+ }
1255
+ Tok::Case => {
1256
+ self.next();
1257
+ let scrut = self.expr()?;
1258
+ self.expect(Tok::Of, "'of'")?;
1259
+ let alts = self.block(|p| p.alt().map(Some))?;
1260
+ if alts.is_empty() {
1261
+ return self.err("a case expression needs at least one alternative");
1262
+ }
1263
+ Ok(Expr::Case(Box::new(scrut), alts))
1264
+ }
1265
+ Tok::Do => self.err("'do' blocks are not supported (monads are out of scope)"),
1266
+ _ => self.fexp(),
1267
+ }
1268
+ }
1269
+
1270
+ /// Comma-separated qualifiers (guards, `pat <- e`, `let`).
1271
+ fn quals(&mut self) -> Result<Vec<Qual>> {
1272
+ let mut quals = Vec::new();
1273
+ loop {
1274
+ quals.push(self.qual()?);
1275
+ if self.at(Tok::Comma) {
1276
+ self.next();
1277
+ } else {
1278
+ break;
1279
+ }
1280
+ }
1281
+ Ok(quals)
1282
+ }
1283
+
1284
+ fn alt(&mut self) -> Result<Alt> {
1285
+ let (line, _) = self.here();
1286
+ let pat = self.pattern()?;
1287
+ let (rhs, wheres) = self.rhs(Tok::RArrow)?;
1288
+ Ok(Alt {
1289
+ pat,
1290
+ rhs,
1291
+ wheres,
1292
+ line,
1293
+ })
1294
+ }
1295
+
1296
+ fn starts_aexp(&self) -> bool {
1297
+ matches!(
1298
+ self.peek(),
1299
+ Tok::VarId(_)
1300
+ | Tok::ConId(_)
1301
+ | Tok::Int(_)
1302
+ | Tok::Float(_)
1303
+ | Tok::Char(_)
1304
+ | Tok::Str(_)
1305
+ | Tok::LParen
1306
+ | Tok::LBracket
1307
+ )
1308
+ }
1309
+
1310
+ /// Function application: `aexp aexp*`.
1311
+ fn fexp(&mut self) -> Result<Expr> {
1312
+ let f = self.aexp_record()?;
1313
+ let mut args = Vec::new();
1314
+ while self.starts_aexp() {
1315
+ args.push(self.aexp_record()?);
1316
+ }
1317
+ if args.is_empty() {
1318
+ Ok(f)
1319
+ } else {
1320
+ Ok(Expr::App(Box::new(f), args))
1321
+ }
1322
+ }
1323
+
1324
+ /// An atomic expression optionally followed by record braces:
1325
+ /// `Con { f = e }` constructs, `e { f = e }` updates.
1326
+ fn aexp_record(&mut self) -> Result<Expr> {
1327
+ let mut e = self.aexp()?;
1328
+ while self.at(Tok::LBrace) {
1329
+ self.next();
1330
+ let mut fields = Vec::new();
1331
+ if !self.at(Tok::RBrace) {
1332
+ loop {
1333
+ let f = match self.next() {
1334
+ Tok::VarId(f) => f,
1335
+ t => {
1336
+ return self
1337
+ .err(format!("expected a field name but found {}", describe(&t)))
1338
+ }
1339
+ };
1340
+ let v = if self.at(Tok::Equals) {
1341
+ self.next();
1342
+ self.expr()?
1343
+ } else {
1344
+ Expr::Var(f.clone()) // NamedFieldPuns
1345
+ };
1346
+ fields.push((f, v));
1347
+ match self.next() {
1348
+ Tok::Comma => {}
1349
+ Tok::RBrace => break,
1350
+ t => {
1351
+ return self.err(format!(
1352
+ "expected ',' or '}}' in record syntax but found {}",
1353
+ describe(&t)
1354
+ ))
1355
+ }
1356
+ }
1357
+ }
1358
+ } else {
1359
+ self.next();
1360
+ }
1361
+ e = match e {
1362
+ Expr::Con(c) => Expr::RecCon(c, fields),
1363
+ other => Expr::RecUpdate(Box::new(other), fields),
1364
+ };
1365
+ }
1366
+ Ok(e)
1367
+ }
1368
+
1369
+ fn aexp(&mut self) -> Result<Expr> {
1370
+ match self.next() {
1371
+ Tok::VarId(v) => Ok(Expr::Var(v)),
1372
+ Tok::ConId(c) => Ok(Expr::Con(unqualify(c))),
1373
+ Tok::Int(s) => Ok(Expr::Lit(Literal::Int(s))),
1374
+ Tok::Float(s) => Ok(Expr::Lit(Literal::Float(s))),
1375
+ Tok::Char(c) => Ok(Expr::Lit(Literal::Char(c))),
1376
+ Tok::Str(s) => Ok(Expr::Lit(Literal::Str(s))),
1377
+ Tok::LParen => self.paren(),
1378
+ Tok::LBracket => self.bracket(),
1379
+ Tok::Underscore => self.err("'_' is not an expression"),
1380
+ t => self.err(format!("unexpected {} in expression", describe(&t))),
1381
+ }
1382
+ }
1383
+
1384
+ /// After `(`: unit, parenthesised expression, tuple, section, or `(op)`.
1385
+ fn paren(&mut self) -> Result<Expr> {
1386
+ if self.at(Tok::RParen) {
1387
+ self.next();
1388
+ return Ok(Expr::Tuple(vec![]));
1389
+ }
1390
+ // (op) or right section (op e), but `(- e)` is negation
1391
+ if let Some((op, width)) = self.peek_op() {
1392
+ let is_minus = op == "-";
1393
+ let after_op = self.peek_at(width).clone();
1394
+ if after_op == Tok::RParen {
1395
+ for _ in 0..width {
1396
+ self.next();
1397
+ }
1398
+ self.next();
1399
+ return Ok(Expr::OpFun(op));
1400
+ }
1401
+ if !is_minus {
1402
+ for _ in 0..width {
1403
+ self.next();
1404
+ }
1405
+ let (prec, _) = self.fixity(&op);
1406
+ let e = self.infix_expr(prec)?;
1407
+ self.expect(Tok::RParen, "')' to close section")?;
1408
+ return Ok(Expr::SectionR(op, Box::new(e)));
1409
+ }
1410
+ }
1411
+ // TupleSections: `(,x)`, `(x,)`, `(,,)` ...
1412
+ if self.at(Tok::Comma) {
1413
+ return self.tuple_section(None);
1414
+ }
1415
+ let first = self.expr()?;
1416
+ // left section (e op)
1417
+ if let Some((op, width)) = self.peek_op() {
1418
+ if self.peek_at(width) == &Tok::RParen {
1419
+ for _ in 0..width {
1420
+ self.next();
1421
+ }
1422
+ self.next();
1423
+ return Ok(Expr::SectionL(op, Box::new(first)));
1424
+ }
1425
+ }
1426
+ if self.at(Tok::Comma) {
1427
+ return self.tuple_section(Some(first));
1428
+ }
1429
+ self.expect(Tok::RParen, "')'")?;
1430
+ Ok(first)
1431
+ }
1432
+
1433
+ /// The rest of a tuple after its first slot (`first`, or `None` when the
1434
+ /// first slot is empty). Empty slots make the tuple a function of the
1435
+ /// missing components (TupleSections); with no empty slot it is a tuple.
1436
+ fn tuple_section(&mut self, first: Option<Expr>) -> Result<Expr> {
1437
+ let mut slots: Vec<Option<Expr>> = vec![first];
1438
+ while self.at(Tok::Comma) {
1439
+ self.next();
1440
+ if self.at(Tok::Comma) || self.at(Tok::RParen) {
1441
+ slots.push(None);
1442
+ } else {
1443
+ slots.push(Some(self.expr()?));
1444
+ }
1445
+ }
1446
+ self.expect(Tok::RParen, "')' to close tuple")?;
1447
+ if slots.iter().all(|s| s.is_some()) {
1448
+ return Ok(Expr::Tuple(slots.into_iter().map(|s| s.unwrap()).collect()));
1449
+ }
1450
+ let mut params = Vec::new();
1451
+ let items = slots
1452
+ .into_iter()
1453
+ .map(|s| match s {
1454
+ Some(e) => e,
1455
+ None => {
1456
+ let v = self.fresh("ts");
1457
+ params.push(RawPat::Var(v.clone()));
1458
+ Expr::Var(v)
1459
+ }
1460
+ })
1461
+ .collect();
1462
+ Ok(Expr::Lambda(params, Box::new(Expr::Tuple(items))))
1463
+ }
1464
+
1465
+ /// After `[`: list, range or comprehension.
1466
+ fn bracket(&mut self) -> Result<Expr> {
1467
+ if self.at(Tok::RBracket) {
1468
+ self.next();
1469
+ return Ok(Expr::List(vec![]));
1470
+ }
1471
+ let first = self.expr()?;
1472
+ match self.peek() {
1473
+ Tok::DotDot => {
1474
+ self.next();
1475
+ let to = if self.at(Tok::RBracket) {
1476
+ None
1477
+ } else {
1478
+ Some(Box::new(self.expr()?))
1479
+ };
1480
+ self.expect(Tok::RBracket, "']'")?;
1481
+ Ok(Expr::Range {
1482
+ from: Box::new(first),
1483
+ then: None,
1484
+ to,
1485
+ })
1486
+ }
1487
+ Tok::Comma => {
1488
+ self.next();
1489
+ let second = self.expr()?;
1490
+ if self.at(Tok::DotDot) {
1491
+ self.next();
1492
+ let to = if self.at(Tok::RBracket) {
1493
+ None
1494
+ } else {
1495
+ Some(Box::new(self.expr()?))
1496
+ };
1497
+ self.expect(Tok::RBracket, "']'")?;
1498
+ return Ok(Expr::Range {
1499
+ from: Box::new(first),
1500
+ then: Some(Box::new(second)),
1501
+ to,
1502
+ });
1503
+ }
1504
+ let mut items = vec![first, second];
1505
+ while self.at(Tok::Comma) {
1506
+ self.next();
1507
+ items.push(self.expr()?);
1508
+ }
1509
+ self.expect(Tok::RBracket, "']'")?;
1510
+ Ok(Expr::List(items))
1511
+ }
1512
+ Tok::Pipe => {
1513
+ self.next();
1514
+ let mut quals = Vec::new();
1515
+ loop {
1516
+ quals.push(self.qual()?);
1517
+ if self.at(Tok::Comma) {
1518
+ self.next();
1519
+ } else {
1520
+ break;
1521
+ }
1522
+ }
1523
+ self.expect(Tok::RBracket, "']' to close comprehension")?;
1524
+ Ok(Expr::Comp(Box::new(first), quals))
1525
+ }
1526
+ _ => {
1527
+ self.expect(Tok::RBracket, "']'")?;
1528
+ Ok(Expr::List(vec![first]))
1529
+ }
1530
+ }
1531
+ }
1532
+
1533
+ fn qual(&mut self) -> Result<Qual> {
1534
+ if self.at(Tok::Let) {
1535
+ self.next();
1536
+ let items = self.block(|p| p.decl().map(Some))?;
1537
+ return Ok(Qual::Let(group(items, self)?));
1538
+ }
1539
+ // generator `pat <- e`: try to find `<-` before the next `,` / `]` at depth 0
1540
+ let save = self.i;
1541
+ if self.starts_apat() {
1542
+ if let Ok(pat) = self.pattern() {
1543
+ if self.at(Tok::LArrow) {
1544
+ self.next();
1545
+ let e = self.expr()?;
1546
+ return Ok(Qual::Gen(pat, e));
1547
+ }
1548
+ }
1549
+ }
1550
+ self.i = save;
1551
+ Ok(Qual::Guard(self.expr()?))
1552
+ }
1553
+ }
1554
+
1555
+ #[cfg(test)]
1556
+ mod tests {
1557
+ use super::*;
1558
+
1559
+ fn parse(src: &str) -> Module {
1560
+ parse_module(src).unwrap_or_else(|e| panic!("{}: {}", e.kind as u8, e.message))
1561
+ }
1562
+
1563
+ fn fun<'a>(m: &'a Module, name: &str) -> &'a Vec<Equation> {
1564
+ m.decls
1565
+ .iter()
1566
+ .find_map(|d| match d {
1567
+ Decl::Fun(eqs) if eqs[0].name == name => Some(eqs),
1568
+ _ => None,
1569
+ })
1570
+ .unwrap_or_else(|| panic!("no function {}", name))
1571
+ }
1572
+
1573
+ #[test]
1574
+ fn equations_guards_where() {
1575
+ let m = parse(
1576
+ "module Geometry where\n\
1577
+ data Shape = Circle Double | Rect Double Double deriving (Show, Eq)\n\
1578
+ area :: Shape -> Double\n\
1579
+ area (Circle r) = pi * r * r\n\
1580
+ area (Rect w h) = w * h\n\
1581
+ describe s\n | area s > 100 = \"big\"\n | otherwise = \"small\"\n\
1582
+ sumTo n = go n 0\n where go 0 acc = acc\n go k acc = go (k - 1) (acc + k)\n",
1583
+ );
1584
+ assert_eq!(m.name.as_deref(), Some("Geometry"));
1585
+ assert!(
1586
+ matches!(&m.decls[0], Decl::Data { deriving, .. } if deriving == &vec!["Show".to_string(), "Eq".to_string()])
1587
+ );
1588
+ assert!(
1589
+ matches!(&m.decls[1], Decl::Sig { names, arity: 1, .. } if names == &vec!["area".to_string()])
1590
+ );
1591
+ let area = fun(&m, "area");
1592
+ assert_eq!(area.len(), 2);
1593
+ assert_eq!(render_pat(&area[0].pats[0]), "Circle hs_r");
1594
+ let describe = fun(&m, "describe");
1595
+ assert!(matches!(describe[0].rhs, Rhs::Guarded(ref g) if g.len() == 2));
1596
+ let sum_to = fun(&m, "sumTo");
1597
+ assert_eq!(sum_to[0].wheres.len(), 1);
1598
+ if let Decl::Fun(go) = &sum_to[0].wheres[0] {
1599
+ assert_eq!(go.len(), 2);
1600
+ assert_eq!(render_pat(&go[1].pats[0]), "hs_k");
1601
+ } else {
1602
+ panic!("where should hold a function");
1603
+ }
1604
+ }
1605
+
1606
+ #[test]
1607
+ fn expressions() {
1608
+ let m = parse("f x = x + 2 * 3 - 1\ng = (+ 1) . (* 2) $ 3\nh = [1, 2] ++ [x * 2 | x <- [1..10], even x]\nk = \\a b -> if a then (a, b) else (b, a)\nl = let y = 1; z = 2 in y + z\nm xs = case xs of\n [] -> 0\n (y:_) | y > 0 -> y\n | otherwise -> 0\nn = negate (-5) `div` 2\no = [1, 3 ..]\np = 'c' : \"ab\"\nq = (subtract 1) 5\n");
1609
+ let f = fun(&m, "f");
1610
+ // x + ((2 * 3) - 1)? No: + and - are both infixl 6: ((x + (2*3)) - 1)
1611
+ assert_eq!(
1612
+ f[0].rhs,
1613
+ Rhs::Plain(Expr::BinOp(
1614
+ "-".into(),
1615
+ Box::new(Expr::BinOp(
1616
+ "+".into(),
1617
+ Box::new(Expr::Var("x".into())),
1618
+ Box::new(Expr::BinOp(
1619
+ "*".into(),
1620
+ Box::new(Expr::Lit(Literal::Int("2".into()))),
1621
+ Box::new(Expr::Lit(Literal::Int("3".into())))
1622
+ ))
1623
+ )),
1624
+ Box::new(Expr::Lit(Literal::Int("1".into())))
1625
+ ))
1626
+ );
1627
+ let g = m
1628
+ .decls
1629
+ .iter()
1630
+ .find_map(|d| {
1631
+ if let Decl::PatBind {
1632
+ pat: RawPat::Var(n),
1633
+ rhs,
1634
+ ..
1635
+ } = d
1636
+ {
1637
+ (n == "g").then_some(rhs)
1638
+ } else {
1639
+ None
1640
+ }
1641
+ })
1642
+ .unwrap();
1643
+ // `.` binds tighter than `$`: ((+1) . (*2)) $ 3
1644
+ assert!(matches!(g, Rhs::Plain(Expr::BinOp(op, _, _)) if op == "$"));
1645
+ let h = m
1646
+ .decls
1647
+ .iter()
1648
+ .find_map(|d| {
1649
+ if let Decl::PatBind {
1650
+ pat: RawPat::Var(n),
1651
+ rhs,
1652
+ ..
1653
+ } = d
1654
+ {
1655
+ (n == "h").then_some(rhs)
1656
+ } else {
1657
+ None
1658
+ }
1659
+ })
1660
+ .unwrap();
1661
+ assert!(
1662
+ matches!(h, Rhs::Plain(Expr::BinOp(op, _, r)) if op == "++" && matches!(**r, Expr::Comp(_, ref q) if q.len() == 2))
1663
+ );
1664
+ let m_fn = fun(&m, "m");
1665
+ assert!(
1666
+ matches!(&m_fn[0].rhs, Rhs::Plain(Expr::Case(_, alts)) if alts.len() == 2 && matches!(alts[1].rhs, Rhs::Guarded(ref g) if g.len() == 2))
1667
+ );
1668
+ let o = m
1669
+ .decls
1670
+ .iter()
1671
+ .find_map(|d| {
1672
+ if let Decl::PatBind {
1673
+ pat: RawPat::Var(n),
1674
+ rhs,
1675
+ ..
1676
+ } = d
1677
+ {
1678
+ (n == "o").then_some(rhs)
1679
+ } else {
1680
+ None
1681
+ }
1682
+ })
1683
+ .unwrap();
1684
+ assert!(matches!(
1685
+ o,
1686
+ Rhs::Plain(Expr::Range {
1687
+ then: Some(_),
1688
+ to: None,
1689
+ ..
1690
+ })
1691
+ ));
1692
+ }
1693
+
1694
+ #[test]
1695
+ fn errors() {
1696
+ assert!(parse_module("f x = ").is_err());
1697
+ assert!(parse_module("f x = case x of").is_err());
1698
+ assert!(parse_module("class Foo a where\n foo :: a").is_err());
1699
+ assert!(parse_module("f = do\n x").is_err());
1700
+ assert!(parse_module("f 0 = 1\nf x y = 2").is_err());
1701
+ assert!(parse_module("f 0 = 1\ng = 2\nf x = 3").is_err());
1702
+ let e = parse_module("f = (1 +").unwrap_err();
1703
+ assert!(e.message.starts_with("1:"), "{}", e.message);
1704
+ }
1705
+
1706
+ #[test]
1707
+ fn operators_fixities_and_infix_definitions() {
1708
+ let m = parse(
1709
+ "infixl 6 <+>\n\
1710
+ infixr 5 `cons'`\n\
1711
+ (<+>) :: Int -> Int -> Int\n\
1712
+ a <+> b = a + b * 2\n\
1713
+ (<->) a b = a - b\n\
1714
+ x `cons'` xs = x : xs\n\
1715
+ f = 1 <+> 2 <+> 3 <-> 4\n\
1716
+ g = 1 `cons'` 2 `cons'` []\n",
1717
+ );
1718
+ assert_eq!(fun(&m, "<+>")[0].pats.len(), 2);
1719
+ assert_eq!(fun(&m, "<->")[0].pats.len(), 2);
1720
+ assert_eq!(fun(&m, "cons'")[0].pats.len(), 2);
1721
+ // `<+>` is infixl 6 (binds tighter than the default-9 `<->`? no: `<->`
1722
+ // defaults to infixl 9, so `3 <-> 4` groups first)
1723
+ let f = m.decls.iter().find_map(|d| match d {
1724
+ Decl::PatBind {
1725
+ pat: RawPat::Var(n),
1726
+ rhs: Rhs::Plain(e),
1727
+ ..
1728
+ } if n == "f" => Some(e.clone()),
1729
+ _ => None,
1730
+ });
1731
+ match f.unwrap() {
1732
+ Expr::BinOp(op, l, r) => {
1733
+ assert_eq!(op, "<+>");
1734
+ assert!(matches!(*l, Expr::BinOp(ref o, ..) if o == "<+>"));
1735
+ assert!(matches!(*r, Expr::BinOp(ref o, ..) if o == "<->"));
1736
+ }
1737
+ other => panic!("unexpected {:?}", other),
1738
+ }
1739
+ // infixr: `1 `cons'` (2 `cons'` [])`
1740
+ let g = m.decls.iter().find_map(|d| match d {
1741
+ Decl::PatBind {
1742
+ pat: RawPat::Var(n),
1743
+ rhs: Rhs::Plain(e),
1744
+ ..
1745
+ } if n == "g" => Some(e.clone()),
1746
+ _ => None,
1747
+ });
1748
+ match g.unwrap() {
1749
+ Expr::BinOp(op, _, r) => {
1750
+ assert_eq!(op, "cons'");
1751
+ assert!(matches!(*r, Expr::BinOp(ref o, ..) if o == "cons'"));
1752
+ }
1753
+ other => panic!("unexpected {:?}", other),
1754
+ }
1755
+ assert!(parse_module("infixl 10 <+>\nf = 1").is_err());
1756
+ assert!(parse_module("f x <+> y = 1").is_err());
1757
+ }
1758
+
1759
+ #[test]
1760
+ fn infix_constructors() {
1761
+ let m = parse(
1762
+ "data C = Double :+: Double | (:*:) Int Int\nre (a :+: _) = a\nmk a b = a :+: b\n",
1763
+ );
1764
+ match &m.decls[0] {
1765
+ Decl::Data { decl, .. } => {
1766
+ assert_eq!(decl.cons[0].name, ":+:");
1767
+ assert_eq!(decl.cons[0].arity, 2);
1768
+ assert_eq!(decl.cons[1].name, ":*:");
1769
+ }
1770
+ other => panic!("unexpected {:?}", other),
1771
+ }
1772
+ assert_eq!(render_pat(&fun(&m, "re")[0].pats[0]), "(hs_a :+: _)");
1773
+ assert!(matches!(&fun(&m, "mk")[0].rhs, Rhs::Plain(Expr::BinOp(op, ..)) if op == ":+:"));
1774
+ }
1775
+
1776
+ #[test]
1777
+ fn pattern_guards_multiway_if_lambda_case_tuple_sections() {
1778
+ let m = parse(
1779
+ "f m k\n | Just v <- lookup k m, v > 0 = v\n | let w = k * 2, w > 10 = w\n | otherwise = 0\n\
1780
+ g x = if | x < 0 -> \"neg\"\n | x == 0 -> \"zero\"\n | otherwise -> \"pos\"\n\
1781
+ h = \\case\n 0 -> \"z\"\n _ -> \"nz\"\n\
1782
+ p = (,1)\n\
1783
+ q = (1,,3)\n",
1784
+ );
1785
+ match &fun(&m, "f")[0].rhs {
1786
+ Rhs::Guarded(arms) => {
1787
+ assert_eq!(arms.len(), 3);
1788
+ assert!(matches!(&arms[0].0[0], Qual::Gen(RawPat::Con(c, _), _) if c == "Just"));
1789
+ assert!(matches!(&arms[0].0[1], Qual::Guard(_)));
1790
+ assert!(matches!(&arms[1].0[0], Qual::Let(_)));
1791
+ }
1792
+ other => panic!("unexpected {:?}", other),
1793
+ }
1794
+ assert!(matches!(&fun(&m, "g")[0].rhs, Rhs::Plain(Expr::MultiIf(arms)) if arms.len() == 3));
1795
+ let h = m
1796
+ .decls
1797
+ .iter()
1798
+ .find_map(|d| match d {
1799
+ Decl::PatBind {
1800
+ pat: RawPat::Var(n),
1801
+ rhs: Rhs::Plain(e),
1802
+ ..
1803
+ } if n == "h" => Some(e.clone()),
1804
+ _ => None,
1805
+ })
1806
+ .unwrap();
1807
+ assert!(
1808
+ matches!(h, Expr::Lambda(ref ps, ref body) if ps.len() == 1 && matches!(**body, Expr::Case(..)))
1809
+ );
1810
+ let p = m
1811
+ .decls
1812
+ .iter()
1813
+ .find_map(|d| match d {
1814
+ Decl::PatBind {
1815
+ pat: RawPat::Var(n),
1816
+ rhs: Rhs::Plain(e),
1817
+ ..
1818
+ } if n == "p" => Some(e.clone()),
1819
+ _ => None,
1820
+ })
1821
+ .unwrap();
1822
+ assert!(
1823
+ matches!(p, Expr::Lambda(ref ps, ref body) if ps.len() == 1 && matches!(**body, Expr::Tuple(ref items) if items.len() == 2))
1824
+ );
1825
+ let q = m
1826
+ .decls
1827
+ .iter()
1828
+ .find_map(|d| match d {
1829
+ Decl::PatBind {
1830
+ pat: RawPat::Var(n),
1831
+ rhs: Rhs::Plain(e),
1832
+ ..
1833
+ } if n == "q" => Some(e.clone()),
1834
+ _ => None,
1835
+ })
1836
+ .unwrap();
1837
+ assert!(matches!(q, Expr::Lambda(ref ps, _) if ps.len() == 1));
1838
+ }
1839
+
1840
+ #[test]
1841
+ fn left_and_right_sections() {
1842
+ let m = parse("f = map (3 <+>) xs\ng = map (<+> 3) xs\nh = (1 + 2 <+>)\n");
1843
+ let body = |n: &str| {
1844
+ m.decls
1845
+ .iter()
1846
+ .find_map(|d| match d {
1847
+ Decl::PatBind {
1848
+ pat: RawPat::Var(v),
1849
+ rhs: Rhs::Plain(e),
1850
+ ..
1851
+ } if v == n => Some(e.clone()),
1852
+ _ => None,
1853
+ })
1854
+ .unwrap()
1855
+ };
1856
+ assert!(
1857
+ matches!(body("f"), Expr::App(_, args) if matches!(&args[0], Expr::SectionL(op, _) if op == "<+>"))
1858
+ );
1859
+ assert!(
1860
+ matches!(body("g"), Expr::App(_, args) if matches!(&args[0], Expr::SectionR(op, _) if op == "<+>"))
1861
+ );
1862
+ assert!(
1863
+ matches!(body("h"), Expr::SectionL(op, inner) if op == "<+>" && matches!(*inner, Expr::BinOp(..)))
1864
+ );
1865
+ }
1866
+
1867
+ #[test]
1868
+ fn record_construction_and_update() {
1869
+ let m = parse("mk = P { nm = \"a\", yrs = 1 }\nolder p = p { yrs = yrs p + 1 }\npun nm = P { nm, yrs = 0 }\n");
1870
+ let body = |n: &str| {
1871
+ m.decls
1872
+ .iter()
1873
+ .find_map(|d| match d {
1874
+ Decl::PatBind {
1875
+ pat: RawPat::Var(v),
1876
+ rhs: Rhs::Plain(e),
1877
+ ..
1878
+ } if v == n => Some(e.clone()),
1879
+ Decl::Fun(eqs) if eqs[0].name == n => match &eqs[0].rhs {
1880
+ Rhs::Plain(e) => Some(e.clone()),
1881
+ _ => None,
1882
+ },
1883
+ _ => None,
1884
+ })
1885
+ .unwrap()
1886
+ };
1887
+ assert!(matches!(body("mk"), Expr::RecCon(c, fs) if c == "P" && fs.len() == 2));
1888
+ assert!(
1889
+ matches!(body("older"), Expr::RecUpdate(_, fs) if fs.len() == 1 && fs[0].0 == "yrs")
1890
+ );
1891
+ assert!(
1892
+ matches!(body("pun"), Expr::RecCon(_, fs) if matches!(&fs[0].1, Expr::Var(v) if v == "nm"))
1893
+ );
1894
+ }
1895
+
1896
+ #[test]
1897
+ fn imports_and_exports() {
1898
+ let m = parse(
1899
+ "module M (f, (<+>), T(..), module X) where\n\
1900
+ import Data.List (sortBy, (\\\\))\n\
1901
+ import qualified Data.Map as Map hiding (foldr)\n\
1902
+ import Geometry\n\
1903
+ f = 1\n",
1904
+ );
1905
+ assert_eq!(
1906
+ m.exports,
1907
+ Some(vec!["f".to_string(), "<+>".to_string(), "T".to_string()])
1908
+ );
1909
+ match &m.decls[0] {
1910
+ Decl::Import {
1911
+ module,
1912
+ items,
1913
+ qualified,
1914
+ ..
1915
+ } => {
1916
+ assert_eq!(module, "Data.List");
1917
+ assert_eq!(
1918
+ items.as_ref().unwrap(),
1919
+ &vec!["sortBy".to_string(), "\\\\".to_string()]
1920
+ );
1921
+ assert!(!qualified);
1922
+ }
1923
+ other => panic!("unexpected {:?}", other),
1924
+ }
1925
+ match &m.decls[1] {
1926
+ Decl::Import {
1927
+ module,
1928
+ alias,
1929
+ qualified,
1930
+ hiding,
1931
+ items,
1932
+ ..
1933
+ } => {
1934
+ assert_eq!(module, "Data.Map");
1935
+ assert_eq!(alias.as_deref(), Some("Map"));
1936
+ assert!(*qualified && *hiding);
1937
+ assert_eq!(items.as_ref().unwrap(), &vec!["foldr".to_string()]);
1938
+ }
1939
+ other => panic!("unexpected {:?}", other),
1940
+ }
1941
+ assert!(
1942
+ matches!(&m.decls[2], Decl::Import { module, items: None, .. } if module == "Geometry")
1943
+ );
1944
+ }
1945
+ }