Line data Source code
1 : // wok_parse -- stage 3. Recursive descent over the post-layout token stream.
2 : //
3 : // One function per production in section 7 of the frontend design spec, named
4 : // after the production. Nothing here reads a token's bytes to make a decision:
5 : // every choice is a kind or a word compare, so a misspelling fails to compile.
6 : //
7 : // Three rules of FORM are enforced (they are grammar facts, not analyses):
8 : // - a `handle` STATEMENT must write its label (P1/D13);
9 : // - a control clause binds exactly one bare lowercase name after its comma
10 : // (C8/D14), which is what lets a later pass compare pattern count to
11 : // arity for every clause kind alike;
12 : // - `once` at clause-head position gets the v1 migration diagnostic (D25).
13 : //
14 : // Operator chains stay FLAT. src/Wok/Reordering.hs owns fixity, so no
15 : // precedence table lives here.
16 :
17 : #include "wok_parse.h"
18 :
19 : #include "wok_utf8.h"
20 :
21 : #include <stdio.h>
22 :
23 : #include "wok_layout.h"
24 : #include "wok_trivia.h"
25 :
26 : // ---------------------------------------------------------------- state
27 :
28 : typedef struct {
29 : const WokToken *tok;
30 : usize n;
31 : usize i;
32 : const char *src;
33 : WokArena *a;
34 : WokDiagSink *d;
35 : u32 depth;
36 : // A NEWLINE that closed a nested block is also the enclosing block's item
37 : // separator; closing the inner block carries it out here.
38 : bool sep;
39 : // The current item is damaged. One message per item is the whole recovery
40 : // contract, so every report site is gated on this.
41 : bool panic;
42 : // `own`/`lend`/`copy` are contextual: they are transfer modes only at the
43 : // head of a foreign member's signature type, and ordinary names everywhere
44 : // else (spec.md section 2 writes `Bytes.copy` itself).
45 : bool foreign_sig;
46 : u32 last_end;
47 : char desc[64];
48 : } P;
49 :
50 : // ---------------------------------------------------------------- cursor
51 :
52 6194243 : static const WokToken *cur(const P *p) { return &p->tok[p->i]; }
53 :
54 159455 : static WokKind kind_at(const P *p, usize k) {
55 159455 : usize j = p->i + k;
56 159455 : if (j >= p->n) j = p->n - 1;
57 159455 : return (WokKind)p->tok[j].kind;
58 : }
59 :
60 2049 : static WokWord word_at(const P *p, usize k) {
61 2049 : usize j = p->i + k;
62 2049 : if (j >= p->n) j = p->n - 1;
63 2049 : return (WokWord)p->tok[j].word;
64 : }
65 :
66 : // The one place the parser reads a COLUMN: which inline body an indented
67 : // continuation belongs to (see parse_block_body). It is a token field like
68 : // any other -- the stage split forbids the LAYOUT filter from naming a
69 : // keyword, not the parser from reading a position.
70 498 : static u32 col_at(const P *p, usize k) {
71 498 : usize j = p->i + k;
72 498 : if (j >= p->n) j = p->n - 1;
73 498 : return p->tok[j].col;
74 : }
75 :
76 2310353 : static bool at(const P *p, WokKind k) { return (WokKind)cur(p)->kind == k; }
77 :
78 788084 : static bool at_word(const P *p, WokWord w) { return (WokWord)cur(p)->word == w; }
79 :
80 1101284 : static void bump(P *p) {
81 1101284 : const WokToken *t = cur(p);
82 1101284 : if (t->len > 0) p->last_end = t->off + t->len;
83 1101284 : if (p->i + 1 < p->n) p->i++;
84 1101284 : }
85 :
86 646530 : static u32 span_end(const P *p) { return p->last_end; }
87 :
88 275649 : static WokSpan tok_span(const WokToken *t) { return wok_span(t->off, t->len); }
89 :
90 : // Allocates and marks production coverage in one place, so a form no corpus
91 : // file reaches names itself rather than sitting silently uncovered.
92 646530 : static WokNode *mk(P *p, WokTag tag, u32 start, u32 end) {
93 646530 : wok_cover_mark(tag);
94 646530 : return wok_node(p->a, tag, start, end > start ? end - start : 0);
95 : }
96 :
97 : // ------------------------------------------------------------ diagnostics
98 :
99 9388 : static const char *tok_desc(P *p, const WokToken *t) {
100 9388 : if ((WokKind)t->kind == WT_EOF) return "end of file";
101 9388 : if ((WokKind)t->kind == WT_NEWLINE) return "end of line";
102 7636 : if ((WokKind)t->kind == WT_INDENT) return "an indented block";
103 7636 : if ((WokKind)t->kind == WT_DEDENT) return "the end of a block";
104 : // A BYTE cap would cut a multi-byte character in half and put an
105 : // ill-formed sequence into the message -- on valid input.
106 7621 : usize len = wok_utf8_truncate((const unsigned char *)p->src + t->off,
107 7621 : t->len, 40);
108 7621 : snprintf(p->desc, sizeof p->desc, "`%.*s`", (int)len, p->src + t->off);
109 7621 : return p->desc;
110 : }
111 :
112 : // E1. A layout token carries the position of the token it PRECEDES --
113 : // wok_layout.c builds it from the next token, which is right for the block
114 : // rule and wrong for blame. Reporting one sends the reader to the line AFTER
115 : // the broken one, which is usually a perfectly good declaration.
116 : //
117 : // So a fault on a layout token is blamed at the end of the last thing the
118 : // author actually wrote, which is where a missing `=` or `->` belongs. All
119 : // layout tokens have len 0, and `bump` only advances `last_end` past tokens
120 : // with len > 0, so that field is already exactly what is wanted.
121 12659 : static WokSpan blame(const P *p, const WokToken *t) {
122 12659 : if (t->len == 0) return wok_span(p->last_end, 0);
123 7914 : return wok_span(t->off, t->len);
124 : }
125 :
126 245 : static void perr_at(P *p, WokDiagCode code, const WokToken *t,
127 : const char *msg) {
128 245 : if (p->panic) return;
129 245 : WokSpan b = blame(p, t);
130 245 : wok_diag_add(p->d, code, b.off, b.len, "%s", msg);
131 245 : p->panic = true;
132 : }
133 :
134 : // Reports without entering panic: the item is otherwise complete, so keeping
135 : // its node is worth more than discarding it, and no second message can follow.
136 333 : static void perr_form(P *p, WokDiagCode code, const WokToken *t,
137 : const char *msg) {
138 333 : if (p->panic) return;
139 296 : WokSpan b = blame(p, t);
140 296 : wok_diag_add(p->d, code, b.off, b.len, "%s", msg);
141 : }
142 :
143 32536 : static void perr_expect(P *p, const char *what) {
144 32536 : if (p->panic) return;
145 10753 : const WokToken *t = cur(p);
146 10753 : if ((WokKind)t->kind == WT_INDENT) {
147 : // D-LAY-3. The corpus contains zero of these, which is what lets the
148 : // parser carry no continuation machinery at all.
149 1365 : wok_diag_add(p->d, WOK_E_LAY_INDENT, blame(p, t).off, blame(p, t).len,
150 : "unexpected indentation; to continue a line, begin it with "
151 : "an operator, or bracket the expression");
152 : } else {
153 9388 : WokSpan b = blame(p, t);
154 9388 : wok_diag_add(p->d, WOK_E_PARSE, b.off, b.len, "expected %s, found %s",
155 : what, tok_desc(p, t));
156 : }
157 10753 : p->panic = true;
158 : }
159 :
160 : // TIER 1 (single-token insert / delete / substitute local repair, Diekmann &
161 : // Tratt CPCT+ with a fixed budget) WOULD GO HERE, between the report and the
162 : // caller's fallback. It is a later slice; today every fault falls straight
163 : // through to tier 2 region discard in the block-item loop.
164 :
165 115240 : static bool expect(P *p, WokKind k, const char *what) {
166 115240 : if (at(p, k)) {
167 105973 : bump(p);
168 105973 : return true;
169 : }
170 9267 : perr_expect(p, what);
171 9267 : return false;
172 : }
173 :
174 13048 : static bool expect_word(P *p, WokWord w, const char *what) {
175 13048 : if (at_word(p, w)) {
176 12895 : bump(p);
177 12895 : return true;
178 : }
179 153 : perr_expect(p, what);
180 153 : return false;
181 : }
182 :
183 69489 : static WokSpan take_kind(P *p, WokKind k, const char *what) {
184 69489 : const WokToken *t = cur(p);
185 69489 : if ((WokKind)t->kind == k) {
186 68344 : bump(p);
187 68344 : return tok_span(t);
188 : }
189 1145 : perr_expect(p, what);
190 1145 : return wok_span(t->off, 0);
191 : }
192 :
193 1572 : static WokSpan take_any_name(P *p, const char *what) {
194 1572 : const WokToken *t = cur(p);
195 1572 : if ((WokKind)t->kind == WT_VARID || (WokKind)t->kind == WT_CONID) {
196 1557 : bump(p);
197 1557 : return tok_span(t);
198 : }
199 15 : perr_expect(p, what);
200 15 : return wok_span(t->off, 0);
201 : }
202 :
203 : // Bounded recursion: `((((((...` exhausting the C stack is the second classic
204 : // parser CVE after literal overflow, and <stdckdint.h> only covers the first.
205 608542 : static bool enter(P *p) {
206 608542 : if (p->depth >= WOK_PARSE_MAX_DEPTH) {
207 0 : if (!p->panic) {
208 0 : const WokToken *t = cur(p);
209 0 : wok_diag_add(p->d, WOK_E_DEPTH, t->off, t->len,
210 : "nested deeper than %d levels", WOK_PARSE_MAX_DEPTH);
211 0 : p->panic = true;
212 : }
213 0 : return false;
214 : }
215 608542 : p->depth++;
216 608542 : return true;
217 : }
218 :
219 608542 : static void leave(P *p) { p->depth--; }
220 :
221 27038 : static WokNode *mk_error(P *p, WokTag tag, u32 start) {
222 27038 : WokNode *n = mk(p, tag, start, span_end(p));
223 27038 : WokSpan text = wok_span(start, n->len);
224 27038 : if (tag == D_Error)
225 8991 : D_Error_set_text(n, text);
226 : else
227 18047 : E_Error_set_text(n, text);
228 27038 : return n;
229 : }
230 :
231 16841 : static WokNode *mk_err(P *p) { return mk_error(p, E_Error, cur(p)->off); }
232 :
233 : // -------------------------------------------------------------- the block
234 : //
235 : // BLOCK(x) := NEWLINE INDENT x (NEWLINE x)* DEDENT | x
236 : //
237 : // Called ONLY where the grammar already owes a block: after `=`, `of`, `->`,
238 : // `where`, `in`, `:=`, and after an effect / class / instance / foreign module
239 : // / handler head. A DEDENT is not always preceded by a NEWLINE -- a
240 : // continuation line emits its DEDENTs with no item separator, which is the
241 : // whole point of rule L4.
242 :
243 : typedef struct {
244 : bool indented;
245 : } Block;
246 :
247 66742 : static Block block_begin(P *p) {
248 66742 : Block b = {.indented = false};
249 66742 : if (p->panic) return b;
250 59144 : if (at(p, WT_NEWLINE) && kind_at(p, 1) == WT_INDENT) {
251 19892 : bump(p);
252 19892 : bump(p);
253 19892 : b.indented = true;
254 39252 : } else if (at(p, WT_NEWLINE) || at(p, WT_DEDENT) || at(p, WT_EOF)) {
255 245 : perr_at(p, WOK_E_LAY_EXPECTED_BLOCK, cur(p),
256 : "expected a body here: write it on this line, or on the next line "
257 : "indented further");
258 : }
259 59144 : return b;
260 : }
261 :
262 38372 : static bool block_next(P *p, const Block *b) {
263 38372 : if (!b->indented) return false;
264 37694 : if (at(p, WT_DEDENT)) return false;
265 34855 : if (p->sep) {
266 1392 : p->sep = false;
267 1392 : return true;
268 : }
269 33463 : if (at(p, WT_NEWLINE)) {
270 32917 : if (kind_at(p, 1) == WT_DEDENT) return false;
271 16250 : bump(p);
272 16250 : return true;
273 : }
274 : // A continuation lead (`where`, `in`, ...) belongs to the caller.
275 : return false;
276 : }
277 :
278 66902 : static void block_end(P *p, const Block *b) {
279 66902 : if (!b->indented) return;
280 20052 : bool sep = p->sep;
281 20052 : p->sep = false;
282 20052 : if (at(p, WT_NEWLINE) && kind_at(p, 1) == WT_DEDENT) {
283 16667 : bump(p);
284 16667 : sep = true;
285 : }
286 20052 : if (at(p, WT_DEDENT))
287 19746 : bump(p);
288 306 : else if (!at(p, WT_EOF))
289 282 : perr_expect(p, "the end of this block");
290 20052 : p->sep = sep;
291 : }
292 :
293 : // ---------------------------------------------------------------- recovery
294 : //
295 : // TIER 2 -- region discard (de Jonge / Kats / Visser / Soderberg). Abandon the
296 : // item, emit an error node so the block skeleton survives, skip to the next
297 : // NEWLINE at this block's level or to its DEDENT. DEDENT is a free
298 : // synchronisation point: it is arithmetic from columns, not a guess about what
299 : // a closing brace meant, so a damaged item can never swallow its block.
300 :
301 11083 : static void resync_to_boundary(P *p) {
302 11083 : int br = 0, ind = 0;
303 347054 : for (;;) {
304 347054 : WokKind k = (WokKind)cur(p)->kind;
305 347054 : if (k == WT_EOF) return;
306 345770 : if (br == 0) {
307 198824 : if (k == WT_INDENT) {
308 1483 : ind++;
309 1483 : bump(p);
310 1483 : continue;
311 : }
312 197341 : if (k == WT_DEDENT) {
313 71 : if (ind == 0) return;
314 43 : ind--;
315 43 : bump(p);
316 43 : continue;
317 : }
318 197270 : if (k == WT_NEWLINE) {
319 10696 : if (ind == 0) return;
320 : // The NEWLINE that precedes a run of DEDENTs is the separator of every
321 : // level it closes, including ours. Consume exactly the ones we skipped
322 : // into and hand the separator to the block loop.
323 : int d = 0;
324 3635 : while (kind_at(p, (usize)d + 1) == WT_DEDENT) d++;
325 2192 : if (d >= ind) {
326 1267 : bump(p);
327 2618 : for (int j = 0; j < ind; j++) bump(p);
328 1267 : ind = 0;
329 1267 : if ((WokKind)cur(p)->kind == WT_DEDENT) return;
330 1204 : p->sep = true;
331 1204 : return;
332 : }
333 925 : bump(p);
334 925 : continue;
335 : }
336 : }
337 333520 : if (wok_kind_is_open_bracket(k))
338 5764 : br++;
339 327756 : else if (wok_kind_is_close_bracket(k) && br > 0)
340 3509 : br--;
341 333520 : bump(p);
342 : }
343 : }
344 :
345 : // The words that BEGIN a declaration, and the production each one names.
346 : //
347 : // ONE roster, because two questions share this answer and must never drift
348 : // apart: parse_decl asks WHICH PRODUCTION parses a declaration, and
349 : // word_starts_decl asks whether a token is a safe place for recovery to
350 : // RESUME. They agree by construction rather than by convention -- forward-only
351 : // declarations (D23) are what makes a declaration keyword unambiguous enough
352 : // to be an anchor, so the two questions have one answer by design.
353 : //
354 : // They were two hand-written lists 1,500 lines apart, and dropping a word from
355 : // one of them compiled, passed every suite, and reported a fault on GOOD
356 : // source: recovery ran past the declaration it should have stopped at and into
357 : // its body. A wrong diagnostic on correct code is the worst kind, because a
358 : // reader believes it.
359 : #define WOK_DECL_WORDS(X) \
360 : X(WW_MODULE, parse_module_decl) X(WW_IMPORT, parse_import_decl) \
361 : X(WW_TYPE, parse_type_decl) X(WW_ALIAS, parse_alias_decl) \
362 : X(WW_EFFECT, parse_effect_decl) X(WW_CLASS, parse_class_decl) \
363 : X(WW_INSTANCE, parse_instance_decl) X(WW_FOREIGN, parse_foreign_decl) \
364 : X(WW_EXTERN, parse_extern_decl) X(WW_FIXITY, parse_fixity_decl)
365 :
366 722 : WOK_PURE static bool word_starts_decl(WokWord w) {
367 : #define WOK_X(word, fn) if (w == word) return true;
368 722 : WOK_DECL_WORDS(WOK_X)
369 : #undef WOK_X
370 : return false;
371 : }
372 :
373 : // Forward-only declarations (D23) are what make a signature the strongest
374 : // anchor available: `name :` at a block column can never be the tail of a
375 : // damaged item.
376 7035 : static bool at_decl_anchor(const P *p, usize j) {
377 7035 : if (j >= p->n) return false;
378 7035 : const WokToken *t = &p->tok[j];
379 : // E4. resync_to_boundary stops at a NEWLINE at the block's OWN level, and
380 : // the layout filter emits one exactly where an item begins -- so the
381 : // boundary is already exact and the anchor's only job is to reject
382 : // WRECKAGE. A `)` or `->` stranded at the block column cannot start a
383 : // declaration, and those are precisely the CONTINUATION LEADS, which is a
384 : // question the scanner already answers.
385 : //
386 : // The previous rule accepted only a declaration keyword or `name :`. That
387 : // made a damaged EQUATION not an anchor, so recovery walked over every one
388 : // it met: five broken equations in a row reported only the first, and the
389 : // batch stopped early exactly when a file was uniformly broken.
390 : // A KEYWORD still has to be a declaration keyword: `let` or `case` at the
391 : // top level is not a fresh declaration, it is wreckage from a damaged one.
392 7035 : if ((WokKind)t->kind == WT_KEYWORD) return word_starts_decl((WokWord)t->word);
393 6313 : return !wok_token_is_continuation_lead(t);
394 : }
395 :
396 9792 : static void resync_decl(P *p) {
397 9962 : for (;;) {
398 9877 : resync_to_boundary(p);
399 9877 : if (!at(p, WT_NEWLINE)) return;
400 7426 : if (kind_at(p, 1) == WT_DEDENT) return;
401 7035 : if (at_decl_anchor(p, p->i + 1)) return;
402 85 : bump(p);
403 : }
404 : }
405 :
406 : // ------------------------------------------------------------ predicates
407 :
408 76205 : static bool starts_atom(const P *p) {
409 76205 : WokKind k = (WokKind)cur(p)->kind;
410 76205 : return k == WT_VARID || k == WT_CONID || k == WT_INT || k == WT_STRING ||
411 76205 : k == WT_CHAR || k == WT_LPAREN || k == WT_LBRACKET;
412 : }
413 :
414 51881 : static bool starts_atompat(const P *p) {
415 51881 : WokKind k = (WokKind)cur(p)->kind;
416 51881 : if (k == WT_VARID || k == WT_CONID || k == WT_UNDERSCORE || k == WT_INT ||
417 : k == WT_STRING || k == WT_CHAR || k == WT_LPAREN || k == WT_LBRACKET)
418 18100 : return true;
419 : // `-` Int is the only pattern an operator can begin.
420 152 : if (k == WT_VARSYM) return kind_at(p, 1) == WT_INT;
421 : return false;
422 : }
423 :
424 103210 : static bool starts_atomtype(const P *p) {
425 103210 : WokKind k = (WokKind)cur(p)->kind;
426 103210 : return k == WT_VARID || k == WT_CONID || k == WT_LPAREN || k == WT_LBRACKET;
427 : }
428 :
429 16457 : static bool starts_typaram(const P *p) {
430 16457 : if (at(p, WT_VARID)) return true;
431 12264 : return at(p, WT_LPAREN) && word_at(p, 1) == WW_ROW;
432 : }
433 :
434 64628 : static bool at_infixop(const P *p) {
435 64628 : WokKind k = (WokKind)cur(p)->kind;
436 64628 : if (k == WT_VARSYM || k == WT_COLONCOLON) return true;
437 58333 : return k == WT_BACKTICK && kind_at(p, 1) == WT_VARID &&
438 312 : kind_at(p, 2) == WT_BACKTICK;
439 : }
440 :
441 : // ------------------------------------------------------------- prototypes
442 :
443 : static WokNode *parse_name(P *p);
444 : static WokNode *parse_modpath(P *p);
445 : static WokNode *parse_decl(P *p);
446 : static WokNode *parse_sig_or_equation(P *p);
447 : static WokNode *parse_type(P *p);
448 : static WokNode *parse_arrow(P *p);
449 : static WokNode *parse_typeapp(P *p);
450 : static WokNode *parse_atomtype(P *p);
451 : static WokSeq parse_row(P *p);
452 : static WokNode *parse_rowentry(P *p);
453 : static WokNode *parse_pat(P *p);
454 : static WokNode *parse_patapp(P *p);
455 : static WokNode *parse_atompat(P *p);
456 : static WokNode *parse_expr(P *p);
457 : static WokNode *parse_chain(P *p);
458 : static WokNode *parse_app(P *p);
459 : static WokNode *parse_atom(P *p);
460 : static WokNode *parse_stmt(P *p);
461 : static WokNode *parse_body(P *p);
462 : static WokNode *parse_bind(P *p);
463 : static WokNode *parse_alt(P *p);
464 : static WokNode *parse_clause(P *p);
465 : static WokSeq parse_where(P *p);
466 :
467 : // ------------------------------------------------------------ block lists
468 :
469 : typedef WokNode *(*ItemFn)(P *);
470 :
471 20730 : static WokSeq parse_block_list(P *p, const Block *b, ItemFn item,
472 : bool decl_block) {
473 20730 : WokNodeBuf buf;
474 20730 : wok_buf_init(&buf, p->a);
475 38372 : do {
476 38372 : usize before = p->i;
477 38372 : u32 start = cur(p)->off;
478 38372 : WokNode *n = item(p);
479 38372 : if (p->panic) {
480 1602 : if (decl_block)
481 396 : resync_decl(p);
482 : else
483 1206 : resync_to_boundary(p);
484 2808 : n = mk_error(p, decl_block ? D_Error : E_Error, start);
485 1602 : p->panic = false;
486 : }
487 38372 : wok_buf_push(&buf, n);
488 38372 : if (p->i == before && !at(p, WT_EOF) && !at(p, WT_NEWLINE) &&
489 0 : !at(p, WT_DEDENT))
490 0 : bump(p);
491 38372 : } while (block_next(p, b));
492 20730 : return wok_buf_seq(&buf);
493 : }
494 :
495 : // A statement that is not also an expression. It carries no value, so it is
496 : // meaningful only as an ITEM of a block; standing alone as a body it is a
497 : // `let` (or `handle`, or `use`) whose continuation was never written. Read
498 : // from the schema rather than hand-listed: the STMT family IS this set, and
499 : // a new statement form joins the check by joining the family.
500 46012 : static bool is_statement_only(const WokNode *n) {
501 46012 : return wok_node_desc[n->tag].family == WFAM_STMT;
502 : }
503 :
504 : // Named per form, because the repair differs: three of them are missing an
505 : // `in`, and the fourth cannot be repaired that way at all -- `_ = e` throws
506 : // its value away, so it can only be one line of a block, never the thing a
507 : // body evaluates to. An if-chain rather than a switch: this is four tags out
508 : // of eighty-two, so -Wswitch has nothing to hold down here.
509 41 : static void perr_unfinished_stmt(P *p, const WokNode *n) {
510 41 : if (n->tag == S_Let)
511 7 : perr_expect(p, "`in` after this binding");
512 34 : else if (n->tag == S_Handle)
513 34 : perr_expect(p, "`in` after the handler of this `handle`");
514 0 : else if (n->tag == S_Use)
515 0 : perr_expect(p, "`in` after these bridges");
516 : else
517 0 : perr_expect(p, "a value here; `_ =` discards a result");
518 41 : }
519 :
520 : // A body is `expr | E_Block`. E_Block is used whenever the block form was
521 : // taken -- even for one statement -- so a printer can re-derive line breaks.
522 : //
523 : // The block form has TWO spellings. The first is the ordinary one: the body
524 : // opens its own block under the head. The second is the HANGING body --
525 : // the first statement shares the head's line and the rest are indented under
526 : // it:
527 : //
528 : // add x, k -> let t = t + x False -> budget := budget - 1
529 : // t := 9 k (lookup q)
530 : //
531 : // Both are normative (spec.md 1.1's column-aware arm bodies; spec-min section
532 : // 6's `race`; reject/13). The layout filter already emits NEWLINE INDENT for
533 : // the continuation, so the whole difference is that the block's FIRST item was
534 : // read before the block opened -- which is why this cannot be decided by
535 : // lookahead: an inline `case` opens a block of its own on the same line, and
536 : // only parsing tells the two INDENTs apart.
537 50107 : static WokNode *parse_block_body(P *p, const Block *b) {
538 50107 : u32 start = cur(p)->off;
539 50107 : if (b->indented) {
540 3935 : WokSeq stmts = parse_block_list(p, b, parse_stmt, false);
541 3935 : WokNode *n = mk(p, E_Block, start, span_end(p));
542 3935 : E_Block_set_stmts(n, stmts);
543 3935 : return n;
544 : }
545 :
546 : // THE ANCHOR. Inline bodies nest on one line -- `let t = t + x` is a clause
547 : // body holding a binding whose own body is `t + x` -- and every one of them
548 : // is looking at the same INDENT. The block belongs to the body whose first
549 : // token stands in the block's column, which is the offside rule read
550 : // literally and the only reading that lets reject/13 mean what it says:
551 : //
552 : // add x, k -> let t = t + x the continuation is in `let`'s column,
553 : // t := 9 so it continues the CLAUSE body, and
554 : // k () `let t = t + x` is one statement of it.
555 : //
556 : // A column matching no inline body is not silently attached to the nearest
557 : // one: it falls through to D-LAY-3, which is what a misaligned line is.
558 : //
559 : // Limit, stated: the first statement must be SUB-BLOCK-FREE. If it opens
560 : // its own indented block (`set x -> case x of` with the alts deeper), that
561 : // block's DEDENT closes every level at or right of the anchor, so a
562 : // continuation standing in the anchor column arrives with no open level to
563 : // match and is D-LAY-3, not a clause-body line. Only a sub-block-free
564 : // first statement can share the arrow's line and still be continued
565 : // (README, Limits).
566 46172 : u32 anchor = cur(p)->col;
567 46172 : WokNode *first = parse_stmt(p);
568 : // The panic path takes the same statement guard as the fall-through below:
569 : // an enclosing block list may absorb and CLEAR the panic, and then a STMT
570 : // node returned here would stand in an EXPR slot of the final tree.
571 46172 : if (p->panic) return is_statement_only(first) ? mk_err(p) : first;
572 :
573 38170 : if (at(p, WT_NEWLINE) && kind_at(p, 1) == WT_INDENT && col_at(p, 2) == anchor) {
574 160 : Block hb = {.indented = true};
575 160 : bump(p);
576 160 : bump(p);
577 160 : WokNodeBuf buf;
578 160 : wok_buf_init(&buf, p->a);
579 160 : wok_buf_push(&buf, first);
580 160 : WokSeq rest = parse_block_list(p, &hb, parse_stmt, false);
581 473 : for (u32 i = 0; i < rest.n; i++) wok_buf_push(&buf, rest.items[i]);
582 160 : block_end(p, &hb);
583 160 : WokNode *n = mk(p, E_Block, start, span_end(p));
584 160 : E_Block_set_stmts(n, wok_buf_seq(&buf));
585 160 : return n;
586 : }
587 :
588 38010 : if (is_statement_only(first)) {
589 41 : perr_unfinished_stmt(p, first);
590 : // The node's FAMILY is STMT and an expression is due, so returning it
591 : // would put a statement where the schema demands an expression. Damage
592 : // is a wildcard family precisely so a damaged parse still dumps.
593 41 : return mk_err(p);
594 : }
595 : return first;
596 : }
597 :
598 17530 : static WokNode *parse_body(P *p) {
599 17530 : Block b = block_begin(p);
600 17530 : WokNode *n = parse_block_body(p, &b);
601 17530 : block_end(p, &b);
602 17530 : return n;
603 : }
604 :
605 2750 : static WokSeq parse_where(P *p) {
606 2750 : bump(p); // `where`
607 2750 : Block b = block_begin(p);
608 2750 : WokSeq s = parse_block_list(p, &b, parse_sig_or_equation, true);
609 2750 : block_end(p, &b);
610 2750 : return s;
611 : }
612 :
613 : // ------------------------------------------------------------------ names
614 :
615 70770 : static WokNode *parse_name(P *p) {
616 70770 : const WokToken *t = cur(p);
617 70770 : u32 start = t->off;
618 70770 : bool upper = (WokKind)t->kind == WT_CONID;
619 70770 : WokSpan text;
620 70770 : if (upper || (WokKind)t->kind == WT_VARID) {
621 70650 : text = tok_span(t);
622 70650 : bump(p);
623 : } else {
624 120 : perr_expect(p, "a name");
625 120 : text = wok_span(t->off, 0);
626 120 : upper = false;
627 : }
628 70770 : WokNode *n = mk(p, N_Name, start, span_end(p));
629 70770 : N_Name_set_text(n, text);
630 70770 : N_Name_set_upper(n, upper);
631 70770 : return n;
632 : }
633 :
634 65862 : static WokNode *parse_modpath(P *p) {
635 65862 : u32 start = cur(p)->off;
636 65862 : WokNodeBuf parts;
637 65862 : wok_buf_init(&parts, p->a);
638 65862 : wok_buf_push(&parts, parse_name(p));
639 68930 : while (at(p, WT_DOT) && kind_at(p, 1) == WT_CONID && !p->panic) {
640 3068 : bump(p);
641 3068 : wok_buf_push(&parts, parse_name(p));
642 : }
643 65862 : WokNode *n = mk(p, N_ModPath, start, span_end(p));
644 65862 : N_ModPath_set_parts(n, wok_buf_seq(&parts));
645 65862 : return n;
646 : }
647 :
648 : // ------------------------------------------------------------------ types
649 :
650 55532 : static WokNode *parse_type(P *p) {
651 55532 : if (!enter(p)) return mk_err(p);
652 55532 : u32 start = cur(p)->off;
653 55532 : WokNode *lhs = parse_arrow(p);
654 55532 : WokNode *r = lhs;
655 55532 : if (at(p, WT_FATARROW)) {
656 2453 : bump(p);
657 2453 : WokNode *body = parse_type(p);
658 2453 : r = mk(p, T_Qual, start, span_end(p));
659 2453 : T_Qual_set_ctx(r, lhs);
660 2453 : T_Qual_set_body(r, body);
661 53079 : } else if (at_word(p, WW_WITH)) {
662 4415 : bump(p);
663 4415 : WokSeq row = parse_row(p);
664 4415 : r = mk(p, T_With, start, span_end(p));
665 4415 : T_With_set_body(r, lhs);
666 4415 : T_With_set_row(r, row);
667 : }
668 55532 : leave(p);
669 55532 : return r;
670 : }
671 :
672 70537 : static WokNode *parse_arrow(P *p) {
673 70537 : if (!enter(p)) return mk_err(p);
674 70537 : u32 start = cur(p)->off;
675 70537 : WokNode *l = parse_typeapp(p);
676 70537 : WokNode *r = l;
677 70537 : if (at(p, WT_ARROW)) {
678 15005 : bump(p);
679 15005 : WokNode *to = parse_arrow(p);
680 15005 : r = mk(p, T_Fun, start, span_end(p));
681 15005 : T_Fun_set_from(r, l);
682 15005 : T_Fun_set_to(r, to);
683 : }
684 70537 : leave(p);
685 70537 : return r;
686 : }
687 :
688 76507 : static WokNode *parse_typeapp(P *p) {
689 76507 : u32 start = cur(p)->off;
690 76507 : u64 mode = WOK_TRANSFER_OWN;
691 76507 : bool transfer = false;
692 76507 : if (p->foreign_sig && at(p, WT_VARID)) {
693 1181 : WokWord w = (WokWord)cur(p)->word;
694 1181 : if (w == WW_OWN) {
695 : mode = WOK_TRANSFER_OWN;
696 : transfer = true;
697 : } else if (w == WW_LEND) {
698 : mode = WOK_TRANSFER_LEND;
699 : transfer = true;
700 : } else if (w == WW_COPY) {
701 : mode = WOK_TRANSFER_COPY;
702 : transfer = true;
703 : }
704 392 : if (transfer) bump(p);
705 : }
706 76507 : WokNode *t = parse_atomtype(p);
707 94642 : while (starts_atomtype(p) && !p->panic) {
708 18135 : WokNode *arg = parse_atomtype(p);
709 18135 : WokNode *app = mk(p, T_App, start, span_end(p));
710 18135 : T_App_set_fn(app, t);
711 18135 : T_App_set_arg(app, arg);
712 18135 : t = app;
713 : }
714 76507 : if (transfer) {
715 392 : WokNode *tr = mk(p, T_Transfer, start, span_end(p));
716 392 : T_Transfer_set_mode(tr, mode);
717 392 : T_Transfer_set_body(tr, t);
718 392 : t = tr;
719 : }
720 76507 : return t;
721 : }
722 :
723 98037 : static WokNode *parse_atomtype(P *p) {
724 98037 : if (!enter(p)) return mk_err(p);
725 98037 : u32 start = cur(p)->off;
726 98037 : WokNode *r;
727 98037 : if (at(p, WT_VARID)) {
728 18726 : const WokToken *t = cur(p);
729 18726 : bump(p);
730 18726 : r = mk(p, T_Var, start, span_end(p));
731 18726 : T_Var_set_name(r, tok_span(t));
732 79311 : } else if (at(p, WT_CONID)) {
733 48109 : WokNode *path = parse_modpath(p);
734 48109 : r = mk(p, T_Con, start, span_end(p));
735 48109 : T_Con_set_path(r, path);
736 31202 : } else if (at(p, WT_LBRACKET)) {
737 4403 : bump(p);
738 4403 : WokNode *elem = parse_type(p);
739 4403 : expect(p, WT_RBRACKET, "`]` to close this list type");
740 4403 : r = mk(p, T_List, start, span_end(p));
741 4403 : T_List_set_elem(r, elem);
742 26799 : } else if (at(p, WT_LPAREN)) {
743 25445 : bump(p);
744 25445 : if (at(p, WT_RPAREN)) {
745 9836 : bump(p);
746 9836 : r = mk(p, T_Unit, start, span_end(p));
747 15609 : } else if (at_word(p, WW_ROW) && kind_at(p, 1) == WT_VARID &&
748 12158 : kind_at(p, 2) == WT_RPAREN) {
749 6079 : bump(p);
750 6079 : const WokToken *v = cur(p);
751 6079 : bump(p);
752 6079 : bump(p);
753 6079 : r = mk(p, T_RowArg, start, span_end(p));
754 6079 : T_RowArg_set_name(r, tok_span(v));
755 : } else {
756 9530 : WokNodeBuf items;
757 9530 : wok_buf_init(&items, p->a);
758 9530 : wok_buf_push(&items, parse_type(p));
759 15158 : while (at(p, WT_COMMA) && !p->panic) {
760 5628 : bump(p);
761 5628 : wok_buf_push(&items, parse_type(p));
762 : }
763 9530 : expect(p, WT_RPAREN, "`)` to close this type");
764 9530 : if (wok_buf_count(&items) == 1) {
765 4567 : r = wok_buf_at(&items, 0);
766 : } else {
767 4963 : r = mk(p, T_Tuple, start, span_end(p));
768 4963 : T_Tuple_set_items(r, wok_buf_seq(&items));
769 : }
770 : }
771 : } else {
772 1354 : perr_expect(p, "a type");
773 1354 : r = mk_err(p);
774 : }
775 98037 : leave(p);
776 98037 : return r;
777 : }
778 :
779 4415 : static WokSeq parse_row(P *p) {
780 4415 : WokNodeBuf buf;
781 4415 : wok_buf_init(&buf, p->a);
782 4415 : wok_buf_push(&buf, parse_rowentry(p));
783 6794 : while (at_word(p, WW_PLUS) && !p->panic) {
784 2379 : bump(p);
785 2379 : wok_buf_push(&buf, parse_rowentry(p));
786 : }
787 4415 : return wok_buf_seq(&buf);
788 : }
789 :
790 6794 : static WokNode *parse_rowentry(P *p) {
791 6794 : u32 start = cur(p)->off;
792 6794 : WokNode *n;
793 6794 : if (at(p, WT_LPAREN) && kind_at(p, 1) == WT_VARID &&
794 2733 : kind_at(p, 2) == WT_COLON) {
795 : // A role obligation (D20). The label is lowercase by construction.
796 1129 : bump(p);
797 1129 : const WokToken *label = cur(p);
798 1129 : bump(p);
799 1129 : bump(p);
800 1129 : WokNode *ty = parse_typeapp(p);
801 1129 : expect(p, WT_RPAREN, "`)` to close this role obligation");
802 1129 : n = mk(p, H_RowEntry, start, span_end(p));
803 1129 : H_RowEntry_set_kind(n, WOK_ROW_ROLE);
804 1129 : H_RowEntry_set_label(n, tok_span(label));
805 1129 : H_RowEntry_set_type(n, ty);
806 6489 : } else if (at_word(p, WW_EFF) && kind_at(p, 1) == WT_VARID) {
807 824 : bump(p);
808 824 : const WokToken *v = cur(p);
809 824 : bump(p);
810 824 : n = mk(p, H_RowEntry, start, span_end(p));
811 824 : H_RowEntry_set_kind(n, WOK_ROW_VAR);
812 824 : H_RowEntry_set_label(n, tok_span(v));
813 824 : H_RowEntry_set_type(n, nullptr);
814 : } else {
815 4841 : WokNode *ty = parse_typeapp(p);
816 4841 : n = mk(p, H_RowEntry, start, span_end(p));
817 4841 : H_RowEntry_set_kind(n, WOK_ROW_SLOT);
818 4841 : H_RowEntry_set_label(n, wok_span(start, 0));
819 4841 : H_RowEntry_set_type(n, ty);
820 : }
821 6794 : return n;
822 : }
823 :
824 : // --------------------------------------------------------------- patterns
825 :
826 805 : static WokNode *parse_fieldpat(P *p) {
827 805 : u32 start = cur(p)->off;
828 805 : WokSpan name = take_kind(p, WT_VARID, "a field name");
829 805 : WokNode *pat;
830 805 : if (at(p, WT_EQUALS)) {
831 607 : bump(p);
832 607 : pat = parse_pat(p);
833 : } else {
834 : // Punned: `{ x }` binds the field to its own name.
835 198 : pat = mk(p, P_Var, start, span_end(p));
836 198 : P_Var_set_name(pat, name);
837 : }
838 805 : WokNode *n = mk(p, H_FieldPat, start, span_end(p));
839 805 : H_FieldPat_set_name(n, name);
840 805 : H_FieldPat_set_pat(n, pat);
841 805 : return n;
842 : }
843 :
844 1195 : static WokNode *parse_record_pat(P *p, u32 start, WokNode *path) {
845 1195 : bump(p); // `{`
846 1195 : bool is_open = false;
847 1195 : WokSpan rest = wok_span(start, 0);
848 1195 : if (at(p, WT_DOTDOT)) {
849 590 : bump(p);
850 590 : is_open = true;
851 590 : if (at(p, WT_VARID)) {
852 376 : rest = tok_span(cur(p));
853 376 : bump(p);
854 : }
855 590 : if (at(p, WT_COMMA)) bump(p);
856 : }
857 1195 : WokNodeBuf fields;
858 1195 : wok_buf_init(&fields, p->a);
859 1195 : if (!at(p, WT_RBRACE) && !p->panic) {
860 510 : wok_buf_push(&fields, parse_fieldpat(p));
861 805 : while (at(p, WT_COMMA) && !p->panic) {
862 295 : bump(p);
863 295 : wok_buf_push(&fields, parse_fieldpat(p));
864 : }
865 : }
866 1195 : expect(p, WT_RBRACE, "`}` to close this record pattern");
867 1195 : WokNode *n = mk(p, P_Record, start, span_end(p));
868 1195 : P_Record_set_path(n, path);
869 1195 : P_Record_set_fields(n, wok_buf_seq(&fields));
870 1195 : P_Record_set_is_open(n, is_open);
871 1195 : P_Record_set_rest(n, rest);
872 1195 : return n;
873 : }
874 :
875 42200 : static WokNode *parse_as_tail(P *p, WokNode *inner, u32 start) {
876 42701 : while (at_word(p, WW_AS) && !p->panic) {
877 501 : bump(p);
878 501 : WokSpan name = take_kind(p, WT_VARID, "a name after `as`");
879 501 : WokNode *n = mk(p, P_As, start, span_end(p));
880 501 : P_As_set_pat(n, inner);
881 501 : P_As_set_name(n, name);
882 501 : inner = n;
883 : }
884 42200 : return inner;
885 : }
886 :
887 40515 : static WokNode *parse_atompat(P *p) {
888 40515 : if (!enter(p)) return mk_err(p);
889 40515 : u32 start = cur(p)->off;
890 40515 : WokNode *r;
891 40515 : if (at(p, WT_VARID)) {
892 17998 : const WokToken *t = cur(p);
893 17998 : bump(p);
894 17998 : r = mk(p, P_Var, start, span_end(p));
895 17998 : P_Var_set_name(r, tok_span(t));
896 22517 : } else if (at(p, WT_UNDERSCORE)) {
897 1547 : bump(p);
898 1547 : r = mk(p, P_Wild, start, span_end(p));
899 20970 : } else if (at(p, WT_INT)) {
900 1095 : const WokToken *t = cur(p);
901 1095 : u64 v = 0;
902 1095 : (void)wok_token_int_value(p->src, t, p->d, &v);
903 1095 : bump(p);
904 1095 : r = mk(p, P_Int, start, span_end(p));
905 1095 : P_Int_set_value(r, v);
906 1095 : P_Int_set_negative(r, false);
907 20620 : } else if (at(p, WT_VARSYM) && kind_at(p, 1) == WT_INT) {
908 745 : bump(p);
909 745 : const WokToken *t = cur(p);
910 745 : u64 v = 0;
911 745 : (void)wok_token_int_value(p->src, t, p->d, &v);
912 745 : bump(p);
913 745 : r = mk(p, P_Int, start, span_end(p));
914 745 : P_Int_set_value(r, v);
915 745 : P_Int_set_negative(r, true);
916 19130 : } else if (at(p, WT_STRING)) {
917 1267 : const WokToken *t = cur(p);
918 1267 : bump(p);
919 1267 : r = mk(p, P_Str, start, span_end(p));
920 1267 : P_Str_set_text(r, tok_span(t));
921 17863 : } else if (at(p, WT_CHAR)) {
922 1231 : const WokToken *t = cur(p);
923 1231 : bump(p);
924 1231 : r = mk(p, P_Char, start, span_end(p));
925 1231 : P_Char_set_text(r, tok_span(t));
926 16632 : } else if (at(p, WT_CONID)) {
927 2096 : WokNode *path = parse_modpath(p);
928 2096 : if (at(p, WT_LBRACE)) {
929 703 : r = parse_record_pat(p, start, path);
930 : } else {
931 1393 : r = mk(p, P_Con, start, span_end(p));
932 1393 : P_Con_set_path(r, path);
933 1393 : P_Con_set_args(r, wok_seq_empty());
934 : }
935 14536 : } else if (at(p, WT_LPAREN)) {
936 5086 : bump(p);
937 5086 : if (at(p, WT_RPAREN)) {
938 2671 : bump(p);
939 2671 : r = mk(p, P_Unit, start, span_end(p));
940 : } else {
941 2415 : WokNodeBuf items;
942 2415 : wok_buf_init(&items, p->a);
943 2415 : wok_buf_push(&items, parse_pat(p));
944 3569 : while (at(p, WT_COMMA) && !p->panic) {
945 1154 : bump(p);
946 1154 : wok_buf_push(&items, parse_pat(p));
947 : }
948 2415 : expect(p, WT_RPAREN, "`)` to close this pattern");
949 2415 : if (wok_buf_count(&items) == 1) {
950 1375 : r = wok_buf_at(&items, 0);
951 : } else {
952 1040 : r = mk(p, P_Tuple, start, span_end(p));
953 1040 : P_Tuple_set_items(r, wok_buf_seq(&items));
954 : }
955 : }
956 9450 : } else if (at(p, WT_LBRACKET)) {
957 1107 : bump(p);
958 1107 : WokNodeBuf items;
959 1107 : wok_buf_init(&items, p->a);
960 1107 : if (!at(p, WT_RBRACKET) && !p->panic) {
961 239 : wok_buf_push(&items, parse_pat(p));
962 331 : while (at(p, WT_COMMA) && !p->panic) {
963 92 : bump(p);
964 92 : wok_buf_push(&items, parse_pat(p));
965 : }
966 : }
967 1107 : expect(p, WT_RBRACKET, "`]` to close this list pattern");
968 1107 : r = mk(p, P_List, start, span_end(p));
969 1107 : P_List_set_items(r, wok_buf_seq(&items));
970 : } else {
971 8343 : perr_expect(p, "a pattern");
972 8343 : r = mk_err(p);
973 : }
974 40515 : r = parse_as_tail(p, r, start);
975 40515 : leave(p);
976 40515 : return r;
977 : }
978 :
979 13160 : static WokNode *parse_patapp(P *p) {
980 13160 : if (!at(p, WT_CONID)) return parse_atompat(p);
981 3280 : u32 start = cur(p)->off;
982 3280 : WokNode *path = parse_modpath(p);
983 3280 : if (at(p, WT_LBRACE))
984 492 : return parse_as_tail(p, parse_record_pat(p, start, path), start);
985 2788 : if (!starts_atompat(p)) {
986 1193 : WokNode *bare = mk(p, P_Con, start, span_end(p));
987 1193 : P_Con_set_path(bare, path);
988 1193 : P_Con_set_args(bare, wok_seq_empty());
989 1193 : return parse_as_tail(p, bare, start);
990 : }
991 1595 : WokNodeBuf args;
992 1595 : wok_buf_init(&args, p->a);
993 3477 : while (starts_atompat(p) && !p->panic) wok_buf_push(&args, parse_atompat(p));
994 1595 : WokNode *n = mk(p, P_Con, start, span_end(p));
995 1595 : P_Con_set_path(n, path);
996 1595 : P_Con_set_args(n, wok_buf_seq(&args));
997 1595 : return n;
998 : }
999 :
1000 13160 : static WokNode *parse_pat(P *p) {
1001 13160 : if (!enter(p)) return mk_err(p);
1002 13160 : u32 start = cur(p)->off;
1003 13160 : WokNode *head = parse_patapp(p);
1004 13160 : WokNode *r = head;
1005 13160 : if (at(p, WT_COLONCOLON)) {
1006 1003 : bump(p);
1007 1003 : WokNode *tail = parse_pat(p);
1008 1003 : r = mk(p, P_Cons, start, span_end(p));
1009 1003 : P_Cons_set_head(r, head);
1010 1003 : P_Cons_set_tail(r, tail);
1011 : }
1012 13160 : leave(p);
1013 13160 : return r;
1014 : }
1015 :
1016 : // ------------------------------------------------------------ expressions
1017 :
1018 867 : static WokNode *parse_field(P *p) {
1019 867 : u32 start = cur(p)->off;
1020 867 : WokSpan name = take_kind(p, WT_VARID, "a field name");
1021 867 : WokNode *value;
1022 867 : if (at(p, WT_EQUALS)) {
1023 641 : bump(p);
1024 641 : value = parse_expr(p);
1025 : } else {
1026 226 : value = mk(p, E_Var, start, span_end(p));
1027 226 : E_Var_set_name(value, name);
1028 : }
1029 867 : WokNode *n = mk(p, H_Field, start, span_end(p));
1030 867 : H_Field_set_name(n, name);
1031 867 : H_Field_set_value(n, value);
1032 867 : return n;
1033 : }
1034 :
1035 688 : static WokNode *parse_record_expr(P *p, u32 start, WokNode *path) {
1036 688 : bump(p); // `{`
1037 688 : WokNode *spread = nullptr;
1038 688 : if (at(p, WT_DOTDOT)) {
1039 326 : bump(p);
1040 326 : spread = parse_expr(p);
1041 326 : if (at(p, WT_COMMA)) bump(p);
1042 : }
1043 688 : WokNodeBuf fields;
1044 688 : wok_buf_init(&fields, p->a);
1045 688 : if (!at(p, WT_RBRACE) && !p->panic) {
1046 475 : wok_buf_push(&fields, parse_field(p));
1047 867 : while (at(p, WT_COMMA) && !p->panic) {
1048 392 : bump(p);
1049 392 : wok_buf_push(&fields, parse_field(p));
1050 : }
1051 : }
1052 688 : expect(p, WT_RBRACE, "`}` to close this record");
1053 688 : WokNode *n = mk(p, E_Record, start, span_end(p));
1054 688 : E_Record_set_path(n, path);
1055 688 : E_Record_set_spread(n, spread);
1056 688 : E_Record_set_fields(n, wok_buf_seq(&fields));
1057 688 : return n;
1058 : }
1059 :
1060 693 : static bool is_con_atom(const WokNode *n) {
1061 693 : if (n->tag == E_Con) return true;
1062 85 : return n->tag == E_Dot && E_Dot_upper(n);
1063 : }
1064 :
1065 76205 : static WokNode *parse_atom(P *p) {
1066 76205 : if (!enter(p)) return mk_err(p);
1067 76205 : u32 start = cur(p)->off;
1068 76205 : WokNode *r;
1069 76205 : if (at(p, WT_VARID)) {
1070 31857 : const WokToken *t = cur(p);
1071 31857 : bump(p);
1072 31857 : r = mk(p, E_Var, start, span_end(p));
1073 31857 : E_Var_set_name(r, tok_span(t));
1074 44348 : } else if (at(p, WT_CONID)) {
1075 6046 : const WokToken *t = cur(p);
1076 6046 : bump(p);
1077 6046 : r = mk(p, E_Con, start, span_end(p));
1078 6046 : E_Con_set_name(r, tok_span(t));
1079 38302 : } else if (at(p, WT_INT)) {
1080 17101 : const WokToken *t = cur(p);
1081 17101 : u64 v = 0;
1082 17101 : (void)wok_token_int_value(p->src, t, p->d, &v);
1083 17101 : bump(p);
1084 17101 : r = mk(p, E_Int, start, span_end(p));
1085 17101 : E_Int_set_value(r, v);
1086 21201 : } else if (at(p, WT_STRING)) {
1087 1938 : const WokToken *t = cur(p);
1088 1938 : bump(p);
1089 1938 : r = mk(p, E_Str, start, span_end(p));
1090 1938 : E_Str_set_text(r, tok_span(t));
1091 19263 : } else if (at(p, WT_CHAR)) {
1092 1223 : const WokToken *t = cur(p);
1093 1223 : bump(p);
1094 1223 : r = mk(p, E_Char, start, span_end(p));
1095 1223 : E_Char_set_text(r, tok_span(t));
1096 18040 : } else if (at(p, WT_LPAREN)) {
1097 9509 : bump(p);
1098 9509 : if (at(p, WT_RPAREN)) {
1099 3199 : bump(p);
1100 3199 : r = mk(p, E_Unit, start, span_end(p));
1101 7621 : } else if (at(p, WT_VARSYM) && kind_at(p, 1) == WT_RPAREN) {
1102 1311 : const WokToken *t = cur(p);
1103 1311 : bump(p);
1104 1311 : bump(p);
1105 1311 : r = mk(p, E_OpRef, start, span_end(p));
1106 1311 : E_OpRef_set_name(r, tok_span(t));
1107 : } else {
1108 4999 : WokNodeBuf items;
1109 4999 : wok_buf_init(&items, p->a);
1110 4999 : wok_buf_push(&items, parse_expr(p));
1111 7255 : while (at(p, WT_COMMA) && !p->panic) {
1112 2256 : bump(p);
1113 2256 : wok_buf_push(&items, parse_expr(p));
1114 : }
1115 4999 : expect(p, WT_RPAREN, "`)` to close this expression");
1116 4999 : if (wok_buf_count(&items) == 1) {
1117 3080 : r = wok_buf_at(&items, 0);
1118 : } else {
1119 1919 : r = mk(p, E_Tuple, start, span_end(p));
1120 1919 : E_Tuple_set_items(r, wok_buf_seq(&items));
1121 : }
1122 : }
1123 8531 : } else if (at(p, WT_LBRACKET)) {
1124 1479 : bump(p);
1125 1479 : WokNodeBuf items;
1126 1479 : wok_buf_init(&items, p->a);
1127 1479 : if (!at(p, WT_RBRACKET) && !p->panic) {
1128 930 : wok_buf_push(&items, parse_expr(p));
1129 2833 : while (at(p, WT_COMMA) && !p->panic) {
1130 1903 : bump(p);
1131 1903 : wok_buf_push(&items, parse_expr(p));
1132 : }
1133 : }
1134 1479 : expect(p, WT_RBRACKET, "`]` to close this list");
1135 1479 : r = mk(p, E_List, start, span_end(p));
1136 1479 : E_List_set_items(r, wok_buf_seq(&items));
1137 : } else {
1138 7052 : perr_expect(p, "an expression");
1139 7052 : r = mk_err(p);
1140 : }
1141 : // ONE Dot node for `M.f`, `st.get` and `p.x`: spec 1.5 resolves qualifier /
1142 : // label / projection later, and its collision rule needs them
1143 : // undistinguished at parse time.
1144 80847 : while (!p->panic) {
1145 72741 : if (at(p, WT_DOT) &&
1146 3965 : (kind_at(p, 1) == WT_VARID || kind_at(p, 1) == WT_CONID)) {
1147 3954 : bump(p);
1148 3954 : const WokToken *t = cur(p);
1149 3954 : bool upper = (WokKind)t->kind == WT_CONID;
1150 3954 : bump(p);
1151 3954 : WokNode *dot = mk(p, E_Dot, start, span_end(p));
1152 3954 : E_Dot_set_recv(dot, r);
1153 3954 : E_Dot_set_name(dot, tok_span(t));
1154 3954 : E_Dot_set_upper(dot, upper);
1155 3954 : r = dot;
1156 3954 : continue;
1157 : }
1158 68787 : if (at(p, WT_LBRACE) && is_con_atom(r)) {
1159 688 : r = parse_record_expr(p, start, r);
1160 688 : continue;
1161 : }
1162 : break;
1163 : }
1164 76205 : leave(p);
1165 76205 : return r;
1166 : }
1167 :
1168 65368 : static WokNode *parse_app(P *p) {
1169 65368 : if (!enter(p)) return mk_err(p);
1170 65368 : u32 start = cur(p)->off;
1171 65368 : WokNode *r;
1172 65368 : if (at(p, WT_VARSYM)) {
1173 : // In operand position the only prefix operator is `-` (D-LEX-1): negation
1174 : // is never glued to its literal, so this needs no text compare.
1175 740 : bump(p);
1176 740 : WokNode *body = parse_app(p);
1177 740 : r = mk(p, E_Neg, start, span_end(p));
1178 740 : E_Neg_set_body(r, body);
1179 : } else {
1180 64628 : r = parse_atom(p);
1181 76205 : while (starts_atom(p) && !p->panic) {
1182 11577 : WokNode *arg = parse_atom(p);
1183 11577 : WokNode *app = mk(p, E_App, start, span_end(p));
1184 11577 : E_App_set_fn(app, r);
1185 11577 : E_App_set_arg(app, arg);
1186 11577 : r = app;
1187 : }
1188 : }
1189 65368 : leave(p);
1190 65368 : return r;
1191 : }
1192 :
1193 57839 : static WokNode *parse_chain(P *p) {
1194 57839 : u32 start = cur(p)->off;
1195 57839 : WokNode *head = parse_app(p);
1196 57839 : WokNodeBuf ops;
1197 57839 : wok_buf_init(&ops, p->a);
1198 64628 : while (at_infixop(p) && !p->panic) {
1199 6789 : u32 ostart = cur(p)->off;
1200 6789 : WokSpan name;
1201 6789 : bool backtick = false;
1202 6789 : if (at(p, WT_BACKTICK)) {
1203 256 : bump(p);
1204 256 : name = tok_span(cur(p));
1205 256 : backtick = true;
1206 256 : bump(p);
1207 256 : expect(p, WT_BACKTICK, "a closing backtick");
1208 : } else {
1209 6533 : name = tok_span(cur(p));
1210 6533 : bump(p);
1211 : }
1212 6789 : WokNode *rhs = parse_app(p);
1213 6789 : WokNode *op = mk(p, H_ChainOp, ostart, span_end(p));
1214 6789 : H_ChainOp_set_op(op, name);
1215 6789 : H_ChainOp_set_backtick(op, backtick);
1216 6789 : H_ChainOp_set_rhs(op, rhs);
1217 6789 : wok_buf_push(&ops, op);
1218 : }
1219 57839 : if (wok_buf_count(&ops) == 0) return head;
1220 5965 : WokNode *n = mk(p, E_Chain, start, span_end(p));
1221 5965 : E_Chain_set_head(n, head);
1222 5965 : E_Chain_set_ops(n, wok_buf_seq(&ops));
1223 5965 : return n;
1224 : }
1225 :
1226 1313 : static WokNode *parse_lambda(P *p) {
1227 1313 : u32 start = cur(p)->off;
1228 1313 : bump(p); // `\`
1229 1313 : WokNodeBuf params;
1230 1313 : wok_buf_init(¶ms, p->a);
1231 2542 : while (starts_atompat(p) && !p->panic)
1232 1229 : wok_buf_push(¶ms, parse_atompat(p));
1233 1313 : expect(p, WT_ARROW, "`->` after the lambda's parameters");
1234 1313 : WokNode *body = parse_body(p);
1235 1313 : WokNode *n = mk(p, E_Lambda, start, span_end(p));
1236 1313 : E_Lambda_set_params(n, wok_buf_seq(¶ms));
1237 1313 : E_Lambda_set_body(n, body);
1238 1313 : return n;
1239 : }
1240 :
1241 576 : static WokNode *parse_if(P *p) {
1242 576 : u32 start = cur(p)->off;
1243 576 : bump(p); // `if`
1244 576 : WokNode *cond = parse_expr(p);
1245 576 : expect_word(p, WW_THEN, "`then` after the condition");
1246 576 : WokNode *then_ = parse_body(p);
1247 576 : expect_word(p, WW_ELSE, "`else` after the `then` branch");
1248 576 : WokNode *else_ = parse_body(p);
1249 576 : WokNode *n = mk(p, E_If, start, span_end(p));
1250 576 : E_If_set_cond(n, cond);
1251 576 : E_If_set_then_(n, then_);
1252 576 : E_If_set_else_(n, else_);
1253 576 : return n;
1254 : }
1255 :
1256 3100 : static WokNode *parse_case(P *p) {
1257 3100 : u32 start = cur(p)->off;
1258 3100 : bump(p); // `case`
1259 3100 : WokNode *scrut = parse_expr(p);
1260 3100 : expect_word(p, WW_OF, "`of` after the scrutinee");
1261 3100 : Block b = block_begin(p);
1262 3100 : WokSeq alts = parse_block_list(p, &b, parse_alt, false);
1263 3100 : block_end(p, &b);
1264 3100 : WokNode *n = mk(p, E_Case, start, span_end(p));
1265 3100 : E_Case_set_scrut(n, scrut);
1266 3100 : E_Case_set_alts(n, alts);
1267 3100 : return n;
1268 : }
1269 :
1270 3461 : static WokNode *parse_handler(P *p) {
1271 3461 : u32 start = cur(p)->off;
1272 3461 : bump(p); // `handler`
1273 : // `handler E` names its effect MANDATORILY (C3).
1274 3461 : WokSpan effect = take_kind(p, WT_CONID, "the effect this handler handles");
1275 3461 : Block b = block_begin(p);
1276 3461 : WokSeq clauses = parse_block_list(p, &b, parse_clause, false);
1277 3461 : block_end(p, &b);
1278 3461 : WokNode *n = mk(p, E_Handler, start, span_end(p));
1279 3461 : E_Handler_set_effect(n, effect);
1280 3461 : E_Handler_set_clauses(n, clauses);
1281 3461 : return n;
1282 : }
1283 :
1284 717 : static WokSeq parse_usebinds(P *p) {
1285 717 : WokNodeBuf buf;
1286 717 : wok_buf_init(&buf, p->a);
1287 69 : for (;;) {
1288 786 : u32 start = cur(p)->off;
1289 786 : WokSpan from = take_any_name(p, "the label to bridge from");
1290 786 : expect_word(p, WW_AS, "`as` between the two labels");
1291 786 : WokSpan to = take_any_name(p, "the label to bridge to");
1292 786 : WokNode *n = mk(p, H_UseBind, start, span_end(p));
1293 786 : H_UseBind_set_from(n, from);
1294 786 : H_UseBind_set_to(n, to);
1295 786 : wok_buf_push(&buf, n);
1296 786 : if (p->panic || !at(p, WT_COMMA)) break;
1297 69 : bump(p);
1298 : }
1299 717 : return wok_buf_seq(&buf);
1300 : }
1301 :
1302 : // A label is written only when a name is immediately followed by `=`.
1303 3331 : static bool at_handle_label(const P *p) {
1304 3331 : return (at(p, WT_VARID) || at(p, WT_CONID)) && kind_at(p, 1) == WT_EQUALS;
1305 : }
1306 :
1307 66883 : static WokNode *parse_expr(P *p) {
1308 66883 : if (!enter(p)) return mk_err(p);
1309 66883 : u32 start = cur(p)->off;
1310 66883 : WokNode *r;
1311 66883 : if (at(p, WT_LAMBDA)) {
1312 1313 : r = parse_lambda(p);
1313 65570 : } else if (at_word(p, WW_LET)) {
1314 90 : bump(p);
1315 90 : WokNode *bind = parse_bind(p);
1316 90 : expect_word(p, WW_IN, "`in` after this binding");
1317 90 : WokNode *body = parse_body(p);
1318 90 : r = mk(p, E_LetIn, start, span_end(p));
1319 90 : E_LetIn_set_bind(r, bind);
1320 90 : E_LetIn_set_body(r, body);
1321 65480 : } else if (at_word(p, WW_HANDLE)) {
1322 396 : bump(p);
1323 : // The delimited inline form MAY elide the label (D13 two-tier); the
1324 : // default is then read off the handler's type.
1325 396 : WokSpan label = wok_span(start, 0);
1326 396 : if (at_handle_label(p)) {
1327 235 : label = tok_span(cur(p));
1328 235 : bump(p);
1329 235 : bump(p);
1330 : }
1331 396 : WokNode *handler = parse_expr(p);
1332 396 : expect_word(p, WW_IN, "`in` after the handler of this `handle`");
1333 396 : WokNode *body = parse_body(p);
1334 396 : r = mk(p, E_HandleIn, start, span_end(p));
1335 396 : E_HandleIn_set_label(r, label);
1336 396 : E_HandleIn_set_handler(r, handler);
1337 396 : E_HandleIn_set_body(r, body);
1338 65084 : } else if (at_word(p, WW_USE)) {
1339 108 : bump(p);
1340 108 : WokSeq binds = parse_usebinds(p);
1341 108 : expect_word(p, WW_IN, "`in` after these bridges");
1342 108 : WokNode *body = parse_body(p);
1343 108 : r = mk(p, E_UseIn, start, span_end(p));
1344 108 : E_UseIn_set_binds(r, binds);
1345 108 : E_UseIn_set_body(r, body);
1346 64976 : } else if (at_word(p, WW_IF)) {
1347 576 : r = parse_if(p);
1348 64400 : } else if (at_word(p, WW_CASE)) {
1349 3100 : r = parse_case(p);
1350 61300 : } else if (at_word(p, WW_HANDLER)) {
1351 3461 : r = parse_handler(p);
1352 : } else {
1353 57839 : r = parse_chain(p);
1354 57839 : if (at(p, WT_ASSIGN)) {
1355 1447 : bump(p);
1356 1447 : WokNode *value = parse_body(p);
1357 1447 : WokNode *asn = mk(p, E_Assign, start, span_end(p));
1358 1447 : E_Assign_set_target(asn, r);
1359 1447 : E_Assign_set_value(asn, value);
1360 1447 : r = asn;
1361 : }
1362 : }
1363 66883 : leave(p);
1364 66883 : return r;
1365 : }
1366 :
1367 : // --------------------------------------------------------------- statements
1368 :
1369 3300 : static WokNode *parse_bind(P *p) {
1370 3300 : u32 start = cur(p)->off;
1371 3300 : WokNode *lhs;
1372 3300 : if (at(p, WT_VARID)) {
1373 2619 : const WokToken *t = cur(p);
1374 2619 : bump(p);
1375 2619 : WokNodeBuf args;
1376 2619 : wok_buf_init(&args, p->a);
1377 2632 : while (starts_atompat(p) && !p->panic)
1378 13 : wok_buf_push(&args, parse_atompat(p));
1379 2619 : lhs = mk(p, L_Prefix, start, span_end(p));
1380 2619 : L_Prefix_set_name(lhs, tok_span(t));
1381 2619 : L_Prefix_set_paren(lhs, false);
1382 2619 : L_Prefix_set_args(lhs, wok_buf_seq(&args));
1383 : } else {
1384 681 : lhs = parse_pat(p);
1385 : }
1386 3300 : expect(p, WT_EQUALS, "`=` in this binding");
1387 3300 : WokNode *body = parse_body(p);
1388 3300 : WokNode *n = mk(p, H_Bind, start, span_end(p));
1389 3300 : H_Bind_set_lhs(n, lhs);
1390 3300 : H_Bind_set_body(n, body);
1391 3300 : return n;
1392 : }
1393 :
1394 55792 : static WokNode *parse_stmt(P *p) {
1395 55792 : if (!enter(p)) return mk_err(p);
1396 55792 : u32 start = cur(p)->off;
1397 55792 : const WokToken *lead = cur(p);
1398 55792 : WokNode *r;
1399 55792 : if (at_word(p, WW_LET)) {
1400 3210 : bump(p);
1401 3210 : WokNode *bind = parse_bind(p);
1402 : // `in` is a continuation lead, so it arrives with no NEWLINE before it:
1403 : // after the binding, simply look at the current token.
1404 3210 : if (at_word(p, WW_IN)) {
1405 468 : bump(p);
1406 468 : WokNode *body = parse_body(p);
1407 468 : r = mk(p, E_LetIn, start, span_end(p));
1408 468 : E_LetIn_set_bind(r, bind);
1409 468 : E_LetIn_set_body(r, body);
1410 : } else {
1411 2742 : r = mk(p, S_Let, start, span_end(p));
1412 2742 : S_Let_set_bind(r, bind);
1413 : }
1414 52582 : } else if (at_word(p, WW_HANDLE)) {
1415 2935 : bump(p);
1416 2935 : WokSpan label = wok_span(start, 0);
1417 2935 : bool has_label = at_handle_label(p);
1418 2935 : if (has_label) {
1419 1437 : label = tok_span(cur(p));
1420 1437 : bump(p);
1421 1437 : bump(p);
1422 : }
1423 2935 : WokNode *handler = parse_expr(p);
1424 2935 : if (at_word(p, WW_IN)) {
1425 1622 : bump(p);
1426 1622 : WokNode *body = parse_body(p);
1427 1622 : r = mk(p, E_HandleIn, start, span_end(p));
1428 1622 : E_HandleIn_set_label(r, label);
1429 1622 : E_HandleIn_set_handler(r, handler);
1430 1622 : E_HandleIn_set_body(r, body);
1431 : } else {
1432 1313 : if (!has_label)
1433 141 : perr_form(p, WOK_E_HANDLE_LABEL, lead,
1434 : "a `handle` statement must name the label it binds: write "
1435 : "`handle <label> = <handler>`");
1436 1313 : r = mk(p, S_Handle, start, span_end(p));
1437 1313 : S_Handle_set_label(r, label);
1438 1313 : S_Handle_set_handler(r, handler);
1439 : }
1440 49647 : } else if (at_word(p, WW_USE)) {
1441 609 : bump(p);
1442 609 : WokSeq binds = parse_usebinds(p);
1443 609 : if (at_word(p, WW_IN)) {
1444 491 : bump(p);
1445 491 : WokNode *body = parse_body(p);
1446 491 : r = mk(p, E_UseIn, start, span_end(p));
1447 491 : E_UseIn_set_binds(r, binds);
1448 491 : E_UseIn_set_body(r, body);
1449 : } else {
1450 118 : r = mk(p, S_Use, start, span_end(p));
1451 118 : S_Use_set_binds(r, binds);
1452 : }
1453 49255 : } else if (at(p, WT_UNDERSCORE) && kind_at(p, 1) == WT_EQUALS) {
1454 217 : bump(p);
1455 217 : bump(p);
1456 217 : WokNode *body = parse_body(p);
1457 217 : r = mk(p, S_Discard, start, span_end(p));
1458 217 : S_Discard_set_body(r, body);
1459 : } else {
1460 48821 : r = parse_expr(p);
1461 : }
1462 55792 : leave(p);
1463 55792 : return r;
1464 : }
1465 :
1466 5690 : static WokNode *parse_alt(P *p) {
1467 5690 : u32 start = cur(p)->off;
1468 5690 : WokNode *pat = parse_pat(p);
1469 5690 : expect(p, WT_ARROW, "`->` after the pattern of this alternative");
1470 5690 : Block b = block_begin(p);
1471 5690 : WokNode *body = parse_block_body(p, &b);
1472 5690 : WokSeq wheres = wok_seq_empty();
1473 5690 : if (at_word(p, WW_WHERE)) wheres = parse_where(p);
1474 5690 : block_end(p, &b);
1475 5690 : WokNode *n = mk(p, H_Alt, start, span_end(p));
1476 5690 : H_Alt_set_pat(n, pat);
1477 5690 : H_Alt_set_body(n, body);
1478 5690 : H_Alt_set_wheres(n, wheres);
1479 5690 : return n;
1480 : }
1481 :
1482 : // ------------------------------------------------------------ handler clause
1483 : //
1484 : // spec-min section 3, in order, and it reads NOTHING but token kinds and
1485 : // words -- never a name, a type or a count:
1486 : //
1487 : // 1. `var` / `return` / `abort` at the head -> that kind
1488 : // 2. `once` at the head -> migration diagnostic
1489 : // 3. a `,` at clause-head depth before the `->` -> CONTROL, else PLAIN
1490 : // 4. exactly one bare lowercase varid after the `,` -> the continuation
1491 : //
1492 : // Step 3 needs no lookahead and no depth counter. Clause-head binders are
1493 : // ATOM patterns, and every atom pattern that can contain a comma is
1494 : // bracketed, so parse_atompat has already consumed it: a WT_COMMA still
1495 : // visible here is at head depth by construction.
1496 :
1497 : // The clause-head word set, stated ONCE, directly above the ladder that
1498 : // dispatches on it. parse_clause's branches and this predicate must agree
1499 : // forever: a word added to the ladder below without joining this set lets an
1500 : // effect declare an op spelled like it, and every clause for that op then
1501 : // silently parses as the new clause KIND instead of a call -- the
1502 : // parses-silently-and-wrong class. This set churned twice in one week
1503 : // (`once` demoted, `abort` added); adjacency is the guard.
1504 : //
1505 : // Used by parse_opsig for E-RESERVED: a clause naming one of these would be
1506 : // read as that kind of clause and never as a call. Three are keywords;
1507 : // `once` is an ordinary name everywhere else (D25) and would otherwise be
1508 : // accepted as an op name and then be unwritable as a clause.
1509 6592 : static bool at_reserved_opname(const P *p) {
1510 6592 : return at_word(p, WW_ABORT) || at_word(p, WW_RETURN) || at_word(p, WW_VAR) ||
1511 6589 : at_word(p, WW_ONCE);
1512 : }
1513 :
1514 6926 : static WokNode *parse_clause(P *p) {
1515 6926 : u32 start = cur(p)->off;
1516 6926 : u64 kind = WOK_CLAUSE_PLAIN;
1517 6926 : WokSpan name = wok_span(start, 0);
1518 6926 : WokSpan k = wok_span(start, 0);
1519 6926 : WokNodeBuf pats;
1520 6926 : wok_buf_init(&pats, p->a);
1521 6926 : WokNode *body = nullptr;
1522 :
1523 6926 : if (at_word(p, WW_VAR)) {
1524 1149 : bump(p);
1525 1149 : kind = WOK_CLAUSE_VAR;
1526 1149 : name = take_kind(p, WT_VARID, "the baton's name after `var`");
1527 1149 : expect(p, WT_EQUALS, "`=` after the baton's name");
1528 1149 : body = parse_body(p);
1529 5777 : } else if (at_word(p, WW_RETURN)) {
1530 1279 : bump(p);
1531 1279 : kind = WOK_CLAUSE_RETURN;
1532 1279 : wok_buf_push(&pats, parse_pat(p));
1533 1279 : expect(p, WT_ARROW, "`->` after the return clause's pattern");
1534 1279 : body = parse_body(p);
1535 : } else {
1536 : // `abort` is the third head keyword (D24). `once` is not a keyword at
1537 : // all any more (D25) -- it is a contextual name that means something
1538 : // only HERE, and only to say it should not be here.
1539 4498 : if (at_word(p, WW_ABORT)) {
1540 389 : bump(p);
1541 389 : kind = WOK_CLAUSE_ABORT;
1542 4109 : } else if (at_word(p, WW_ONCE)) {
1543 63 : perr_form(p, WOK_E_MIGRATE, cur(p),
1544 : "v1 clause keyword; drop it -- a control clause is spelled "
1545 : "`op args, k -> body` (D25)");
1546 63 : bump(p);
1547 : }
1548 4498 : name = take_kind(p, WT_VARID, "an operation name");
1549 7921 : while (starts_atompat(p) && !p->panic)
1550 3423 : wok_buf_push(&pats, parse_atompat(p));
1551 4498 : if (at(p, WT_COMMA)) {
1552 : // The comma ALONE classifies (D25), so an `abort` head that carries one
1553 : // is a contradiction the reader must be told about rather than a fourth
1554 : // reading to invent.
1555 1472 : if (kind == WOK_CLAUSE_ABORT)
1556 0 : perr_form(p, WOK_E_ARITY, cur(p),
1557 : "an `abort` clause never resumes, so it binds no "
1558 : "continuation: drop the `,` and the name after it");
1559 : else
1560 : kind = WOK_CLAUSE_CONTROL;
1561 1472 : bump(p);
1562 1472 : if (at(p, WT_VARID)) {
1563 : // The ABORT contradiction was reported at the comma; the binder is
1564 : // consumed for recovery but NOT stored, so the recovered node keeps
1565 : // wok_ast.h's invariant that `k` is empty for every non-control kind.
1566 1407 : if (kind != WOK_CLAUSE_ABORT) k = tok_span(cur(p));
1567 1407 : bump(p);
1568 : // C8: EXACTLY one name. A second binder is an argument written on
1569 : // the wrong side of the comma, which is an arity fault about the op,
1570 : // not about the continuation.
1571 1407 : if (starts_atompat(p) && !p->panic)
1572 64 : perr_form(p, WOK_E_ARITY, cur(p),
1573 : "a control clause binds exactly one continuation after "
1574 : "the `,`; the op's arguments go before it");
1575 65 : } else if (!p->panic) {
1576 65 : perr_form(p, WOK_E_ARITY, cur(p),
1577 : "the name after `,` is the continuation binder and must be "
1578 : "a plain lowercase name, never a pattern");
1579 : // The recovered node keeps wok_ast.h's invariant that a CONTROL
1580 : // clause has a continuation binder: no binder was stored, so the
1581 : // clause is demoted to the plain reading rather than left as a
1582 : // CONTROL with an empty `k` that would not re-print.
1583 65 : if (kind == WOK_CLAUSE_CONTROL) kind = WOK_CLAUSE_PLAIN;
1584 : }
1585 : // Whatever followed the comma, the arrow is still where the head ends,
1586 : // so a surplus binder is skipped rather than left to derail the body.
1587 1592 : while (starts_atompat(p) && !p->panic) (void)parse_atompat(p);
1588 : }
1589 4498 : expect(p, WT_ARROW, "`->` after the clause's patterns");
1590 4498 : body = parse_body(p);
1591 : }
1592 :
1593 6926 : WokNode *n = mk(p, H_Clause, start, span_end(p));
1594 6926 : H_Clause_set_kind(n, kind);
1595 6926 : H_Clause_set_name(n, name);
1596 6926 : H_Clause_set_pats(n, wok_buf_seq(&pats));
1597 6926 : H_Clause_set_k(n, k);
1598 6926 : H_Clause_set_body(n, body ? body : mk_err(p));
1599 6926 : return n;
1600 : }
1601 :
1602 : // -------------------------------------------------------------- declarations
1603 :
1604 6238 : static WokNode *parse_typaram(P *p) {
1605 6238 : u32 start = cur(p)->off;
1606 6238 : bool is_row = false;
1607 6238 : WokSpan name;
1608 6238 : if (at(p, WT_LPAREN)) {
1609 2038 : bump(p);
1610 2038 : expect_word(p, WW_ROW, "`row` inside this parameter");
1611 2038 : name = take_kind(p, WT_VARID, "a row-variable name");
1612 2038 : expect(p, WT_RPAREN, "`)` to close this row parameter");
1613 2038 : is_row = true;
1614 : } else {
1615 4200 : name = take_kind(p, WT_VARID, "a type parameter");
1616 : }
1617 6238 : WokNode *n = mk(p, H_TyParam, start, span_end(p));
1618 6238 : H_TyParam_set_name(n, name);
1619 6238 : H_TyParam_set_is_row(n, is_row);
1620 6238 : return n;
1621 : }
1622 :
1623 10219 : static WokSeq parse_typarams(P *p) {
1624 10219 : WokNodeBuf buf;
1625 10219 : wok_buf_init(&buf, p->a);
1626 16457 : while (starts_typaram(p) && !p->panic) wok_buf_push(&buf, parse_typaram(p));
1627 10219 : return wok_buf_seq(&buf);
1628 : }
1629 :
1630 3016 : static WokNode *parse_fieldtype(P *p) {
1631 3016 : u32 start = cur(p)->off;
1632 3016 : WokSpan name = take_kind(p, WT_VARID, "a field name");
1633 3016 : expect(p, WT_COLON, "`:` after the field name");
1634 3016 : WokNode *type = parse_type(p);
1635 3016 : WokNode *n = mk(p, H_FieldType, start, span_end(p));
1636 3016 : H_FieldType_set_name(n, name);
1637 3016 : H_FieldType_set_type(n, type);
1638 3016 : return n;
1639 : }
1640 :
1641 1643 : static WokSeq parse_fieldtypes(P *p) {
1642 1643 : bump(p); // `{`
1643 1643 : WokNodeBuf buf;
1644 1643 : wok_buf_init(&buf, p->a);
1645 1643 : if (!at(p, WT_RBRACE) && !p->panic) {
1646 1505 : wok_buf_push(&buf, parse_fieldtype(p));
1647 3016 : while (at(p, WT_COMMA) && !p->panic) {
1648 1511 : bump(p);
1649 1511 : wok_buf_push(&buf, parse_fieldtype(p));
1650 : }
1651 : }
1652 1643 : expect(p, WT_RBRACE, "`}` to close these fields");
1653 1643 : return wok_buf_seq(&buf);
1654 : }
1655 :
1656 5822 : static WokNode *parse_condef(P *p) {
1657 5822 : u32 start = cur(p)->off;
1658 5822 : WokSpan name = wok_span(start, 0);
1659 5822 : WokSeq args = wok_seq_empty();
1660 5822 : WokSeq fields = wok_seq_empty();
1661 5822 : bool is_record = false;
1662 5822 : if (at(p, WT_LBRACE)) {
1663 : // The elided record form: `type Wrapped = { value : U64 }`.
1664 657 : fields = parse_fieldtypes(p);
1665 657 : is_record = true;
1666 : } else {
1667 5165 : name = take_kind(p, WT_CONID, "a constructor name");
1668 5165 : if (at(p, WT_LBRACE)) {
1669 986 : fields = parse_fieldtypes(p);
1670 986 : is_record = true;
1671 : } else {
1672 4179 : WokNodeBuf buf;
1673 4179 : wok_buf_init(&buf, p->a);
1674 6590 : while (starts_atomtype(p) && !p->panic)
1675 2411 : wok_buf_push(&buf, parse_atomtype(p));
1676 4179 : args = wok_buf_seq(&buf);
1677 : }
1678 : }
1679 5822 : WokNode *n = mk(p, H_ConDef, start, span_end(p));
1680 5822 : H_ConDef_set_name(n, name);
1681 5822 : H_ConDef_set_args(n, args);
1682 5822 : H_ConDef_set_fields(n, fields);
1683 5822 : H_ConDef_set_is_record(n, is_record);
1684 5822 : return n;
1685 : }
1686 :
1687 22436 : static WokNode *parse_signame(P *p) {
1688 22436 : u32 start = cur(p)->off;
1689 22436 : bool paren = false;
1690 22436 : WokSpan name;
1691 22436 : if (at(p, WT_LPAREN)) {
1692 1780 : bump(p);
1693 1780 : name = take_kind(p, WT_VARSYM, "an operator name");
1694 1780 : expect(p, WT_RPAREN, "`)` after the operator name");
1695 1780 : paren = true;
1696 : } else {
1697 20656 : name = take_kind(p, WT_VARID, "a name being declared");
1698 : }
1699 22436 : WokNode *n = mk(p, H_SigName, start, span_end(p));
1700 22436 : H_SigName_set_name(n, name);
1701 22436 : H_SigName_set_paren(n, paren);
1702 22436 : return n;
1703 : }
1704 :
1705 20526 : static WokNode *parse_sig(P *p, bool is_extern, u32 start) {
1706 20526 : WokNodeBuf names;
1707 20526 : wok_buf_init(&names, p->a);
1708 20526 : wok_buf_push(&names, parse_signame(p));
1709 22436 : while (at(p, WT_COMMA) && !p->panic) {
1710 1910 : bump(p);
1711 1910 : wok_buf_push(&names, parse_signame(p));
1712 : }
1713 20526 : expect(p, WT_COLON, "`:` between the names and their type");
1714 20526 : WokNode *type = parse_type(p);
1715 20526 : WokNode *n = mk(p, D_Sig, start, span_end(p));
1716 20526 : D_Sig_set_names(n, wok_buf_seq(&names));
1717 20526 : D_Sig_set_type(n, type);
1718 20526 : D_Sig_set_is_extern(n, is_extern);
1719 20526 : return n;
1720 : }
1721 :
1722 26887 : static WokNode *parse_lhs(P *p) {
1723 26887 : u32 start = cur(p)->off;
1724 26887 : bool paren = at(p, WT_LPAREN) && kind_at(p, 1) == WT_VARSYM &&
1725 793 : kind_at(p, 2) == WT_RPAREN;
1726 26887 : bool prefix = at(p, WT_VARID) && kind_at(p, 1) != WT_VARSYM &&
1727 : kind_at(p, 1) != WT_BACKTICK;
1728 26887 : if (paren || prefix) {
1729 19776 : WokSpan name;
1730 19776 : if (paren) {
1731 634 : bump(p);
1732 634 : name = tok_span(cur(p));
1733 634 : bump(p);
1734 634 : bump(p);
1735 : } else {
1736 19142 : name = tok_span(cur(p));
1737 19142 : bump(p);
1738 : }
1739 19776 : WokNodeBuf args;
1740 19776 : wok_buf_init(&args, p->a);
1741 29522 : while (starts_atompat(p) && !p->panic)
1742 9746 : wok_buf_push(&args, parse_atompat(p));
1743 19776 : WokNode *n = mk(p, L_Prefix, start, span_end(p));
1744 19776 : L_Prefix_set_name(n, name);
1745 19776 : L_Prefix_set_paren(n, paren);
1746 19776 : L_Prefix_set_args(n, wok_buf_seq(&args));
1747 19776 : return n;
1748 : }
1749 7111 : WokNode *left = parse_atompat(p);
1750 7111 : WokSpan op = wok_span(cur(p)->off, 0);
1751 7111 : bool backtick = false;
1752 7111 : if (at(p, WT_BACKTICK)) {
1753 743 : bump(p);
1754 743 : op = tok_span(cur(p));
1755 743 : backtick = true;
1756 743 : bump(p);
1757 743 : expect(p, WT_BACKTICK, "a closing backtick");
1758 6368 : } else if (at(p, WT_VARSYM)) {
1759 2639 : op = tok_span(cur(p));
1760 2639 : bump(p);
1761 : } else {
1762 3729 : perr_expect(p, "an infix operator in this left-hand side");
1763 : }
1764 7111 : WokNode *right = parse_atompat(p);
1765 7111 : WokNode *n = mk(p, L_Infix, start, span_end(p));
1766 7111 : L_Infix_set_left(n, left);
1767 7111 : L_Infix_set_op(n, op);
1768 7111 : L_Infix_set_backtick(n, backtick);
1769 7111 : L_Infix_set_right(n, right);
1770 7111 : return n;
1771 : }
1772 :
1773 26887 : static WokNode *parse_equation(P *p) {
1774 26887 : u32 start = cur(p)->off;
1775 26887 : WokNode *lhs = parse_lhs(p);
1776 26887 : expect(p, WT_EQUALS, "`=` after the left-hand side");
1777 26887 : Block b = block_begin(p);
1778 26887 : WokNode *body = parse_block_body(p, &b);
1779 : // `where` is a continuation lead, so it arrives inside the body's block
1780 : // region with no separator before it.
1781 26887 : WokSeq wheres = wok_seq_empty();
1782 26887 : if (at_word(p, WW_WHERE)) wheres = parse_where(p);
1783 26887 : block_end(p, &b);
1784 26887 : WokNode *n = mk(p, D_Equation, start, span_end(p));
1785 26887 : D_Equation_set_lhs(n, lhs);
1786 26887 : D_Equation_set_body(n, body);
1787 26887 : D_Equation_set_wheres(n, wheres);
1788 26887 : return n;
1789 : }
1790 :
1791 : // `:` before `=` at bracket depth zero is the only thing that separates a
1792 : // signature from an equation, and forward-only declarations (D23) guarantee
1793 : // one of the two appears on the item's first logical line.
1794 46867 : static bool item_is_sig(const P *p) {
1795 46867 : int br = 0;
1796 352553 : for (usize j = p->i; j < p->n; j++) {
1797 351620 : WokKind k = (WokKind)p->tok[j].kind;
1798 351620 : if (br == 0) {
1799 229207 : if (k == WT_NEWLINE || k == WT_INDENT || k == WT_DEDENT || k == WT_EOF)
1800 : return false;
1801 224354 : if (k == WT_COLON) return true;
1802 204374 : if (k == WT_EQUALS) return false;
1803 : }
1804 305686 : if (wok_kind_is_open_bracket(k))
1805 10129 : br++;
1806 314164 : else if (wok_kind_is_close_bracket(k) && br > 0)
1807 8478 : br--;
1808 : }
1809 : return false;
1810 : }
1811 :
1812 46867 : static WokNode *parse_sig_or_equation(P *p) {
1813 46867 : u32 start = cur(p)->off;
1814 46867 : if (item_is_sig(p)) return parse_sig(p, false, start);
1815 26887 : return parse_equation(p);
1816 : }
1817 :
1818 6466 : static WokNode *parse_module_decl(P *p) {
1819 6466 : u32 start = cur(p)->off;
1820 6466 : bump(p);
1821 6466 : WokNode *path = parse_modpath(p);
1822 6466 : WokNode *n = mk(p, D_Module, start, span_end(p));
1823 6466 : D_Module_set_path(n, path);
1824 6466 : return n;
1825 : }
1826 :
1827 5911 : static WokNode *parse_import_decl(P *p) {
1828 5911 : u32 start = cur(p)->off;
1829 5911 : bump(p);
1830 5911 : WokNode *path = parse_modpath(p);
1831 5911 : WokNodeBuf names;
1832 5911 : wok_buf_init(&names, p->a);
1833 5911 : if (at(p, WT_LPAREN)) {
1834 715 : bump(p);
1835 715 : if (!at(p, WT_RPAREN) && !p->panic) {
1836 713 : wok_buf_push(&names, parse_name(p));
1837 1151 : while (at(p, WT_COMMA) && !p->panic) {
1838 438 : bump(p);
1839 438 : wok_buf_push(&names, parse_name(p));
1840 : }
1841 : }
1842 715 : expect(p, WT_RPAREN, "`)` to close the import list");
1843 : }
1844 5911 : WokNode *alias = nullptr;
1845 5911 : if (at_word(p, WW_AS)) {
1846 689 : bump(p);
1847 689 : alias = parse_name(p);
1848 : }
1849 5911 : WokNode *n = mk(p, D_Import, start, span_end(p));
1850 5911 : D_Import_set_path(n, path);
1851 5911 : D_Import_set_names(n, wok_buf_seq(&names));
1852 5911 : D_Import_set_alias(n, alias);
1853 5911 : return n;
1854 : }
1855 :
1856 2893 : static WokNode *parse_type_decl(P *p) {
1857 2893 : u32 start = cur(p)->off;
1858 2893 : bump(p);
1859 2893 : WokSpan name = take_kind(p, WT_CONID, "a type name");
1860 2893 : WokSeq params = parse_typarams(p);
1861 2893 : expect(p, WT_EQUALS, "`=` before the constructors");
1862 2893 : WokNodeBuf cons;
1863 2893 : wok_buf_init(&cons, p->a);
1864 2893 : wok_buf_push(&cons, parse_condef(p));
1865 5822 : while (at(p, WT_BAR) && !p->panic) {
1866 2929 : bump(p);
1867 2929 : wok_buf_push(&cons, parse_condef(p));
1868 : }
1869 2893 : WokNode *n = mk(p, D_Type, start, span_end(p));
1870 2893 : D_Type_set_name(n, name);
1871 2893 : D_Type_set_params(n, params);
1872 2893 : D_Type_set_cons(n, wok_buf_seq(&cons));
1873 2893 : return n;
1874 : }
1875 :
1876 985 : static WokNode *parse_alias_decl(P *p) {
1877 985 : u32 start = cur(p)->off;
1878 985 : bump(p);
1879 985 : WokSpan name = take_kind(p, WT_CONID, "an alias name");
1880 985 : WokSeq params = parse_typarams(p);
1881 985 : expect(p, WT_EQUALS, "`=` before the aliased type");
1882 985 : WokNode *body = parse_type(p);
1883 985 : WokNode *n = mk(p, D_Alias, start, span_end(p));
1884 985 : D_Alias_set_name(n, name);
1885 985 : D_Alias_set_params(n, params);
1886 985 : D_Alias_set_body(n, body);
1887 985 : return n;
1888 : }
1889 :
1890 6592 : static WokNode *parse_opsig(P *p) {
1891 6592 : u32 start = cur(p)->off;
1892 6592 : if (at_reserved_opname(p)) {
1893 4 : const WokToken *t = cur(p);
1894 : // perr_form's body, with the word quoted in: naming it is the whole
1895 : // message, and quoting text into a diagnostic is the one thing the parser
1896 : // may do with a token's bytes.
1897 4 : if (!p->panic)
1898 4 : wok_diag_add(p->d, WOK_E_RESERVED, t->off, t->len,
1899 : "`%.*s` heads a clause, so an operation cannot be called "
1900 : "that",
1901 4 : (int)t->len, p->src + t->off);
1902 4 : bump(p);
1903 4 : expect(p, WT_COLON, "`:` after the operation name");
1904 4 : WokNode *ty = parse_type(p);
1905 4 : WokNode *bad = mk(p, H_OpSig, start, span_end(p));
1906 4 : H_OpSig_set_name(bad, tok_span(t));
1907 4 : H_OpSig_set_type(bad, ty);
1908 4 : return bad;
1909 : }
1910 6588 : WokSpan name = take_kind(p, WT_VARID, "an operation name");
1911 6588 : expect(p, WT_COLON, "`:` after the operation name");
1912 6588 : WokNode *type = parse_type(p);
1913 6588 : WokNode *n = mk(p, H_OpSig, start, span_end(p));
1914 6588 : H_OpSig_set_name(n, name);
1915 6588 : H_OpSig_set_type(n, type);
1916 6588 : return n;
1917 : }
1918 :
1919 4557 : static WokNode *parse_effect_decl(P *p) {
1920 4557 : u32 start = cur(p)->off;
1921 4557 : bump(p);
1922 4557 : WokSpan name = take_kind(p, WT_CONID, "an effect name");
1923 4557 : WokSeq params = parse_typarams(p);
1924 4557 : Block b = block_begin(p);
1925 4557 : WokSeq ops = parse_block_list(p, &b, parse_opsig, true);
1926 4557 : block_end(p, &b);
1927 4557 : WokNode *n = mk(p, D_Effect, start, span_end(p));
1928 4557 : D_Effect_set_name(n, name);
1929 4557 : D_Effect_set_params(n, params);
1930 4557 : D_Effect_set_ops(n, ops);
1931 4557 : return n;
1932 : }
1933 :
1934 900 : static WokNode *parse_class_decl(P *p) {
1935 900 : u32 start = cur(p)->off;
1936 900 : bump(p);
1937 900 : WokSpan name = take_kind(p, WT_CONID, "a class name");
1938 900 : WokSeq params = parse_typarams(p);
1939 900 : Block b = block_begin(p);
1940 900 : WokSeq body = parse_block_list(p, &b, parse_sig_or_equation, true);
1941 900 : block_end(p, &b);
1942 900 : WokNode *n = mk(p, D_Class, start, span_end(p));
1943 900 : D_Class_set_name(n, name);
1944 900 : D_Class_set_params(n, params);
1945 900 : D_Class_set_body(n, body);
1946 900 : return n;
1947 : }
1948 :
1949 994 : static WokNode *parse_instance_decl(P *p) {
1950 994 : u32 start = cur(p)->off;
1951 994 : bump(p);
1952 994 : WokNode *ctx = nullptr;
1953 994 : if (at(p, WT_LPAREN)) {
1954 593 : bump(p);
1955 593 : ctx = parse_type(p);
1956 593 : expect(p, WT_RPAREN, "`)` to close the instance context");
1957 593 : expect(p, WT_FATARROW, "`=>` after the instance context");
1958 : }
1959 994 : WokSpan name = take_kind(p, WT_CONID, "a class name");
1960 994 : WokNodeBuf args;
1961 994 : wok_buf_init(&args, p->a);
1962 1978 : while (starts_atomtype(p) && !p->panic)
1963 984 : wok_buf_push(&args, parse_atomtype(p));
1964 994 : Block b = block_begin(p);
1965 994 : WokSeq body = parse_block_list(p, &b, parse_sig_or_equation, true);
1966 994 : block_end(p, &b);
1967 994 : WokNode *n = mk(p, D_Instance, start, span_end(p));
1968 994 : D_Instance_set_ctx(n, ctx);
1969 994 : D_Instance_set_name(n, name);
1970 994 : D_Instance_set_args(n, wok_buf_seq(&args));
1971 994 : D_Instance_set_body(n, body);
1972 994 : return n;
1973 : }
1974 :
1975 1806 : static WokNode *parse_foreign_member(P *p) {
1976 1806 : u32 start = cur(p)->off;
1977 1806 : WokSpan name = take_kind(p, WT_VARID, "a foreign member name");
1978 1806 : WokSpan symbol = wok_span(start, 0);
1979 1806 : if (at(p, WT_STRING)) {
1980 1139 : symbol = tok_span(cur(p));
1981 1139 : bump(p);
1982 : }
1983 1806 : expect(p, WT_COLON, "`:` after the foreign member name");
1984 1806 : bool saved = p->foreign_sig;
1985 1806 : p->foreign_sig = true;
1986 1806 : WokNode *type = parse_type(p);
1987 1806 : p->foreign_sig = saved;
1988 1806 : WokNode *n = mk(p, H_ForeignMember, start, span_end(p));
1989 1806 : H_ForeignMember_set_name(n, name);
1990 1806 : H_ForeignMember_set_symbol(n, symbol);
1991 1806 : H_ForeignMember_set_type(n, type);
1992 1806 : return n;
1993 : }
1994 :
1995 873 : static WokNode *parse_foreign_decl(P *p) {
1996 873 : u32 start = cur(p)->off;
1997 873 : bump(p); // `foreign`
1998 873 : expect_word(p, WW_MODULE, "`module` after `foreign`");
1999 873 : WokSpan name = take_kind(p, WT_CONID, "the foreign module's name");
2000 873 : WokSpan lib = take_kind(p, WT_STRING, "the library name as a string");
2001 873 : Block b = block_begin(p);
2002 873 : WokSeq members = parse_block_list(p, &b, parse_foreign_member, true);
2003 873 : block_end(p, &b);
2004 873 : WokNode *n = mk(p, D_Foreign, start, span_end(p));
2005 873 : D_Foreign_set_name(n, name);
2006 873 : D_Foreign_set_lib(n, lib);
2007 873 : D_Foreign_set_members(n, members);
2008 873 : return n;
2009 : }
2010 :
2011 : // `fixity + left tighter than *`
2012 : //
2013 : // An operator is named by a SYMBOL RUN (`+`) or by a bare identifier meant to
2014 : // be used infix in backticks (`div`); `alpha` records which, because they are
2015 : // different names that their text alone does not always tell apart.
2016 : //
2017 : // The associativity word is REQUIRED -- there is no `none` tier. An operator
2018 : // that has been declared at all has an answer for ties against itself, which
2019 : // is what lets the reassociator resolve a run of one operator without ever
2020 : // consulting the order.
2021 4353 : static bool take_fix_name(P *p, WokSpan *out, bool *alpha) {
2022 4353 : if (at(p, WT_VARSYM) || at(p, WT_VARID)) {
2023 4351 : *alpha = at(p, WT_VARID);
2024 4351 : *out = tok_span(cur(p));
2025 4351 : bump(p);
2026 4351 : return true;
2027 : }
2028 2 : perr_expect(p, "an operator: a symbol run like `+`, or a name used infix");
2029 2 : *out = wok_span(cur(p)->off, 0);
2030 2 : *alpha = false;
2031 2 : return false;
2032 : }
2033 :
2034 2094 : static WokNode *parse_fixrel(P *p) {
2035 2094 : u32 start = cur(p)->off;
2036 2094 : u64 sense = WOK_FIXREL_TIGHTER;
2037 2094 : if (at_word(p, WW_LOOSER)) {
2038 1048 : sense = WOK_FIXREL_LOOSER;
2039 1048 : bump(p);
2040 : } else {
2041 1046 : expect_word(p, WW_TIGHTER, "`tighter` or `looser`");
2042 : }
2043 2094 : expect_word(p, WW_THAN, "`than` after `tighter` or `looser`");
2044 2094 : WokSpan name = wok_span(cur(p)->off, 0);
2045 2094 : bool alpha = false;
2046 2094 : (void)take_fix_name(p, &name, &alpha);
2047 2094 : WokNode *n = mk(p, H_FixRel, start, span_end(p));
2048 2094 : H_FixRel_set_sense(n, sense);
2049 2094 : H_FixRel_set_name(n, name);
2050 2094 : H_FixRel_set_alpha(n, alpha);
2051 2094 : return n;
2052 : }
2053 :
2054 2259 : static WokNode *parse_fixity_decl(P *p) {
2055 2259 : u32 start = cur(p)->off;
2056 2259 : bump(p); // `fixity`
2057 2259 : WokSpan name = wok_span(cur(p)->off, 0);
2058 2259 : bool alpha = false;
2059 2259 : (void)take_fix_name(p, &name, &alpha);
2060 2259 : u64 assoc = WOK_ASSOC_LEFT;
2061 2259 : if (at_word(p, WW_RIGHT)) {
2062 894 : assoc = WOK_ASSOC_RIGHT;
2063 894 : bump(p);
2064 : } else {
2065 1365 : expect_word(p, WW_LEFT, "`left` or `right`, the operator's associativity");
2066 : }
2067 2259 : WokNodeBuf rels;
2068 2259 : wok_buf_init(&rels, p->a);
2069 4353 : while ((at_word(p, WW_TIGHTER) || at_word(p, WW_LOOSER)) && !p->panic)
2070 2094 : wok_buf_push(&rels, parse_fixrel(p));
2071 2259 : WokNode *n = mk(p, D_Fixity, start, span_end(p));
2072 2259 : D_Fixity_set_name(n, name);
2073 2259 : D_Fixity_set_alpha(n, alpha);
2074 2259 : D_Fixity_set_assoc(n, assoc);
2075 2259 : D_Fixity_set_rels(n, wok_buf_seq(&rels));
2076 2259 : return n;
2077 : }
2078 :
2079 1430 : static WokNode *parse_extern_decl(P *p) {
2080 1430 : u32 start = cur(p)->off;
2081 1430 : bump(p); // `extern`
2082 1430 : if (at_word(p, WW_TYPE)) {
2083 884 : bump(p);
2084 884 : WokSpan name = take_kind(p, WT_CONID, "a type name");
2085 884 : WokSeq params = parse_typarams(p);
2086 884 : WokNode *n = mk(p, D_ExternType, start, span_end(p));
2087 884 : D_ExternType_set_name(n, name);
2088 884 : D_ExternType_set_params(n, params);
2089 884 : return n;
2090 : }
2091 : // `extern` marks a compiler hole: analyses trust the MARKER, never a name.
2092 546 : return parse_sig(p, true, start);
2093 : }
2094 :
2095 66513 : static WokNode *parse_decl(P *p) {
2096 66513 : if (!enter(p)) return mk_error(p, D_Error, cur(p)->off);
2097 66513 : WokNode *r;
2098 66513 : if (at(p, WT_KEYWORD)) {
2099 : // The `default:` here is a real grammar case, not a silenced enumerator:
2100 : // `let`, `then` and `where` are keywords that legitimately reach this and
2101 : // legitimately do not begin a declaration. The -Wswitch ban on `default:`
2102 : // is about traversals, where it would hide a missing node kind.
2103 27384 : switch ((WokWord)cur(p)->word) {
2104 : #define WOK_X(word, fn) \
2105 : case word: \
2106 : r = fn(p); \
2107 : break;
2108 27268 : WOK_DECL_WORDS(WOK_X)
2109 : #undef WOK_X
2110 116 : default:
2111 116 : perr_expect(p, "a declaration");
2112 116 : r = mk_error(p, D_Error, cur(p)->off);
2113 116 : break;
2114 : }
2115 : } else {
2116 39129 : r = parse_sig_or_equation(p);
2117 : }
2118 66513 : leave(p);
2119 66513 : return r;
2120 : }
2121 :
2122 : // ---------------------------------------------------------------- the file
2123 :
2124 20183 : static WokNode *parse_file(P *p) {
2125 20183 : WokNodeBuf decls;
2126 20183 : wok_buf_init(&decls, p->a);
2127 86973 : while (!at(p, WT_EOF)) {
2128 66790 : if (at(p, WT_NEWLINE) || at(p, WT_DEDENT)) {
2129 277 : bump(p);
2130 277 : continue;
2131 : }
2132 66513 : usize before = p->i;
2133 66513 : u32 start = cur(p)->off;
2134 66513 : WokNode *decl = parse_decl(p);
2135 66513 : if (p->panic) {
2136 8479 : resync_decl(p);
2137 8479 : decl = mk_error(p, D_Error, start);
2138 8479 : p->panic = false;
2139 : }
2140 66513 : wok_buf_push(&decls, decl);
2141 66513 : if (p->sep) {
2142 16479 : p->sep = false;
2143 50034 : } else if (at(p, WT_NEWLINE)) {
2144 47845 : bump(p);
2145 2189 : } else if (!at(p, WT_EOF)) {
2146 917 : perr_expect(p, "the end of this declaration");
2147 917 : resync_decl(p);
2148 917 : p->panic = false;
2149 917 : p->sep = false;
2150 917 : if (at(p, WT_NEWLINE)) bump(p);
2151 : }
2152 66513 : if (p->i == before && !at(p, WT_EOF)) bump(p);
2153 : }
2154 20183 : WokNode *n = mk(p, W_File, 0, span_end(p));
2155 20183 : W_File_set_decls(n, wok_buf_seq(&decls));
2156 20183 : return n;
2157 : }
2158 :
2159 20183 : WokNode *wok_parse(WokTokens tokens, const char *src, WokArena *arena,
2160 : WokDiagSink *diag) {
2161 20183 : P p = {.tok = tokens.tok,
2162 20183 : .n = tokens.n,
2163 : .i = 0,
2164 : .src = src,
2165 : .a = arena,
2166 : .d = diag};
2167 20183 : return parse_file(&p);
2168 : }
2169 :
2170 20179 : WokNode *wok_parse_source(const char *src, usize src_len, WokArena *arena,
2171 : WokDiagSink *diag) {
2172 20179 : WokScanResult scanned = wok_scan(src, src_len, arena, diag);
2173 20179 : WokTokens laid_out = wok_layout(scanned.tokens, arena, diag);
2174 20179 : WokNode *file = wok_parse(laid_out, src, arena, diag);
2175 : // The comments the scanner set aside become trivia here, and nowhere else:
2176 : // a tree that never went through this entry point simply has none.
2177 20179 : (void)wok_trivia_attach(file, src, src_len, scanned.comments,
2178 : scanned.ncomments, arena);
2179 20179 : return file;
2180 : }
|